summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sound/hda_codec.h26
-rw-r--r--sound/hda/common/bind.c27
-rw-r--r--sound/hda/common/codec.c56
-rw-r--r--sound/hda/common/hda_local.h11
-rw-r--r--sound/soc/codecs/hda.c27
-rw-r--r--sound/soc/codecs/hdac_hda.c28
6 files changed, 137 insertions, 38 deletions
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h
index c1fe6290d04d..a725ac48c20c 100644
--- a/include/sound/hda_codec.h
+++ b/include/sound/hda_codec.h
@@ -27,6 +27,7 @@ struct hda_beep;
struct hda_codec;
struct hda_pcm;
struct hda_pcm_stream;
+struct hda_codec_ops;
/*
* codec bus
@@ -79,6 +80,17 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *);
#define HDA_CODEC_ID_GENERIC_HDMI 0x00000101
#define HDA_CODEC_ID_GENERIC 0x00000201
+#define HDA_CODEC_ID_REV_MODEL(_vid, _rev, _name, _model) \
+ { .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
+ .api_version = HDA_DEV_LEGACY, .driver_data = (_model) }
+#define HDA_CODEC_ID_MODEL(_vid, _name, _model) \
+ HDA_CODEC_ID_REV_MODEL(_vid, 0, _name, _model)
+#define HDA_CODEC_ID_REV(_vid, _rev, _name) \
+ HDA_CODEC_ID_REV_MODEL(_vid, _rev, _name, 0)
+#define HDA_CODEC_ID(_vid, _name) \
+ HDA_CODEC_ID_REV(_vid, 0, _name)
+
+/* old macros for patch_ops -- to be deprecated */
#define HDA_CODEC_REV_ENTRY(_vid, _rev, _name, _patch) \
{ .vendor_id = (_vid), .rev_id = (_rev), .name = (_name), \
.api_version = HDA_DEV_LEGACY, \
@@ -89,8 +101,12 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *);
struct hda_codec_driver {
struct hdac_driver core;
const struct hda_device_id *id;
+ const struct hda_codec_ops *ops;
};
+#define hda_codec_to_driver(codec) \
+ container_of((codec)->core.dev.driver, struct hda_codec_driver, core.driver)
+
int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name,
struct module *owner);
#define hda_codec_driver_register(drv) \
@@ -102,6 +118,8 @@ void hda_codec_driver_unregister(struct hda_codec_driver *drv);
/* ops set by the preset patch */
struct hda_codec_ops {
+ int (*probe)(struct hda_codec *codec, const struct hda_device_id *id);
+ void (*remove)(struct hda_codec *codec);
int (*build_controls)(struct hda_codec *codec);
int (*build_pcms)(struct hda_codec *codec);
int (*init)(struct hda_codec *codec);
@@ -184,7 +202,7 @@ struct hda_codec {
/* set by patch */
struct hda_codec_ops patch_ops;
- /* PCM to create, set by patch_ops.build_pcms callback */
+ /* PCM to create, set by hda_codec_ops.build_pcms callback */
struct list_head pcm_list_head;
refcount_t pcm_ref;
wait_queue_head_t remove_sleep;
@@ -478,7 +496,11 @@ extern const struct dev_pm_ops hda_codec_driver_pm;
static inline
int hda_call_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
- if (codec->patch_ops.check_power_status)
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
+ if (driver->ops && driver->ops->check_power_status)
+ return driver->ops->check_power_status(codec, nid);
+ else if (codec->patch_ops.check_power_status)
return codec->patch_ops.check_power_status(codec, nid);
return 0;
}
diff --git a/sound/hda/common/bind.c b/sound/hda/common/bind.c
index df8f88beddd0..56975178f533 100644
--- a/sound/hda/common/bind.c
+++ b/sound/hda/common/bind.c
@@ -42,6 +42,7 @@ static int hda_codec_match(struct hdac_device *dev, const struct hdac_driver *dr
static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
{
struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
/* ignore unsol events during shutdown */
if (codec->card->shutdown || codec->bus->shutdown)
@@ -51,7 +52,9 @@ static void hda_codec_unsol_event(struct hdac_device *dev, unsigned int ev)
if (codec->core.dev.power.power_state.event != PM_EVENT_ON)
return;
- if (codec->patch_ops.unsol_event)
+ if (driver->ops && driver->ops->unsol_event)
+ driver->ops->unsol_event(codec, ev);
+ else if (codec->patch_ops.unsol_event)
codec->patch_ops.unsol_event(codec, ev);
}
@@ -87,6 +90,7 @@ static int hda_codec_driver_probe(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
struct module *owner = dev->driver->owner;
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
hda_codec_patch_t patch;
int err;
@@ -111,11 +115,17 @@ static int hda_codec_driver_probe(struct device *dev)
goto error;
}
- patch = (hda_codec_patch_t)codec->preset->driver_data;
- if (patch) {
- err = patch(codec);
+ if (driver->ops && driver->ops->probe) {
+ err = driver->ops->probe(codec, codec->preset);
if (err < 0)
goto error_module_put;
+ } else {
+ patch = (hda_codec_patch_t)codec->preset->driver_data;
+ if (patch) {
+ err = patch(codec);
+ if (err < 0)
+ goto error_module_put;
+ }
}
err = snd_hda_codec_build_pcms(codec);
@@ -136,7 +146,9 @@ static int hda_codec_driver_probe(struct device *dev)
return 0;
error_module:
- if (codec->patch_ops.free)
+ if (driver->ops && driver->ops->remove)
+ driver->ops->remove(codec);
+ else if (codec->patch_ops.free)
codec->patch_ops.free(codec);
error_module_put:
module_put(owner);
@@ -150,6 +162,7 @@ static int hda_codec_driver_probe(struct device *dev)
static int hda_codec_driver_remove(struct device *dev)
{
struct hda_codec *codec = dev_to_hda_codec(dev);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
if (codec->bus->core.ext_ops) {
if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
@@ -163,7 +176,9 @@ static int hda_codec_driver_remove(struct device *dev)
wait_event(codec->remove_sleep, !refcount_read(&codec->pcm_ref));
snd_power_sync_ref(codec->bus->card);
- if (codec->patch_ops.free)
+ if (driver->ops && driver->ops->remove)
+ driver->ops->remove(codec);
+ else if (codec->patch_ops.free)
codec->patch_ops.free(codec);
snd_hda_codec_cleanup_for_unbind(codec);
codec->preset = NULL;
diff --git a/sound/hda/common/codec.c b/sound/hda/common/codec.c
index cb72e9655c8a..8899be764d68 100644
--- a/sound/hda/common/codec.c
+++ b/sound/hda/common/codec.c
@@ -1114,6 +1114,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
u32 stream_tag,
int channel_id, int format)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hda_codec *c;
struct hda_cvt_setup *p;
int type;
@@ -1129,7 +1130,9 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
if (!p)
return;
- if (codec->patch_ops.stream_pm)
+ if (driver->ops && driver->ops->stream_pm)
+ driver->ops->stream_pm(codec, nid, true);
+ else if (codec->patch_ops.stream_pm)
codec->patch_ops.stream_pm(codec, nid, true);
if (codec->pcm_format_first)
update_pcm_format(codec, p, nid, format);
@@ -1190,7 +1193,9 @@ EXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream);
static void really_cleanup_stream(struct hda_codec *codec,
struct hda_cvt_setup *q)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
hda_nid_t nid = q->nid;
+
if (q->stream_tag || q->channel_id)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
if (q->format_id)
@@ -1198,7 +1203,9 @@ static void really_cleanup_stream(struct hda_codec *codec,
);
memset(q, 0, sizeof(*q));
q->nid = nid;
- if (codec->patch_ops.stream_pm)
+ if (driver->ops && driver->ops->stream_pm)
+ driver->ops->stream_pm(codec, nid, false);
+ else if (codec->patch_ops.stream_pm)
codec->patch_ops.stream_pm(codec, nid, false);
}
@@ -2746,6 +2753,7 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter);
static unsigned int hda_set_power_state(struct hda_codec *codec,
unsigned int power_state)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
hda_nid_t fg = codec->core.afg ? codec->core.afg : codec->core.mfg;
int count;
unsigned int state;
@@ -2762,7 +2770,10 @@ static unsigned int hda_set_power_state(struct hda_codec *codec,
/* repeat power states setting at most 10 times*/
for (count = 0; count < 10; count++) {
- if (codec->patch_ops.set_power_state)
+ /* might be called before binding to driver, too */
+ if (driver && driver->ops && driver->ops->set_power_state)
+ driver->ops->set_power_state(codec, fg, power_state);
+ else if (codec->patch_ops.set_power_state)
codec->patch_ops.set_power_state(codec, fg,
power_state);
else {
@@ -2842,10 +2853,13 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
*/
static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
unsigned int state;
snd_hdac_enter_pm(&codec->core);
- if (codec->patch_ops.suspend)
+ if (driver->ops && driver->ops->suspend)
+ driver->ops->suspend(codec);
+ else if (codec->patch_ops.suspend)
codec->patch_ops.suspend(codec);
if (!codec->no_stream_clean_at_suspend)
hda_cleanup_all_streams(codec);
@@ -2860,6 +2874,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec)
*/
static void hda_call_codec_resume(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
snd_hdac_enter_pm(&codec->core);
if (codec->core.regmap)
regcache_mark_dirty(codec->core.regmap);
@@ -2870,11 +2886,12 @@ static void hda_call_codec_resume(struct hda_codec *codec)
restore_shutup_pins(codec);
hda_exec_init_verbs(codec);
snd_hda_jack_set_dirty_all(codec);
- if (codec->patch_ops.resume)
+ if (driver->ops && driver->ops->resume)
+ driver->ops->resume(codec);
+ else if (codec->patch_ops.resume)
codec->patch_ops.resume(codec);
else {
- if (codec->patch_ops.init)
- codec->patch_ops.init(codec);
+ snd_hda_codec_init(codec);
snd_hda_regmap_sync(codec);
}
@@ -3059,15 +3076,20 @@ EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps);
int snd_hda_codec_build_controls(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
int err = 0;
+
hda_exec_init_verbs(codec);
/* continue to initialize... */
- if (codec->patch_ops.init)
- err = codec->patch_ops.init(codec);
- if (!err && codec->patch_ops.build_controls)
- err = codec->patch_ops.build_controls(codec);
- if (err < 0)
- return err;
+ err = snd_hda_codec_init(codec);
+ if (!err) {
+ if (driver->ops && driver->ops->build_controls)
+ err = driver->ops->build_controls(codec);
+ else if (codec->patch_ops.build_controls)
+ err = codec->patch_ops.build_controls(codec);
+ if (err < 0)
+ return err;
+ }
/* we create chmaps here instead of build_pcms */
err = add_std_chmaps(codec);
@@ -3253,16 +3275,20 @@ static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type)
/* call build_pcms ops of the given codec and set up the default parameters */
int snd_hda_codec_parse_pcms(struct hda_codec *codec)
{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hda_pcm *cpcm;
int err;
if (!list_empty(&codec->pcm_list_head))
return 0; /* already parsed */
- if (!codec->patch_ops.build_pcms)
+ if (driver->ops && driver->ops->build_pcms)
+ err = driver->ops->build_pcms(codec);
+ else if (codec->patch_ops.build_pcms)
+ err = codec->patch_ops.build_pcms(codec);
+ else
return 0;
- err = codec->patch_ops.build_pcms(codec);
if (err < 0) {
codec_err(codec, "cannot build PCMs for #%d (error %d)\n",
codec->core.addr, err);
diff --git a/sound/hda/common/hda_local.h b/sound/hda/common/hda_local.h
index 428aa5a06ead..654fe1156d56 100644
--- a/sound/hda/common/hda_local.h
+++ b/sound/hda/common/hda_local.h
@@ -652,6 +652,17 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
void snd_hda_codec_shutdown(struct hda_codec *codec);
+static inline int snd_hda_codec_init(struct hda_codec *codec)
+{
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
+
+ if (driver->ops && driver->ops->init)
+ return driver->ops->init(codec);
+ else if (codec->patch_ops.init)
+ return codec->patch_ops.init(codec);
+ return 0;
+}
+
/*
* AMP control callbacks
*/
diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index dc7794c9ac44..ddb31001657e 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -173,6 +173,7 @@ EXPORT_SYMBOL_GPL(hda_codec_probe_complete);
static int hda_codec_probe(struct snd_soc_component *component)
{
struct hda_codec *codec = dev_to_hda_codec(component->dev);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hdac_device *hdev = &codec->core;
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink;
@@ -214,14 +215,19 @@ static int hda_codec_probe(struct snd_soc_component *component)
goto err;
}
- patch = (hda_codec_patch_t)codec->preset->driver_data;
- if (!patch) {
- dev_err(&hdev->dev, "no patch specified\n");
- ret = -EINVAL;
- goto err;
+ if (driver->ops && driver->ops->probe) {
+ ret = driver->ops->probe(codec, codec->preset);
+ } else {
+ patch = (hda_codec_patch_t)codec->preset->driver_data;
+ if (!patch) {
+ dev_err(&hdev->dev, "no patch specified\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = patch(codec);
}
- ret = patch(codec);
if (ret < 0) {
dev_err(&hdev->dev, "codec init failed: %d\n", ret);
goto err;
@@ -252,7 +258,9 @@ static int hda_codec_probe(struct snd_soc_component *component)
complete_err:
hda_codec_unregister_dais(codec, component);
parse_pcms_err:
- if (codec->patch_ops.free)
+ if (driver->ops && driver->ops->remove)
+ driver->ops->remove(codec);
+ else if (codec->patch_ops.free)
codec->patch_ops.free(codec);
err:
snd_hda_codec_cleanup_for_unbind(codec);
@@ -271,6 +279,7 @@ device_new_err:
static void hda_codec_remove(struct snd_soc_component *component)
{
struct hda_codec *codec = dev_to_hda_codec(component->dev);
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hdac_device *hdev = &codec->core;
struct hdac_bus *bus = hdev->bus;
struct hdac_ext_link *hlink;
@@ -281,7 +290,9 @@ static void hda_codec_remove(struct snd_soc_component *component)
hda_codec_unregister_dais(codec, component);
- if (codec->patch_ops.free)
+ if (driver->ops && driver->ops->remove)
+ driver->ops->remove(codec);
+ else if (codec->patch_ops.free)
codec->patch_ops.free(codec);
snd_hda_codec_cleanup_for_unbind(codec);
diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c
index 29c88de5508b..7bb7845d5e43 100644
--- a/sound/soc/codecs/hdac_hda.c
+++ b/sound/soc/codecs/hdac_hda.c
@@ -409,6 +409,7 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
snd_soc_component_get_dapm(component);
struct hdac_device *hdev = &hda_pvt->codec->core;
struct hda_codec *hcodec = hda_pvt->codec;
+ struct hda_codec_driver *driver = hda_codec_to_driver(hcodec);
struct hdac_ext_link *hlink;
hda_codec_patch_t patch;
int ret;
@@ -484,15 +485,23 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
goto error_pm;
}
- patch = (hda_codec_patch_t)hcodec->preset->driver_data;
- if (patch) {
- ret = patch(hcodec);
+ if (driver->ops && driver->ops->probe) {
+ ret = driver->ops->probe(hcodec, hcodec->preset);
if (ret < 0) {
- dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret);
+ dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret);
goto error_regmap;
}
} else {
- dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__);
+ patch = (hda_codec_patch_t)hcodec->preset->driver_data;
+ if (patch) {
+ ret = patch(hcodec);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "%s: patch failed %d\n", __func__, ret);
+ goto error_regmap;
+ }
+ } else {
+ dev_dbg(&hdev->dev, "%s: no patch file found\n", __func__);
+ }
}
ret = snd_hda_codec_parse_pcms(hcodec);
@@ -531,7 +540,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
return 0;
error_patch:
- if (hcodec->patch_ops.free)
+ if (driver->ops && driver->ops->remove)
+ driver->ops->remove(hcodec);
+ else if (hcodec->patch_ops.free)
hcodec->patch_ops.free(hcodec);
error_regmap:
snd_hdac_regmap_exit(hdev);
@@ -548,6 +559,7 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
snd_soc_component_get_drvdata(component);
struct hdac_device *hdev = &hda_pvt->codec->core;
struct hda_codec *codec = hda_pvt->codec;
+ struct hda_codec_driver *driver = hda_codec_to_driver(codec);
struct hdac_ext_link *hlink = NULL;
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
@@ -559,7 +571,9 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
pm_runtime_disable(&hdev->dev);
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
- if (codec->patch_ops.free)
+ if (driver->ops && driver->ops->remove)
+ driver->ops->remove(codec);
+ else if (codec->patch_ops.free)
codec->patch_ops.free(codec);
snd_hda_codec_cleanup_for_unbind(codec);