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> 24a657f1d0SSubhransu S. Prusty #include <linux/hdmi.h> 2518382eadSSubhransu S. Prusty #include <sound/pcm_params.h> 2618382eadSSubhransu S. Prusty #include <sound/soc.h> 2718382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h> 2807f083abSSubhransu S. Prusty #include <sound/hda_i915.h> 2918382eadSSubhransu S. Prusty #include "../../hda/local.h" 3018382eadSSubhransu S. Prusty 31b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE 0xb080 32b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE 0xb000 3318382eadSSubhransu S. Prusty #define PIN_OUT (AC_PINCTL_OUT_EN) 34b0362adbSSubhransu S. Prusty 3518382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS 32 3618382eadSSubhransu S. Prusty 3718382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params { 3818382eadSSubhransu S. Prusty unsigned int channels_min; 3918382eadSSubhransu S. Prusty unsigned int channels_max; 4018382eadSSubhransu S. Prusty u32 rates; 4118382eadSSubhransu S. Prusty u64 formats; 4218382eadSSubhransu S. Prusty unsigned int maxbps; 4318382eadSSubhransu S. Prusty }; 4418382eadSSubhransu S. Prusty 4518382eadSSubhransu S. Prusty struct hdac_hdmi_cvt { 46*15b91447SSubhransu S. Prusty struct list_head head; 4718382eadSSubhransu S. Prusty hda_nid_t nid; 4818382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params params; 4918382eadSSubhransu S. Prusty }; 5018382eadSSubhransu S. Prusty 5118382eadSSubhransu S. Prusty struct hdac_hdmi_pin { 52*15b91447SSubhransu S. Prusty struct list_head head; 5318382eadSSubhransu S. Prusty hda_nid_t nid; 5418382eadSSubhransu S. Prusty int num_mux_nids; 5518382eadSSubhransu S. Prusty hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; 5618382eadSSubhransu S. Prusty }; 5718382eadSSubhransu S. Prusty 5818382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map { 5918382eadSSubhransu S. Prusty int dai_id; 60*15b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 61*15b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 6218382eadSSubhransu S. Prusty }; 6318382eadSSubhransu S. Prusty 6418382eadSSubhransu S. Prusty struct hdac_hdmi_priv { 6518382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map dai_map[3]; 66*15b91447SSubhransu S. Prusty struct list_head pin_list; 67*15b91447SSubhransu S. Prusty struct list_head cvt_list; 68*15b91447SSubhransu S. Prusty int num_pin; 69*15b91447SSubhransu S. Prusty int num_cvt; 7018382eadSSubhransu S. Prusty }; 7118382eadSSubhransu S. Prusty 72e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 73e342ac08SSubhransu S. Prusty { 7451b2c425SGeliang Tang struct hdac_device *hdac = dev_to_hdac_dev(dev); 75e342ac08SSubhransu S. Prusty 7651b2c425SGeliang Tang return to_ehdac_device(hdac); 77e342ac08SSubhransu S. Prusty } 78e342ac08SSubhransu S. Prusty 79b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, 80b0362adbSSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid, 81b0362adbSSubhransu S. Prusty u32 stream_tag, int format) 82b0362adbSSubhransu S. Prusty { 83b0362adbSSubhransu S. Prusty unsigned int val; 84b0362adbSSubhransu S. Prusty 85b0362adbSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", 86b0362adbSSubhransu S. Prusty cvt_nid, pin_nid, stream_tag, format); 87b0362adbSSubhransu S. Prusty 88b0362adbSSubhransu S. Prusty val = (stream_tag << 4); 89b0362adbSSubhransu S. Prusty 90b0362adbSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 91b0362adbSSubhransu S. Prusty AC_VERB_SET_CHANNEL_STREAMID, val); 92b0362adbSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 93b0362adbSSubhransu S. Prusty AC_VERB_SET_STREAM_FORMAT, format); 94b0362adbSSubhransu S. Prusty 95b0362adbSSubhransu S. Prusty return 0; 96b0362adbSSubhransu S. Prusty } 97b0362adbSSubhransu S. Prusty 98a657f1d0SSubhransu S. Prusty static void 99a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, 100a657f1d0SSubhransu S. Prusty int packet_index, int byte_index) 101a657f1d0SSubhransu S. Prusty { 102a657f1d0SSubhransu S. Prusty int val; 103a657f1d0SSubhransu S. Prusty 104a657f1d0SSubhransu S. Prusty val = (packet_index << 5) | (byte_index & 0x1f); 105a657f1d0SSubhransu S. Prusty 106a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 107a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_INDEX, val); 108a657f1d0SSubhransu S. Prusty } 109a657f1d0SSubhransu S. Prusty 110a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, 111a657f1d0SSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid) 112a657f1d0SSubhransu S. Prusty { 113a657f1d0SSubhransu S. Prusty uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; 114a657f1d0SSubhransu S. Prusty struct hdmi_audio_infoframe frame; 115a657f1d0SSubhransu S. Prusty u8 *dip = (u8 *)&frame; 116a657f1d0SSubhransu S. Prusty int ret; 117a657f1d0SSubhransu S. Prusty int i; 118a657f1d0SSubhransu S. Prusty 119a657f1d0SSubhransu S. Prusty hdmi_audio_infoframe_init(&frame); 120a657f1d0SSubhransu S. Prusty 121a657f1d0SSubhransu S. Prusty /* Default stereo for now */ 122a657f1d0SSubhransu S. Prusty frame.channels = 2; 123a657f1d0SSubhransu S. Prusty 124a657f1d0SSubhransu S. Prusty /* setup channel count */ 125a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 126a657f1d0SSubhransu S. Prusty AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1); 127a657f1d0SSubhransu S. Prusty 128a657f1d0SSubhransu S. Prusty ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); 129a657f1d0SSubhransu S. Prusty if (ret < 0) 130a657f1d0SSubhransu S. Prusty return ret; 131a657f1d0SSubhransu S. Prusty 132a657f1d0SSubhransu S. Prusty /* stop infoframe transmission */ 133a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 134a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 135a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); 136a657f1d0SSubhransu S. Prusty 137a657f1d0SSubhransu S. Prusty 138a657f1d0SSubhransu S. Prusty /* Fill infoframe. Index auto-incremented */ 139a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 140a657f1d0SSubhransu S. Prusty for (i = 0; i < sizeof(frame); i++) 141a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 142a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, dip[i]); 143a657f1d0SSubhransu S. Prusty 144a657f1d0SSubhransu S. Prusty /* Start infoframe */ 145a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 146a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 147a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); 148a657f1d0SSubhransu S. Prusty 149a657f1d0SSubhransu S. Prusty return 0; 150a657f1d0SSubhransu S. Prusty } 151a657f1d0SSubhransu S. Prusty 152b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, 153b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) 154b0362adbSSubhransu S. Prusty { 155b0362adbSSubhransu S. Prusty /* Power up pin widget */ 156*15b91447SSubhransu S. Prusty if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, 157*15b91447SSubhransu S. Prusty pwr_state)) 158*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, 159b0362adbSSubhransu S. Prusty AC_VERB_SET_POWER_STATE, pwr_state); 160b0362adbSSubhransu S. Prusty 161b0362adbSSubhransu S. Prusty /* Power up converter */ 162*15b91447SSubhransu S. Prusty if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, 163*15b91447SSubhransu S. Prusty pwr_state)) 164*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 165b0362adbSSubhransu S. Prusty AC_VERB_SET_POWER_STATE, pwr_state); 166b0362adbSSubhransu S. Prusty } 167b0362adbSSubhransu S. Prusty 168b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, 169b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 170b0362adbSSubhransu S. Prusty { 171b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 172b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 173b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 174b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 175a657f1d0SSubhransu S. Prusty int ret; 176b0362adbSSubhransu S. Prusty 177b0362adbSSubhransu S. Prusty if (dai->id > 0) { 178b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 179b0362adbSSubhransu S. Prusty return -ENODEV; 180b0362adbSSubhransu S. Prusty } 181b0362adbSSubhransu S. Prusty 182b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 183b0362adbSSubhransu S. Prusty 184b0362adbSSubhransu S. Prusty dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 185b0362adbSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", 186b0362adbSSubhransu S. Prusty dd->stream_tag, dd->format); 187b0362adbSSubhransu S. Prusty 188*15b91447SSubhransu S. Prusty ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, 189*15b91447SSubhransu S. Prusty dai_map->pin->nid); 190a657f1d0SSubhransu S. Prusty if (ret < 0) 191a657f1d0SSubhransu S. Prusty return ret; 192a657f1d0SSubhransu S. Prusty 193*15b91447SSubhransu S. Prusty return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, 194*15b91447SSubhransu S. Prusty dai_map->pin->nid, dd->stream_tag, dd->format); 195b0362adbSSubhransu S. Prusty } 196b0362adbSSubhransu S. Prusty 197b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, 198b0362adbSSubhransu S. Prusty struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) 199b0362adbSSubhransu S. Prusty { 200b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 201b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 202b0362adbSSubhransu S. Prusty 203b0362adbSSubhransu S. Prusty if (dai->id > 0) { 204b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 205b0362adbSSubhransu S. Prusty return -ENODEV; 206b0362adbSSubhransu S. Prusty } 207b0362adbSSubhransu S. Prusty 208b0362adbSSubhransu S. Prusty dd = kzalloc(sizeof(*dd), GFP_KERNEL); 2098d33ab24SSudip Mukherjee if (!dd) 2108d33ab24SSudip Mukherjee return -ENOMEM; 211b0362adbSSubhransu S. Prusty dd->format = snd_hdac_calc_stream_format(params_rate(hparams), 212b0362adbSSubhransu S. Prusty params_channels(hparams), params_format(hparams), 213b0362adbSSubhransu S. Prusty 24, 0); 214b0362adbSSubhransu S. Prusty 215b0362adbSSubhransu S. Prusty snd_soc_dai_set_dma_data(dai, substream, (void *)dd); 216b0362adbSSubhransu S. Prusty 217b0362adbSSubhransu S. Prusty return 0; 218b0362adbSSubhransu S. Prusty } 219b0362adbSSubhransu S. Prusty 220b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, 221b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 222b0362adbSSubhransu S. Prusty { 223b0362adbSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); 224b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 225b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 226b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 227b0362adbSSubhransu S. Prusty 228b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 229b0362adbSSubhransu S. Prusty 230*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 231b0362adbSSubhransu S. Prusty AC_VERB_SET_CHANNEL_STREAMID, 0); 232*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 233b0362adbSSubhransu S. Prusty AC_VERB_SET_STREAM_FORMAT, 0); 234b0362adbSSubhransu S. Prusty 235b0362adbSSubhransu S. Prusty dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 236b0362adbSSubhransu S. Prusty snd_soc_dai_set_dma_data(dai, substream, NULL); 237b0362adbSSubhransu S. Prusty 238b0362adbSSubhransu S. Prusty kfree(dd); 239b0362adbSSubhransu S. Prusty 240b0362adbSSubhransu S. Prusty return 0; 241b0362adbSSubhransu S. Prusty } 242b0362adbSSubhransu S. Prusty 243b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, 244b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 245b0362adbSSubhransu S. Prusty { 246b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 247b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 248b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 249b0362adbSSubhransu S. Prusty int val; 250b0362adbSSubhransu S. Prusty 251b0362adbSSubhransu S. Prusty if (dai->id > 0) { 252b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 253b0362adbSSubhransu S. Prusty return -ENODEV; 254b0362adbSSubhransu S. Prusty } 255b0362adbSSubhransu S. Prusty 256b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 257b0362adbSSubhransu S. Prusty 258*15b91447SSubhransu S. Prusty val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0, 259b0362adbSSubhransu S. Prusty AC_VERB_GET_PIN_SENSE, 0); 260b0362adbSSubhransu S. Prusty dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val); 261b0362adbSSubhransu S. Prusty 262b0362adbSSubhransu S. Prusty if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) { 263b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val); 264b0362adbSSubhransu S. Prusty return -ENODEV; 265b0362adbSSubhransu S. Prusty } 266b0362adbSSubhransu S. Prusty 267b0362adbSSubhransu S. Prusty hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); 268b0362adbSSubhransu S. Prusty 269*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, 270b0362adbSSubhransu S. Prusty AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 271b0362adbSSubhransu S. Prusty 272b0362adbSSubhransu S. Prusty snd_pcm_hw_constraint_step(substream->runtime, 0, 273b0362adbSSubhransu S. Prusty SNDRV_PCM_HW_PARAM_CHANNELS, 2); 274b0362adbSSubhransu S. Prusty 275b0362adbSSubhransu S. Prusty return 0; 276b0362adbSSubhransu S. Prusty } 277b0362adbSSubhransu S. Prusty 278b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, 279b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 280b0362adbSSubhransu S. Prusty { 281b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 282b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 283b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 284b0362adbSSubhransu S. Prusty 285b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 286b0362adbSSubhransu S. Prusty 287b0362adbSSubhransu S. Prusty hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); 288b0362adbSSubhransu S. Prusty 289*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, 290b0362adbSSubhransu S. Prusty AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 291b0362adbSSubhransu S. Prusty } 292b0362adbSSubhransu S. Prusty 29318382eadSSubhransu S. Prusty static int 29418382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 29518382eadSSubhransu S. Prusty { 29618382eadSSubhransu S. Prusty int err; 29718382eadSSubhransu S. Prusty 29818382eadSSubhransu S. Prusty /* Only stereo supported as of now */ 29918382eadSSubhransu S. Prusty cvt->params.channels_min = cvt->params.channels_max = 2; 30018382eadSSubhransu S. Prusty 30118382eadSSubhransu S. Prusty err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 30218382eadSSubhransu S. Prusty &cvt->params.rates, 30318382eadSSubhransu S. Prusty &cvt->params.formats, 30418382eadSSubhransu S. Prusty &cvt->params.maxbps); 30518382eadSSubhransu S. Prusty if (err < 0) 30618382eadSSubhransu S. Prusty dev_err(&hdac->dev, 30718382eadSSubhransu S. Prusty "Failed to query pcm params for nid %d: %d\n", 30818382eadSSubhransu S. Prusty cvt->nid, err); 30918382eadSSubhransu S. Prusty 31018382eadSSubhransu S. Prusty return err; 31118382eadSSubhransu S. Prusty } 31218382eadSSubhransu S. Prusty 31318382eadSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, 31418382eadSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 31518382eadSSubhransu S. Prusty { 31618382eadSSubhransu S. Prusty if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { 31718382eadSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 31818382eadSSubhransu S. Prusty "HDMI: pin %d wcaps %#x does not support connection list\n", 31918382eadSSubhransu S. Prusty pin->nid, get_wcaps(&hdac->hdac, pin->nid)); 32018382eadSSubhransu S. Prusty return -EINVAL; 32118382eadSSubhransu S. Prusty } 32218382eadSSubhransu S. Prusty 32318382eadSSubhransu S. Prusty pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, 32418382eadSSubhransu S. Prusty pin->mux_nids, HDA_MAX_CONNECTIONS); 32553072460SSubhransu S. Prusty if (pin->num_mux_nids == 0) 32653072460SSubhransu S. Prusty dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", 32753072460SSubhransu S. Prusty pin->nid); 32853072460SSubhransu S. Prusty 32953072460SSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", 33053072460SSubhransu S. Prusty pin->num_mux_nids, pin->nid); 33118382eadSSubhransu S. Prusty 33218382eadSSubhransu S. Prusty return pin->num_mux_nids; 33318382eadSSubhransu S. Prusty } 33418382eadSSubhransu S. Prusty 33518382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, 33618382eadSSubhransu S. Prusty enum snd_soc_dapm_type id, 33718382eadSSubhransu S. Prusty const char *wname, const char *stream) 33818382eadSSubhransu S. Prusty { 33918382eadSSubhransu S. Prusty w->id = id; 34018382eadSSubhransu S. Prusty w->name = wname; 34118382eadSSubhransu S. Prusty w->sname = stream; 34218382eadSSubhransu S. Prusty w->reg = SND_SOC_NOPM; 34318382eadSSubhransu S. Prusty w->shift = 0; 34418382eadSSubhransu S. Prusty w->kcontrol_news = NULL; 34518382eadSSubhransu S. Prusty w->num_kcontrols = 0; 34618382eadSSubhransu S. Prusty w->priv = NULL; 34718382eadSSubhransu S. Prusty } 34818382eadSSubhransu S. Prusty 34918382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 35018382eadSSubhransu S. Prusty const char *sink, const char *control, const char *src) 35118382eadSSubhransu S. Prusty { 35218382eadSSubhransu S. Prusty route->sink = sink; 35318382eadSSubhransu S. Prusty route->source = src; 35418382eadSSubhransu S. Prusty route->control = control; 35518382eadSSubhransu S. Prusty route->connected = NULL; 35618382eadSSubhransu S. Prusty } 35718382eadSSubhransu S. Prusty 35818382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, 35918382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map) 36018382eadSSubhransu S. Prusty { 36118382eadSSubhransu S. Prusty struct snd_soc_dapm_route route[1]; 36218382eadSSubhransu S. Prusty struct snd_soc_dapm_widget widgets[2] = { {0} }; 36318382eadSSubhransu S. Prusty 36418382eadSSubhransu S. Prusty memset(&route, 0, sizeof(route)); 36518382eadSSubhransu S. Prusty 36618382eadSSubhransu S. Prusty hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, 36718382eadSSubhransu S. Prusty "hif1 Output", NULL); 36818382eadSSubhransu S. Prusty hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, 36918382eadSSubhransu S. Prusty "Coverter 1", "hif1"); 37018382eadSSubhransu S. Prusty 37118382eadSSubhransu S. Prusty hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); 37218382eadSSubhransu S. Prusty 37318382eadSSubhransu S. Prusty snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); 37418382eadSSubhransu S. Prusty snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); 37518382eadSSubhransu S. Prusty } 37618382eadSSubhransu S. Prusty 377*15b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) 37818382eadSSubhransu S. Prusty { 379*15b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 380*15b91447SSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0]; 381*15b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 382*15b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 38318382eadSSubhransu S. Prusty 384*15b91447SSubhransu S. Prusty if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) 385*15b91447SSubhransu S. Prusty return -EINVAL; 38618382eadSSubhransu S. Prusty 387*15b91447SSubhransu S. Prusty /* 388*15b91447SSubhransu S. Prusty * Currently on board only 1 pin and 1 converter is enabled for 389*15b91447SSubhransu S. Prusty * simplification, more will be added eventually 390*15b91447SSubhransu S. Prusty * So using fixed map for dai_id:pin:cvt 391*15b91447SSubhransu S. Prusty */ 392*15b91447SSubhransu S. Prusty cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head); 393*15b91447SSubhransu S. Prusty pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head); 39418382eadSSubhransu S. Prusty 395*15b91447SSubhransu S. Prusty dai_map->dai_id = 0; 396*15b91447SSubhransu S. Prusty dai_map->pin = pin; 397*15b91447SSubhransu S. Prusty 398*15b91447SSubhransu S. Prusty dai_map->cvt = cvt; 39918382eadSSubhransu S. Prusty 40018382eadSSubhransu S. Prusty /* Enable out path for this pin widget */ 401*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 40218382eadSSubhransu S. Prusty AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 40318382eadSSubhransu S. Prusty 40418382eadSSubhransu S. Prusty /* Enable transmission */ 405*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 40618382eadSSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_1, 1); 40718382eadSSubhransu S. Prusty 40818382eadSSubhransu S. Prusty /* Category Code (CC) to zero */ 409*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 41018382eadSSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_2, 0); 41118382eadSSubhransu S. Prusty 412*15b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 41318382eadSSubhransu S. Prusty AC_VERB_SET_CONNECT_SEL, 0); 41418382eadSSubhransu S. Prusty 415*15b91447SSubhransu S. Prusty return 0; 416*15b91447SSubhransu S. Prusty } 417*15b91447SSubhransu S. Prusty 418*15b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) 419*15b91447SSubhransu S. Prusty { 420*15b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 421*15b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 422*15b91447SSubhransu S. Prusty 423*15b91447SSubhransu S. Prusty cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); 424*15b91447SSubhransu S. Prusty if (!cvt) 425*15b91447SSubhransu S. Prusty return -ENOMEM; 426*15b91447SSubhransu S. Prusty 427*15b91447SSubhransu S. Prusty cvt->nid = nid; 428*15b91447SSubhransu S. Prusty 429*15b91447SSubhransu S. Prusty list_add_tail(&cvt->head, &hdmi->cvt_list); 430*15b91447SSubhransu S. Prusty hdmi->num_cvt++; 431*15b91447SSubhransu S. Prusty 432*15b91447SSubhransu S. Prusty return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); 433*15b91447SSubhransu S. Prusty } 434*15b91447SSubhransu S. Prusty 435*15b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) 436*15b91447SSubhransu S. Prusty { 437*15b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 438*15b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 439*15b91447SSubhransu S. Prusty 440*15b91447SSubhransu S. Prusty pin = kzalloc(sizeof(*pin), GFP_KERNEL); 441*15b91447SSubhransu S. Prusty if (!pin) 442*15b91447SSubhransu S. Prusty return -ENOMEM; 443*15b91447SSubhransu S. Prusty 444*15b91447SSubhransu S. Prusty pin->nid = nid; 445*15b91447SSubhransu S. Prusty 446*15b91447SSubhransu S. Prusty list_add_tail(&pin->head, &hdmi->pin_list); 447*15b91447SSubhransu S. Prusty hdmi->num_pin++; 448*15b91447SSubhransu S. Prusty 449*15b91447SSubhransu S. Prusty return 0; 45018382eadSSubhransu S. Prusty } 45118382eadSSubhransu S. Prusty 45218382eadSSubhransu S. Prusty /* 45318382eadSSubhransu S. Prusty * Parse all nodes and store the cvt/pin nids in array 45418382eadSSubhransu S. Prusty * Add one time initialization for pin and cvt widgets 45518382eadSSubhransu S. Prusty */ 45618382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) 45718382eadSSubhransu S. Prusty { 45818382eadSSubhransu S. Prusty hda_nid_t nid; 4593c83ac23SSudip Mukherjee int i, num_nodes; 46018382eadSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 46118382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 462*15b91447SSubhransu S. Prusty int ret; 46318382eadSSubhransu S. Prusty 4643c83ac23SSudip Mukherjee num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); 465541140d4SSubhransu S. Prusty if (!nid || num_nodes <= 0) { 46618382eadSSubhransu S. Prusty dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 46718382eadSSubhransu S. Prusty return -EINVAL; 46818382eadSSubhransu S. Prusty } 46918382eadSSubhransu S. Prusty 4703c83ac23SSudip Mukherjee hdac->num_nodes = num_nodes; 47118382eadSSubhransu S. Prusty hdac->start_nid = nid; 47218382eadSSubhransu S. Prusty 47318382eadSSubhransu S. Prusty for (i = 0; i < hdac->num_nodes; i++, nid++) { 47418382eadSSubhransu S. Prusty unsigned int caps; 47518382eadSSubhransu S. Prusty unsigned int type; 47618382eadSSubhransu S. Prusty 47718382eadSSubhransu S. Prusty caps = get_wcaps(hdac, nid); 47818382eadSSubhransu S. Prusty type = get_wcaps_type(caps); 47918382eadSSubhransu S. Prusty 48018382eadSSubhransu S. Prusty if (!(caps & AC_WCAP_DIGITAL)) 48118382eadSSubhransu S. Prusty continue; 48218382eadSSubhransu S. Prusty 48318382eadSSubhransu S. Prusty switch (type) { 48418382eadSSubhransu S. Prusty 48518382eadSSubhransu S. Prusty case AC_WID_AUD_OUT: 486*15b91447SSubhransu S. Prusty ret = hdac_hdmi_add_cvt(edev, nid); 487*15b91447SSubhransu S. Prusty if (ret < 0) 488*15b91447SSubhransu S. Prusty return ret; 48918382eadSSubhransu S. Prusty break; 49018382eadSSubhransu S. Prusty 49118382eadSSubhransu S. Prusty case AC_WID_PIN: 492*15b91447SSubhransu S. Prusty ret = hdac_hdmi_add_pin(edev, nid); 493*15b91447SSubhransu S. Prusty if (ret < 0) 494*15b91447SSubhransu S. Prusty return ret; 49518382eadSSubhransu S. Prusty break; 49618382eadSSubhransu S. Prusty } 49718382eadSSubhransu S. Prusty } 49818382eadSSubhransu S. Prusty 49918382eadSSubhransu S. Prusty hdac->end_nid = nid; 50018382eadSSubhransu S. Prusty 501*15b91447SSubhransu S. Prusty if (!hdmi->num_pin || !hdmi->num_cvt) 50218382eadSSubhransu S. Prusty return -EIO; 50318382eadSSubhransu S. Prusty 504*15b91447SSubhransu S. Prusty return hdac_hdmi_init_dai_map(edev); 50518382eadSSubhransu S. Prusty } 50618382eadSSubhransu S. Prusty 50718382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec) 50818382eadSSubhransu S. Prusty { 50918382eadSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 51018382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 51118382eadSSubhransu S. Prusty struct snd_soc_dapm_context *dapm = 51218382eadSSubhransu S. Prusty snd_soc_component_get_dapm(&codec->component); 51318382eadSSubhransu S. Prusty 51418382eadSSubhransu S. Prusty edev->scodec = codec; 51518382eadSSubhransu S. Prusty 51618382eadSSubhransu S. Prusty create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); 51718382eadSSubhransu S. Prusty 51818382eadSSubhransu S. Prusty /* Imp: Store the card pointer in hda_codec */ 51918382eadSSubhransu S. Prusty edev->card = dapm->card->snd_card; 52018382eadSSubhransu S. Prusty 521e342ac08SSubhransu S. Prusty /* 522e342ac08SSubhransu S. Prusty * hdac_device core already sets the state to active and calls 523e342ac08SSubhransu S. Prusty * get_noresume. So enable runtime and set the device to suspend. 524e342ac08SSubhransu S. Prusty */ 525e342ac08SSubhransu S. Prusty pm_runtime_enable(&edev->hdac.dev); 526e342ac08SSubhransu S. Prusty pm_runtime_put(&edev->hdac.dev); 527e342ac08SSubhransu S. Prusty pm_runtime_suspend(&edev->hdac.dev); 528e342ac08SSubhransu S. Prusty 529e342ac08SSubhransu S. Prusty return 0; 530e342ac08SSubhransu S. Prusty } 531e342ac08SSubhransu S. Prusty 532e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec) 533e342ac08SSubhransu S. Prusty { 534e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 535e342ac08SSubhransu S. Prusty 536e342ac08SSubhransu S. Prusty pm_runtime_disable(&edev->hdac.dev); 53718382eadSSubhransu S. Prusty return 0; 53818382eadSSubhransu S. Prusty } 53918382eadSSubhransu S. Prusty 54018382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = { 54118382eadSSubhransu S. Prusty .probe = hdmi_codec_probe, 542e342ac08SSubhransu S. Prusty .remove = hdmi_codec_remove, 54318382eadSSubhransu S. Prusty .idle_bias_off = true, 54418382eadSSubhransu S. Prusty }; 54518382eadSSubhransu S. Prusty 546b0362adbSSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = { 547b0362adbSSubhransu S. Prusty .startup = hdac_hdmi_pcm_open, 548b0362adbSSubhransu S. Prusty .shutdown = hdac_hdmi_pcm_close, 549b0362adbSSubhransu S. Prusty .hw_params = hdac_hdmi_set_hw_params, 550b0362adbSSubhransu S. Prusty .prepare = hdac_hdmi_playback_prepare, 551b0362adbSSubhransu S. Prusty .hw_free = hdac_hdmi_playback_cleanup, 552b0362adbSSubhransu S. Prusty }; 553b0362adbSSubhransu S. Prusty 55418382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = { 55518382eadSSubhransu S. Prusty { .name = "intel-hdmi-hif1", 55618382eadSSubhransu S. Prusty .playback = { 55718382eadSSubhransu S. Prusty .stream_name = "hif1", 55818382eadSSubhransu S. Prusty .channels_min = 2, 55918382eadSSubhransu S. Prusty .channels_max = 2, 56018382eadSSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | 56118382eadSSubhransu S. Prusty SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 56218382eadSSubhransu S. Prusty SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 56318382eadSSubhransu S. Prusty SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, 56418382eadSSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | 56518382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S20_3LE | 56618382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE | 56718382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 56818382eadSSubhransu S. Prusty 56918382eadSSubhransu S. Prusty }, 570b0362adbSSubhransu S. Prusty .ops = &hdmi_dai_ops, 57118382eadSSubhransu S. Prusty }, 57218382eadSSubhransu S. Prusty }; 57318382eadSSubhransu S. Prusty 57418382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) 57518382eadSSubhransu S. Prusty { 57618382eadSSubhransu S. Prusty struct hdac_device *codec = &edev->hdac; 57718382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi_priv; 57818382eadSSubhransu S. Prusty int ret = 0; 57918382eadSSubhransu S. Prusty 58018382eadSSubhransu S. Prusty hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 58118382eadSSubhransu S. Prusty if (hdmi_priv == NULL) 58218382eadSSubhransu S. Prusty return -ENOMEM; 58318382eadSSubhransu S. Prusty 58418382eadSSubhransu S. Prusty edev->private_data = hdmi_priv; 58518382eadSSubhransu S. Prusty 58618382eadSSubhransu S. Prusty dev_set_drvdata(&codec->dev, edev); 58718382eadSSubhransu S. Prusty 588*15b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->pin_list); 589*15b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->cvt_list); 590*15b91447SSubhransu S. Prusty 59118382eadSSubhransu S. Prusty ret = hdac_hdmi_parse_and_map_nid(edev); 59218382eadSSubhransu S. Prusty if (ret < 0) 59318382eadSSubhransu S. Prusty return ret; 59418382eadSSubhransu S. Prusty 59518382eadSSubhransu S. Prusty /* ASoC specific initialization */ 59618382eadSSubhransu S. Prusty return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 59718382eadSSubhransu S. Prusty hdmi_dais, ARRAY_SIZE(hdmi_dais)); 59818382eadSSubhransu S. Prusty } 59918382eadSSubhransu S. Prusty 60018382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) 60118382eadSSubhransu S. Prusty { 602*15b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 603*15b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin, *pin_next; 604*15b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt, *cvt_next; 605*15b91447SSubhransu S. Prusty 60618382eadSSubhransu S. Prusty snd_soc_unregister_codec(&edev->hdac.dev); 60718382eadSSubhransu S. Prusty 608*15b91447SSubhransu S. Prusty list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { 609*15b91447SSubhransu S. Prusty list_del(&cvt->head); 610*15b91447SSubhransu S. Prusty kfree(cvt); 611*15b91447SSubhransu S. Prusty } 612*15b91447SSubhransu S. Prusty 613*15b91447SSubhransu S. Prusty list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { 614*15b91447SSubhransu S. Prusty list_del(&pin->head); 615*15b91447SSubhransu S. Prusty kfree(pin); 616*15b91447SSubhransu S. Prusty } 617*15b91447SSubhransu S. Prusty 61818382eadSSubhransu S. Prusty return 0; 61918382eadSSubhransu S. Prusty } 62018382eadSSubhransu S. Prusty 621e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM 622e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev) 623e342ac08SSubhransu S. Prusty { 624e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 625e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 62607f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 62707f083abSSubhransu S. Prusty int err; 628e342ac08SSubhransu S. Prusty 629e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 630e342ac08SSubhransu S. Prusty 63107f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 63207f083abSSubhransu S. Prusty if (!bus) 63307f083abSSubhransu S. Prusty return 0; 63407f083abSSubhransu S. Prusty 635e342ac08SSubhransu S. Prusty /* Power down afg */ 636e342ac08SSubhransu S. Prusty if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) 637e342ac08SSubhransu S. Prusty snd_hdac_codec_write(hdac, hdac->afg, 0, 638e342ac08SSubhransu S. Prusty AC_VERB_SET_POWER_STATE, AC_PWRST_D3); 639e342ac08SSubhransu S. Prusty 64007f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, false); 64107f083abSSubhransu S. Prusty if (err < 0) { 64207f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 64307f083abSSubhransu S. Prusty return err; 64407f083abSSubhransu S. Prusty } 64507f083abSSubhransu S. Prusty 646e342ac08SSubhransu S. Prusty return 0; 647e342ac08SSubhransu S. Prusty } 648e342ac08SSubhransu S. Prusty 649e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev) 650e342ac08SSubhransu S. Prusty { 651e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 652e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 65307f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 65407f083abSSubhransu S. Prusty int err; 655e342ac08SSubhransu S. Prusty 656e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 657e342ac08SSubhransu S. Prusty 65807f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 65907f083abSSubhransu S. Prusty if (!bus) 66007f083abSSubhransu S. Prusty return 0; 66107f083abSSubhransu S. Prusty 66207f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, true); 66307f083abSSubhransu S. Prusty if (err < 0) { 66407f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 66507f083abSSubhransu S. Prusty return err; 66607f083abSSubhransu S. Prusty } 66707f083abSSubhransu S. Prusty 668e342ac08SSubhransu S. Prusty /* Power up afg */ 669e342ac08SSubhransu S. Prusty if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) 670e342ac08SSubhransu S. Prusty snd_hdac_codec_write(hdac, hdac->afg, 0, 671e342ac08SSubhransu S. Prusty AC_VERB_SET_POWER_STATE, AC_PWRST_D0); 672e342ac08SSubhransu S. Prusty 673e342ac08SSubhransu S. Prusty return 0; 674e342ac08SSubhransu S. Prusty } 675e342ac08SSubhransu S. Prusty #else 676e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL 677e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL 678e342ac08SSubhransu S. Prusty #endif 679e342ac08SSubhransu S. Prusty 680e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = { 681e342ac08SSubhransu S. Prusty SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) 682e342ac08SSubhransu S. Prusty }; 683e342ac08SSubhransu S. Prusty 68418382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = { 68518382eadSSubhransu S. Prusty HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), 68618382eadSSubhransu S. Prusty {} 68718382eadSSubhransu S. Prusty }; 68818382eadSSubhransu S. Prusty 68918382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list); 69018382eadSSubhransu S. Prusty 69118382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = { 69218382eadSSubhransu S. Prusty . hdac = { 69318382eadSSubhransu S. Prusty .driver = { 69418382eadSSubhransu S. Prusty .name = "HDMI HDA Codec", 695e342ac08SSubhransu S. Prusty .pm = &hdac_hdmi_pm, 69618382eadSSubhransu S. Prusty }, 69718382eadSSubhransu S. Prusty .id_table = hdmi_list, 69818382eadSSubhransu S. Prusty }, 69918382eadSSubhransu S. Prusty .probe = hdac_hdmi_dev_probe, 70018382eadSSubhransu S. Prusty .remove = hdac_hdmi_dev_remove, 70118382eadSSubhransu S. Prusty }; 70218382eadSSubhransu S. Prusty 70318382eadSSubhransu S. Prusty static int __init hdmi_init(void) 70418382eadSSubhransu S. Prusty { 70518382eadSSubhransu S. Prusty return snd_hda_ext_driver_register(&hdmi_driver); 70618382eadSSubhransu S. Prusty } 70718382eadSSubhransu S. Prusty 70818382eadSSubhransu S. Prusty static void __exit hdmi_exit(void) 70918382eadSSubhransu S. Prusty { 71018382eadSSubhransu S. Prusty snd_hda_ext_driver_unregister(&hdmi_driver); 71118382eadSSubhransu S. Prusty } 71218382eadSSubhransu S. Prusty 71318382eadSSubhransu S. Prusty module_init(hdmi_init); 71418382eadSSubhransu S. Prusty module_exit(hdmi_exit); 71518382eadSSubhransu S. Prusty 71618382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 71718382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec"); 71818382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); 71918382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); 720