118382eadSSubhransu S. Prusty /* 218382eadSSubhransu S. Prusty * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms 318382eadSSubhransu S. Prusty * 418382eadSSubhransu S. Prusty * Copyright (C) 2014-2015 Intel Corp 518382eadSSubhransu S. Prusty * Author: Samreen Nilofer <samreen.nilofer@intel.com> 618382eadSSubhransu S. Prusty * Subhransu S. Prusty <subhransu.s.prusty@intel.com> 718382eadSSubhransu S. Prusty * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 818382eadSSubhransu S. Prusty * 918382eadSSubhransu S. Prusty * This program is free software; you can redistribute it and/or modify 1018382eadSSubhransu S. Prusty * it under the terms of the GNU General Public License as published by 1118382eadSSubhransu S. Prusty * the Free Software Foundation; version 2 of the License. 1218382eadSSubhransu S. Prusty * 1318382eadSSubhransu S. Prusty * This program is distributed in the hope that it will be useful, but 1418382eadSSubhransu S. Prusty * WITHOUT ANY WARRANTY; without even the implied warranty of 1518382eadSSubhransu S. Prusty * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1618382eadSSubhransu S. Prusty * General Public License for more details. 1718382eadSSubhransu S. Prusty * 1818382eadSSubhransu S. Prusty * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1918382eadSSubhransu S. Prusty */ 2018382eadSSubhransu S. Prusty #include <linux/init.h> 2118382eadSSubhransu S. Prusty #include <linux/delay.h> 2218382eadSSubhransu S. Prusty #include <linux/module.h> 2318382eadSSubhransu S. Prusty #include <linux/pm_runtime.h> 2418382eadSSubhransu S. Prusty #include <sound/pcm_params.h> 2518382eadSSubhransu S. Prusty #include <sound/soc.h> 2618382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h> 2718382eadSSubhransu S. Prusty #include "../../hda/local.h" 2818382eadSSubhransu S. Prusty 2918382eadSSubhransu S. Prusty #define PIN_OUT (AC_PINCTL_OUT_EN) 3018382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS 32 3118382eadSSubhransu S. Prusty 3218382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params { 3318382eadSSubhransu S. Prusty unsigned int channels_min; 3418382eadSSubhransu S. Prusty unsigned int channels_max; 3518382eadSSubhransu S. Prusty u32 rates; 3618382eadSSubhransu S. Prusty u64 formats; 3718382eadSSubhransu S. Prusty unsigned int maxbps; 3818382eadSSubhransu S. Prusty }; 3918382eadSSubhransu S. Prusty 4018382eadSSubhransu S. Prusty struct hdac_hdmi_cvt { 4118382eadSSubhransu S. Prusty hda_nid_t nid; 4218382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params params; 4318382eadSSubhransu S. Prusty }; 4418382eadSSubhransu S. Prusty 4518382eadSSubhransu S. Prusty struct hdac_hdmi_pin { 4618382eadSSubhransu S. Prusty hda_nid_t nid; 4718382eadSSubhransu S. Prusty int num_mux_nids; 4818382eadSSubhransu S. Prusty hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; 4918382eadSSubhransu S. Prusty }; 5018382eadSSubhransu S. Prusty 5118382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map { 5218382eadSSubhransu S. Prusty int dai_id; 5318382eadSSubhransu S. Prusty struct hdac_hdmi_pin pin; 5418382eadSSubhransu S. Prusty struct hdac_hdmi_cvt cvt; 5518382eadSSubhransu S. Prusty }; 5618382eadSSubhransu S. Prusty 5718382eadSSubhransu S. Prusty struct hdac_hdmi_priv { 5818382eadSSubhransu S. Prusty hda_nid_t pin_nid[3]; 5918382eadSSubhransu S. Prusty hda_nid_t cvt_nid[3]; 6018382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map dai_map[3]; 6118382eadSSubhransu S. Prusty }; 6218382eadSSubhransu S. Prusty 63*e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 64*e342ac08SSubhransu S. Prusty { 65*e342ac08SSubhransu S. Prusty struct hdac_device *hdac = container_of(dev, struct hdac_device, dev); 66*e342ac08SSubhransu S. Prusty 67*e342ac08SSubhransu S. Prusty return container_of(hdac, struct hdac_ext_device, hdac); 68*e342ac08SSubhransu S. Prusty } 69*e342ac08SSubhransu S. Prusty 7018382eadSSubhransu S. Prusty static int 7118382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 7218382eadSSubhransu S. Prusty { 7318382eadSSubhransu S. Prusty int err; 7418382eadSSubhransu S. Prusty 7518382eadSSubhransu S. Prusty /* Only stereo supported as of now */ 7618382eadSSubhransu S. Prusty cvt->params.channels_min = cvt->params.channels_max = 2; 7718382eadSSubhransu S. Prusty 7818382eadSSubhransu S. Prusty err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 7918382eadSSubhransu S. Prusty &cvt->params.rates, 8018382eadSSubhransu S. Prusty &cvt->params.formats, 8118382eadSSubhransu S. Prusty &cvt->params.maxbps); 8218382eadSSubhransu S. Prusty if (err < 0) 8318382eadSSubhransu S. Prusty dev_err(&hdac->dev, 8418382eadSSubhransu S. Prusty "Failed to query pcm params for nid %d: %d\n", 8518382eadSSubhransu S. Prusty cvt->nid, err); 8618382eadSSubhransu S. Prusty 8718382eadSSubhransu S. Prusty return err; 8818382eadSSubhransu S. Prusty } 8918382eadSSubhransu S. Prusty 9018382eadSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, 9118382eadSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 9218382eadSSubhransu S. Prusty { 9318382eadSSubhransu S. Prusty if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { 9418382eadSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 9518382eadSSubhransu S. Prusty "HDMI: pin %d wcaps %#x does not support connection list\n", 9618382eadSSubhransu S. Prusty pin->nid, get_wcaps(&hdac->hdac, pin->nid)); 9718382eadSSubhransu S. Prusty return -EINVAL; 9818382eadSSubhransu S. Prusty } 9918382eadSSubhransu S. Prusty 10018382eadSSubhransu S. Prusty pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, 10118382eadSSubhransu S. Prusty pin->mux_nids, HDA_MAX_CONNECTIONS); 10218382eadSSubhransu S. Prusty if (pin->num_mux_nids == 0) { 10318382eadSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "No connections found\n"); 10418382eadSSubhransu S. Prusty return -ENODEV; 10518382eadSSubhransu S. Prusty } 10618382eadSSubhransu S. Prusty 10718382eadSSubhransu S. Prusty return pin->num_mux_nids; 10818382eadSSubhransu S. Prusty } 10918382eadSSubhransu S. Prusty 11018382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, 11118382eadSSubhransu S. Prusty enum snd_soc_dapm_type id, 11218382eadSSubhransu S. Prusty const char *wname, const char *stream) 11318382eadSSubhransu S. Prusty { 11418382eadSSubhransu S. Prusty w->id = id; 11518382eadSSubhransu S. Prusty w->name = wname; 11618382eadSSubhransu S. Prusty w->sname = stream; 11718382eadSSubhransu S. Prusty w->reg = SND_SOC_NOPM; 11818382eadSSubhransu S. Prusty w->shift = 0; 11918382eadSSubhransu S. Prusty w->kcontrol_news = NULL; 12018382eadSSubhransu S. Prusty w->num_kcontrols = 0; 12118382eadSSubhransu S. Prusty w->priv = NULL; 12218382eadSSubhransu S. Prusty } 12318382eadSSubhransu S. Prusty 12418382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 12518382eadSSubhransu S. Prusty const char *sink, const char *control, const char *src) 12618382eadSSubhransu S. Prusty { 12718382eadSSubhransu S. Prusty route->sink = sink; 12818382eadSSubhransu S. Prusty route->source = src; 12918382eadSSubhransu S. Prusty route->control = control; 13018382eadSSubhransu S. Prusty route->connected = NULL; 13118382eadSSubhransu S. Prusty } 13218382eadSSubhransu S. Prusty 13318382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, 13418382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map) 13518382eadSSubhransu S. Prusty { 13618382eadSSubhransu S. Prusty struct snd_soc_dapm_route route[1]; 13718382eadSSubhransu S. Prusty struct snd_soc_dapm_widget widgets[2] = { {0} }; 13818382eadSSubhransu S. Prusty 13918382eadSSubhransu S. Prusty memset(&route, 0, sizeof(route)); 14018382eadSSubhransu S. Prusty 14118382eadSSubhransu S. Prusty hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, 14218382eadSSubhransu S. Prusty "hif1 Output", NULL); 14318382eadSSubhransu S. Prusty hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, 14418382eadSSubhransu S. Prusty "Coverter 1", "hif1"); 14518382eadSSubhransu S. Prusty 14618382eadSSubhransu S. Prusty hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); 14718382eadSSubhransu S. Prusty 14818382eadSSubhransu S. Prusty snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); 14918382eadSSubhransu S. Prusty snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); 15018382eadSSubhransu S. Prusty } 15118382eadSSubhransu S. Prusty 15218382eadSSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev, 15318382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map, 15418382eadSSubhransu S. Prusty hda_nid_t pin_nid, hda_nid_t cvt_nid, int dai_id) 15518382eadSSubhransu S. Prusty { 15618382eadSSubhransu S. Prusty int ret; 15718382eadSSubhransu S. Prusty 15818382eadSSubhransu S. Prusty dai_map->dai_id = dai_id; 15918382eadSSubhransu S. Prusty dai_map->pin.nid = pin_nid; 16018382eadSSubhransu S. Prusty 16118382eadSSubhransu S. Prusty ret = hdac_hdmi_query_pin_connlist(edev, &dai_map->pin); 16218382eadSSubhransu S. Prusty if (ret < 0) { 16318382eadSSubhransu S. Prusty dev_err(&edev->hdac.dev, 16418382eadSSubhransu S. Prusty "Error querying connection list: %d\n", ret); 16518382eadSSubhransu S. Prusty return ret; 16618382eadSSubhransu S. Prusty } 16718382eadSSubhransu S. Prusty 16818382eadSSubhransu S. Prusty dai_map->cvt.nid = cvt_nid; 16918382eadSSubhransu S. Prusty 17018382eadSSubhransu S. Prusty /* Enable out path for this pin widget */ 17118382eadSSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, pin_nid, 0, 17218382eadSSubhransu S. Prusty AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 17318382eadSSubhransu S. Prusty 17418382eadSSubhransu S. Prusty /* Enable transmission */ 17518382eadSSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, 17618382eadSSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_1, 1); 17718382eadSSubhransu S. Prusty 17818382eadSSubhransu S. Prusty /* Category Code (CC) to zero */ 17918382eadSSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, cvt_nid, 0, 18018382eadSSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_2, 0); 18118382eadSSubhransu S. Prusty 18218382eadSSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, pin_nid, 0, 18318382eadSSubhransu S. Prusty AC_VERB_SET_CONNECT_SEL, 0); 18418382eadSSubhransu S. Prusty 18518382eadSSubhransu S. Prusty return hdac_hdmi_query_cvt_params(&edev->hdac, &dai_map->cvt); 18618382eadSSubhransu S. Prusty } 18718382eadSSubhransu S. Prusty 18818382eadSSubhransu S. Prusty /* 18918382eadSSubhransu S. Prusty * Parse all nodes and store the cvt/pin nids in array 19018382eadSSubhransu S. Prusty * Add one time initialization for pin and cvt widgets 19118382eadSSubhransu S. Prusty */ 19218382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) 19318382eadSSubhransu S. Prusty { 19418382eadSSubhransu S. Prusty hda_nid_t nid; 19518382eadSSubhransu S. Prusty int i; 19618382eadSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 19718382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 19818382eadSSubhransu S. Prusty int cvt_nid = 0, pin_nid = 0; 19918382eadSSubhransu S. Prusty 20018382eadSSubhransu S. Prusty hdac->num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); 20118382eadSSubhransu S. Prusty if (!nid || hdac->num_nodes < 0) { 20218382eadSSubhransu S. Prusty dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 20318382eadSSubhransu S. Prusty return -EINVAL; 20418382eadSSubhransu S. Prusty } 20518382eadSSubhransu S. Prusty 20618382eadSSubhransu S. Prusty hdac->start_nid = nid; 20718382eadSSubhransu S. Prusty 20818382eadSSubhransu S. Prusty for (i = 0; i < hdac->num_nodes; i++, nid++) { 20918382eadSSubhransu S. Prusty unsigned int caps; 21018382eadSSubhransu S. Prusty unsigned int type; 21118382eadSSubhransu S. Prusty 21218382eadSSubhransu S. Prusty caps = get_wcaps(hdac, nid); 21318382eadSSubhransu S. Prusty type = get_wcaps_type(caps); 21418382eadSSubhransu S. Prusty 21518382eadSSubhransu S. Prusty if (!(caps & AC_WCAP_DIGITAL)) 21618382eadSSubhransu S. Prusty continue; 21718382eadSSubhransu S. Prusty 21818382eadSSubhransu S. Prusty switch (type) { 21918382eadSSubhransu S. Prusty 22018382eadSSubhransu S. Prusty case AC_WID_AUD_OUT: 22118382eadSSubhransu S. Prusty hdmi->cvt_nid[cvt_nid] = nid; 22218382eadSSubhransu S. Prusty cvt_nid++; 22318382eadSSubhransu S. Prusty break; 22418382eadSSubhransu S. Prusty 22518382eadSSubhransu S. Prusty case AC_WID_PIN: 22618382eadSSubhransu S. Prusty hdmi->pin_nid[pin_nid] = nid; 22718382eadSSubhransu S. Prusty pin_nid++; 22818382eadSSubhransu S. Prusty break; 22918382eadSSubhransu S. Prusty } 23018382eadSSubhransu S. Prusty } 23118382eadSSubhransu S. Prusty 23218382eadSSubhransu S. Prusty hdac->end_nid = nid; 23318382eadSSubhransu S. Prusty 23418382eadSSubhransu S. Prusty if (!pin_nid || !cvt_nid) 23518382eadSSubhransu S. Prusty return -EIO; 23618382eadSSubhransu S. Prusty 23718382eadSSubhransu S. Prusty /* 23818382eadSSubhransu S. Prusty * Currently on board only 1 pin and 1 converter is enabled for 23918382eadSSubhransu S. Prusty * simplification, more will be added eventually 24018382eadSSubhransu S. Prusty * So using fixed map for dai_id:pin:cvt 24118382eadSSubhransu S. Prusty */ 24218382eadSSubhransu S. Prusty return hdac_hdmi_init_dai_map(edev, &hdmi->dai_map[0], hdmi->pin_nid[0], 24318382eadSSubhransu S. Prusty hdmi->cvt_nid[0], 0); 24418382eadSSubhransu S. Prusty } 24518382eadSSubhransu S. Prusty 24618382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec) 24718382eadSSubhransu S. Prusty { 24818382eadSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 24918382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 25018382eadSSubhransu S. Prusty struct snd_soc_dapm_context *dapm = 25118382eadSSubhransu S. Prusty snd_soc_component_get_dapm(&codec->component); 25218382eadSSubhransu S. Prusty 25318382eadSSubhransu S. Prusty edev->scodec = codec; 25418382eadSSubhransu S. Prusty 25518382eadSSubhransu S. Prusty create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); 25618382eadSSubhransu S. Prusty 25718382eadSSubhransu S. Prusty /* Imp: Store the card pointer in hda_codec */ 25818382eadSSubhransu S. Prusty edev->card = dapm->card->snd_card; 25918382eadSSubhransu S. Prusty 260*e342ac08SSubhransu S. Prusty /* 261*e342ac08SSubhransu S. Prusty * hdac_device core already sets the state to active and calls 262*e342ac08SSubhransu S. Prusty * get_noresume. So enable runtime and set the device to suspend. 263*e342ac08SSubhransu S. Prusty */ 264*e342ac08SSubhransu S. Prusty pm_runtime_enable(&edev->hdac.dev); 265*e342ac08SSubhransu S. Prusty pm_runtime_put(&edev->hdac.dev); 266*e342ac08SSubhransu S. Prusty pm_runtime_suspend(&edev->hdac.dev); 267*e342ac08SSubhransu S. Prusty 268*e342ac08SSubhransu S. Prusty return 0; 269*e342ac08SSubhransu S. Prusty } 270*e342ac08SSubhransu S. Prusty 271*e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec) 272*e342ac08SSubhransu S. Prusty { 273*e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 274*e342ac08SSubhransu S. Prusty 275*e342ac08SSubhransu S. Prusty pm_runtime_disable(&edev->hdac.dev); 27618382eadSSubhransu S. Prusty return 0; 27718382eadSSubhransu S. Prusty } 27818382eadSSubhransu S. Prusty 27918382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = { 28018382eadSSubhransu S. Prusty .probe = hdmi_codec_probe, 281*e342ac08SSubhransu S. Prusty .remove = hdmi_codec_remove, 28218382eadSSubhransu S. Prusty .idle_bias_off = true, 28318382eadSSubhransu S. Prusty }; 28418382eadSSubhransu S. Prusty 28518382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = { 28618382eadSSubhransu S. Prusty { .name = "intel-hdmi-hif1", 28718382eadSSubhransu S. Prusty .playback = { 28818382eadSSubhransu S. Prusty .stream_name = "hif1", 28918382eadSSubhransu S. Prusty .channels_min = 2, 29018382eadSSubhransu S. Prusty .channels_max = 2, 29118382eadSSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | 29218382eadSSubhransu S. Prusty SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 29318382eadSSubhransu S. Prusty SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 29418382eadSSubhransu S. Prusty SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, 29518382eadSSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | 29618382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S20_3LE | 29718382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE | 29818382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 29918382eadSSubhransu S. Prusty 30018382eadSSubhransu S. Prusty }, 30118382eadSSubhransu S. Prusty }, 30218382eadSSubhransu S. Prusty }; 30318382eadSSubhransu S. Prusty 30418382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) 30518382eadSSubhransu S. Prusty { 30618382eadSSubhransu S. Prusty struct hdac_device *codec = &edev->hdac; 30718382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi_priv; 30818382eadSSubhransu S. Prusty int ret = 0; 30918382eadSSubhransu S. Prusty 31018382eadSSubhransu S. Prusty hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 31118382eadSSubhransu S. Prusty if (hdmi_priv == NULL) 31218382eadSSubhransu S. Prusty return -ENOMEM; 31318382eadSSubhransu S. Prusty 31418382eadSSubhransu S. Prusty edev->private_data = hdmi_priv; 31518382eadSSubhransu S. Prusty 31618382eadSSubhransu S. Prusty dev_set_drvdata(&codec->dev, edev); 31718382eadSSubhransu S. Prusty 31818382eadSSubhransu S. Prusty ret = hdac_hdmi_parse_and_map_nid(edev); 31918382eadSSubhransu S. Prusty if (ret < 0) 32018382eadSSubhransu S. Prusty return ret; 32118382eadSSubhransu S. Prusty 32218382eadSSubhransu S. Prusty /* ASoC specific initialization */ 32318382eadSSubhransu S. Prusty return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 32418382eadSSubhransu S. Prusty hdmi_dais, ARRAY_SIZE(hdmi_dais)); 32518382eadSSubhransu S. Prusty } 32618382eadSSubhransu S. Prusty 32718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) 32818382eadSSubhransu S. Prusty { 32918382eadSSubhransu S. Prusty snd_soc_unregister_codec(&edev->hdac.dev); 33018382eadSSubhransu S. Prusty 33118382eadSSubhransu S. Prusty return 0; 33218382eadSSubhransu S. Prusty } 33318382eadSSubhransu S. Prusty 334*e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM 335*e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev) 336*e342ac08SSubhransu S. Prusty { 337*e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 338*e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 339*e342ac08SSubhransu S. Prusty 340*e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 341*e342ac08SSubhransu S. Prusty 342*e342ac08SSubhransu S. Prusty /* Power down afg */ 343*e342ac08SSubhransu S. Prusty if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) 344*e342ac08SSubhransu S. Prusty snd_hdac_codec_write(hdac, hdac->afg, 0, 345*e342ac08SSubhransu S. Prusty AC_VERB_SET_POWER_STATE, AC_PWRST_D3); 346*e342ac08SSubhransu S. Prusty 347*e342ac08SSubhransu S. Prusty return 0; 348*e342ac08SSubhransu S. Prusty } 349*e342ac08SSubhransu S. Prusty 350*e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev) 351*e342ac08SSubhransu S. Prusty { 352*e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 353*e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 354*e342ac08SSubhransu S. Prusty 355*e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 356*e342ac08SSubhransu S. Prusty 357*e342ac08SSubhransu S. Prusty /* Power up afg */ 358*e342ac08SSubhransu S. Prusty if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) 359*e342ac08SSubhransu S. Prusty snd_hdac_codec_write(hdac, hdac->afg, 0, 360*e342ac08SSubhransu S. Prusty AC_VERB_SET_POWER_STATE, AC_PWRST_D0); 361*e342ac08SSubhransu S. Prusty 362*e342ac08SSubhransu S. Prusty return 0; 363*e342ac08SSubhransu S. Prusty } 364*e342ac08SSubhransu S. Prusty #else 365*e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL 366*e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL 367*e342ac08SSubhransu S. Prusty #endif 368*e342ac08SSubhransu S. Prusty 369*e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = { 370*e342ac08SSubhransu S. Prusty SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) 371*e342ac08SSubhransu S. Prusty }; 372*e342ac08SSubhransu S. Prusty 37318382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = { 37418382eadSSubhransu S. Prusty HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), 37518382eadSSubhransu S. Prusty {} 37618382eadSSubhransu S. Prusty }; 37718382eadSSubhransu S. Prusty 37818382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list); 37918382eadSSubhransu S. Prusty 38018382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = { 38118382eadSSubhransu S. Prusty . hdac = { 38218382eadSSubhransu S. Prusty .driver = { 38318382eadSSubhransu S. Prusty .name = "HDMI HDA Codec", 384*e342ac08SSubhransu S. Prusty .pm = &hdac_hdmi_pm, 38518382eadSSubhransu S. Prusty }, 38618382eadSSubhransu S. Prusty .id_table = hdmi_list, 38718382eadSSubhransu S. Prusty }, 38818382eadSSubhransu S. Prusty .probe = hdac_hdmi_dev_probe, 38918382eadSSubhransu S. Prusty .remove = hdac_hdmi_dev_remove, 39018382eadSSubhransu S. Prusty }; 39118382eadSSubhransu S. Prusty 39218382eadSSubhransu S. Prusty static int __init hdmi_init(void) 39318382eadSSubhransu S. Prusty { 39418382eadSSubhransu S. Prusty return snd_hda_ext_driver_register(&hdmi_driver); 39518382eadSSubhransu S. Prusty } 39618382eadSSubhransu S. Prusty 39718382eadSSubhransu S. Prusty static void __exit hdmi_exit(void) 39818382eadSSubhransu S. Prusty { 39918382eadSSubhransu S. Prusty snd_hda_ext_driver_unregister(&hdmi_driver); 40018382eadSSubhransu S. Prusty } 40118382eadSSubhransu S. Prusty 40218382eadSSubhransu S. Prusty module_init(hdmi_init); 40318382eadSSubhransu S. Prusty module_exit(hdmi_exit); 40418382eadSSubhransu S. Prusty 40518382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 40618382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec"); 40718382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); 40818382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); 409