Commit 6bae5ea9 authored by Rakesh Ughreja's avatar Rakesh Ughreja Committed by Mark Brown

ASoC: hdac_hda: add asoc extension for legacy HDA codec drivers

This patch adds a kernel module which is used by the legacy HDA
codec drivers as library. This implements hdac_ext_bus_ops to enable
the reuse of legacy HDA codec drivers with ASoC platform drivers.
Signed-off-by: default avatarRakesh Ughreja <rakesh.a.ughreja@intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 00deadb5
...@@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev) ...@@ -81,6 +81,12 @@ static int hda_codec_driver_probe(struct device *dev)
hda_codec_patch_t patch; hda_codec_patch_t patch;
int err; int err;
if (codec->bus->core.ext_ops) {
if (WARN_ON(!codec->bus->core.ext_ops->hdev_attach))
return -EINVAL;
return codec->bus->core.ext_ops->hdev_attach(&codec->core);
}
if (WARN_ON(!codec->preset)) if (WARN_ON(!codec->preset))
return -EINVAL; return -EINVAL;
...@@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev) ...@@ -134,6 +140,12 @@ static int hda_codec_driver_remove(struct device *dev)
{ {
struct hda_codec *codec = dev_to_hda_codec(dev); struct hda_codec *codec = dev_to_hda_codec(dev);
if (codec->bus->core.ext_ops) {
if (WARN_ON(!codec->bus->core.ext_ops->hdev_detach))
return -EINVAL;
return codec->bus->core.ext_ops->hdev_detach(&codec->core);
}
if (codec->patch_ops.free) if (codec->patch_ops.free)
codec->patch_ops.free(codec); codec->patch_ops.free(codec);
snd_hda_codec_cleanup_for_unbind(codec); snd_hda_codec_cleanup_for_unbind(codec);
......
...@@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS ...@@ -82,6 +82,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES7241 select SND_SOC_ES7241
select SND_SOC_GTM601 select SND_SOC_GTM601
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
select SND_SOC_HDAC_HDA
select SND_SOC_ICS43432 select SND_SOC_ICS43432
select SND_SOC_INNO_RK3036 select SND_SOC_INNO_RK3036
select SND_SOC_ISABELLE if I2C select SND_SOC_ISABELLE if I2C
...@@ -615,6 +616,10 @@ config SND_SOC_HDAC_HDMI ...@@ -615,6 +616,10 @@ config SND_SOC_HDAC_HDMI
select SND_PCM_ELD select SND_PCM_ELD
select HDMI select HDMI
config SND_SOC_HDAC_HDA
tristate
select SND_HDA
config SND_SOC_ICS43432 config SND_SOC_ICS43432
tristate tristate
......
...@@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o ...@@ -78,6 +78,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-es8328-spi-objs := es8328-spi.o
snd-soc-gtm601-objs := gtm601.o snd-soc-gtm601-objs := gtm601.o
snd-soc-hdac-hdmi-objs := hdac_hdmi.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-ics43432-objs := ics43432.o
snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-inno-rk3036-objs := inno_rk3036.o
snd-soc-isabelle-objs := isabelle.o snd-soc-isabelle-objs := isabelle.o
...@@ -338,6 +339,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o ...@@ -338,6 +339,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_ES8328_SPI)+= snd-soc-es8328-spi.o
obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.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_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_ICS43432) += snd-soc-ics43432.o
obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright(c) 2015-18 Intel Corporation.
*/
#ifndef __HDAC_HDA_H__
#define __HDAC_HDA_H__
struct hdac_hda_pcm {
int stream_tag[2];
};
struct hdac_hda_priv {
struct hda_codec codec;
struct hdac_hda_pcm pcm[2];
};
#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)
struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void);
#endif /* __HDAC_HDA_H__ */
...@@ -283,6 +283,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH ...@@ -283,6 +283,7 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
tristate "SKL/KBL/BXT/APL with HDA Codecs" tristate "SKL/KBL/BXT/APL with HDA Codecs"
select SND_SOC_HDAC_HDMI select SND_SOC_HDAC_HDMI
select SND_SOC_HDAC_HDA
help help
This adds support for ASoC machine driver for Intel platforms This adds support for ASoC machine driver for Intel platforms
SKL/KBL/BXT/APL with iDisp, HDA audio codecs. SKL/KBL/BXT/APL with iDisp, HDA audio codecs.
......
...@@ -69,6 +69,30 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { ...@@ -69,6 +69,30 @@ struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = {
.dpcm_playback = 1, .dpcm_playback = 1,
.no_pcm = 1, .no_pcm = 1,
}, },
{
.name = "Analog Playback and Capture",
.id = 4,
.cpu_dai_name = "Analog CPU DAI",
.codec_name = "ehdaudio0D0",
.codec_dai_name = "Analog Codec DAI",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.dpcm_capture = 1,
.init = NULL,
.no_pcm = 1,
},
{
.name = "Digital Playback and Capture",
.id = 5,
.cpu_dai_name = "Digital CPU DAI",
.codec_name = "ehdaudio0D0",
.codec_dai_name = "Digital Codec DAI",
.platform_name = "0000:00:1f.3",
.dpcm_playback = 1,
.dpcm_capture = 1,
.init = NULL,
.no_pcm = 1,
},
}; };
int skl_hda_hdmi_jack_init(struct snd_soc_card *card) int skl_hda_hdmi_jack_init(struct snd_soc_card *card)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <sound/core.h> #include <sound/core.h>
#include <sound/jack.h> #include <sound/jack.h>
#define HDA_DSP_MAX_BE_DAI_LINKS 3 #define HDA_DSP_MAX_BE_DAI_LINKS 5
struct skl_hda_hdmi_pcm { struct skl_hda_hdmi_pcm {
struct list_head head; struct list_head head;
......
...@@ -16,6 +16,15 @@ ...@@ -16,6 +16,15 @@
#include "../skylake/skl.h" #include "../skylake/skl.h"
#include "skl_hda_dsp_common.h" #include "skl_hda_dsp_common.h"
static const struct snd_soc_dapm_widget skl_hda_widgets[] = {
SND_SOC_DAPM_HP("Analog Out", NULL),
SND_SOC_DAPM_MIC("Analog In", NULL),
SND_SOC_DAPM_HP("Alt Analog Out", NULL),
SND_SOC_DAPM_MIC("Alt Analog In", NULL),
SND_SOC_DAPM_SPK("Digital Out", NULL),
SND_SOC_DAPM_MIC("Digital In", NULL),
};
static const struct snd_soc_dapm_route skl_hda_map[] = { static const struct snd_soc_dapm_route skl_hda_map[] = {
{ "hifi3", NULL, "iDisp3 Tx"}, { "hifi3", NULL, "iDisp3 Tx"},
{ "iDisp3 Tx", NULL, "iDisp3_out"}, { "iDisp3 Tx", NULL, "iDisp3_out"},
...@@ -23,6 +32,29 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { ...@@ -23,6 +32,29 @@ static const struct snd_soc_dapm_route skl_hda_map[] = {
{ "iDisp2 Tx", NULL, "iDisp2_out"}, { "iDisp2 Tx", NULL, "iDisp2_out"},
{ "hifi1", NULL, "iDisp1 Tx"}, { "hifi1", NULL, "iDisp1 Tx"},
{ "iDisp1 Tx", NULL, "iDisp1_out"}, { "iDisp1 Tx", NULL, "iDisp1_out"},
{ "Analog Out", NULL, "Codec Output Pin1" },
{ "Digital Out", NULL, "Codec Output Pin2" },
{ "Alt Analog Out", NULL, "Codec Output Pin3" },
{ "Codec Input Pin1", NULL, "Analog In" },
{ "Codec Input Pin2", NULL, "Digital In" },
{ "Codec Input Pin3", NULL, "Alt Analog In" },
/* CODEC BE connections */
{ "Analog Codec Playback", NULL, "Analog CPU Playback" },
{ "Analog CPU Playback", NULL, "codec0_out" },
{ "Digital Codec Playback", NULL, "Digital CPU Playback" },
{ "Digital CPU Playback", NULL, "codec1_out" },
{ "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" },
{ "Alt Analog CPU Playback", NULL, "codec2_out" },
{ "codec0_in", NULL, "Analog CPU Capture" },
{ "Analog CPU Capture", NULL, "Analog Codec Capture" },
{ "codec1_in", NULL, "Digital CPU Capture" },
{ "Digital CPU Capture", NULL, "Digital Codec Capture" },
{ "codec2_in", NULL, "Alt Analog CPU Capture" },
{ "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" },
}; };
static int skl_hda_card_late_probe(struct snd_soc_card *card) static int skl_hda_card_late_probe(struct snd_soc_card *card)
...@@ -57,6 +89,7 @@ static struct snd_soc_card hda_soc_card = { ...@@ -57,6 +89,7 @@ static struct snd_soc_card hda_soc_card = {
.name = "skl_hda_card", .name = "skl_hda_card",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.dai_link = skl_hda_be_dai_links, .dai_link = skl_hda_be_dai_links,
.dapm_widgets = skl_hda_widgets,
.dapm_routes = skl_hda_map, .dapm_routes = skl_hda_map,
.add_dai_link = skl_hda_add_dai_link, .add_dai_link = skl_hda_add_dai_link,
.fully_routed = true, .fully_routed = true,
...@@ -80,6 +113,11 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata) ...@@ -80,6 +113,11 @@ static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) { if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
num_links = IDISP_DAI_COUNT; num_links = IDISP_DAI_COUNT;
num_route = IDISP_ROUTE_COUNT; num_route = IDISP_ROUTE_COUNT;
} else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) {
num_links = ARRAY_SIZE(skl_hda_be_dai_links);
num_route = ARRAY_SIZE(skl_hda_map),
card->dapm_widgets = skl_hda_widgets;
card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets);
} else { } else {
return -EINVAL; return -EINVAL;
} }
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "skl.h" #include "skl.h"
#include "skl-sst-dsp.h" #include "skl-sst-dsp.h"
#include "skl-sst-ipc.h" #include "skl-sst-ipc.h"
#include "../../../soc/codecs/hdac_hda.h"
/* /*
* initialize the PCI registers * initialize the PCI registers
...@@ -657,6 +658,24 @@ static void skl_clock_device_unregister(struct skl *skl) ...@@ -657,6 +658,24 @@ static void skl_clock_device_unregister(struct skl *skl)
platform_device_unregister(skl->clk_dev); platform_device_unregister(skl->clk_dev);
} }
#define IDISP_INTEL_VENDOR_ID 0x80860000
/*
* load the legacy codec driver
*/
static void load_codec_module(struct hda_codec *codec)
{
#ifdef MODULE
char modalias[MODULE_NAME_LEN];
const char *mod = NULL;
snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias));
mod = modalias;
dev_dbg(&codec->core.dev, "loading %s codec module\n", mod);
request_module(mod);
#endif
}
/* /*
* Probe the given codec address * Probe the given codec address
*/ */
...@@ -666,7 +685,9 @@ static int probe_codec(struct hdac_bus *bus, int addr) ...@@ -666,7 +685,9 @@ static int probe_codec(struct hdac_bus *bus, int addr)
(AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
unsigned int res = -1; unsigned int res = -1;
struct skl *skl = bus_to_skl(bus); struct skl *skl = bus_to_skl(bus);
struct hdac_hda_priv *hda_codec;
struct hdac_device *hdev; struct hdac_device *hdev;
int err;
mutex_lock(&bus->cmd_mutex); mutex_lock(&bus->cmd_mutex);
snd_hdac_bus_send_cmd(bus, cmd); snd_hdac_bus_send_cmd(bus, cmd);
...@@ -676,11 +697,24 @@ static int probe_codec(struct hdac_bus *bus, int addr) ...@@ -676,11 +697,24 @@ static int probe_codec(struct hdac_bus *bus, int addr)
return -EIO; return -EIO;
dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res);
hdev = devm_kzalloc(&skl->pci->dev, sizeof(*hdev), GFP_KERNEL); hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec),
if (!hdev) GFP_KERNEL);
if (!hda_codec)
return -ENOMEM; return -ENOMEM;
return snd_hdac_ext_bus_device_init(bus, addr, hdev); hda_codec->codec.bus = skl_to_hbus(skl);
hdev = &hda_codec->codec.core;
err = snd_hdac_ext_bus_device_init(bus, addr, hdev);
if (err < 0)
return err;
/* use legacy bus only for HDA codecs, idisp uses ext bus */
if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) {
hdev->type = HDA_DEV_LEGACY;
load_codec_module(&hda_codec->codec);
}
return 0;
} }
/* Codec initialization */ /* Codec initialization */
...@@ -815,6 +849,7 @@ static int skl_create(struct pci_dev *pci, ...@@ -815,6 +849,7 @@ static int skl_create(struct pci_dev *pci,
const struct hdac_io_ops *io_ops, const struct hdac_io_ops *io_ops,
struct skl **rskl) struct skl **rskl)
{ {
struct hdac_ext_bus_ops *ext_ops = NULL;
struct skl *skl; struct skl *skl;
struct hdac_bus *bus; struct hdac_bus *bus;
struct hda_bus *hbus; struct hda_bus *hbus;
...@@ -834,7 +869,11 @@ static int skl_create(struct pci_dev *pci, ...@@ -834,7 +869,11 @@ static int skl_create(struct pci_dev *pci,
hbus = skl_to_hbus(skl); hbus = skl_to_hbus(skl);
bus = skl_to_bus(skl); bus = skl_to_bus(skl);
snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, NULL);
#if IS_ENABLED(CONFIG_SND_SOC_HDAC_HDA)
ext_ops = snd_soc_hdac_hda_get_ops();
#endif
snd_hdac_ext_bus_init(bus, &pci->dev, &bus_core_ops, io_ops, ext_ops);
bus->use_posbuf = 1; bus->use_posbuf = 1;
skl->pci = pci; skl->pci = pci;
INIT_WORK(&skl->probe_work, skl_probe_work); INIT_WORK(&skl->probe_work, skl_probe_work);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment