This patch adds ASoC based HDA codec driver that can be used with all Intel platforms.
Signed-off-by: Rakesh Ughreja rakesh.a.ughreja@intel.com --- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_generic.c | 25 ++++++++++++ sound/soc/codecs/Kconfig | 6 +++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/hdac_hda.c | 94 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/hdac_hda.h | 22 ++++++++++ sound/soc/intel/skylake/skl.c | 10 ++++- 7 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 sound/soc/codecs/hdac_hda.c create mode 100644 sound/soc/codecs/hdac_hda.h
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index ef626cf..1525c5a 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -96,6 +96,7 @@ typedef int (*hda_codec_patch_t)(struct hda_codec *);
struct hda_codec_driver { struct hdac_driver core; + struct hdac_driver *asocdrv; const struct hda_device_id *id; };
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 09ab02e..e0b46a4 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -38,6 +38,7 @@ #include "hda_jack.h" #include "hda_beep.h" #include "hda_generic.h" +#include "../../sound/soc/codecs/hdac_hda.h"
/** @@ -5964,12 +5965,36 @@ static int snd_hda_parse_generic_codec(struct hda_codec *codec) int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, struct module *owner) { + int ret; + + /* + * Register ASoC HDA driver as well + */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA)) { + + drv->core.id_table = drv->id; + drv->asocdrv = kmalloc(sizeof(*drv->asocdrv), GFP_KERNEL); + if (!drv->asocdrv) + return -ENOMEM; + + ret = __hdac_hda_codec_driver_register(&drv->core, name, owner); + if (ret < 0) + return ret; + } return __hda_legacy_codec_driver_register(drv, name, owner); } EXPORT_SYMBOL_GPL(__hda_codec_driver_register);
void hda_codec_driver_unregister(struct hda_codec_driver *drv) { + /* + * Unregister ASoC HDA driver as well + */ + if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA)) { + hdac_hda_codec_driver_unregister(&drv->core); + kfree(drv->asocdrv); + } + hda_legacy_codec_driver_unregister(drv); } EXPORT_SYMBOL_GPL(hda_codec_driver_unregister); diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ba5de07..1d41d11 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -79,6 +79,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES7134 select SND_SOC_GTM601 select SND_SOC_HDAC_HDMI + select SND_SOC_HDAC_HDA select SND_SOC_ICS43432 select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C @@ -581,6 +582,11 @@ config SND_SOC_HDAC_HDMI select SND_PCM_ELD select HDMI
+config SND_SOC_HDAC_HDA + tristate + select SND_HDA_EXT_CORE + select SND_PCM_ELD + config SND_SOC_ICS43432 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0977349..dd5f90f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -73,6 +73,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o snd-soc-hdac-hdmi-objs := hdac_hdmi.o +snd-soc-hdac-hda-objs := hdac_hda.o snd-soc-ics43432-objs := ics43432.o snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o @@ -317,6 +318,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o +obj-$(CONFIG_SND_SOC_HDAC_HDA) += snd-soc-hdac-hda.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c new file mode 100644 index 0000000..387b00f --- /dev/null +++ b/sound/soc/codecs/hdac_hda.c @@ -0,0 +1,94 @@ +/* + * hdac_hda.c - ASoc HDA-HDA codec driver for Intel platforms + * + * Copyright (C) 2015-2017 Intel Corp + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/hdaudio_ext.h> +#include <sound/hda_register.h> +#include "../../hda/local.h" +#include "../../pci/hda/hda_codec.h" +#include "hdac_hda.h" + +static int hdac_hda_dev_probe(struct hdac_device *hdev) +{ + struct hdac_ext_link *hlink = NULL; + struct hdac_hda_priv *hda_pvt; + int ret; + + dev_dbg(&hdev->dev, "%s: entry\n", __func__); + + /* hold the ref while we probe */ + hlink = snd_hdac_ext_bus_get_link(hdev->bus, dev_name(&hdev->dev)); + if (!hlink) { + dev_err(&hdev->dev, "hdac link not found\n"); + return -EIO; + } + snd_hdac_ext_bus_link_get(hdev->bus, hlink); + + hda_pvt = hdac_to_hda_priv(hdev); + if (hda_pvt == NULL) + return -ENOMEM; + + dev_set_drvdata(&hdev->dev, hda_pvt); + snd_hdac_ext_bus_link_put(hdev->bus, hlink); + + return ret; +} + +static int hdac_hda_dev_remove(struct hdac_device *hdev) +{ + dev_dbg(&hdev->dev, "%s: entry\n", __func__); + return 0; +} + +#define hdac_hda_runtime_suspend NULL +#define hdac_hda_runtime_resume NULL + +static const struct dev_pm_ops hdac_hda_pm = { + SET_RUNTIME_PM_OPS(hdac_hda_runtime_suspend, + hdac_hda_runtime_resume, NULL) +}; + +int __hdac_hda_codec_driver_register(struct hdac_driver *drv, + const char *name, struct module *owner) +{ + char new_name[strlen(name) + strlen("-asoc")]; + + sprintf(new_name, "%s-asoc", name); + drv->driver.name = new_name; + drv->driver.pm = &hdac_hda_pm; + drv->probe = hdac_hda_dev_probe; + drv->remove = hdac_hda_dev_remove; + + return snd_hda_ext_driver_register(drv); +} +EXPORT_SYMBOL_GPL(__hdac_hda_codec_driver_register); + +void hdac_hda_codec_driver_unregister(struct hdac_driver *drv) +{ + snd_hda_ext_driver_unregister(drv); +} +EXPORT_SYMBOL_GPL(hdac_hda_codec_driver_unregister); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("ASoC HDA codec driver"); +MODULE_AUTHOR("Rakesh Ughrejarakesh.a.ughreja@intel.com"); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h new file mode 100644 index 0000000..a089ec5 --- /dev/null +++ b/sound/soc/codecs/hdac_hda.h @@ -0,0 +1,22 @@ +#ifndef __HDAC_HDA_H__ +#define __HDAC_HDA_H__ + +struct hdac_hda_priv { + struct hda_codec codec; + struct hda_bus *hbus; + int stream_tag; + + struct snd_soc_codec *scodec; +}; + +#define hdac_to_hda_priv(_hdac) \ + container_of(_hdac, struct hdac_hda_priv, codec.core) +#define hdac_to_hda_codec(_hdac) container_of(_hdac, struct hda_codec, core) + +int __hdac_hda_codec_driver_register(struct hdac_driver *drv, + const char *name, struct module *owner); +#define hdac_hda_codec_driver_register(drv) \ + __hdac_hda_codec_driver_register(drv, KBUILD_MODNAME, THIS_MODULE) +void hdac_hda_codec_driver_unregister(struct hdac_driver *drv); + +#endif /* __HDAC_HDA_H__ */ diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index c2e9c19..a56a916 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -36,6 +36,7 @@ #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" #include "../../../pci/hda/hda_codec.h" +#include "../../../soc/codecs/hdac_hda.h"
static struct skl_machine_pdata skl_dmic_data;
@@ -619,6 +620,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; unsigned int res = -1; struct skl *skl = bus_to_skl(bus); + struct hdac_hda_priv *hda_codec; struct hdac_device *hdev;
mutex_lock(&bus->cmd_mutex); @@ -637,10 +639,14 @@ static int probe_codec(struct hdac_bus *bus, int addr) * codec driver. If legacy controller driver can be changed this * code change can be avoided. */ - hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); - if (!hdev) + hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), + GFP_KERNEL); + if (!hda_codec) return -ENOMEM;
+ hda_codec->hbus = skl_to_hbus(skl); + hdev = &hda_codec->codec.core; + return snd_hdac_ext_bus_device_init(bus, addr, hdev); }