162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * HD-audio codec driver binding
462306a36Sopenharmony_ci * Copyright (c) Takashi Iwai <tiwai@suse.de>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/init.h>
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/mutex.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/export.h>
1262306a36Sopenharmony_ci#include <linux/pm.h>
1362306a36Sopenharmony_ci#include <sound/core.h>
1462306a36Sopenharmony_ci#include <sound/hda_codec.h>
1562306a36Sopenharmony_ci#include "hda_local.h"
1662306a36Sopenharmony_ci#include "hda_jack.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * find a matching codec id
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cistatic int hda_codec_match(struct hdac_device *dev, struct hdac_driver *drv)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
2462306a36Sopenharmony_ci	struct hda_codec_driver *driver =
2562306a36Sopenharmony_ci		container_of(drv, struct hda_codec_driver, core);
2662306a36Sopenharmony_ci	const struct hda_device_id *list;
2762306a36Sopenharmony_ci	/* check probe_id instead of vendor_id if set */
2862306a36Sopenharmony_ci	u32 id = codec->probe_id ? codec->probe_id : codec->core.vendor_id;
2962306a36Sopenharmony_ci	u32 rev_id = codec->core.revision_id;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	for (list = driver->id; list->vendor_id; list++) {
3262306a36Sopenharmony_ci		if (list->vendor_id == id &&
3362306a36Sopenharmony_ci		    (!list->rev_id || list->rev_id == rev_id)) {
3462306a36Sopenharmony_ci			codec->preset = list;
3562306a36Sopenharmony_ci			return 1;
3662306a36Sopenharmony_ci		}
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci	return 0;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* process an unsolicited event */
4262306a36Sopenharmony_cistatic void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct hda_codec *codec = container_of(dev, struct hda_codec, core);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* ignore unsol events during shutdown */
4762306a36Sopenharmony_ci	if (codec->bus->shutdown)
4862306a36Sopenharmony_ci		return;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* ignore unsol events during system suspend/resume */
5162306a36Sopenharmony_ci	if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
5262306a36Sopenharmony_ci		return;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (codec->patch_ops.unsol_event)
5562306a36Sopenharmony_ci		codec->patch_ops.unsol_event(codec, ev);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * snd_hda_codec_set_name - set the codec name
6062306a36Sopenharmony_ci * @codec: the HDA codec
6162306a36Sopenharmony_ci * @name: name string to set
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_ciint snd_hda_codec_set_name(struct hda_codec *codec, const char *name)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	int err;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (!name)
6862306a36Sopenharmony_ci		return 0;
6962306a36Sopenharmony_ci	err = snd_hdac_device_set_chip_name(&codec->core, name);
7062306a36Sopenharmony_ci	if (err < 0)
7162306a36Sopenharmony_ci		return err;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* update the mixer name */
7462306a36Sopenharmony_ci	if (!*codec->card->mixername ||
7562306a36Sopenharmony_ci	    codec->bus->mixer_assigned >= codec->core.addr) {
7662306a36Sopenharmony_ci		snprintf(codec->card->mixername,
7762306a36Sopenharmony_ci			 sizeof(codec->card->mixername), "%s %s",
7862306a36Sopenharmony_ci			 codec->core.vendor_name, codec->core.chip_name);
7962306a36Sopenharmony_ci		codec->bus->mixer_assigned = codec->core.addr;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_set_name);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int hda_codec_driver_probe(struct device *dev)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
8962306a36Sopenharmony_ci	struct module *owner = dev->driver->owner;
9062306a36Sopenharmony_ci	hda_codec_patch_t patch;
9162306a36Sopenharmony_ci	int err;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (codec->bus->core.ext_ops) {
9462306a36Sopenharmony_ci		if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
9562306a36Sopenharmony_ci			return -EINVAL;
9662306a36Sopenharmony_ci		return codec->bus->core.ext_ops->hdev_attach(&codec->core);
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (WARN_ON(!codec->preset))
10062306a36Sopenharmony_ci		return -EINVAL;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	err = snd_hda_codec_set_name(codec, codec->preset->name);
10362306a36Sopenharmony_ci	if (err < 0)
10462306a36Sopenharmony_ci		goto error;
10562306a36Sopenharmony_ci	err = snd_hdac_regmap_init(&codec->core);
10662306a36Sopenharmony_ci	if (err < 0)
10762306a36Sopenharmony_ci		goto error;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!try_module_get(owner)) {
11062306a36Sopenharmony_ci		err = -EINVAL;
11162306a36Sopenharmony_ci		goto error;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	patch = (hda_codec_patch_t)codec->preset->driver_data;
11562306a36Sopenharmony_ci	if (patch) {
11662306a36Sopenharmony_ci		err = patch(codec);
11762306a36Sopenharmony_ci		if (err < 0)
11862306a36Sopenharmony_ci			goto error_module_put;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	err = snd_hda_codec_build_pcms(codec);
12262306a36Sopenharmony_ci	if (err < 0)
12362306a36Sopenharmony_ci		goto error_module;
12462306a36Sopenharmony_ci	err = snd_hda_codec_build_controls(codec);
12562306a36Sopenharmony_ci	if (err < 0)
12662306a36Sopenharmony_ci		goto error_module;
12762306a36Sopenharmony_ci	/* only register after the bus probe finished; otherwise it's racy */
12862306a36Sopenharmony_ci	if (!codec->bus->bus_probing && codec->card->registered) {
12962306a36Sopenharmony_ci		err = snd_card_register(codec->card);
13062306a36Sopenharmony_ci		if (err < 0)
13162306a36Sopenharmony_ci			goto error_module;
13262306a36Sopenharmony_ci		snd_hda_codec_register(codec);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	codec->core.lazy_cache = true;
13662306a36Sopenharmony_ci	return 0;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci error_module:
13962306a36Sopenharmony_ci	if (codec->patch_ops.free)
14062306a36Sopenharmony_ci		codec->patch_ops.free(codec);
14162306a36Sopenharmony_ci error_module_put:
14262306a36Sopenharmony_ci	module_put(owner);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci error:
14562306a36Sopenharmony_ci	snd_hda_codec_cleanup_for_unbind(codec);
14662306a36Sopenharmony_ci	codec->preset = NULL;
14762306a36Sopenharmony_ci	return err;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int hda_codec_driver_remove(struct device *dev)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct hda_codec *codec = dev_to_hda_codec(dev);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (codec->bus->core.ext_ops) {
15562306a36Sopenharmony_ci		if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
15662306a36Sopenharmony_ci			return -EINVAL;
15762306a36Sopenharmony_ci		return codec->bus->core.ext_ops->hdev_detach(&codec->core);
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	snd_hda_codec_disconnect_pcms(codec);
16162306a36Sopenharmony_ci	snd_hda_jack_tbl_disconnect(codec);
16262306a36Sopenharmony_ci	if (!refcount_dec_and_test(&codec->pcm_ref))
16362306a36Sopenharmony_ci		wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
16462306a36Sopenharmony_ci	snd_power_sync_ref(codec->bus->card);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (codec->patch_ops.free)
16762306a36Sopenharmony_ci		codec->patch_ops.free(codec);
16862306a36Sopenharmony_ci	snd_hda_codec_cleanup_for_unbind(codec);
16962306a36Sopenharmony_ci	codec->preset = NULL;
17062306a36Sopenharmony_ci	module_put(dev->driver->owner);
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistatic void hda_codec_driver_shutdown(struct device *dev)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	snd_hda_codec_shutdown(dev_to_hda_codec(dev));
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciint __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
18062306a36Sopenharmony_ci			       struct module *owner)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	drv->core.driver.name = name;
18362306a36Sopenharmony_ci	drv->core.driver.owner = owner;
18462306a36Sopenharmony_ci	drv->core.driver.bus = &snd_hda_bus_type;
18562306a36Sopenharmony_ci	drv->core.driver.probe = hda_codec_driver_probe;
18662306a36Sopenharmony_ci	drv->core.driver.remove = hda_codec_driver_remove;
18762306a36Sopenharmony_ci	drv->core.driver.shutdown = hda_codec_driver_shutdown;
18862306a36Sopenharmony_ci	drv->core.driver.pm = &hda_codec_driver_pm;
18962306a36Sopenharmony_ci	drv->core.type = HDA_DEV_LEGACY;
19062306a36Sopenharmony_ci	drv->core.match = hda_codec_match;
19162306a36Sopenharmony_ci	drv->core.unsol_event = hda_codec_unsol_event;
19262306a36Sopenharmony_ci	return driver_register(&drv->core.driver);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__hda_codec_driver_register);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_civoid hda_codec_driver_unregister(struct hda_codec_driver *drv)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	driver_unregister(&drv->core.driver);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(hda_codec_driver_unregister);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic inline bool codec_probed(struct hda_codec *codec)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	return device_attach(hda_codec_dev(codec)) > 0 && codec->preset;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* try to auto-load codec module */
20862306a36Sopenharmony_cistatic void request_codec_module(struct hda_codec *codec)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci#ifdef MODULE
21162306a36Sopenharmony_ci	char modalias[32];
21262306a36Sopenharmony_ci	const char *mod = NULL;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	switch (codec->probe_id) {
21562306a36Sopenharmony_ci	case HDA_CODEC_ID_GENERIC_HDMI:
21662306a36Sopenharmony_ci#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
21762306a36Sopenharmony_ci		mod = "snd-hda-codec-hdmi";
21862306a36Sopenharmony_ci#endif
21962306a36Sopenharmony_ci		break;
22062306a36Sopenharmony_ci	case HDA_CODEC_ID_GENERIC:
22162306a36Sopenharmony_ci#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
22262306a36Sopenharmony_ci		mod = "snd-hda-codec-generic";
22362306a36Sopenharmony_ci#endif
22462306a36Sopenharmony_ci		break;
22562306a36Sopenharmony_ci	default:
22662306a36Sopenharmony_ci		snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias));
22762306a36Sopenharmony_ci		mod = modalias;
22862306a36Sopenharmony_ci		break;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (mod)
23262306a36Sopenharmony_ci		request_module(mod);
23362306a36Sopenharmony_ci#endif /* MODULE */
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/* try to auto-load and bind the codec module */
23762306a36Sopenharmony_cistatic void codec_bind_module(struct hda_codec *codec)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci#ifdef MODULE
24062306a36Sopenharmony_ci	request_codec_module(codec);
24162306a36Sopenharmony_ci	if (codec_probed(codec))
24262306a36Sopenharmony_ci		return;
24362306a36Sopenharmony_ci#endif
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
24762306a36Sopenharmony_ci/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
24862306a36Sopenharmony_cistatic bool is_likely_hdmi_codec(struct hda_codec *codec)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	hda_nid_t nid;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/*
25362306a36Sopenharmony_ci	 * For ASoC users, if snd_hda_hdmi_codec module is denylisted and any
25462306a36Sopenharmony_ci	 * event causes i915 enumeration to fail, ->wcaps remains uninitialized.
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	if (!codec->wcaps)
25762306a36Sopenharmony_ci		return true;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	for_each_hda_codec_node(nid, codec) {
26062306a36Sopenharmony_ci		unsigned int wcaps = get_wcaps(codec, nid);
26162306a36Sopenharmony_ci		switch (get_wcaps_type(wcaps)) {
26262306a36Sopenharmony_ci		case AC_WID_AUD_IN:
26362306a36Sopenharmony_ci			return false; /* HDMI parser supports only HDMI out */
26462306a36Sopenharmony_ci		case AC_WID_AUD_OUT:
26562306a36Sopenharmony_ci			if (!(wcaps & AC_WCAP_DIGITAL))
26662306a36Sopenharmony_ci				return false;
26762306a36Sopenharmony_ci			break;
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci	return true;
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci#else
27362306a36Sopenharmony_ci/* no HDMI codec parser support */
27462306a36Sopenharmony_ci#define is_likely_hdmi_codec(codec)	false
27562306a36Sopenharmony_ci#endif /* CONFIG_SND_HDA_CODEC_HDMI */
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic int codec_bind_generic(struct hda_codec *codec)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	if (codec->probe_id)
28062306a36Sopenharmony_ci		return -ENODEV;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (is_likely_hdmi_codec(codec)) {
28362306a36Sopenharmony_ci		codec->probe_id = HDA_CODEC_ID_GENERIC_HDMI;
28462306a36Sopenharmony_ci		request_codec_module(codec);
28562306a36Sopenharmony_ci		if (codec_probed(codec))
28662306a36Sopenharmony_ci			return 0;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	codec->probe_id = HDA_CODEC_ID_GENERIC;
29062306a36Sopenharmony_ci	request_codec_module(codec);
29162306a36Sopenharmony_ci	if (codec_probed(codec))
29262306a36Sopenharmony_ci		return 0;
29362306a36Sopenharmony_ci	return -ENODEV;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
29762306a36Sopenharmony_ci#define is_generic_config(codec) \
29862306a36Sopenharmony_ci	(codec->modelname && !strcmp(codec->modelname, "generic"))
29962306a36Sopenharmony_ci#else
30062306a36Sopenharmony_ci#define is_generic_config(codec)	0
30162306a36Sopenharmony_ci#endif
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci/**
30462306a36Sopenharmony_ci * snd_hda_codec_configure - (Re-)configure the HD-audio codec
30562306a36Sopenharmony_ci * @codec: the HDA codec
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci * Start parsing of the given codec tree and (re-)initialize the whole
30862306a36Sopenharmony_ci * patch instance.
30962306a36Sopenharmony_ci *
31062306a36Sopenharmony_ci * Returns 0 if successful or a negative error code.
31162306a36Sopenharmony_ci */
31262306a36Sopenharmony_ciint snd_hda_codec_configure(struct hda_codec *codec)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	int err;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (codec->configured)
31762306a36Sopenharmony_ci		return 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (is_generic_config(codec))
32062306a36Sopenharmony_ci		codec->probe_id = HDA_CODEC_ID_GENERIC;
32162306a36Sopenharmony_ci	else
32262306a36Sopenharmony_ci		codec->probe_id = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!device_is_registered(&codec->core.dev)) {
32562306a36Sopenharmony_ci		err = snd_hdac_device_register(&codec->core);
32662306a36Sopenharmony_ci		if (err < 0)
32762306a36Sopenharmony_ci			return err;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (!codec->preset)
33162306a36Sopenharmony_ci		codec_bind_module(codec);
33262306a36Sopenharmony_ci	if (!codec->preset) {
33362306a36Sopenharmony_ci		err = codec_bind_generic(codec);
33462306a36Sopenharmony_ci		if (err < 0) {
33562306a36Sopenharmony_ci			codec_dbg(codec, "Unable to bind the codec\n");
33662306a36Sopenharmony_ci			return err;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	codec->configured = 1;
34162306a36Sopenharmony_ci	return 0;
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_hda_codec_configure);
344