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> 252428bca3SSubhransu S. Prusty #include <drm/drm_edid.h> 2618382eadSSubhransu S. Prusty #include <sound/pcm_params.h> 274a3478deSJeeja KP #include <sound/jack.h> 2818382eadSSubhransu S. Prusty #include <sound/soc.h> 2918382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h> 3007f083abSSubhransu S. Prusty #include <sound/hda_i915.h> 312428bca3SSubhransu S. Prusty #include <sound/pcm_drm_eld.h> 32bcced704SSubhransu S. Prusty #include <sound/hda_chmap.h> 3318382eadSSubhransu S. Prusty #include "../../hda/local.h" 344a3478deSJeeja KP #include "hdac_hdmi.h" 3518382eadSSubhransu S. Prusty 3617a42c45SSubhransu S. Prusty #define NAME_SIZE 32 3717a42c45SSubhransu S. Prusty 38b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE 0xb080 39b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE 0xb000 4018382eadSSubhransu S. Prusty #define PIN_OUT (AC_PINCTL_OUT_EN) 41b0362adbSSubhransu S. Prusty 4218382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS 32 4318382eadSSubhransu S. Prusty 44148569fdSSubhransu S. Prusty #define HDA_MAX_CVTS 3 45148569fdSSubhransu S. Prusty 46b8a54545SSubhransu S. Prusty #define ELD_MAX_SIZE 256 47b8a54545SSubhransu S. Prusty #define ELD_FIXED_BYTES 20 48b8a54545SSubhransu S. Prusty 49f6fa11a3SSandeep Tayal #define ELD_VER_CEA_861D 2 50f6fa11a3SSandeep Tayal #define ELD_VER_PARTIAL 31 51f6fa11a3SSandeep Tayal #define ELD_MAX_MNL 16 52f6fa11a3SSandeep Tayal 5318382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params { 5418382eadSSubhransu S. Prusty unsigned int channels_min; 5518382eadSSubhransu S. Prusty unsigned int channels_max; 5618382eadSSubhransu S. Prusty u32 rates; 5718382eadSSubhransu S. Prusty u64 formats; 5818382eadSSubhransu S. Prusty unsigned int maxbps; 5918382eadSSubhransu S. Prusty }; 6018382eadSSubhransu S. Prusty 6118382eadSSubhransu S. Prusty struct hdac_hdmi_cvt { 6215b91447SSubhransu S. Prusty struct list_head head; 6318382eadSSubhransu S. Prusty hda_nid_t nid; 644a3478deSJeeja KP const char *name; 6518382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params params; 6618382eadSSubhransu S. Prusty }; 6718382eadSSubhransu S. Prusty 68b7756edeSSubhransu S. Prusty /* Currently only spk_alloc, more to be added */ 69b7756edeSSubhransu S. Prusty struct hdac_hdmi_parsed_eld { 70b7756edeSSubhransu S. Prusty u8 spk_alloc; 71b7756edeSSubhransu S. Prusty }; 72b7756edeSSubhransu S. Prusty 73b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld { 74b8a54545SSubhransu S. Prusty bool monitor_present; 75b8a54545SSubhransu S. Prusty bool eld_valid; 76b8a54545SSubhransu S. Prusty int eld_size; 77b8a54545SSubhransu S. Prusty char eld_buffer[ELD_MAX_SIZE]; 78b7756edeSSubhransu S. Prusty struct hdac_hdmi_parsed_eld info; 79b8a54545SSubhransu S. Prusty }; 80b8a54545SSubhransu S. Prusty 8118382eadSSubhransu S. Prusty struct hdac_hdmi_pin { 8215b91447SSubhransu S. Prusty struct list_head head; 8318382eadSSubhransu S. Prusty hda_nid_t nid; 8418382eadSSubhransu S. Prusty int num_mux_nids; 8518382eadSSubhransu S. Prusty hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; 86b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld eld; 87b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev; 8818382eadSSubhransu S. Prusty }; 8918382eadSSubhransu S. Prusty 904a3478deSJeeja KP struct hdac_hdmi_pcm { 914a3478deSJeeja KP struct list_head head; 924a3478deSJeeja KP int pcm_id; 934a3478deSJeeja KP struct hdac_hdmi_pin *pin; 944a3478deSJeeja KP struct hdac_hdmi_cvt *cvt; 954a3478deSJeeja KP struct snd_jack *jack; 96c9bfb5d7SJeeja KP int stream_tag; 97c9bfb5d7SJeeja KP int channels; 98c9bfb5d7SJeeja KP int format; 99*ab1eea19SJeeja KP bool chmap_set; 100*ab1eea19SJeeja KP unsigned char chmap[8]; /* ALSA API channel-map */ 101*ab1eea19SJeeja KP struct mutex lock; 1024a3478deSJeeja KP }; 1034a3478deSJeeja KP 10418382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map { 10518382eadSSubhransu S. Prusty int dai_id; 10615b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 10715b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 10818382eadSSubhransu S. Prusty }; 10918382eadSSubhransu S. Prusty 11018382eadSSubhransu S. Prusty struct hdac_hdmi_priv { 111148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; 11215b91447SSubhransu S. Prusty struct list_head pin_list; 11315b91447SSubhransu S. Prusty struct list_head cvt_list; 1144a3478deSJeeja KP struct list_head pcm_list; 11515b91447SSubhransu S. Prusty int num_pin; 11615b91447SSubhransu S. Prusty int num_cvt; 1174a3478deSJeeja KP struct mutex pin_mutex; 118bcced704SSubhransu S. Prusty struct hdac_chmap chmap; 11918382eadSSubhransu S. Prusty }; 12018382eadSSubhransu S. Prusty 121c9bfb5d7SJeeja KP static struct hdac_hdmi_pcm * 122c9bfb5d7SJeeja KP hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, 123c9bfb5d7SJeeja KP struct hdac_hdmi_cvt *cvt) 124c9bfb5d7SJeeja KP { 125c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 1261de777feSJeeja KP 127c9bfb5d7SJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 128c9bfb5d7SJeeja KP if (pcm->cvt == cvt) 129c9bfb5d7SJeeja KP break; 130c9bfb5d7SJeeja KP } 131c9bfb5d7SJeeja KP 132c9bfb5d7SJeeja KP return pcm; 133c9bfb5d7SJeeja KP } 1341de777feSJeeja KP 1352889099eSSubhransu S. Prusty static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, 1362889099eSSubhransu S. Prusty int pcm_idx) 1372889099eSSubhransu S. Prusty { 1382889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm; 1392889099eSSubhransu S. Prusty 1402889099eSSubhransu S. Prusty list_for_each_entry(pcm, &hdmi->pcm_list, head) { 1412889099eSSubhransu S. Prusty if (pcm->pcm_id == pcm_idx) 1422889099eSSubhransu S. Prusty return pcm; 1432889099eSSubhransu S. Prusty } 1442889099eSSubhransu S. Prusty 1452889099eSSubhransu S. Prusty return NULL; 1462889099eSSubhransu S. Prusty } 1472889099eSSubhransu S. Prusty 148e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 149e342ac08SSubhransu S. Prusty { 15051b2c425SGeliang Tang struct hdac_device *hdac = dev_to_hdac_dev(dev); 151e342ac08SSubhransu S. Prusty 15251b2c425SGeliang Tang return to_ehdac_device(hdac); 153e342ac08SSubhransu S. Prusty } 154e342ac08SSubhransu S. Prusty 1552428bca3SSubhransu S. Prusty static unsigned int sad_format(const u8 *sad) 1562428bca3SSubhransu S. Prusty { 1572428bca3SSubhransu S. Prusty return ((sad[0] >> 0x3) & 0x1f); 1582428bca3SSubhransu S. Prusty } 1592428bca3SSubhransu S. Prusty 1602428bca3SSubhransu S. Prusty static unsigned int sad_sample_bits_lpcm(const u8 *sad) 1612428bca3SSubhransu S. Prusty { 1622428bca3SSubhransu S. Prusty return (sad[2] & 7); 1632428bca3SSubhransu S. Prusty } 1642428bca3SSubhransu S. Prusty 1652428bca3SSubhransu S. Prusty static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime, 1662428bca3SSubhransu S. Prusty void *eld) 1672428bca3SSubhransu S. Prusty { 1682428bca3SSubhransu S. Prusty u64 formats = SNDRV_PCM_FMTBIT_S16; 1692428bca3SSubhransu S. Prusty int i; 1702428bca3SSubhransu S. Prusty const u8 *sad, *eld_buf = eld; 1712428bca3SSubhransu S. Prusty 1722428bca3SSubhransu S. Prusty sad = drm_eld_sad(eld_buf); 1732428bca3SSubhransu S. Prusty if (!sad) 1742428bca3SSubhransu S. Prusty goto format_constraint; 1752428bca3SSubhransu S. Prusty 1762428bca3SSubhransu S. Prusty for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) { 1772428bca3SSubhransu S. Prusty if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */ 1782428bca3SSubhransu S. Prusty 1792428bca3SSubhransu S. Prusty /* 1802428bca3SSubhransu S. Prusty * the controller support 20 and 24 bits in 32 bit 1812428bca3SSubhransu S. Prusty * container so we set S32 1822428bca3SSubhransu S. Prusty */ 1832428bca3SSubhransu S. Prusty if (sad_sample_bits_lpcm(sad) & 0x6) 1842428bca3SSubhransu S. Prusty formats |= SNDRV_PCM_FMTBIT_S32; 1852428bca3SSubhransu S. Prusty } 1862428bca3SSubhransu S. Prusty } 1872428bca3SSubhransu S. Prusty 1882428bca3SSubhransu S. Prusty format_constraint: 1892428bca3SSubhransu S. Prusty return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, 1902428bca3SSubhransu S. Prusty formats); 1912428bca3SSubhransu S. Prusty 1922428bca3SSubhransu S. Prusty } 1932428bca3SSubhransu S. Prusty 194a657f1d0SSubhransu S. Prusty static void 195a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, 196a657f1d0SSubhransu S. Prusty int packet_index, int byte_index) 197a657f1d0SSubhransu S. Prusty { 198a657f1d0SSubhransu S. Prusty int val; 199a657f1d0SSubhransu S. Prusty 200a657f1d0SSubhransu S. Prusty val = (packet_index << 5) | (byte_index & 0x1f); 201a657f1d0SSubhransu S. Prusty 202a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 203a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_INDEX, val); 204a657f1d0SSubhransu S. Prusty } 205a657f1d0SSubhransu S. Prusty 206478f544eSSubhransu S. Prusty struct dp_audio_infoframe { 207478f544eSSubhransu S. Prusty u8 type; /* 0x84 */ 208478f544eSSubhransu S. Prusty u8 len; /* 0x1b */ 209478f544eSSubhransu S. Prusty u8 ver; /* 0x11 << 2 */ 210478f544eSSubhransu S. Prusty 211478f544eSSubhransu S. Prusty u8 CC02_CT47; /* match with HDMI infoframe from this on */ 212478f544eSSubhransu S. Prusty u8 SS01_SF24; 213478f544eSSubhransu S. Prusty u8 CXT04; 214478f544eSSubhransu S. Prusty u8 CA; 215478f544eSSubhransu S. Prusty u8 LFEPBL01_LSV36_DM_INH7; 216478f544eSSubhransu S. Prusty }; 217478f544eSSubhransu S. Prusty 218a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, 219*ab1eea19SJeeja KP struct hdac_hdmi_pcm *pcm, struct hdac_hdmi_pin *pin) 220a657f1d0SSubhransu S. Prusty { 221a657f1d0SSubhransu S. Prusty uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; 222a657f1d0SSubhransu S. Prusty struct hdmi_audio_infoframe frame; 223478f544eSSubhransu S. Prusty struct dp_audio_infoframe dp_ai; 224478f544eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 225*ab1eea19SJeeja KP struct hdac_hdmi_cvt *cvt = pcm->cvt; 226478f544eSSubhransu S. Prusty u8 *dip; 227a657f1d0SSubhransu S. Prusty int ret; 228a657f1d0SSubhransu S. Prusty int i; 229478f544eSSubhransu S. Prusty const u8 *eld_buf; 230478f544eSSubhransu S. Prusty u8 conn_type; 231bcced704SSubhransu S. Prusty int channels, ca; 232a657f1d0SSubhransu S. Prusty 233bcced704SSubhransu S. Prusty ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, 234*ab1eea19SJeeja KP pcm->channels, pcm->chmap_set, true, pcm->chmap); 235bcced704SSubhransu S. Prusty 236bcced704SSubhransu S. Prusty channels = snd_hdac_get_active_channels(ca); 237*ab1eea19SJeeja KP hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt->nid, channels); 238bcced704SSubhransu S. Prusty 239bcced704SSubhransu S. Prusty snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, 240*ab1eea19SJeeja KP pcm->channels, pcm->chmap, pcm->chmap_set); 241bcced704SSubhransu S. Prusty 242478f544eSSubhransu S. Prusty eld_buf = pin->eld.eld_buffer; 243478f544eSSubhransu S. Prusty conn_type = drm_eld_get_conn_type(eld_buf); 244a657f1d0SSubhransu S. Prusty 245478f544eSSubhransu S. Prusty switch (conn_type) { 246478f544eSSubhransu S. Prusty case DRM_ELD_CONN_TYPE_HDMI: 247478f544eSSubhransu S. Prusty hdmi_audio_infoframe_init(&frame); 248478f544eSSubhransu S. Prusty 249478f544eSSubhransu S. Prusty frame.channels = channels; 250bcced704SSubhransu S. Prusty frame.channel_allocation = ca; 251a657f1d0SSubhransu S. Prusty 252a657f1d0SSubhransu S. Prusty ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); 253a657f1d0SSubhransu S. Prusty if (ret < 0) 254a657f1d0SSubhransu S. Prusty return ret; 255a657f1d0SSubhransu S. Prusty 256478f544eSSubhransu S. Prusty break; 257478f544eSSubhransu S. Prusty 258478f544eSSubhransu S. Prusty case DRM_ELD_CONN_TYPE_DP: 259478f544eSSubhransu S. Prusty memset(&dp_ai, 0, sizeof(dp_ai)); 260478f544eSSubhransu S. Prusty dp_ai.type = 0x84; 261478f544eSSubhransu S. Prusty dp_ai.len = 0x1b; 262478f544eSSubhransu S. Prusty dp_ai.ver = 0x11 << 2; 263478f544eSSubhransu S. Prusty dp_ai.CC02_CT47 = channels - 1; 264bcced704SSubhransu S. Prusty dp_ai.CA = ca; 265478f544eSSubhransu S. Prusty 266478f544eSSubhransu S. Prusty dip = (u8 *)&dp_ai; 267478f544eSSubhransu S. Prusty break; 268478f544eSSubhransu S. Prusty 269478f544eSSubhransu S. Prusty default: 270478f544eSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n", 271478f544eSSubhransu S. Prusty conn_type); 272478f544eSSubhransu S. Prusty return -EIO; 273478f544eSSubhransu S. Prusty } 274478f544eSSubhransu S. Prusty 275a657f1d0SSubhransu S. Prusty /* stop infoframe transmission */ 276*ab1eea19SJeeja KP hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); 277*ab1eea19SJeeja KP snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 278a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); 279a657f1d0SSubhransu S. Prusty 280a657f1d0SSubhransu S. Prusty 281a657f1d0SSubhransu S. Prusty /* Fill infoframe. Index auto-incremented */ 282*ab1eea19SJeeja KP hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); 283478f544eSSubhransu S. Prusty if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { 284391005e8SSubhransu S. Prusty for (i = 0; i < sizeof(buffer); i++) 285*ab1eea19SJeeja KP snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 286391005e8SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); 287478f544eSSubhransu S. Prusty } else { 288478f544eSSubhransu S. Prusty for (i = 0; i < sizeof(dp_ai); i++) 289*ab1eea19SJeeja KP snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 290478f544eSSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, dip[i]); 291478f544eSSubhransu S. Prusty } 292a657f1d0SSubhransu S. Prusty 293a657f1d0SSubhransu S. Prusty /* Start infoframe */ 294*ab1eea19SJeeja KP hdac_hdmi_set_dip_index(hdac, pin->nid, 0x0, 0x0); 295*ab1eea19SJeeja KP snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 296a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); 297a657f1d0SSubhransu S. Prusty 298a657f1d0SSubhransu S. Prusty return 0; 299a657f1d0SSubhransu S. Prusty } 300a657f1d0SSubhransu S. Prusty 301c9bfb5d7SJeeja KP static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, 302c9bfb5d7SJeeja KP unsigned int tx_mask, unsigned int rx_mask, 303c9bfb5d7SJeeja KP int slots, int slot_width) 304b0362adbSSubhransu S. Prusty { 305c9bfb5d7SJeeja KP struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); 306c9bfb5d7SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 307b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 308c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 309c9bfb5d7SJeeja KP 310c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask); 311b0362adbSSubhransu S. Prusty 312b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 313b0362adbSSubhransu S. Prusty 314c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); 315b0362adbSSubhransu S. Prusty 316c9bfb5d7SJeeja KP if (pcm) 317c9bfb5d7SJeeja KP pcm->stream_tag = (tx_mask << 4); 318bcced704SSubhransu S. Prusty 319c9bfb5d7SJeeja KP return 0; 320b0362adbSSubhransu S. Prusty } 321b0362adbSSubhransu S. Prusty 322b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, 323b0362adbSSubhransu S. Prusty struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) 324b0362adbSSubhransu S. Prusty { 325b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 32654dfa1eaSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 32754dfa1eaSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 32854dfa1eaSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 329c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 330c9bfb5d7SJeeja KP int format; 331b0362adbSSubhransu S. Prusty 33254dfa1eaSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 33354dfa1eaSSubhransu S. Prusty pin = dai_map->pin; 33454dfa1eaSSubhransu S. Prusty 33554dfa1eaSSubhransu S. Prusty if (!pin) 33654dfa1eaSSubhransu S. Prusty return -ENODEV; 33754dfa1eaSSubhransu S. Prusty 33854dfa1eaSSubhransu S. Prusty if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { 33954dfa1eaSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", 34054dfa1eaSSubhransu S. Prusty pin->nid); 341b0362adbSSubhransu S. Prusty return -ENODEV; 342b0362adbSSubhransu S. Prusty } 343b0362adbSSubhransu S. Prusty 344c9bfb5d7SJeeja KP format = snd_hdac_calc_stream_format(params_rate(hparams), 345b0362adbSSubhransu S. Prusty params_channels(hparams), params_format(hparams), 346b0362adbSSubhransu S. Prusty 24, 0); 347b0362adbSSubhransu S. Prusty 348c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); 349c9bfb5d7SJeeja KP if (!pcm) 350148569fdSSubhransu S. Prusty return -EIO; 351148569fdSSubhransu S. Prusty 352c9bfb5d7SJeeja KP pcm->format = format; 353c9bfb5d7SJeeja KP pcm->channels = params_channels(hparams); 354148569fdSSubhransu S. Prusty 355148569fdSSubhransu S. Prusty return 0; 356148569fdSSubhransu S. Prusty } 357148569fdSSubhransu S. Prusty 358148569fdSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, 359148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 360148569fdSSubhransu S. Prusty { 361148569fdSSubhransu S. Prusty if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { 362148569fdSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 363148569fdSSubhransu S. Prusty "HDMI: pin %d wcaps %#x does not support connection list\n", 364148569fdSSubhransu S. Prusty pin->nid, get_wcaps(&hdac->hdac, pin->nid)); 365148569fdSSubhransu S. Prusty return -EINVAL; 366148569fdSSubhransu S. Prusty } 367148569fdSSubhransu S. Prusty 368148569fdSSubhransu S. Prusty pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, 369148569fdSSubhransu S. Prusty pin->mux_nids, HDA_MAX_CONNECTIONS); 370148569fdSSubhransu S. Prusty if (pin->num_mux_nids == 0) 371148569fdSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", 372148569fdSSubhransu S. Prusty pin->nid); 373148569fdSSubhransu S. Prusty 374148569fdSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", 375148569fdSSubhransu S. Prusty pin->num_mux_nids, pin->nid); 376148569fdSSubhransu S. Prusty 377148569fdSSubhransu S. Prusty return pin->num_mux_nids; 378148569fdSSubhransu S. Prusty } 379148569fdSSubhransu S. Prusty 380148569fdSSubhransu S. Prusty /* 381148569fdSSubhransu S. Prusty * Query pcm list and return pin widget to which stream is routed. 382148569fdSSubhransu S. Prusty * 383148569fdSSubhransu S. Prusty * Also query connection list of the pin, to validate the cvt to pin map. 384148569fdSSubhransu S. Prusty * 385148569fdSSubhransu S. Prusty * Same stream rendering to multiple pins simultaneously can be done 386148569fdSSubhransu S. Prusty * possibly, but not supported for now in driver. So return the first pin 387148569fdSSubhransu S. Prusty * connected. 388148569fdSSubhransu S. Prusty */ 389148569fdSSubhransu S. Prusty static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( 390148569fdSSubhransu S. Prusty struct hdac_ext_device *edev, 391148569fdSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi, 392148569fdSSubhransu S. Prusty struct hdac_hdmi_cvt *cvt) 393148569fdSSubhransu S. Prusty { 394148569fdSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm; 395148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin = NULL; 396148569fdSSubhransu S. Prusty int ret, i; 397148569fdSSubhransu S. Prusty 398148569fdSSubhransu S. Prusty list_for_each_entry(pcm, &hdmi->pcm_list, head) { 399148569fdSSubhransu S. Prusty if (pcm->cvt == cvt) { 400148569fdSSubhransu S. Prusty pin = pcm->pin; 401148569fdSSubhransu S. Prusty break; 402148569fdSSubhransu S. Prusty } 403148569fdSSubhransu S. Prusty } 404148569fdSSubhransu S. Prusty 405148569fdSSubhransu S. Prusty if (pin) { 406148569fdSSubhransu S. Prusty ret = hdac_hdmi_query_pin_connlist(edev, pin); 407148569fdSSubhransu S. Prusty if (ret < 0) 408148569fdSSubhransu S. Prusty return NULL; 409148569fdSSubhransu S. Prusty 410148569fdSSubhransu S. Prusty for (i = 0; i < pin->num_mux_nids; i++) { 411148569fdSSubhransu S. Prusty if (pin->mux_nids[i] == cvt->nid) 412148569fdSSubhransu S. Prusty return pin; 413148569fdSSubhransu S. Prusty } 414148569fdSSubhransu S. Prusty } 415148569fdSSubhransu S. Prusty 416148569fdSSubhransu S. Prusty return NULL; 417148569fdSSubhransu S. Prusty } 418148569fdSSubhransu S. Prusty 41954dfa1eaSSubhransu S. Prusty /* 42054dfa1eaSSubhransu S. Prusty * This tries to get a valid pin and set the HW constraints based on the 42154dfa1eaSSubhransu S. Prusty * ELD. Even if a valid pin is not found return success so that device open 42254dfa1eaSSubhransu S. Prusty * doesn't fail. 42354dfa1eaSSubhransu S. Prusty */ 424b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, 425b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 426b0362adbSSubhransu S. Prusty { 427b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 428b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 429b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 430148569fdSSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 431148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 4322428bca3SSubhransu S. Prusty int ret; 433b0362adbSSubhransu S. Prusty 434b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 435b0362adbSSubhransu S. Prusty 436148569fdSSubhransu S. Prusty cvt = dai_map->cvt; 437148569fdSSubhransu S. Prusty pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); 43854dfa1eaSSubhransu S. Prusty 43954dfa1eaSSubhransu S. Prusty /* 44054dfa1eaSSubhransu S. Prusty * To make PA and other userland happy. 44154dfa1eaSSubhransu S. Prusty * userland scans devices so returning error does not help. 44254dfa1eaSSubhransu S. Prusty */ 443148569fdSSubhransu S. Prusty if (!pin) 44454dfa1eaSSubhransu S. Prusty return 0; 445148569fdSSubhransu S. Prusty 446148569fdSSubhransu S. Prusty if ((!pin->eld.monitor_present) || 447148569fdSSubhransu S. Prusty (!pin->eld.eld_valid)) { 448b0362adbSSubhransu S. Prusty 44954dfa1eaSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 4503fb7b4e4SColin Ian King "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", 451148569fdSSubhransu S. Prusty pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); 452b8a54545SSubhransu S. Prusty 45354dfa1eaSSubhransu S. Prusty return 0; 454b0362adbSSubhransu S. Prusty } 455b0362adbSSubhransu S. Prusty 456148569fdSSubhransu S. Prusty dai_map->pin = pin; 457b0362adbSSubhransu S. Prusty 4582428bca3SSubhransu S. Prusty ret = hdac_hdmi_eld_limit_formats(substream->runtime, 459148569fdSSubhransu S. Prusty pin->eld.eld_buffer); 4602428bca3SSubhransu S. Prusty if (ret < 0) 4612428bca3SSubhransu S. Prusty return ret; 462b0362adbSSubhransu S. Prusty 4632428bca3SSubhransu S. Prusty return snd_pcm_hw_constraint_eld(substream->runtime, 464148569fdSSubhransu S. Prusty pin->eld.eld_buffer); 465b0362adbSSubhransu S. Prusty } 466b0362adbSSubhransu S. Prusty 467b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, 468b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 469b0362adbSSubhransu S. Prusty { 470b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 471b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 472b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 473*ab1eea19SJeeja KP struct hdac_hdmi_pcm *pcm; 474b0362adbSSubhransu S. Prusty 475b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 476b0362adbSSubhransu S. Prusty 477*ab1eea19SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); 478bcced704SSubhransu S. Prusty 479*ab1eea19SJeeja KP if (pcm) { 480*ab1eea19SJeeja KP mutex_lock(&pcm->lock); 481*ab1eea19SJeeja KP pcm->chmap_set = false; 482*ab1eea19SJeeja KP memset(pcm->chmap, 0, sizeof(pcm->chmap)); 483*ab1eea19SJeeja KP pcm->channels = 0; 484*ab1eea19SJeeja KP mutex_unlock(&pcm->lock); 485b0362adbSSubhransu S. Prusty } 486*ab1eea19SJeeja KP 487*ab1eea19SJeeja KP if (dai_map->pin) 488*ab1eea19SJeeja KP dai_map->pin = NULL; 48954dfa1eaSSubhransu S. Prusty } 490b0362adbSSubhransu S. Prusty 49118382eadSSubhransu S. Prusty static int 49218382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 49318382eadSSubhransu S. Prusty { 494bcced704SSubhransu S. Prusty unsigned int chans; 495bcced704SSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 496bcced704SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 49718382eadSSubhransu S. Prusty int err; 49818382eadSSubhransu S. Prusty 499bcced704SSubhransu S. Prusty chans = get_wcaps(hdac, cvt->nid); 500bcced704SSubhransu S. Prusty chans = get_wcaps_channels(chans); 501bcced704SSubhransu S. Prusty 502bcced704SSubhransu S. Prusty cvt->params.channels_min = 2; 503bcced704SSubhransu S. Prusty 504bcced704SSubhransu S. Prusty cvt->params.channels_max = chans; 505bcced704SSubhransu S. Prusty if (chans > hdmi->chmap.channels_max) 506bcced704SSubhransu S. Prusty hdmi->chmap.channels_max = chans; 50718382eadSSubhransu S. Prusty 50818382eadSSubhransu S. Prusty err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 50918382eadSSubhransu S. Prusty &cvt->params.rates, 51018382eadSSubhransu S. Prusty &cvt->params.formats, 51118382eadSSubhransu S. Prusty &cvt->params.maxbps); 51218382eadSSubhransu S. Prusty if (err < 0) 51318382eadSSubhransu S. Prusty dev_err(&hdac->dev, 51418382eadSSubhransu S. Prusty "Failed to query pcm params for nid %d: %d\n", 51518382eadSSubhransu S. Prusty cvt->nid, err); 51618382eadSSubhransu S. Prusty 51718382eadSSubhransu S. Prusty return err; 51818382eadSSubhransu S. Prusty } 51918382eadSSubhransu S. Prusty 52079f4e922SSubhransu S. Prusty static int hdac_hdmi_fill_widget_info(struct device *dev, 521c9bfb5d7SJeeja KP struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id, 522c9bfb5d7SJeeja KP void *priv, const char *wname, const char *stream, 523c9bfb5d7SJeeja KP struct snd_kcontrol_new *wc, int numkc, 524c9bfb5d7SJeeja KP int (*event)(struct snd_soc_dapm_widget *, 525c9bfb5d7SJeeja KP struct snd_kcontrol *, int), unsigned short event_flags) 52618382eadSSubhransu S. Prusty { 52718382eadSSubhransu S. Prusty w->id = id; 52879f4e922SSubhransu S. Prusty w->name = devm_kstrdup(dev, wname, GFP_KERNEL); 52979f4e922SSubhransu S. Prusty if (!w->name) 53079f4e922SSubhransu S. Prusty return -ENOMEM; 53179f4e922SSubhransu S. Prusty 53218382eadSSubhransu S. Prusty w->sname = stream; 53318382eadSSubhransu S. Prusty w->reg = SND_SOC_NOPM; 53418382eadSSubhransu S. Prusty w->shift = 0; 53579f4e922SSubhransu S. Prusty w->kcontrol_news = wc; 53679f4e922SSubhransu S. Prusty w->num_kcontrols = numkc; 53779f4e922SSubhransu S. Prusty w->priv = priv; 538c9bfb5d7SJeeja KP w->event = event; 539c9bfb5d7SJeeja KP w->event_flags = event_flags; 54079f4e922SSubhransu S. Prusty 54179f4e922SSubhransu S. Prusty return 0; 54218382eadSSubhransu S. Prusty } 54318382eadSSubhransu S. Prusty 54418382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 54579f4e922SSubhransu S. Prusty const char *sink, const char *control, const char *src, 54679f4e922SSubhransu S. Prusty int (*handler)(struct snd_soc_dapm_widget *src, 54779f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *sink)) 54818382eadSSubhransu S. Prusty { 54918382eadSSubhransu S. Prusty route->sink = sink; 55018382eadSSubhransu S. Prusty route->source = src; 55118382eadSSubhransu S. Prusty route->control = control; 55279f4e922SSubhransu S. Prusty route->connected = handler; 55318382eadSSubhransu S. Prusty } 55418382eadSSubhransu S. Prusty 5554a3478deSJeeja KP static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, 5564a3478deSJeeja KP struct hdac_hdmi_pin *pin) 5574a3478deSJeeja KP { 5584a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 5594a3478deSJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 5604a3478deSJeeja KP 5614a3478deSJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 5624a3478deSJeeja KP if (pcm->pin == pin) 5634a3478deSJeeja KP return pcm; 5644a3478deSJeeja KP } 5654a3478deSJeeja KP 5664a3478deSJeeja KP return NULL; 5674a3478deSJeeja KP } 5684a3478deSJeeja KP 569c9bfb5d7SJeeja KP static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, 570c9bfb5d7SJeeja KP hda_nid_t nid, unsigned int pwr_state) 571c9bfb5d7SJeeja KP { 572c9bfb5d7SJeeja KP if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) { 573c9bfb5d7SJeeja KP if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state)) 574c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, nid, 0, 575c9bfb5d7SJeeja KP AC_VERB_SET_POWER_STATE, pwr_state); 576c9bfb5d7SJeeja KP } 577c9bfb5d7SJeeja KP } 578c9bfb5d7SJeeja KP 579c9bfb5d7SJeeja KP static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, 580c9bfb5d7SJeeja KP hda_nid_t nid, int val) 581c9bfb5d7SJeeja KP { 582c9bfb5d7SJeeja KP if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP) 583c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, nid, 0, 584c9bfb5d7SJeeja KP AC_VERB_SET_AMP_GAIN_MUTE, val); 585c9bfb5d7SJeeja KP } 586c9bfb5d7SJeeja KP 587c9bfb5d7SJeeja KP 588c9bfb5d7SJeeja KP static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, 589c9bfb5d7SJeeja KP struct snd_kcontrol *kc, int event) 590c9bfb5d7SJeeja KP { 591c9bfb5d7SJeeja KP struct hdac_hdmi_pin *pin = w->priv; 592c9bfb5d7SJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); 593c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 594c9bfb5d7SJeeja KP 595c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", 596c9bfb5d7SJeeja KP __func__, w->name, event); 597c9bfb5d7SJeeja KP 598c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm(edev, pin); 599c9bfb5d7SJeeja KP if (!pcm) 600c9bfb5d7SJeeja KP return -EIO; 601c9bfb5d7SJeeja KP 602c9bfb5d7SJeeja KP switch (event) { 603c9bfb5d7SJeeja KP case SND_SOC_DAPM_PRE_PMU: 604c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D0); 605c9bfb5d7SJeeja KP 606c9bfb5d7SJeeja KP /* Enable out path for this pin widget */ 607c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 608c9bfb5d7SJeeja KP AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 609c9bfb5d7SJeeja KP 610c9bfb5d7SJeeja KP hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); 611c9bfb5d7SJeeja KP 612*ab1eea19SJeeja KP return hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); 613c9bfb5d7SJeeja KP 614c9bfb5d7SJeeja KP case SND_SOC_DAPM_POST_PMD: 615c9bfb5d7SJeeja KP hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); 616c9bfb5d7SJeeja KP 617c9bfb5d7SJeeja KP /* Disable out path for this pin widget */ 618c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 619c9bfb5d7SJeeja KP AC_VERB_SET_PIN_WIDGET_CONTROL, 0); 620c9bfb5d7SJeeja KP 621c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D3); 622c9bfb5d7SJeeja KP break; 623c9bfb5d7SJeeja KP 624c9bfb5d7SJeeja KP } 625c9bfb5d7SJeeja KP 626c9bfb5d7SJeeja KP return 0; 627c9bfb5d7SJeeja KP } 628c9bfb5d7SJeeja KP 629c9bfb5d7SJeeja KP static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, 630c9bfb5d7SJeeja KP struct snd_kcontrol *kc, int event) 631c9bfb5d7SJeeja KP { 632c9bfb5d7SJeeja KP struct hdac_hdmi_cvt *cvt = w->priv; 633c9bfb5d7SJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); 634c9bfb5d7SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 635c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 636c9bfb5d7SJeeja KP 637c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", 638c9bfb5d7SJeeja KP __func__, w->name, event); 639c9bfb5d7SJeeja KP 640c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt); 641c9bfb5d7SJeeja KP if (!pcm) 642c9bfb5d7SJeeja KP return -EIO; 643c9bfb5d7SJeeja KP 644c9bfb5d7SJeeja KP switch (event) { 645c9bfb5d7SJeeja KP case SND_SOC_DAPM_PRE_PMU: 646c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0); 647c9bfb5d7SJeeja KP 648c9bfb5d7SJeeja KP /* Enable transmission */ 649c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 650c9bfb5d7SJeeja KP AC_VERB_SET_DIGI_CONVERT_1, 1); 651c9bfb5d7SJeeja KP 652c9bfb5d7SJeeja KP /* Category Code (CC) to zero */ 653c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 654c9bfb5d7SJeeja KP AC_VERB_SET_DIGI_CONVERT_2, 0); 655c9bfb5d7SJeeja KP 656c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 657c9bfb5d7SJeeja KP AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag); 658c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 659c9bfb5d7SJeeja KP AC_VERB_SET_STREAM_FORMAT, pcm->format); 660c9bfb5d7SJeeja KP break; 661c9bfb5d7SJeeja KP 662c9bfb5d7SJeeja KP case SND_SOC_DAPM_POST_PMD: 663c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 664c9bfb5d7SJeeja KP AC_VERB_SET_CHANNEL_STREAMID, 0); 665c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 666c9bfb5d7SJeeja KP AC_VERB_SET_STREAM_FORMAT, 0); 667c9bfb5d7SJeeja KP 668c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3); 669c9bfb5d7SJeeja KP break; 670c9bfb5d7SJeeja KP 671c9bfb5d7SJeeja KP } 672c9bfb5d7SJeeja KP 673c9bfb5d7SJeeja KP return 0; 674c9bfb5d7SJeeja KP } 675c9bfb5d7SJeeja KP 676c9bfb5d7SJeeja KP static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, 677c9bfb5d7SJeeja KP struct snd_kcontrol *kc, int event) 678c9bfb5d7SJeeja KP { 679c9bfb5d7SJeeja KP struct hdac_hdmi_pin *pin = w->priv; 680c9bfb5d7SJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); 681c9bfb5d7SJeeja KP int mux_idx; 682c9bfb5d7SJeeja KP 683c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", 684c9bfb5d7SJeeja KP __func__, w->name, event); 685c9bfb5d7SJeeja KP 686c9bfb5d7SJeeja KP if (!kc) 687c9bfb5d7SJeeja KP kc = w->kcontrols[0]; 688c9bfb5d7SJeeja KP 689c9bfb5d7SJeeja KP mux_idx = dapm_kcontrol_get_value(kc); 690c9bfb5d7SJeeja KP if (mux_idx > 0) { 691c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 692c9bfb5d7SJeeja KP AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); 693c9bfb5d7SJeeja KP } 694c9bfb5d7SJeeja KP 695c9bfb5d7SJeeja KP return 0; 696c9bfb5d7SJeeja KP } 697c9bfb5d7SJeeja KP 6984a3478deSJeeja KP /* 6994a3478deSJeeja KP * Based on user selection, map the PINs with the PCMs. 7004a3478deSJeeja KP */ 7014a3478deSJeeja KP static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, 7024a3478deSJeeja KP struct snd_ctl_elem_value *ucontrol) 7034a3478deSJeeja KP { 7044a3478deSJeeja KP int ret; 7054a3478deSJeeja KP struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 7064a3478deSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 7074a3478deSJeeja KP struct snd_soc_dapm_context *dapm = w->dapm; 7084a3478deSJeeja KP struct hdac_hdmi_pin *pin = w->priv; 7094a3478deSJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 7104a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 7114a3478deSJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 7124a3478deSJeeja KP const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; 7134a3478deSJeeja KP 7144a3478deSJeeja KP ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); 7154a3478deSJeeja KP if (ret < 0) 7164a3478deSJeeja KP return ret; 7174a3478deSJeeja KP 7184a3478deSJeeja KP mutex_lock(&hdmi->pin_mutex); 7194a3478deSJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 7204a3478deSJeeja KP if (pcm->pin == pin) 7214a3478deSJeeja KP pcm->pin = NULL; 7224a3478deSJeeja KP 7234a3478deSJeeja KP /* 7244a3478deSJeeja KP * Jack status is not reported during device probe as the 7254a3478deSJeeja KP * PCMs are not registered by then. So report it here. 7264a3478deSJeeja KP */ 7274a3478deSJeeja KP if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { 7284a3478deSJeeja KP pcm->pin = pin; 7294a3478deSJeeja KP if (pin->eld.monitor_present && pin->eld.eld_valid) { 7304a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 7314a3478deSJeeja KP "jack report for pcm=%d\n", 7324a3478deSJeeja KP pcm->pcm_id); 7334a3478deSJeeja KP 7344a3478deSJeeja KP snd_jack_report(pcm->jack, SND_JACK_AVOUT); 7354a3478deSJeeja KP } 7364a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 7374a3478deSJeeja KP return ret; 7384a3478deSJeeja KP } 7394a3478deSJeeja KP } 7404a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 7414a3478deSJeeja KP 7424a3478deSJeeja KP return ret; 7434a3478deSJeeja KP } 7444a3478deSJeeja KP 74579f4e922SSubhransu S. Prusty /* 74679f4e922SSubhransu S. Prusty * Ideally the Mux inputs should be based on the num_muxs enumerated, but 74779f4e922SSubhransu S. Prusty * the display driver seem to be programming the connection list for the pin 74879f4e922SSubhransu S. Prusty * widget runtime. 74979f4e922SSubhransu S. Prusty * 75079f4e922SSubhransu S. Prusty * So programming all the possible inputs for the mux, the user has to take 75179f4e922SSubhransu S. Prusty * care of selecting the right one and leaving all other inputs selected to 75279f4e922SSubhransu S. Prusty * "NONE" 75379f4e922SSubhransu S. Prusty */ 75479f4e922SSubhransu S. Prusty static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, 75579f4e922SSubhransu S. Prusty struct hdac_hdmi_pin *pin, 75679f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widget, 75779f4e922SSubhransu S. Prusty const char *widget_name) 75818382eadSSubhransu S. Prusty { 75979f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 76079f4e922SSubhransu S. Prusty struct snd_kcontrol_new *kc; 76179f4e922SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 76279f4e922SSubhransu S. Prusty struct soc_enum *se; 76379f4e922SSubhransu S. Prusty char kc_name[NAME_SIZE]; 76479f4e922SSubhransu S. Prusty char mux_items[NAME_SIZE]; 76579f4e922SSubhransu S. Prusty /* To hold inputs to the Pin mux */ 76679f4e922SSubhransu S. Prusty char *items[HDA_MAX_CONNECTIONS]; 76779f4e922SSubhransu S. Prusty int i = 0; 76879f4e922SSubhransu S. Prusty int num_items = hdmi->num_cvt + 1; 76918382eadSSubhransu S. Prusty 77079f4e922SSubhransu S. Prusty kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL); 77179f4e922SSubhransu S. Prusty if (!kc) 77279f4e922SSubhransu S. Prusty return -ENOMEM; 77318382eadSSubhransu S. Prusty 77479f4e922SSubhransu S. Prusty se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL); 77579f4e922SSubhransu S. Prusty if (!se) 77679f4e922SSubhransu S. Prusty return -ENOMEM; 77718382eadSSubhransu S. Prusty 77879f4e922SSubhransu S. Prusty sprintf(kc_name, "Pin %d Input", pin->nid); 77979f4e922SSubhransu S. Prusty kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); 78079f4e922SSubhransu S. Prusty if (!kc->name) 78179f4e922SSubhransu S. Prusty return -ENOMEM; 78218382eadSSubhransu S. Prusty 78379f4e922SSubhransu S. Prusty kc->private_value = (long)se; 78479f4e922SSubhransu S. Prusty kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 78579f4e922SSubhransu S. Prusty kc->access = 0; 78679f4e922SSubhransu S. Prusty kc->info = snd_soc_info_enum_double; 7874a3478deSJeeja KP kc->put = hdac_hdmi_set_pin_mux; 78879f4e922SSubhransu S. Prusty kc->get = snd_soc_dapm_get_enum_double; 78979f4e922SSubhransu S. Prusty 79079f4e922SSubhransu S. Prusty se->reg = SND_SOC_NOPM; 79179f4e922SSubhransu S. Prusty 79279f4e922SSubhransu S. Prusty /* enum texts: ["NONE", "cvt #", "cvt #", ...] */ 79379f4e922SSubhransu S. Prusty se->items = num_items; 79479f4e922SSubhransu S. Prusty se->mask = roundup_pow_of_two(se->items) - 1; 79579f4e922SSubhransu S. Prusty 79679f4e922SSubhransu S. Prusty sprintf(mux_items, "NONE"); 79779f4e922SSubhransu S. Prusty items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); 79879f4e922SSubhransu S. Prusty if (!items[i]) 79979f4e922SSubhransu S. Prusty return -ENOMEM; 80079f4e922SSubhransu S. Prusty 80179f4e922SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 80279f4e922SSubhransu S. Prusty i++; 80379f4e922SSubhransu S. Prusty sprintf(mux_items, "cvt %d", cvt->nid); 80479f4e922SSubhransu S. Prusty items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); 80579f4e922SSubhransu S. Prusty if (!items[i]) 80679f4e922SSubhransu S. Prusty return -ENOMEM; 80779f4e922SSubhransu S. Prusty } 80879f4e922SSubhransu S. Prusty 80979f4e922SSubhransu S. Prusty se->texts = devm_kmemdup(&edev->hdac.dev, items, 81079f4e922SSubhransu S. Prusty (num_items * sizeof(char *)), GFP_KERNEL); 81179f4e922SSubhransu S. Prusty if (!se->texts) 81279f4e922SSubhransu S. Prusty return -ENOMEM; 81379f4e922SSubhransu S. Prusty 81479f4e922SSubhransu S. Prusty return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, 815c9bfb5d7SJeeja KP snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1, 816c9bfb5d7SJeeja KP hdac_hdmi_pin_mux_widget_event, 817c9bfb5d7SJeeja KP SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); 81879f4e922SSubhransu S. Prusty } 81979f4e922SSubhransu S. Prusty 82079f4e922SSubhransu S. Prusty /* Add cvt <- input <- mux route map */ 82179f4e922SSubhransu S. Prusty static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, 82279f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widgets, 82379f4e922SSubhransu S. Prusty struct snd_soc_dapm_route *route, int rindex) 82479f4e922SSubhransu S. Prusty { 82579f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 82679f4e922SSubhransu S. Prusty const struct snd_kcontrol_new *kc; 82779f4e922SSubhransu S. Prusty struct soc_enum *se; 82879f4e922SSubhransu S. Prusty int mux_index = hdmi->num_cvt + hdmi->num_pin; 82979f4e922SSubhransu S. Prusty int i, j; 83079f4e922SSubhransu S. Prusty 83179f4e922SSubhransu S. Prusty for (i = 0; i < hdmi->num_pin; i++) { 83279f4e922SSubhransu S. Prusty kc = widgets[mux_index].kcontrol_news; 83379f4e922SSubhransu S. Prusty se = (struct soc_enum *)kc->private_value; 83479f4e922SSubhransu S. Prusty for (j = 0; j < hdmi->num_cvt; j++) { 83579f4e922SSubhransu S. Prusty hdac_hdmi_fill_route(&route[rindex], 83679f4e922SSubhransu S. Prusty widgets[mux_index].name, 83779f4e922SSubhransu S. Prusty se->texts[j + 1], 83879f4e922SSubhransu S. Prusty widgets[j].name, NULL); 83979f4e922SSubhransu S. Prusty 84079f4e922SSubhransu S. Prusty rindex++; 84179f4e922SSubhransu S. Prusty } 84279f4e922SSubhransu S. Prusty 84379f4e922SSubhransu S. Prusty mux_index++; 84479f4e922SSubhransu S. Prusty } 84579f4e922SSubhransu S. Prusty } 84679f4e922SSubhransu S. Prusty 84779f4e922SSubhransu S. Prusty /* 84879f4e922SSubhransu S. Prusty * Widgets are added in the below sequence 84979f4e922SSubhransu S. Prusty * Converter widgets for num converters enumerated 85079f4e922SSubhransu S. Prusty * Pin widgets for num pins enumerated 85179f4e922SSubhransu S. Prusty * Pin mux widgets to represent connenction list of pin widget 85279f4e922SSubhransu S. Prusty * 85379f4e922SSubhransu S. Prusty * Total widgets elements = num_cvt + num_pin + num_pin; 85479f4e922SSubhransu S. Prusty * 85579f4e922SSubhransu S. Prusty * Routes are added as below: 85679f4e922SSubhransu S. Prusty * pin mux -> pin (based on num_pins) 85779f4e922SSubhransu S. Prusty * cvt -> "Input sel control" -> pin_mux 85879f4e922SSubhransu S. Prusty * 85979f4e922SSubhransu S. Prusty * Total route elements: 86079f4e922SSubhransu S. Prusty * num_pins + (pin_muxes * num_cvt) 86179f4e922SSubhransu S. Prusty */ 86279f4e922SSubhransu S. Prusty static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) 86379f4e922SSubhransu S. Prusty { 86479f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widgets; 86579f4e922SSubhransu S. Prusty struct snd_soc_dapm_route *route; 86679f4e922SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 86779f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 86879f4e922SSubhransu S. Prusty struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; 86979f4e922SSubhransu S. Prusty char widget_name[NAME_SIZE]; 87079f4e922SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 87179f4e922SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 87279f4e922SSubhransu S. Prusty int ret, i = 0, num_routes = 0; 87379f4e922SSubhransu S. Prusty 87479f4e922SSubhransu S. Prusty if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) 87579f4e922SSubhransu S. Prusty return -EINVAL; 87679f4e922SSubhransu S. Prusty 87779f4e922SSubhransu S. Prusty widgets = devm_kzalloc(dapm->dev, 87879f4e922SSubhransu S. Prusty (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), 87979f4e922SSubhransu S. Prusty GFP_KERNEL); 88079f4e922SSubhransu S. Prusty 88179f4e922SSubhransu S. Prusty if (!widgets) 88279f4e922SSubhransu S. Prusty return -ENOMEM; 88379f4e922SSubhransu S. Prusty 88479f4e922SSubhransu S. Prusty /* DAPM widgets to represent each converter widget */ 88579f4e922SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 88679f4e922SSubhransu S. Prusty sprintf(widget_name, "Converter %d", cvt->nid); 88779f4e922SSubhransu S. Prusty ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], 888c9bfb5d7SJeeja KP snd_soc_dapm_aif_in, cvt, 889c9bfb5d7SJeeja KP widget_name, dai_drv[i].playback.stream_name, NULL, 0, 890c9bfb5d7SJeeja KP hdac_hdmi_cvt_output_widget_event, 891c9bfb5d7SJeeja KP SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); 89279f4e922SSubhransu S. Prusty if (ret < 0) 89379f4e922SSubhransu S. Prusty return ret; 89479f4e922SSubhransu S. Prusty i++; 89579f4e922SSubhransu S. Prusty } 89679f4e922SSubhransu S. Prusty 89779f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 89879f4e922SSubhransu S. Prusty sprintf(widget_name, "hif%d Output", pin->nid); 89979f4e922SSubhransu S. Prusty ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], 900c9bfb5d7SJeeja KP snd_soc_dapm_output, pin, 901c9bfb5d7SJeeja KP widget_name, NULL, NULL, 0, 902c9bfb5d7SJeeja KP hdac_hdmi_pin_output_widget_event, 903c9bfb5d7SJeeja KP SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); 90479f4e922SSubhransu S. Prusty if (ret < 0) 90579f4e922SSubhransu S. Prusty return ret; 90679f4e922SSubhransu S. Prusty i++; 90779f4e922SSubhransu S. Prusty } 90879f4e922SSubhransu S. Prusty 90979f4e922SSubhransu S. Prusty /* DAPM widgets to represent the connection list to pin widget */ 91079f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 91179f4e922SSubhransu S. Prusty sprintf(widget_name, "Pin %d Mux", pin->nid); 91279f4e922SSubhransu S. Prusty ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], 91379f4e922SSubhransu S. Prusty widget_name); 91479f4e922SSubhransu S. Prusty if (ret < 0) 91579f4e922SSubhransu S. Prusty return ret; 91679f4e922SSubhransu S. Prusty i++; 91779f4e922SSubhransu S. Prusty 91879f4e922SSubhransu S. Prusty /* For cvt to pin_mux mapping */ 91979f4e922SSubhransu S. Prusty num_routes += hdmi->num_cvt; 92079f4e922SSubhransu S. Prusty 92179f4e922SSubhransu S. Prusty /* For pin_mux to pin mapping */ 92279f4e922SSubhransu S. Prusty num_routes++; 92379f4e922SSubhransu S. Prusty } 92479f4e922SSubhransu S. Prusty 92579f4e922SSubhransu S. Prusty route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), 92679f4e922SSubhransu S. Prusty GFP_KERNEL); 92779f4e922SSubhransu S. Prusty if (!route) 92879f4e922SSubhransu S. Prusty return -ENOMEM; 92979f4e922SSubhransu S. Prusty 93079f4e922SSubhransu S. Prusty i = 0; 93179f4e922SSubhransu S. Prusty /* Add pin <- NULL <- mux route map */ 93279f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 93379f4e922SSubhransu S. Prusty int sink_index = i + hdmi->num_cvt; 93479f4e922SSubhransu S. Prusty int src_index = sink_index + hdmi->num_pin; 93579f4e922SSubhransu S. Prusty 93679f4e922SSubhransu S. Prusty hdac_hdmi_fill_route(&route[i], 93779f4e922SSubhransu S. Prusty widgets[sink_index].name, NULL, 93879f4e922SSubhransu S. Prusty widgets[src_index].name, NULL); 93979f4e922SSubhransu S. Prusty i++; 94079f4e922SSubhransu S. Prusty 94179f4e922SSubhransu S. Prusty } 94279f4e922SSubhransu S. Prusty 94379f4e922SSubhransu S. Prusty hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i); 94479f4e922SSubhransu S. Prusty 94579f4e922SSubhransu S. Prusty snd_soc_dapm_new_controls(dapm, widgets, 94679f4e922SSubhransu S. Prusty ((2 * hdmi->num_pin) + hdmi->num_cvt)); 94779f4e922SSubhransu S. Prusty 94879f4e922SSubhransu S. Prusty snd_soc_dapm_add_routes(dapm, route, num_routes); 94979f4e922SSubhransu S. Prusty snd_soc_dapm_new_widgets(dapm->card); 95079f4e922SSubhransu S. Prusty 95179f4e922SSubhransu S. Prusty return 0; 95279f4e922SSubhransu S. Prusty 95318382eadSSubhransu S. Prusty } 95418382eadSSubhransu S. Prusty 95515b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) 95618382eadSSubhransu S. Prusty { 95715b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 958148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 95915b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 960148569fdSSubhransu S. Prusty int dai_id = 0; 96118382eadSSubhransu S. Prusty 962148569fdSSubhransu S. Prusty if (list_empty(&hdmi->cvt_list)) 96315b91447SSubhransu S. Prusty return -EINVAL; 96418382eadSSubhransu S. Prusty 965148569fdSSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 966148569fdSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai_id]; 967148569fdSSubhransu S. Prusty dai_map->dai_id = dai_id; 96815b91447SSubhransu S. Prusty dai_map->cvt = cvt; 96918382eadSSubhransu S. Prusty 970148569fdSSubhransu S. Prusty dai_id++; 971148569fdSSubhransu S. Prusty 972148569fdSSubhransu S. Prusty if (dai_id == HDA_MAX_CVTS) { 973148569fdSSubhransu S. Prusty dev_warn(&edev->hdac.dev, 974148569fdSSubhransu S. Prusty "Max dais supported: %d\n", dai_id); 975148569fdSSubhransu S. Prusty break; 976148569fdSSubhransu S. Prusty } 977148569fdSSubhransu S. Prusty } 97818382eadSSubhransu S. Prusty 97915b91447SSubhransu S. Prusty return 0; 98015b91447SSubhransu S. Prusty } 98115b91447SSubhransu S. Prusty 98215b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) 98315b91447SSubhransu S. Prusty { 98415b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 98515b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 9864a3478deSJeeja KP char name[NAME_SIZE]; 98715b91447SSubhransu S. Prusty 98815b91447SSubhransu S. Prusty cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); 98915b91447SSubhransu S. Prusty if (!cvt) 99015b91447SSubhransu S. Prusty return -ENOMEM; 99115b91447SSubhransu S. Prusty 99215b91447SSubhransu S. Prusty cvt->nid = nid; 9934a3478deSJeeja KP sprintf(name, "cvt %d", cvt->nid); 9944a3478deSJeeja KP cvt->name = kstrdup(name, GFP_KERNEL); 99515b91447SSubhransu S. Prusty 99615b91447SSubhransu S. Prusty list_add_tail(&cvt->head, &hdmi->cvt_list); 99715b91447SSubhransu S. Prusty hdmi->num_cvt++; 99815b91447SSubhransu S. Prusty 99915b91447SSubhransu S. Prusty return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); 100015b91447SSubhransu S. Prusty } 100115b91447SSubhransu S. Prusty 1002f6fa11a3SSandeep Tayal static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, 1003b7756edeSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 1004b7756edeSSubhransu S. Prusty { 1005f6fa11a3SSandeep Tayal unsigned int ver, mnl; 1006f6fa11a3SSandeep Tayal 1007f6fa11a3SSandeep Tayal ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) 1008f6fa11a3SSandeep Tayal >> DRM_ELD_VER_SHIFT; 1009f6fa11a3SSandeep Tayal 1010f6fa11a3SSandeep Tayal if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { 1011f6fa11a3SSandeep Tayal dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); 1012f6fa11a3SSandeep Tayal return -EINVAL; 1013b7756edeSSubhransu S. Prusty } 1014b7756edeSSubhransu S. Prusty 1015f6fa11a3SSandeep Tayal mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & 1016f6fa11a3SSandeep Tayal DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; 1017f6fa11a3SSandeep Tayal 1018f6fa11a3SSandeep Tayal if (mnl > ELD_MAX_MNL) { 1019f6fa11a3SSandeep Tayal dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); 1020f6fa11a3SSandeep Tayal return -EINVAL; 1021f6fa11a3SSandeep Tayal } 1022f6fa11a3SSandeep Tayal 1023f6fa11a3SSandeep Tayal pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; 1024f6fa11a3SSandeep Tayal 1025f6fa11a3SSandeep Tayal return 0; 1026f6fa11a3SSandeep Tayal } 1027f6fa11a3SSandeep Tayal 1028f6fa11a3SSandeep Tayal static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) 1029b8a54545SSubhransu S. Prusty { 1030b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = pin->edev; 10314a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 10324a3478deSJeeja KP struct hdac_hdmi_pcm *pcm; 1033f6fa11a3SSandeep Tayal int size; 10344a3478deSJeeja KP 10354a3478deSJeeja KP mutex_lock(&hdmi->pin_mutex); 1036f6fa11a3SSandeep Tayal pin->eld.monitor_present = false; 1037f6fa11a3SSandeep Tayal 1038f6fa11a3SSandeep Tayal size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, 1039f6fa11a3SSandeep Tayal &pin->eld.monitor_present, pin->eld.eld_buffer, 1040f6fa11a3SSandeep Tayal ELD_MAX_SIZE); 1041f6fa11a3SSandeep Tayal 1042f6fa11a3SSandeep Tayal if (size > 0) { 1043f6fa11a3SSandeep Tayal size = min(size, ELD_MAX_SIZE); 1044f6fa11a3SSandeep Tayal if (hdac_hdmi_parse_eld(edev, pin) < 0) 1045f6fa11a3SSandeep Tayal size = -EINVAL; 1046f6fa11a3SSandeep Tayal } 1047f6fa11a3SSandeep Tayal 1048f6fa11a3SSandeep Tayal if (size > 0) { 1049f6fa11a3SSandeep Tayal pin->eld.eld_valid = true; 1050f6fa11a3SSandeep Tayal pin->eld.eld_size = size; 1051f6fa11a3SSandeep Tayal } else { 1052f6fa11a3SSandeep Tayal pin->eld.eld_valid = false; 1053f6fa11a3SSandeep Tayal pin->eld.eld_size = 0; 1054f6fa11a3SSandeep Tayal } 1055b8a54545SSubhransu S. Prusty 10564a3478deSJeeja KP pcm = hdac_hdmi_get_pcm(edev, pin); 10574a3478deSJeeja KP 1058b8a54545SSubhransu S. Prusty if (!pin->eld.monitor_present || !pin->eld.eld_valid) { 1059b8a54545SSubhransu S. Prusty 1060b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", 1061b8a54545SSubhransu S. Prusty __func__, pin->nid); 10624a3478deSJeeja KP 10634a3478deSJeeja KP /* 10644a3478deSJeeja KP * PCMs are not registered during device probe, so don't 10654a3478deSJeeja KP * report jack here. It will be done in usermode mux 10664a3478deSJeeja KP * control select. 10674a3478deSJeeja KP */ 10684a3478deSJeeja KP if (pcm) { 10694a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 10704a3478deSJeeja KP "jack report for pcm=%d\n", pcm->pcm_id); 10714a3478deSJeeja KP 10724a3478deSJeeja KP snd_jack_report(pcm->jack, 0); 10734a3478deSJeeja KP } 10744a3478deSJeeja KP 10754a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 1076f6fa11a3SSandeep Tayal return; 1077b8a54545SSubhransu S. Prusty } 1078b8a54545SSubhransu S. Prusty 1079b8a54545SSubhransu S. Prusty if (pin->eld.monitor_present && pin->eld.eld_valid) { 10804a3478deSJeeja KP if (pcm) { 10814a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 10824a3478deSJeeja KP "jack report for pcm=%d\n", 10834a3478deSJeeja KP pcm->pcm_id); 10844a3478deSJeeja KP 10854a3478deSJeeja KP snd_jack_report(pcm->jack, SND_JACK_AVOUT); 10864a3478deSJeeja KP } 10874a3478deSJeeja KP 1088f6fa11a3SSandeep Tayal print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, 1089f6fa11a3SSandeep Tayal pin->eld.eld_buffer, pin->eld.eld_size, false); 10904a3478deSJeeja KP } 10914a3478deSJeeja KP 10924a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 1093b8a54545SSubhransu S. Prusty } 1094b8a54545SSubhransu S. Prusty 109515b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) 109615b91447SSubhransu S. Prusty { 109715b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 109815b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 109915b91447SSubhransu S. Prusty 110015b91447SSubhransu S. Prusty pin = kzalloc(sizeof(*pin), GFP_KERNEL); 110115b91447SSubhransu S. Prusty if (!pin) 110215b91447SSubhransu S. Prusty return -ENOMEM; 110315b91447SSubhransu S. Prusty 110415b91447SSubhransu S. Prusty pin->nid = nid; 110515b91447SSubhransu S. Prusty 110615b91447SSubhransu S. Prusty list_add_tail(&pin->head, &hdmi->pin_list); 110715b91447SSubhransu S. Prusty hdmi->num_pin++; 110815b91447SSubhransu S. Prusty 1109b8a54545SSubhransu S. Prusty pin->edev = edev; 1110b8a54545SSubhransu S. Prusty 111115b91447SSubhransu S. Prusty return 0; 111218382eadSSubhransu S. Prusty } 111318382eadSSubhransu S. Prusty 1114211caab7SSubhransu S. Prusty #define INTEL_VENDOR_NID 0x08 1115211caab7SSubhransu S. Prusty #define INTEL_GET_VENDOR_VERB 0xf81 1116211caab7SSubhransu S. Prusty #define INTEL_SET_VENDOR_VERB 0x781 1117211caab7SSubhransu S. Prusty #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ 1118211caab7SSubhransu S. Prusty #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ 1119211caab7SSubhransu S. Prusty 1120211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) 1121211caab7SSubhransu S. Prusty { 1122211caab7SSubhransu S. Prusty unsigned int vendor_param; 1123211caab7SSubhransu S. Prusty 1124211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1125211caab7SSubhransu S. Prusty INTEL_GET_VENDOR_VERB, 0); 1126211caab7SSubhransu S. Prusty if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) 1127211caab7SSubhransu S. Prusty return; 1128211caab7SSubhransu S. Prusty 1129211caab7SSubhransu S. Prusty vendor_param |= INTEL_EN_ALL_PIN_CVTS; 1130211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1131211caab7SSubhransu S. Prusty INTEL_SET_VENDOR_VERB, vendor_param); 1132211caab7SSubhransu S. Prusty if (vendor_param == -1) 1133211caab7SSubhransu S. Prusty return; 1134211caab7SSubhransu S. Prusty } 1135211caab7SSubhransu S. Prusty 1136211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) 1137211caab7SSubhransu S. Prusty { 1138211caab7SSubhransu S. Prusty unsigned int vendor_param; 1139211caab7SSubhransu S. Prusty 1140211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1141211caab7SSubhransu S. Prusty INTEL_GET_VENDOR_VERB, 0); 1142211caab7SSubhransu S. Prusty if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) 1143211caab7SSubhransu S. Prusty return; 1144211caab7SSubhransu S. Prusty 1145211caab7SSubhransu S. Prusty /* enable DP1.2 mode */ 1146211caab7SSubhransu S. Prusty vendor_param |= INTEL_EN_DP12; 1147211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1148211caab7SSubhransu S. Prusty INTEL_SET_VENDOR_VERB, vendor_param); 1149211caab7SSubhransu S. Prusty if (vendor_param == -1) 1150211caab7SSubhransu S. Prusty return; 1151211caab7SSubhransu S. Prusty 1152211caab7SSubhransu S. Prusty } 1153211caab7SSubhransu S. Prusty 115417a42c45SSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = { 115517a42c45SSubhransu S. Prusty .startup = hdac_hdmi_pcm_open, 115617a42c45SSubhransu S. Prusty .shutdown = hdac_hdmi_pcm_close, 115717a42c45SSubhransu S. Prusty .hw_params = hdac_hdmi_set_hw_params, 1158c9bfb5d7SJeeja KP .set_tdm_slot = hdac_hdmi_set_tdm_slot, 115917a42c45SSubhransu S. Prusty }; 116017a42c45SSubhransu S. Prusty 116117a42c45SSubhransu S. Prusty /* 116217a42c45SSubhransu S. Prusty * Each converter can support a stream independently. So a dai is created 116317a42c45SSubhransu S. Prusty * based on the number of converter queried. 116417a42c45SSubhransu S. Prusty */ 116517a42c45SSubhransu S. Prusty static int hdac_hdmi_create_dais(struct hdac_device *hdac, 116617a42c45SSubhransu S. Prusty struct snd_soc_dai_driver **dais, 116717a42c45SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi, int num_dais) 116817a42c45SSubhransu S. Prusty { 116917a42c45SSubhransu S. Prusty struct snd_soc_dai_driver *hdmi_dais; 117017a42c45SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 117117a42c45SSubhransu S. Prusty char name[NAME_SIZE], dai_name[NAME_SIZE]; 117217a42c45SSubhransu S. Prusty int i = 0; 117317a42c45SSubhransu S. Prusty u32 rates, bps; 117417a42c45SSubhransu S. Prusty unsigned int rate_max = 384000, rate_min = 8000; 117517a42c45SSubhransu S. Prusty u64 formats; 117617a42c45SSubhransu S. Prusty int ret; 117717a42c45SSubhransu S. Prusty 117817a42c45SSubhransu S. Prusty hdmi_dais = devm_kzalloc(&hdac->dev, 117917a42c45SSubhransu S. Prusty (sizeof(*hdmi_dais) * num_dais), 118017a42c45SSubhransu S. Prusty GFP_KERNEL); 118117a42c45SSubhransu S. Prusty if (!hdmi_dais) 118217a42c45SSubhransu S. Prusty return -ENOMEM; 118317a42c45SSubhransu S. Prusty 118417a42c45SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 118517a42c45SSubhransu S. Prusty ret = snd_hdac_query_supported_pcm(hdac, cvt->nid, 118617a42c45SSubhransu S. Prusty &rates, &formats, &bps); 118717a42c45SSubhransu S. Prusty if (ret) 118817a42c45SSubhransu S. Prusty return ret; 118917a42c45SSubhransu S. Prusty 119017a42c45SSubhransu S. Prusty sprintf(dai_name, "intel-hdmi-hifi%d", i+1); 119117a42c45SSubhransu S. Prusty hdmi_dais[i].name = devm_kstrdup(&hdac->dev, 119217a42c45SSubhransu S. Prusty dai_name, GFP_KERNEL); 119317a42c45SSubhransu S. Prusty 119417a42c45SSubhransu S. Prusty if (!hdmi_dais[i].name) 119517a42c45SSubhransu S. Prusty return -ENOMEM; 119617a42c45SSubhransu S. Prusty 119717a42c45SSubhransu S. Prusty snprintf(name, sizeof(name), "hifi%d", i+1); 119817a42c45SSubhransu S. Prusty hdmi_dais[i].playback.stream_name = 119917a42c45SSubhransu S. Prusty devm_kstrdup(&hdac->dev, name, GFP_KERNEL); 120017a42c45SSubhransu S. Prusty if (!hdmi_dais[i].playback.stream_name) 120117a42c45SSubhransu S. Prusty return -ENOMEM; 120217a42c45SSubhransu S. Prusty 120317a42c45SSubhransu S. Prusty /* 120417a42c45SSubhransu S. Prusty * Set caps based on capability queried from the converter. 120517a42c45SSubhransu S. Prusty * It will be constrained runtime based on ELD queried. 120617a42c45SSubhransu S. Prusty */ 120717a42c45SSubhransu S. Prusty hdmi_dais[i].playback.formats = formats; 120817a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rates = rates; 120917a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rate_max = rate_max; 121017a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rate_min = rate_min; 121117a42c45SSubhransu S. Prusty hdmi_dais[i].playback.channels_min = 2; 121217a42c45SSubhransu S. Prusty hdmi_dais[i].playback.channels_max = 2; 121317a42c45SSubhransu S. Prusty hdmi_dais[i].ops = &hdmi_dai_ops; 121417a42c45SSubhransu S. Prusty 121517a42c45SSubhransu S. Prusty i++; 121617a42c45SSubhransu S. Prusty } 121717a42c45SSubhransu S. Prusty 121817a42c45SSubhransu S. Prusty *dais = hdmi_dais; 121917a42c45SSubhransu S. Prusty 122017a42c45SSubhransu S. Prusty return 0; 122117a42c45SSubhransu S. Prusty } 122217a42c45SSubhransu S. Prusty 122318382eadSSubhransu S. Prusty /* 122418382eadSSubhransu S. Prusty * Parse all nodes and store the cvt/pin nids in array 122518382eadSSubhransu S. Prusty * Add one time initialization for pin and cvt widgets 122618382eadSSubhransu S. Prusty */ 122717a42c45SSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, 122817a42c45SSubhransu S. Prusty struct snd_soc_dai_driver **dais, int *num_dais) 122918382eadSSubhransu S. Prusty { 123018382eadSSubhransu S. Prusty hda_nid_t nid; 12313c83ac23SSudip Mukherjee int i, num_nodes; 123218382eadSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 123318382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 123415b91447SSubhransu S. Prusty int ret; 123518382eadSSubhransu S. Prusty 1236211caab7SSubhransu S. Prusty hdac_hdmi_skl_enable_all_pins(hdac); 1237211caab7SSubhransu S. Prusty hdac_hdmi_skl_enable_dp12(hdac); 1238211caab7SSubhransu S. Prusty 12393c83ac23SSudip Mukherjee num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); 1240541140d4SSubhransu S. Prusty if (!nid || num_nodes <= 0) { 124118382eadSSubhransu S. Prusty dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 124218382eadSSubhransu S. Prusty return -EINVAL; 124318382eadSSubhransu S. Prusty } 124418382eadSSubhransu S. Prusty 12453c83ac23SSudip Mukherjee hdac->num_nodes = num_nodes; 124618382eadSSubhransu S. Prusty hdac->start_nid = nid; 124718382eadSSubhransu S. Prusty 124818382eadSSubhransu S. Prusty for (i = 0; i < hdac->num_nodes; i++, nid++) { 124918382eadSSubhransu S. Prusty unsigned int caps; 125018382eadSSubhransu S. Prusty unsigned int type; 125118382eadSSubhransu S. Prusty 125218382eadSSubhransu S. Prusty caps = get_wcaps(hdac, nid); 125318382eadSSubhransu S. Prusty type = get_wcaps_type(caps); 125418382eadSSubhransu S. Prusty 125518382eadSSubhransu S. Prusty if (!(caps & AC_WCAP_DIGITAL)) 125618382eadSSubhransu S. Prusty continue; 125718382eadSSubhransu S. Prusty 125818382eadSSubhransu S. Prusty switch (type) { 125918382eadSSubhransu S. Prusty 126018382eadSSubhransu S. Prusty case AC_WID_AUD_OUT: 126115b91447SSubhransu S. Prusty ret = hdac_hdmi_add_cvt(edev, nid); 126215b91447SSubhransu S. Prusty if (ret < 0) 126315b91447SSubhransu S. Prusty return ret; 126418382eadSSubhransu S. Prusty break; 126518382eadSSubhransu S. Prusty 126618382eadSSubhransu S. Prusty case AC_WID_PIN: 126715b91447SSubhransu S. Prusty ret = hdac_hdmi_add_pin(edev, nid); 126815b91447SSubhransu S. Prusty if (ret < 0) 126915b91447SSubhransu S. Prusty return ret; 127018382eadSSubhransu S. Prusty break; 127118382eadSSubhransu S. Prusty } 127218382eadSSubhransu S. Prusty } 127318382eadSSubhransu S. Prusty 127418382eadSSubhransu S. Prusty hdac->end_nid = nid; 127518382eadSSubhransu S. Prusty 127615b91447SSubhransu S. Prusty if (!hdmi->num_pin || !hdmi->num_cvt) 127718382eadSSubhransu S. Prusty return -EIO; 127818382eadSSubhransu S. Prusty 127917a42c45SSubhransu S. Prusty ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt); 128017a42c45SSubhransu S. Prusty if (ret) { 128117a42c45SSubhransu S. Prusty dev_err(&hdac->dev, "Failed to create dais with err: %d\n", 128217a42c45SSubhransu S. Prusty ret); 128317a42c45SSubhransu S. Prusty return ret; 128417a42c45SSubhransu S. Prusty } 128517a42c45SSubhransu S. Prusty 128617a42c45SSubhransu S. Prusty *num_dais = hdmi->num_cvt; 128717a42c45SSubhransu S. Prusty 128815b91447SSubhransu S. Prusty return hdac_hdmi_init_dai_map(edev); 128918382eadSSubhransu S. Prusty } 129018382eadSSubhransu S. Prusty 1291f9318941SPandiyan, Dhinakaran static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) 1292b8a54545SSubhransu S. Prusty { 1293b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = aptr; 1294b8a54545SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 1295b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 1296b8a54545SSubhransu S. Prusty struct snd_soc_codec *codec = edev->scodec; 1297b8a54545SSubhransu S. Prusty 1298b8a54545SSubhransu S. Prusty /* Don't know how this mapping is derived */ 1299b8a54545SSubhransu S. Prusty hda_nid_t pin_nid = port + 0x04; 1300b8a54545SSubhransu S. Prusty 1301b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); 1302b8a54545SSubhransu S. Prusty 1303b8a54545SSubhransu S. Prusty /* 1304b8a54545SSubhransu S. Prusty * skip notification during system suspend (but not in runtime PM); 1305b8a54545SSubhransu S. Prusty * the state will be updated at resume. Also since the ELD and 1306b8a54545SSubhransu S. Prusty * connection states are updated in anyway at the end of the resume, 1307b8a54545SSubhransu S. Prusty * we can skip it when received during PM process. 1308b8a54545SSubhransu S. Prusty */ 1309b8a54545SSubhransu S. Prusty if (snd_power_get_state(codec->component.card->snd_card) != 1310b8a54545SSubhransu S. Prusty SNDRV_CTL_POWER_D0) 1311b8a54545SSubhransu S. Prusty return; 1312b8a54545SSubhransu S. Prusty 1313b8a54545SSubhransu S. Prusty if (atomic_read(&edev->hdac.in_pm)) 1314b8a54545SSubhransu S. Prusty return; 1315b8a54545SSubhransu S. Prusty 1316b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 1317b8a54545SSubhransu S. Prusty if (pin->nid == pin_nid) 1318f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1319b8a54545SSubhransu S. Prusty } 1320b8a54545SSubhransu S. Prusty } 1321b8a54545SSubhransu S. Prusty 1322b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = { 1323b8a54545SSubhransu S. Prusty .pin_eld_notify = hdac_hdmi_eld_notify_cb, 1324b8a54545SSubhransu S. Prusty }; 1325b8a54545SSubhransu S. Prusty 13262889099eSSubhransu S. Prusty static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, 13272889099eSSubhransu S. Prusty int device) 13282889099eSSubhransu S. Prusty { 13292889099eSSubhransu S. Prusty struct snd_soc_pcm_runtime *rtd; 13302889099eSSubhransu S. Prusty 13312889099eSSubhransu S. Prusty list_for_each_entry(rtd, &card->rtd_list, list) { 13322889099eSSubhransu S. Prusty if (rtd->pcm && (rtd->pcm->device == device)) 13332889099eSSubhransu S. Prusty return rtd->pcm; 13342889099eSSubhransu S. Prusty } 13352889099eSSubhransu S. Prusty 13362889099eSSubhransu S. Prusty return NULL; 13372889099eSSubhransu S. Prusty } 13382889099eSSubhransu S. Prusty 13394a3478deSJeeja KP int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) 13404a3478deSJeeja KP { 13414a3478deSJeeja KP char jack_name[NAME_SIZE]; 13424a3478deSJeeja KP struct snd_soc_codec *codec = dai->codec; 13434a3478deSJeeja KP struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 13444a3478deSJeeja KP struct snd_soc_dapm_context *dapm = 13454a3478deSJeeja KP snd_soc_component_get_dapm(&codec->component); 13464a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 13474a3478deSJeeja KP struct hdac_hdmi_pcm *pcm; 13482889099eSSubhransu S. Prusty struct snd_pcm *snd_pcm; 13492889099eSSubhransu S. Prusty int err; 13504a3478deSJeeja KP 13514a3478deSJeeja KP /* 13524a3478deSJeeja KP * this is a new PCM device, create new pcm and 13534a3478deSJeeja KP * add to the pcm list 13544a3478deSJeeja KP */ 13554a3478deSJeeja KP pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); 13564a3478deSJeeja KP if (!pcm) 13574a3478deSJeeja KP return -ENOMEM; 13584a3478deSJeeja KP pcm->pcm_id = device; 13594a3478deSJeeja KP pcm->cvt = hdmi->dai_map[dai->id].cvt; 1360*ab1eea19SJeeja KP mutex_init(&pcm->lock); 13614a3478deSJeeja KP 13622889099eSSubhransu S. Prusty snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); 13632889099eSSubhransu S. Prusty if (snd_pcm) { 13642889099eSSubhransu S. Prusty err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); 13652889099eSSubhransu S. Prusty if (err < 0) { 13662889099eSSubhransu S. Prusty dev_err(&edev->hdac.dev, 13672889099eSSubhransu S. Prusty "chmap control add failed with err: %d for pcm: %d\n", 13682889099eSSubhransu S. Prusty err, device); 13692889099eSSubhransu S. Prusty kfree(pcm); 13702889099eSSubhransu S. Prusty return err; 13712889099eSSubhransu S. Prusty } 13722889099eSSubhransu S. Prusty } 13732889099eSSubhransu S. Prusty 13744a3478deSJeeja KP list_add_tail(&pcm->head, &hdmi->pcm_list); 13754a3478deSJeeja KP 13764a3478deSJeeja KP sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); 13774a3478deSJeeja KP 13784a3478deSJeeja KP return snd_jack_new(dapm->card->snd_card, jack_name, 13794a3478deSJeeja KP SND_JACK_AVOUT, &pcm->jack, true, false); 13804a3478deSJeeja KP } 13814a3478deSJeeja KP EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); 13824a3478deSJeeja KP 138318382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec) 138418382eadSSubhransu S. Prusty { 138518382eadSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 138618382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 138718382eadSSubhransu S. Prusty struct snd_soc_dapm_context *dapm = 138818382eadSSubhransu S. Prusty snd_soc_component_get_dapm(&codec->component); 1389b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 1390b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 1391b8a54545SSubhransu S. Prusty int ret; 139218382eadSSubhransu S. Prusty 139318382eadSSubhransu S. Prusty edev->scodec = codec; 139418382eadSSubhransu S. Prusty 1395b2047e99SVinod Koul /* 1396b2047e99SVinod Koul * hold the ref while we probe, also no need to drop the ref on 1397b2047e99SVinod Koul * exit, we call pm_runtime_suspend() so that will do for us 1398b2047e99SVinod Koul */ 1399b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); 1400500e06b9SVinod Koul if (!hlink) { 1401500e06b9SVinod Koul dev_err(&edev->hdac.dev, "hdac link not found\n"); 1402500e06b9SVinod Koul return -EIO; 1403500e06b9SVinod Koul } 1404500e06b9SVinod Koul 1405b2047e99SVinod Koul snd_hdac_ext_bus_link_get(edev->ebus, hlink); 1406b2047e99SVinod Koul 140779f4e922SSubhransu S. Prusty ret = create_fill_widget_route_map(dapm); 140879f4e922SSubhransu S. Prusty if (ret < 0) 140979f4e922SSubhransu S. Prusty return ret; 141018382eadSSubhransu S. Prusty 1411b8a54545SSubhransu S. Prusty aops.audio_ptr = edev; 1412b8a54545SSubhransu S. Prusty ret = snd_hdac_i915_register_notifier(&aops); 1413b8a54545SSubhransu S. Prusty if (ret < 0) { 1414b8a54545SSubhransu S. Prusty dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n", 1415b8a54545SSubhransu S. Prusty ret); 1416b8a54545SSubhransu S. Prusty return ret; 1417b8a54545SSubhransu S. Prusty } 1418b8a54545SSubhransu S. Prusty 1419b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) 1420f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1421b8a54545SSubhransu S. Prusty 142218382eadSSubhransu S. Prusty /* Imp: Store the card pointer in hda_codec */ 142318382eadSSubhransu S. Prusty edev->card = dapm->card->snd_card; 142418382eadSSubhransu S. Prusty 1425e342ac08SSubhransu S. Prusty /* 1426e342ac08SSubhransu S. Prusty * hdac_device core already sets the state to active and calls 1427e342ac08SSubhransu S. Prusty * get_noresume. So enable runtime and set the device to suspend. 1428e342ac08SSubhransu S. Prusty */ 1429e342ac08SSubhransu S. Prusty pm_runtime_enable(&edev->hdac.dev); 1430e342ac08SSubhransu S. Prusty pm_runtime_put(&edev->hdac.dev); 1431e342ac08SSubhransu S. Prusty pm_runtime_suspend(&edev->hdac.dev); 1432e342ac08SSubhransu S. Prusty 1433e342ac08SSubhransu S. Prusty return 0; 1434e342ac08SSubhransu S. Prusty } 1435e342ac08SSubhransu S. Prusty 1436e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec) 1437e342ac08SSubhransu S. Prusty { 1438e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 1439e342ac08SSubhransu S. Prusty 1440e342ac08SSubhransu S. Prusty pm_runtime_disable(&edev->hdac.dev); 144118382eadSSubhransu S. Prusty return 0; 144218382eadSSubhransu S. Prusty } 144318382eadSSubhransu S. Prusty 1444571d5078SJeeja KP #ifdef CONFIG_PM 14451b377ccdSSubhransu S. Prusty static int hdmi_codec_prepare(struct device *dev) 14461b377ccdSSubhransu S. Prusty { 14471b377ccdSSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 14481b377ccdSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 14491b377ccdSSubhransu S. Prusty 14501b377ccdSSubhransu S. Prusty pm_runtime_get_sync(&edev->hdac.dev); 14511b377ccdSSubhransu S. Prusty 14521b377ccdSSubhransu S. Prusty /* 14531b377ccdSSubhransu S. Prusty * Power down afg. 14541b377ccdSSubhransu S. Prusty * codec_read is preferred over codec_write to set the power state. 14551b377ccdSSubhransu S. Prusty * This way verb is send to set the power state and response 14561b377ccdSSubhransu S. Prusty * is received. So setting power state is ensured without using loop 14571b377ccdSSubhransu S. Prusty * to read the state. 14581b377ccdSSubhransu S. Prusty */ 14591b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 14601b377ccdSSubhransu S. Prusty AC_PWRST_D3); 14611b377ccdSSubhransu S. Prusty 14621b377ccdSSubhransu S. Prusty return 0; 14631b377ccdSSubhransu S. Prusty } 14641b377ccdSSubhransu S. Prusty 14650fee1798SSubhransu S. Prusty static void hdmi_codec_complete(struct device *dev) 1466571d5078SJeeja KP { 14670fee1798SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1468571d5078SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 1469571d5078SJeeja KP struct hdac_hdmi_pin *pin; 1470571d5078SJeeja KP struct hdac_device *hdac = &edev->hdac; 14711b377ccdSSubhransu S. Prusty 14721b377ccdSSubhransu S. Prusty /* Power up afg */ 14731b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 14741b377ccdSSubhransu S. Prusty AC_PWRST_D0); 1475571d5078SJeeja KP 1476571d5078SJeeja KP hdac_hdmi_skl_enable_all_pins(&edev->hdac); 1477571d5078SJeeja KP hdac_hdmi_skl_enable_dp12(&edev->hdac); 1478571d5078SJeeja KP 1479571d5078SJeeja KP /* 1480571d5078SJeeja KP * As the ELD notify callback request is not entertained while the 1481571d5078SJeeja KP * device is in suspend state. Need to manually check detection of 1482571d5078SJeeja KP * all pins here. 1483571d5078SJeeja KP */ 1484571d5078SJeeja KP list_for_each_entry(pin, &hdmi->pin_list, head) 1485f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1486571d5078SJeeja KP 14871b377ccdSSubhransu S. Prusty pm_runtime_put_sync(&edev->hdac.dev); 1488571d5078SJeeja KP } 1489571d5078SJeeja KP #else 14901b377ccdSSubhransu S. Prusty #define hdmi_codec_prepare NULL 14910fee1798SSubhransu S. Prusty #define hdmi_codec_complete NULL 1492571d5078SJeeja KP #endif 1493571d5078SJeeja KP 149418382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = { 149518382eadSSubhransu S. Prusty .probe = hdmi_codec_probe, 1496e342ac08SSubhransu S. Prusty .remove = hdmi_codec_remove, 149718382eadSSubhransu S. Prusty .idle_bias_off = true, 149818382eadSSubhransu S. Prusty }; 149918382eadSSubhransu S. Prusty 15002889099eSSubhransu S. Prusty static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, 15012889099eSSubhransu S. Prusty unsigned char *chmap) 15022889099eSSubhransu S. Prusty { 15032889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15042889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15052889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15062889099eSSubhransu S. Prusty 1507*ab1eea19SJeeja KP memcpy(chmap, pcm->chmap, ARRAY_SIZE(pcm->chmap)); 15082889099eSSubhransu S. Prusty } 15092889099eSSubhransu S. Prusty 15102889099eSSubhransu S. Prusty static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, 15112889099eSSubhransu S. Prusty unsigned char *chmap, int prepared) 15122889099eSSubhransu S. Prusty { 15132889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15142889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15152889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15162889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15172889099eSSubhransu S. Prusty 1518*ab1eea19SJeeja KP mutex_lock(&pcm->lock); 1519*ab1eea19SJeeja KP pcm->chmap_set = true; 1520*ab1eea19SJeeja KP memcpy(pcm->chmap, chmap, ARRAY_SIZE(pcm->chmap)); 15212889099eSSubhransu S. Prusty if (prepared) 1522*ab1eea19SJeeja KP hdac_hdmi_setup_audio_infoframe(edev, pcm, pin); 1523*ab1eea19SJeeja KP mutex_unlock(&pcm->lock); 15242889099eSSubhransu S. Prusty } 15252889099eSSubhransu S. Prusty 15262889099eSSubhransu S. Prusty static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) 15272889099eSSubhransu S. Prusty { 15282889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15292889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15302889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15312889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15322889099eSSubhransu S. Prusty 15332889099eSSubhransu S. Prusty return pin ? true:false; 15342889099eSSubhransu S. Prusty } 15352889099eSSubhransu S. Prusty 15362889099eSSubhransu S. Prusty static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) 15372889099eSSubhransu S. Prusty { 15382889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15392889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15402889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15412889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15422889099eSSubhransu S. Prusty 15438f658815SDan Carpenter if (!pin || !pin->eld.eld_valid) 15442889099eSSubhransu S. Prusty return 0; 15452889099eSSubhransu S. Prusty 15462889099eSSubhransu S. Prusty return pin->eld.info.spk_alloc; 15472889099eSSubhransu S. Prusty } 15482889099eSSubhransu S. Prusty 154918382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) 155018382eadSSubhransu S. Prusty { 155118382eadSSubhransu S. Prusty struct hdac_device *codec = &edev->hdac; 155218382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi_priv; 155317a42c45SSubhransu S. Prusty struct snd_soc_dai_driver *hdmi_dais = NULL; 1554b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 155517a42c45SSubhransu S. Prusty int num_dais = 0; 155618382eadSSubhransu S. Prusty int ret = 0; 155718382eadSSubhransu S. Prusty 1558b2047e99SVinod Koul /* hold the ref while we probe */ 1559b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); 1560500e06b9SVinod Koul if (!hlink) { 1561500e06b9SVinod Koul dev_err(&edev->hdac.dev, "hdac link not found\n"); 1562500e06b9SVinod Koul return -EIO; 1563500e06b9SVinod Koul } 1564500e06b9SVinod Koul 1565b2047e99SVinod Koul snd_hdac_ext_bus_link_get(edev->ebus, hlink); 1566b2047e99SVinod Koul 156718382eadSSubhransu S. Prusty hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 156818382eadSSubhransu S. Prusty if (hdmi_priv == NULL) 156918382eadSSubhransu S. Prusty return -ENOMEM; 157018382eadSSubhransu S. Prusty 157118382eadSSubhransu S. Prusty edev->private_data = hdmi_priv; 1572bcced704SSubhransu S. Prusty snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); 15732889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; 15742889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; 15752889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; 15762889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; 157718382eadSSubhransu S. Prusty 157818382eadSSubhransu S. Prusty dev_set_drvdata(&codec->dev, edev); 157918382eadSSubhransu S. Prusty 158015b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->pin_list); 158115b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->cvt_list); 15824a3478deSJeeja KP INIT_LIST_HEAD(&hdmi_priv->pcm_list); 15834a3478deSJeeja KP mutex_init(&hdmi_priv->pin_mutex); 158415b91447SSubhransu S. Prusty 1585aeaccef0SRamesh Babu /* 1586aeaccef0SRamesh Babu * Turned off in the runtime_suspend during the first explicit 1587aeaccef0SRamesh Babu * pm_runtime_suspend call. 1588aeaccef0SRamesh Babu */ 1589aeaccef0SRamesh Babu ret = snd_hdac_display_power(edev->hdac.bus, true); 1590aeaccef0SRamesh Babu if (ret < 0) { 1591aeaccef0SRamesh Babu dev_err(&edev->hdac.dev, 1592aeaccef0SRamesh Babu "Cannot turn on display power on i915 err: %d\n", 1593aeaccef0SRamesh Babu ret); 1594aeaccef0SRamesh Babu return ret; 1595aeaccef0SRamesh Babu } 1596aeaccef0SRamesh Babu 159717a42c45SSubhransu S. Prusty ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); 159817a42c45SSubhransu S. Prusty if (ret < 0) { 159917a42c45SSubhransu S. Prusty dev_err(&codec->dev, 160017a42c45SSubhransu S. Prusty "Failed in parse and map nid with err: %d\n", ret); 160118382eadSSubhransu S. Prusty return ret; 160217a42c45SSubhransu S. Prusty } 160318382eadSSubhransu S. Prusty 160418382eadSSubhransu S. Prusty /* ASoC specific initialization */ 1605b2047e99SVinod Koul ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 160617a42c45SSubhransu S. Prusty hdmi_dais, num_dais); 1607b2047e99SVinod Koul 1608b2047e99SVinod Koul snd_hdac_ext_bus_link_put(edev->ebus, hlink); 1609b2047e99SVinod Koul 1610b2047e99SVinod Koul return ret; 161118382eadSSubhransu S. Prusty } 161218382eadSSubhransu S. Prusty 161318382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) 161418382eadSSubhransu S. Prusty { 161515b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 161615b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin, *pin_next; 161715b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt, *cvt_next; 16184a3478deSJeeja KP struct hdac_hdmi_pcm *pcm, *pcm_next; 161915b91447SSubhransu S. Prusty 162018382eadSSubhransu S. Prusty snd_soc_unregister_codec(&edev->hdac.dev); 162118382eadSSubhransu S. Prusty 16224a3478deSJeeja KP list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { 16234a3478deSJeeja KP pcm->cvt = NULL; 16244a3478deSJeeja KP pcm->pin = NULL; 16254a3478deSJeeja KP list_del(&pcm->head); 16264a3478deSJeeja KP kfree(pcm); 16274a3478deSJeeja KP } 16284a3478deSJeeja KP 162915b91447SSubhransu S. Prusty list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { 163015b91447SSubhransu S. Prusty list_del(&cvt->head); 16314a3478deSJeeja KP kfree(cvt->name); 163215b91447SSubhransu S. Prusty kfree(cvt); 163315b91447SSubhransu S. Prusty } 163415b91447SSubhransu S. Prusty 163515b91447SSubhransu S. Prusty list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { 163615b91447SSubhransu S. Prusty list_del(&pin->head); 163715b91447SSubhransu S. Prusty kfree(pin); 163815b91447SSubhransu S. Prusty } 163915b91447SSubhransu S. Prusty 164018382eadSSubhransu S. Prusty return 0; 164118382eadSSubhransu S. Prusty } 164218382eadSSubhransu S. Prusty 1643e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM 1644e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev) 1645e342ac08SSubhransu S. Prusty { 1646e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1647e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 164807f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 1649b2047e99SVinod Koul struct hdac_ext_bus *ebus = hbus_to_ebus(bus); 1650b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 165107f083abSSubhransu S. Prusty int err; 1652e342ac08SSubhransu S. Prusty 1653e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 1654e342ac08SSubhransu S. Prusty 165507f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 165607f083abSSubhransu S. Prusty if (!bus) 165707f083abSSubhransu S. Prusty return 0; 165807f083abSSubhransu S. Prusty 16591b377ccdSSubhransu S. Prusty /* 16601b377ccdSSubhransu S. Prusty * Power down afg. 16611b377ccdSSubhransu S. Prusty * codec_read is preferred over codec_write to set the power state. 16621b377ccdSSubhransu S. Prusty * This way verb is send to set the power state and response 16631b377ccdSSubhransu S. Prusty * is received. So setting power state is ensured without using loop 16641b377ccdSSubhransu S. Prusty * to read the state. 16651b377ccdSSubhransu S. Prusty */ 16661b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 16671b377ccdSSubhransu S. Prusty AC_PWRST_D3); 166807f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, false); 166907f083abSSubhransu S. Prusty if (err < 0) { 167007f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 167107f083abSSubhransu S. Prusty return err; 167207f083abSSubhransu S. Prusty } 167307f083abSSubhransu S. Prusty 1674b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); 1675500e06b9SVinod Koul if (!hlink) { 1676500e06b9SVinod Koul dev_err(dev, "hdac link not found\n"); 1677500e06b9SVinod Koul return -EIO; 1678500e06b9SVinod Koul } 1679500e06b9SVinod Koul 1680b2047e99SVinod Koul snd_hdac_ext_bus_link_put(ebus, hlink); 1681b2047e99SVinod Koul 1682e342ac08SSubhransu S. Prusty return 0; 1683e342ac08SSubhransu S. Prusty } 1684e342ac08SSubhransu S. Prusty 1685e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev) 1686e342ac08SSubhransu S. Prusty { 1687e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1688e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 168907f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 1690b2047e99SVinod Koul struct hdac_ext_bus *ebus = hbus_to_ebus(bus); 1691b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 169207f083abSSubhransu S. Prusty int err; 1693e342ac08SSubhransu S. Prusty 1694e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 1695e342ac08SSubhransu S. Prusty 169607f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 169707f083abSSubhransu S. Prusty if (!bus) 169807f083abSSubhransu S. Prusty return 0; 169907f083abSSubhransu S. Prusty 1700b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); 1701500e06b9SVinod Koul if (!hlink) { 1702500e06b9SVinod Koul dev_err(dev, "hdac link not found\n"); 1703500e06b9SVinod Koul return -EIO; 1704500e06b9SVinod Koul } 1705500e06b9SVinod Koul 1706b2047e99SVinod Koul snd_hdac_ext_bus_link_get(ebus, hlink); 1707b2047e99SVinod Koul 170807f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, true); 170907f083abSSubhransu S. Prusty if (err < 0) { 171007f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 171107f083abSSubhransu S. Prusty return err; 171207f083abSSubhransu S. Prusty } 171307f083abSSubhransu S. Prusty 1714ab85f5b3SSubhransu S. Prusty hdac_hdmi_skl_enable_all_pins(&edev->hdac); 1715ab85f5b3SSubhransu S. Prusty hdac_hdmi_skl_enable_dp12(&edev->hdac); 1716ab85f5b3SSubhransu S. Prusty 1717e342ac08SSubhransu S. Prusty /* Power up afg */ 17181b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 17191b377ccdSSubhransu S. Prusty AC_PWRST_D0); 1720e342ac08SSubhransu S. Prusty 1721e342ac08SSubhransu S. Prusty return 0; 1722e342ac08SSubhransu S. Prusty } 1723e342ac08SSubhransu S. Prusty #else 1724e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL 1725e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL 1726e342ac08SSubhransu S. Prusty #endif 1727e342ac08SSubhransu S. Prusty 1728e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = { 1729e342ac08SSubhransu S. Prusty SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) 17301b377ccdSSubhransu S. Prusty .prepare = hdmi_codec_prepare, 17310fee1798SSubhransu S. Prusty .complete = hdmi_codec_complete, 1732e342ac08SSubhransu S. Prusty }; 1733e342ac08SSubhransu S. Prusty 173418382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = { 173518382eadSSubhransu S. Prusty HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), 1736e2304803SJeeja KP HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), 1737cc216887SShreyas NC HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), 173818382eadSSubhransu S. Prusty {} 173918382eadSSubhransu S. Prusty }; 174018382eadSSubhransu S. Prusty 174118382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list); 174218382eadSSubhransu S. Prusty 174318382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = { 174418382eadSSubhransu S. Prusty . hdac = { 174518382eadSSubhransu S. Prusty .driver = { 174618382eadSSubhransu S. Prusty .name = "HDMI HDA Codec", 1747e342ac08SSubhransu S. Prusty .pm = &hdac_hdmi_pm, 174818382eadSSubhransu S. Prusty }, 174918382eadSSubhransu S. Prusty .id_table = hdmi_list, 175018382eadSSubhransu S. Prusty }, 175118382eadSSubhransu S. Prusty .probe = hdac_hdmi_dev_probe, 175218382eadSSubhransu S. Prusty .remove = hdac_hdmi_dev_remove, 175318382eadSSubhransu S. Prusty }; 175418382eadSSubhransu S. Prusty 175518382eadSSubhransu S. Prusty static int __init hdmi_init(void) 175618382eadSSubhransu S. Prusty { 175718382eadSSubhransu S. Prusty return snd_hda_ext_driver_register(&hdmi_driver); 175818382eadSSubhransu S. Prusty } 175918382eadSSubhransu S. Prusty 176018382eadSSubhransu S. Prusty static void __exit hdmi_exit(void) 176118382eadSSubhransu S. Prusty { 176218382eadSSubhransu S. Prusty snd_hda_ext_driver_unregister(&hdmi_driver); 176318382eadSSubhransu S. Prusty } 176418382eadSSubhransu S. Prusty 176518382eadSSubhransu S. Prusty module_init(hdmi_init); 176618382eadSSubhransu S. Prusty module_exit(hdmi_exit); 176718382eadSSubhransu S. Prusty 176818382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 176918382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec"); 177018382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); 177118382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); 1772