Message ID | 1445931737-30393-3-git-send-email-vinod.koul@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Oct 27, 2015 at 04:42:13PM +0900, Vinod Koul wrote: > + if (err < 0) > + dev_err(&hdac->dev, "Failed to query pcm params for nid: %d\n", cvt->nid); That looks like the NID is being printed as an error code. > + /* > + * Currently on board only 1 pin and 1 converter enabled for > + * simplification, more will be added eventually > + * So using fixed map for dai_id:pin:cvt > + */ > + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], > + hdmi->cvt_nid[0], 0); I'm not entirely sure I understand what this is all doing. It looks like it's trying to translate the HDA widget map into a DAPM map which seems sensible but it appears it's making some simplifying assumptions about the device it's dealing with? > +static const struct hda_device_id hdmi_list[] = { > + HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), > + {} > +}; Which is plausible since it's a driver for a specific HDA CODEC.
On Sun, Nov 01, 2015 at 12:02:31PM +0900, Mark Brown wrote: > On Tue, Oct 27, 2015 at 04:42:13PM +0900, Vinod Koul wrote: > > > + if (err < 0) > > + dev_err(&hdac->dev, "Failed to query pcm params for nid: %d\n", cvt->nid); > > That looks like the NID is being printed as an error code. No this prints the NID for which query fails, but agree we should print the error code too, that might be very helpful :) > > + /* > > + * Currently on board only 1 pin and 1 converter enabled for > > + * simplification, more will be added eventually > > + * So using fixed map for dai_id:pin:cvt > > + */ > > + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], > > + hdmi->cvt_nid[0], 0); > > I'm not entirely sure I understand what this is all doing. It looks > like it's trying to translate the HDA widget map into a DAPM map which > seems sensible but it appears it's making some simplifying assumptions > about the device it's dealing with? The device is actually quite simple and yes we simplified even further by ignoring multiple pins for now. We will keep adding more features and adding stuff to map as we go along..
On Mon, Nov 02, 2015 at 03:36:42PM +0530, Vinod Koul wrote: > On Sun, Nov 01, 2015 at 12:02:31PM +0900, Mark Brown wrote: > > On Tue, Oct 27, 2015 at 04:42:13PM +0900, Vinod Koul wrote: > > > + if (err < 0) > > > + dev_err(&hdac->dev, "Failed to query pcm params for nid: %d\n", cvt->nid); > > That looks like the NID is being printed as an error code. > No this prints the NID for which query fails, but agree we should print the > error code too, that might be very helpful :) No, it's also the format for the message - normally we do "message: code". > > > + /* > > > + * Currently on board only 1 pin and 1 converter enabled for > > > + * simplification, more will be added eventually > > > + * So using fixed map for dai_id:pin:cvt > > > + */ > > > + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], > > > + hdmi->cvt_nid[0], 0); > > I'm not entirely sure I understand what this is all doing. It looks > > like it's trying to translate the HDA widget map into a DAPM map which > > seems sensible but it appears it's making some simplifying assumptions > > about the device it's dealing with? > The device is actually quite simple and yes we simplified even further by > ignoring multiple pins for now. We will keep adding more features and adding > stuff to map as we go along.. That's not giving me a clear picture of what the code is doing or how we're working with the device - we've got some code parsing the HDA graph, some code hard coding things and I don't really know why or how anything fits together so I'm a bit nonplussed about what I'm reviewing here.
On Wed, Nov 04, 2015 at 02:48:45PM +0000, Mark Brown wrote: > > > > + /* > > > > + * Currently on board only 1 pin and 1 converter enabled for > > > > + * simplification, more will be added eventually > > > > + * So using fixed map for dai_id:pin:cvt > > > > + */ > > > > + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], > > > > + hdmi->cvt_nid[0], 0); > > > > I'm not entirely sure I understand what this is all doing. It looks > > > like it's trying to translate the HDA widget map into a DAPM map which > > > seems sensible but it appears it's making some simplifying assumptions > > > about the device it's dealing with? > > > The device is actually quite simple and yes we simplified even further by > > ignoring multiple pins for now. We will keep adding more features and adding > > stuff to map as we go along.. > > That's not giving me a clear picture of what the code is doing or how > we're working with the device - we've got some code parsing the HDA > graph, some code hard coding things and I don't really know why or how > anything fits together so I'm a bit nonplussed about what I'm reviewing > here. Sorry for late reply, somehow seemed to miss this earlier.. Here is the complete picture let me know if things are not clear This code has below structure (from the specs). Root Node (0) | AFG (1) | Converter (2) ---------------- Pin Widget (5) | Converter (3) ---------------- Pin Widget (6) | Converter (4) ---------------- Pin Widget (7) | Vendor Widget (8) Numbers in braces indicated NID values for these nodes Currently we are using only one pin which is used on our ref board and seems to be default config. After the base driver is done we will add code to enumerate all the nodes. Based on node capability we will parse and add widgets for all the queried nodes. So for this case will be 3 nodes and 3 widgets created Since coding for each widget would not make sense so we created a generic function hdac_hdmi_init_dai_map() based on the node passed which we will use later for all the queried pins Thanks
On Mon, 09 Nov 2015 05:39:20 +0100, Vinod Koul wrote: > > On Wed, Nov 04, 2015 at 02:48:45PM +0000, Mark Brown wrote: > > > > > + /* > > > > > + * Currently on board only 1 pin and 1 converter enabled for > > > > > + * simplification, more will be added eventually > > > > > + * So using fixed map for dai_id:pin:cvt > > > > > + */ > > > > > + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], > > > > > + hdmi->cvt_nid[0], 0); > > > > > > I'm not entirely sure I understand what this is all doing. It looks > > > > like it's trying to translate the HDA widget map into a DAPM map which > > > > seems sensible but it appears it's making some simplifying assumptions > > > > about the device it's dealing with? > > > > > The device is actually quite simple and yes we simplified even further by > > > ignoring multiple pins for now. We will keep adding more features and adding > > > stuff to map as we go along.. > > > > That's not giving me a clear picture of what the code is doing or how > > we're working with the device - we've got some code parsing the HDA > > graph, some code hard coding things and I don't really know why or how > > anything fits together so I'm a bit nonplussed about what I'm reviewing > > here. > > Sorry for late reply, somehow seemed to miss this earlier.. > > Here is the complete picture let me know if things are not clear > > This code has below structure (from the specs). > > Root Node (0) > | > AFG (1) > | > Converter (2) ---------------- Pin Widget (5) > | > Converter (3) ---------------- Pin Widget (6) > | > Converter (4) ---------------- Pin Widget (7) > | > Vendor Widget (8) > > Numbers in braces indicated NID values for these nodes > > Currently we are using only one pin which is used on our ref board and seems > to be default config. > After the base driver is done we will add code to enumerate all the nodes. > Based on node capability we will parse and add widgets for all the queried > nodes. So for this case will be 3 nodes and 3 widgets created > > Since coding for each widget would not make sense so we created a generic > function hdac_hdmi_init_dai_map() based on the node passed which we will use > later for all the queried pins Note that the mapping between converters and pins are arbitrary on many HDMI/DP codecs. Although it's implicitly implemented as 1:1 on a few Intel codecs (in GPU), with the extension of MST, the routing will be again dynamic, too. Also, many codecs have amp on converter or pin in addition. Since it's targeted only for ASoC skylake and upward, it's fine to start from the simplest assumption. But you need to make clear how generic your driver will support in feature, as the code complexity will depend on it. Takashi
On Mon, Nov 09, 2015 at 08:51:11AM +0100, Takashi Iwai wrote: > On Mon, 09 Nov 2015 05:39:20 +0100, > Vinod Koul wrote: > > > > On Wed, Nov 04, 2015 at 02:48:45PM +0000, Mark Brown wrote: > > > > > > + /* > > > > > > + * Currently on board only 1 pin and 1 converter enabled for > > > > > > + * simplification, more will be added eventually > > > > > > + * So using fixed map for dai_id:pin:cvt > > > > > > + */ > > > > > > + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], > > > > > > + hdmi->cvt_nid[0], 0); > > > > > > > > I'm not entirely sure I understand what this is all doing. It looks > > > > > like it's trying to translate the HDA widget map into a DAPM map which > > > > > seems sensible but it appears it's making some simplifying assumptions > > > > > about the device it's dealing with? > > > > > > > The device is actually quite simple and yes we simplified even further by > > > > ignoring multiple pins for now. We will keep adding more features and adding > > > > stuff to map as we go along.. > > > > > > That's not giving me a clear picture of what the code is doing or how > > > we're working with the device - we've got some code parsing the HDA > > > graph, some code hard coding things and I don't really know why or how > > > anything fits together so I'm a bit nonplussed about what I'm reviewing > > > here. > > > > Sorry for late reply, somehow seemed to miss this earlier.. > > > > Here is the complete picture let me know if things are not clear > > > > This code has below structure (from the specs). > > > > Root Node (0) > > | > > AFG (1) > > | > > Converter (2) ---------------- Pin Widget (5) > > | > > Converter (3) ---------------- Pin Widget (6) > > | > > Converter (4) ---------------- Pin Widget (7) > > | > > Vendor Widget (8) > > > > Numbers in braces indicated NID values for these nodes > > > > Currently we are using only one pin which is used on our ref board and seems > > to be default config. > > After the base driver is done we will add code to enumerate all the nodes. > > Based on node capability we will parse and add widgets for all the queried > > nodes. So for this case will be 3 nodes and 3 widgets created > > > > Since coding for each widget would not make sense so we created a generic > > function hdac_hdmi_init_dai_map() based on the node passed which we will use > > later for all the queried pins > > Note that the mapping between converters and pins are arbitrary on > many HDMI/DP codecs. Although it's implicitly implemented as 1:1 on a > few Intel codecs (in GPU), with the extension of MST, the routing will > be again dynamic, too. Also, many codecs have amp on converter or pin > in addition. Yes that is why we didn't say converter pin pair although by looking at diagram one can assume that and in many case it is true but we should not rely on this in our code > Since it's targeted only for ASoC skylake and upward, it's fine to > start from the simplest assumption. But you need to make clear how > generic your driver will support in feature, as the code complexity > will depend on it. So right now we are going to use 1:1 mapping as simple design but the thinking from us is that we should add DAPM widgets for converters and pins and routing to pin should be decided by DAPM map. The converter to pin configuration should be derived by the user settings.
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 70e5a75901aa..00662ff1c280 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -66,6 +66,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES8328_I2C if I2C select SND_SOC_GTM601 select SND_SOC_ICS43432 + select SND_SOC_HDAC_HDMI select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -446,6 +447,10 @@ config SND_SOC_BT_SCO config SND_SOC_DMIC tristate +config SND_SOC_HDAC_HDMI + tristate + select SND_HDA_EXT_CORE + config SND_SOC_ES8328 tristate "Everest Semi ES8328 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index be1491acb6ae..d2cc5ea67e2c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -59,6 +59,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-ics43432-objs := ics43432.o +snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -251,6 +252,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_ICS43432) += snd-soc-ics43432.o +obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c new file mode 100644 index 000000000000..bda91a31f839 --- /dev/null +++ b/sound/soc/codecs/hdac_hdmi.c @@ -0,0 +1,349 @@ +/* + * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Samreen Nilofer <samreen.nilofer@intel.com> + * Subhransu S. Prusty <subhransu.s.prusty@intel.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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 "../../hda/local.h" + +#define PIN_OUT (AC_PINCTL_OUT_EN) +#define HDA_MAX_CONNECTIONS 32 + +struct hdac_hdmi_cvt_params { + unsigned int channels_min; + unsigned int channels_max; + u32 rates; + u64 formats; + unsigned int maxbps; +}; + +struct hdac_hdmi_cvt { + hda_nid_t nid; + struct hdac_hdmi_cvt_params params; +}; + +struct hdac_hdmi_pin { + hda_nid_t nid; + int num_mux_nids; + hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; +}; + +struct hdac_hdmi_dai_pin_map { + int dai_id; + struct hdac_hdmi_pin pin; + struct hdac_hdmi_cvt cvt; +}; + +struct hdac_hdmi_priv { + hda_nid_t pin_nid[3]; + hda_nid_t cvt_nid[3]; + struct hdac_hdmi_dai_pin_map dai_map[3]; +}; + +static int hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) +{ + int err; + + /* Only stereo supported as of now */ + cvt->params.channels_min = cvt->params.channels_max = 2; + + err = snd_hdac_query_supported_pcm(hdac, cvt->nid, + &cvt->params.rates, + &cvt->params.formats, + &cvt->params.maxbps); + if (err < 0) + dev_err(&hdac->dev, "Failed to query pcm params for nid: %d\n", cvt->nid); + + return err; +} + +static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, + struct hdac_hdmi_pin *pin) +{ + if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { + dev_warn(&hdac->hdac.dev, "HDMI: pin %d wcaps %#x does not support connection list\n", + pin->nid, get_wcaps(&hdac->hdac, pin->nid)); + return -EINVAL; + } + + pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, + pin->mux_nids, HDA_MAX_CONNECTIONS); + if (pin->num_mux_nids == 0) { + dev_err(&hdac->hdac.dev, "No connections found\n"); + return -ENODEV; + } + + dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin %d\n", pin->num_mux_nids, pin->nid); + + return pin->num_mux_nids; +} + +static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, + enum snd_soc_dapm_type id, const char *wname, const char *stream) +{ + w->id = id; + w->name = wname; + w->sname = stream; + w->reg = SND_SOC_NOPM; + w->shift = 0; + w->kcontrol_news = NULL; + w->num_kcontrols = 0; + w->priv = NULL; +} + +static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, + const char *sink, const char *control, const char *src) +{ + route->sink = sink; + route->source = src; + route->control = control; + route->connected = NULL; +} + +static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, + struct hdac_hdmi_dai_pin_map *dai_map) +{ + struct snd_soc_dapm_route route[1]; + struct snd_soc_dapm_widget widgets[2] = { {0} }; + + memset(&route, 0, sizeof(route)); + + hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, + "hif1 Output", NULL); + hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, + "Coverter 1", "hif1"); + + hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); + + snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); + snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); +} + +static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map, + hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id) +{ + int ret; + + dai_map->dai_id = dai_id; + dai_map->pin.nid = pin_nid; + + ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin); + if (ret < 0) { + dev_err(&edev->hdac.dev, "Error querying connection list: %d\n", + ret); + return ret; + } + + dai_map->cvt.nid = cvt_nid; + + /* Enable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + /* Enable transmission */ + snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, 1); + + /* Category Code (CC) to zero */ + snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0); + + snd_hdac_codec_write(&edev->hdac, pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, 0); + + return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt); +} + +/* + * Parse all nodes and store the cvt/pin nids in array + * Add one time initialization for pin and cvt widgets + */ +static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) +{ + hda_nid_t nid; + int i; + struct hdac_device *hdac = &edev->hdac; + struct hdac_hdmi_priv *hdmi = edev->private_data; + int cvt_nid = 0, pin_nid = 0; + + hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); + if (!nid || hdac->num_nodes < 0) { + dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); + return -EINVAL; + } + + hdac->start_nid = nid; + + dev_dbg(&hdac->dev, "Number of nodes %d\n", hdac->num_nodes); + + for (i = 0; i < hdac->num_nodes; i++, nid++) { + unsigned int caps; + unsigned int type; + + caps = get_wcaps(hdac, nid); + type = get_wcaps_type(caps); + + dev_dbg(&hdac->dev, "nid: %d type: %d\n", nid, type); + + if (!(caps & AC_WCAP_DIGITAL)) + continue; + + switch (type) { + + case AC_WID_AUD_OUT: + hdmi->cvt_nid[cvt_nid] = nid; + cvt_nid++; + break; + + case AC_WID_PIN: + hdmi->pin_nid[pin_nid] = nid; + pin_nid++; + break; + } + } + + hdac->end_nid = nid; + + dev_dbg(&hdac->dev, "Number of pin nid: %d cvt nid: %d\n", + pin_nid, cvt_nid); + + if (!pin_nid || !cvt_nid) + return -EIO; + + /* + * Currently on board only 1 pin and 1 converter enabled for + * simplification, more will be added eventually + * So using fixed map for dai_id:pin:cvt + */ + return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], + hdmi->cvt_nid[0], 0); +} + +static int hdmi_codec_probe(struct snd_soc_codec *codec) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(&codec->component); + + edev->scodec = codec; + + create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); + + /* Imp: Store the card pointer in hda_codec */ + edev->card = dapm->card->snd_card; + + return 0; +} + +static struct snd_soc_codec_driver hdmi_hda_codec = { + .probe = hdmi_codec_probe, + .idle_bias_off = true, +}; + +static struct snd_soc_dai_driver hdmi_dais[] = { + { .name = "intel-hdmi-hif1", + .playback = { + .stream_name = "hif1", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + + }, + }, +}; + +static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) +{ + struct hdac_device *codec = &edev->hdac; + struct hdac_hdmi_priv *hdmi_priv; + int ret = 0; + + dev_dbg(&codec->dev, "%s vendor_id:rev_id %x:%x\n", __func__, + codec->vendor_id, codec->revision_id); + + hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); + if (hdmi_priv == NULL) + return -ENOMEM; + + edev->private_data = hdmi_priv; + + dev_set_drvdata(&codec->dev, edev); + + ret = hdac_hdmi_parse_and_map_nid(edev); + if (ret < 0) + return ret; + + /* ASoC specific initialization */ + return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, + hdmi_dais, ARRAY_SIZE(hdmi_dais)); +} + +static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) +{ + snd_soc_unregister_codec(&edev->hdac.dev); + + return 0; +} + +static const struct hda_device_id hdmi_list[] = { + HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), + {} +}; + +MODULE_DEVICE_TABLE(hdaudio, hdmi_list); + +static struct hdac_ext_driver hdmi_driver = { + . hdac = { + .driver = { + .name = "HDMI HDA Codec", + }, + .id_table = hdmi_list, + }, + .probe = hdac_hdmi_dev_probe, + .remove = hdac_hdmi_dev_remove, +}; + +static int __init hdmi_init(void) +{ + return snd_hda_ext_driver_register(&hdmi_driver); +} + +static void __exit hdmi_exit(void) +{ + snd_hda_ext_driver_unregister(&hdmi_driver); +} + +module_init(hdmi_init); +module_exit(hdmi_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HDMI HD codec"); +MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); +MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>");