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; 88bcced704SSubhransu S. Prusty struct mutex lock; 89bcced704SSubhransu S. Prusty bool chmap_set; 90bcced704SSubhransu S. Prusty unsigned char chmap[8]; /* ALSA API channel-map */ 91bcced704SSubhransu S. Prusty int channels; /* current number of channels */ 9218382eadSSubhransu S. Prusty }; 9318382eadSSubhransu S. Prusty 944a3478deSJeeja KP struct hdac_hdmi_pcm { 954a3478deSJeeja KP struct list_head head; 964a3478deSJeeja KP int pcm_id; 974a3478deSJeeja KP struct hdac_hdmi_pin *pin; 984a3478deSJeeja KP struct hdac_hdmi_cvt *cvt; 994a3478deSJeeja KP struct snd_jack *jack; 100*c9bfb5d7SJeeja KP int stream_tag; 101*c9bfb5d7SJeeja KP int channels; 102*c9bfb5d7SJeeja KP int format; 1034a3478deSJeeja KP }; 1044a3478deSJeeja KP 10518382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map { 10618382eadSSubhransu S. Prusty int dai_id; 10715b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 10815b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 10918382eadSSubhransu S. Prusty }; 11018382eadSSubhransu S. Prusty 11118382eadSSubhransu S. Prusty struct hdac_hdmi_priv { 112148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; 11315b91447SSubhransu S. Prusty struct list_head pin_list; 11415b91447SSubhransu S. Prusty struct list_head cvt_list; 1154a3478deSJeeja KP struct list_head pcm_list; 11615b91447SSubhransu S. Prusty int num_pin; 11715b91447SSubhransu S. Prusty int num_cvt; 1184a3478deSJeeja KP struct mutex pin_mutex; 119bcced704SSubhransu S. Prusty struct hdac_chmap chmap; 12018382eadSSubhransu S. Prusty }; 12118382eadSSubhransu S. Prusty 122*c9bfb5d7SJeeja KP static struct hdac_hdmi_pcm * 123*c9bfb5d7SJeeja KP hdac_hdmi_get_pcm_from_cvt(struct hdac_hdmi_priv *hdmi, 124*c9bfb5d7SJeeja KP struct hdac_hdmi_cvt *cvt) 125*c9bfb5d7SJeeja KP { 126*c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 1271de777feSJeeja KP 128*c9bfb5d7SJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 129*c9bfb5d7SJeeja KP if (pcm->cvt == cvt) 130*c9bfb5d7SJeeja KP break; 131*c9bfb5d7SJeeja KP } 132*c9bfb5d7SJeeja KP 133*c9bfb5d7SJeeja KP return pcm; 134*c9bfb5d7SJeeja KP } 1351de777feSJeeja KP 1362889099eSSubhransu S. Prusty static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, 1372889099eSSubhransu S. Prusty int pcm_idx) 1382889099eSSubhransu S. Prusty { 1392889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm; 1402889099eSSubhransu S. Prusty 1412889099eSSubhransu S. Prusty list_for_each_entry(pcm, &hdmi->pcm_list, head) { 1422889099eSSubhransu S. Prusty if (pcm->pcm_id == pcm_idx) 1432889099eSSubhransu S. Prusty return pcm; 1442889099eSSubhransu S. Prusty } 1452889099eSSubhransu S. Prusty 1462889099eSSubhransu S. Prusty return NULL; 1472889099eSSubhransu S. Prusty } 1482889099eSSubhransu S. Prusty 149e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 150e342ac08SSubhransu S. Prusty { 15151b2c425SGeliang Tang struct hdac_device *hdac = dev_to_hdac_dev(dev); 152e342ac08SSubhransu S. Prusty 15351b2c425SGeliang Tang return to_ehdac_device(hdac); 154e342ac08SSubhransu S. Prusty } 155e342ac08SSubhransu S. Prusty 1562428bca3SSubhransu S. Prusty static unsigned int sad_format(const u8 *sad) 1572428bca3SSubhransu S. Prusty { 1582428bca3SSubhransu S. Prusty return ((sad[0] >> 0x3) & 0x1f); 1592428bca3SSubhransu S. Prusty } 1602428bca3SSubhransu S. Prusty 1612428bca3SSubhransu S. Prusty static unsigned int sad_sample_bits_lpcm(const u8 *sad) 1622428bca3SSubhransu S. Prusty { 1632428bca3SSubhransu S. Prusty return (sad[2] & 7); 1642428bca3SSubhransu S. Prusty } 1652428bca3SSubhransu S. Prusty 1662428bca3SSubhransu S. Prusty static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime, 1672428bca3SSubhransu S. Prusty void *eld) 1682428bca3SSubhransu S. Prusty { 1692428bca3SSubhransu S. Prusty u64 formats = SNDRV_PCM_FMTBIT_S16; 1702428bca3SSubhransu S. Prusty int i; 1712428bca3SSubhransu S. Prusty const u8 *sad, *eld_buf = eld; 1722428bca3SSubhransu S. Prusty 1732428bca3SSubhransu S. Prusty sad = drm_eld_sad(eld_buf); 1742428bca3SSubhransu S. Prusty if (!sad) 1752428bca3SSubhransu S. Prusty goto format_constraint; 1762428bca3SSubhransu S. Prusty 1772428bca3SSubhransu S. Prusty for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) { 1782428bca3SSubhransu S. Prusty if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */ 1792428bca3SSubhransu S. Prusty 1802428bca3SSubhransu S. Prusty /* 1812428bca3SSubhransu S. Prusty * the controller support 20 and 24 bits in 32 bit 1822428bca3SSubhransu S. Prusty * container so we set S32 1832428bca3SSubhransu S. Prusty */ 1842428bca3SSubhransu S. Prusty if (sad_sample_bits_lpcm(sad) & 0x6) 1852428bca3SSubhransu S. Prusty formats |= SNDRV_PCM_FMTBIT_S32; 1862428bca3SSubhransu S. Prusty } 1872428bca3SSubhransu S. Prusty } 1882428bca3SSubhransu S. Prusty 1892428bca3SSubhransu S. Prusty format_constraint: 1902428bca3SSubhransu S. Prusty return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, 1912428bca3SSubhransu S. Prusty formats); 1922428bca3SSubhransu S. Prusty 1932428bca3SSubhransu S. Prusty } 1942428bca3SSubhransu S. Prusty 195a657f1d0SSubhransu S. Prusty static void 196a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, 197a657f1d0SSubhransu S. Prusty int packet_index, int byte_index) 198a657f1d0SSubhransu S. Prusty { 199a657f1d0SSubhransu S. Prusty int val; 200a657f1d0SSubhransu S. Prusty 201a657f1d0SSubhransu S. Prusty val = (packet_index << 5) | (byte_index & 0x1f); 202a657f1d0SSubhransu S. Prusty 203a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 204a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_INDEX, val); 205a657f1d0SSubhransu S. Prusty } 206a657f1d0SSubhransu S. Prusty 207478f544eSSubhransu S. Prusty struct dp_audio_infoframe { 208478f544eSSubhransu S. Prusty u8 type; /* 0x84 */ 209478f544eSSubhransu S. Prusty u8 len; /* 0x1b */ 210478f544eSSubhransu S. Prusty u8 ver; /* 0x11 << 2 */ 211478f544eSSubhransu S. Prusty 212478f544eSSubhransu S. Prusty u8 CC02_CT47; /* match with HDMI infoframe from this on */ 213478f544eSSubhransu S. Prusty u8 SS01_SF24; 214478f544eSSubhransu S. Prusty u8 CXT04; 215478f544eSSubhransu S. Prusty u8 CA; 216478f544eSSubhransu S. Prusty u8 LFEPBL01_LSV36_DM_INH7; 217478f544eSSubhransu S. Prusty }; 218478f544eSSubhransu S. Prusty 219a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, 220a657f1d0SSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid) 221a657f1d0SSubhransu S. Prusty { 222a657f1d0SSubhransu S. Prusty uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; 223a657f1d0SSubhransu S. Prusty struct hdmi_audio_infoframe frame; 224478f544eSSubhransu S. Prusty struct dp_audio_infoframe dp_ai; 225478f544eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 226478f544eSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 227478f544eSSubhransu S. Prusty u8 *dip; 228a657f1d0SSubhransu S. Prusty int ret; 229a657f1d0SSubhransu S. Prusty int i; 230478f544eSSubhransu S. Prusty const u8 *eld_buf; 231478f544eSSubhransu S. Prusty u8 conn_type; 232bcced704SSubhransu S. Prusty int channels, ca; 233a657f1d0SSubhransu S. Prusty 234478f544eSSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 235478f544eSSubhransu S. Prusty if (pin->nid == pin_nid) 236478f544eSSubhransu S. Prusty break; 237478f544eSSubhransu S. Prusty } 238a657f1d0SSubhransu S. Prusty 239bcced704SSubhransu S. Prusty ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, 240bcced704SSubhransu S. Prusty pin->channels, pin->chmap_set, true, pin->chmap); 241bcced704SSubhransu S. Prusty 242bcced704SSubhransu S. Prusty channels = snd_hdac_get_active_channels(ca); 243bcced704SSubhransu S. Prusty hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); 244bcced704SSubhransu S. Prusty 245bcced704SSubhransu S. Prusty snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, 246bcced704SSubhransu S. Prusty pin->channels, pin->chmap, pin->chmap_set); 247bcced704SSubhransu S. Prusty 248478f544eSSubhransu S. Prusty eld_buf = pin->eld.eld_buffer; 249478f544eSSubhransu S. Prusty conn_type = drm_eld_get_conn_type(eld_buf); 250a657f1d0SSubhransu S. Prusty 251478f544eSSubhransu S. Prusty switch (conn_type) { 252478f544eSSubhransu S. Prusty case DRM_ELD_CONN_TYPE_HDMI: 253478f544eSSubhransu S. Prusty hdmi_audio_infoframe_init(&frame); 254478f544eSSubhransu S. Prusty 255478f544eSSubhransu S. Prusty frame.channels = channels; 256bcced704SSubhransu S. Prusty frame.channel_allocation = ca; 257a657f1d0SSubhransu S. Prusty 258a657f1d0SSubhransu S. Prusty ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); 259a657f1d0SSubhransu S. Prusty if (ret < 0) 260a657f1d0SSubhransu S. Prusty return ret; 261a657f1d0SSubhransu S. Prusty 262478f544eSSubhransu S. Prusty break; 263478f544eSSubhransu S. Prusty 264478f544eSSubhransu S. Prusty case DRM_ELD_CONN_TYPE_DP: 265478f544eSSubhransu S. Prusty memset(&dp_ai, 0, sizeof(dp_ai)); 266478f544eSSubhransu S. Prusty dp_ai.type = 0x84; 267478f544eSSubhransu S. Prusty dp_ai.len = 0x1b; 268478f544eSSubhransu S. Prusty dp_ai.ver = 0x11 << 2; 269478f544eSSubhransu S. Prusty dp_ai.CC02_CT47 = channels - 1; 270bcced704SSubhransu S. Prusty dp_ai.CA = ca; 271478f544eSSubhransu S. Prusty 272478f544eSSubhransu S. Prusty dip = (u8 *)&dp_ai; 273478f544eSSubhransu S. Prusty break; 274478f544eSSubhransu S. Prusty 275478f544eSSubhransu S. Prusty default: 276478f544eSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n", 277478f544eSSubhransu S. Prusty conn_type); 278478f544eSSubhransu S. Prusty return -EIO; 279478f544eSSubhransu S. Prusty } 280478f544eSSubhransu S. Prusty 281a657f1d0SSubhransu S. Prusty /* stop infoframe transmission */ 282a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 283a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 284a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); 285a657f1d0SSubhransu S. Prusty 286a657f1d0SSubhransu S. Prusty 287a657f1d0SSubhransu S. Prusty /* Fill infoframe. Index auto-incremented */ 288a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 289478f544eSSubhransu S. Prusty if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { 290391005e8SSubhransu S. Prusty for (i = 0; i < sizeof(buffer); i++) 291a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 292391005e8SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); 293478f544eSSubhransu S. Prusty } else { 294478f544eSSubhransu S. Prusty for (i = 0; i < sizeof(dp_ai); i++) 295478f544eSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 296478f544eSSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, dip[i]); 297478f544eSSubhransu S. Prusty } 298a657f1d0SSubhransu S. Prusty 299a657f1d0SSubhransu S. Prusty /* Start infoframe */ 300a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 301a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 302a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); 303a657f1d0SSubhransu S. Prusty 304a657f1d0SSubhransu S. Prusty return 0; 305a657f1d0SSubhransu S. Prusty } 306a657f1d0SSubhransu S. Prusty 307*c9bfb5d7SJeeja KP static int hdac_hdmi_set_tdm_slot(struct snd_soc_dai *dai, 308*c9bfb5d7SJeeja KP unsigned int tx_mask, unsigned int rx_mask, 309*c9bfb5d7SJeeja KP int slots, int slot_width) 310b0362adbSSubhransu S. Prusty { 311*c9bfb5d7SJeeja KP struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); 312*c9bfb5d7SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 313b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 314*c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 315*c9bfb5d7SJeeja KP 316*c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: strm_tag: %d\n", __func__, tx_mask); 317b0362adbSSubhransu S. Prusty 318b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 319b0362adbSSubhransu S. Prusty 320*c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); 321b0362adbSSubhransu S. Prusty 322*c9bfb5d7SJeeja KP if (pcm) 323*c9bfb5d7SJeeja KP pcm->stream_tag = (tx_mask << 4); 324bcced704SSubhransu S. Prusty 325*c9bfb5d7SJeeja KP return 0; 326b0362adbSSubhransu S. Prusty } 327b0362adbSSubhransu S. Prusty 328b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, 329b0362adbSSubhransu S. Prusty struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) 330b0362adbSSubhransu S. Prusty { 331b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 33254dfa1eaSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 33354dfa1eaSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 33454dfa1eaSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 335*c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 336*c9bfb5d7SJeeja KP int format; 337b0362adbSSubhransu S. Prusty 33854dfa1eaSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 33954dfa1eaSSubhransu S. Prusty pin = dai_map->pin; 34054dfa1eaSSubhransu S. Prusty 34154dfa1eaSSubhransu S. Prusty if (!pin) 34254dfa1eaSSubhransu S. Prusty return -ENODEV; 34354dfa1eaSSubhransu S. Prusty 34454dfa1eaSSubhransu S. Prusty if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { 34554dfa1eaSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", 34654dfa1eaSSubhransu S. Prusty pin->nid); 347b0362adbSSubhransu S. Prusty return -ENODEV; 348b0362adbSSubhransu S. Prusty } 349b0362adbSSubhransu S. Prusty 350*c9bfb5d7SJeeja KP format = snd_hdac_calc_stream_format(params_rate(hparams), 351b0362adbSSubhransu S. Prusty params_channels(hparams), params_format(hparams), 352b0362adbSSubhransu S. Prusty 24, 0); 353b0362adbSSubhransu S. Prusty 354*c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, dai_map->cvt); 355*c9bfb5d7SJeeja KP if (!pcm) 356148569fdSSubhransu S. Prusty return -EIO; 357148569fdSSubhransu S. Prusty 358*c9bfb5d7SJeeja KP pcm->format = format; 359*c9bfb5d7SJeeja KP pcm->channels = params_channels(hparams); 360148569fdSSubhransu S. Prusty 361148569fdSSubhransu S. Prusty return 0; 362148569fdSSubhransu S. Prusty } 363148569fdSSubhransu S. Prusty 364148569fdSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, 365148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 366148569fdSSubhransu S. Prusty { 367148569fdSSubhransu S. Prusty if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { 368148569fdSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 369148569fdSSubhransu S. Prusty "HDMI: pin %d wcaps %#x does not support connection list\n", 370148569fdSSubhransu S. Prusty pin->nid, get_wcaps(&hdac->hdac, pin->nid)); 371148569fdSSubhransu S. Prusty return -EINVAL; 372148569fdSSubhransu S. Prusty } 373148569fdSSubhransu S. Prusty 374148569fdSSubhransu S. Prusty pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, 375148569fdSSubhransu S. Prusty pin->mux_nids, HDA_MAX_CONNECTIONS); 376148569fdSSubhransu S. Prusty if (pin->num_mux_nids == 0) 377148569fdSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", 378148569fdSSubhransu S. Prusty pin->nid); 379148569fdSSubhransu S. Prusty 380148569fdSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", 381148569fdSSubhransu S. Prusty pin->num_mux_nids, pin->nid); 382148569fdSSubhransu S. Prusty 383148569fdSSubhransu S. Prusty return pin->num_mux_nids; 384148569fdSSubhransu S. Prusty } 385148569fdSSubhransu S. Prusty 386148569fdSSubhransu S. Prusty /* 387148569fdSSubhransu S. Prusty * Query pcm list and return pin widget to which stream is routed. 388148569fdSSubhransu S. Prusty * 389148569fdSSubhransu S. Prusty * Also query connection list of the pin, to validate the cvt to pin map. 390148569fdSSubhransu S. Prusty * 391148569fdSSubhransu S. Prusty * Same stream rendering to multiple pins simultaneously can be done 392148569fdSSubhransu S. Prusty * possibly, but not supported for now in driver. So return the first pin 393148569fdSSubhransu S. Prusty * connected. 394148569fdSSubhransu S. Prusty */ 395148569fdSSubhransu S. Prusty static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( 396148569fdSSubhransu S. Prusty struct hdac_ext_device *edev, 397148569fdSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi, 398148569fdSSubhransu S. Prusty struct hdac_hdmi_cvt *cvt) 399148569fdSSubhransu S. Prusty { 400148569fdSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm; 401148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin = NULL; 402148569fdSSubhransu S. Prusty int ret, i; 403148569fdSSubhransu S. Prusty 404148569fdSSubhransu S. Prusty list_for_each_entry(pcm, &hdmi->pcm_list, head) { 405148569fdSSubhransu S. Prusty if (pcm->cvt == cvt) { 406148569fdSSubhransu S. Prusty pin = pcm->pin; 407148569fdSSubhransu S. Prusty break; 408148569fdSSubhransu S. Prusty } 409148569fdSSubhransu S. Prusty } 410148569fdSSubhransu S. Prusty 411148569fdSSubhransu S. Prusty if (pin) { 412148569fdSSubhransu S. Prusty ret = hdac_hdmi_query_pin_connlist(edev, pin); 413148569fdSSubhransu S. Prusty if (ret < 0) 414148569fdSSubhransu S. Prusty return NULL; 415148569fdSSubhransu S. Prusty 416148569fdSSubhransu S. Prusty for (i = 0; i < pin->num_mux_nids; i++) { 417148569fdSSubhransu S. Prusty if (pin->mux_nids[i] == cvt->nid) 418148569fdSSubhransu S. Prusty return pin; 419148569fdSSubhransu S. Prusty } 420148569fdSSubhransu S. Prusty } 421148569fdSSubhransu S. Prusty 422148569fdSSubhransu S. Prusty return NULL; 423148569fdSSubhransu S. Prusty } 424148569fdSSubhransu S. Prusty 42554dfa1eaSSubhransu S. Prusty /* 42654dfa1eaSSubhransu S. Prusty * This tries to get a valid pin and set the HW constraints based on the 42754dfa1eaSSubhransu S. Prusty * ELD. Even if a valid pin is not found return success so that device open 42854dfa1eaSSubhransu S. Prusty * doesn't fail. 42954dfa1eaSSubhransu S. Prusty */ 430b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, 431b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 432b0362adbSSubhransu S. Prusty { 433b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 434b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 435b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 436148569fdSSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 437148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 4382428bca3SSubhransu S. Prusty int ret; 439b0362adbSSubhransu S. Prusty 440b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 441b0362adbSSubhransu S. Prusty 442148569fdSSubhransu S. Prusty cvt = dai_map->cvt; 443148569fdSSubhransu S. Prusty pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); 44454dfa1eaSSubhransu S. Prusty 44554dfa1eaSSubhransu S. Prusty /* 44654dfa1eaSSubhransu S. Prusty * To make PA and other userland happy. 44754dfa1eaSSubhransu S. Prusty * userland scans devices so returning error does not help. 44854dfa1eaSSubhransu S. Prusty */ 449148569fdSSubhransu S. Prusty if (!pin) 45054dfa1eaSSubhransu S. Prusty return 0; 451148569fdSSubhransu S. Prusty 452148569fdSSubhransu S. Prusty if ((!pin->eld.monitor_present) || 453148569fdSSubhransu S. Prusty (!pin->eld.eld_valid)) { 454b0362adbSSubhransu S. Prusty 45554dfa1eaSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 4563fb7b4e4SColin Ian King "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", 457148569fdSSubhransu S. Prusty pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); 458b8a54545SSubhransu S. Prusty 45954dfa1eaSSubhransu S. Prusty return 0; 460b0362adbSSubhransu S. Prusty } 461b0362adbSSubhransu S. Prusty 462148569fdSSubhransu S. Prusty dai_map->pin = pin; 463b0362adbSSubhransu S. Prusty 4642428bca3SSubhransu S. Prusty ret = hdac_hdmi_eld_limit_formats(substream->runtime, 465148569fdSSubhransu S. Prusty pin->eld.eld_buffer); 4662428bca3SSubhransu S. Prusty if (ret < 0) 4672428bca3SSubhransu S. Prusty return ret; 468b0362adbSSubhransu S. Prusty 4692428bca3SSubhransu S. Prusty return snd_pcm_hw_constraint_eld(substream->runtime, 470148569fdSSubhransu S. Prusty pin->eld.eld_buffer); 471b0362adbSSubhransu S. Prusty } 472b0362adbSSubhransu S. Prusty 473b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, 474b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 475b0362adbSSubhransu S. Prusty { 476b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 477b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 478b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 479b0362adbSSubhransu S. Prusty 480b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 481b0362adbSSubhransu S. Prusty 48254dfa1eaSSubhransu S. Prusty if (dai_map->pin) { 483bcced704SSubhransu S. Prusty mutex_lock(&dai_map->pin->lock); 4842889099eSSubhransu S. Prusty dai_map->pin->chmap_set = false; 4852889099eSSubhransu S. Prusty memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); 486bcced704SSubhransu S. Prusty dai_map->pin->channels = 0; 487bcced704SSubhransu S. Prusty mutex_unlock(&dai_map->pin->lock); 488bcced704SSubhransu S. Prusty 489148569fdSSubhransu S. Prusty dai_map->pin = NULL; 490b0362adbSSubhransu S. Prusty } 49154dfa1eaSSubhransu S. Prusty } 492b0362adbSSubhransu S. Prusty 49318382eadSSubhransu S. Prusty static int 49418382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 49518382eadSSubhransu S. Prusty { 496bcced704SSubhransu S. Prusty unsigned int chans; 497bcced704SSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 498bcced704SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 49918382eadSSubhransu S. Prusty int err; 50018382eadSSubhransu S. Prusty 501bcced704SSubhransu S. Prusty chans = get_wcaps(hdac, cvt->nid); 502bcced704SSubhransu S. Prusty chans = get_wcaps_channels(chans); 503bcced704SSubhransu S. Prusty 504bcced704SSubhransu S. Prusty cvt->params.channels_min = 2; 505bcced704SSubhransu S. Prusty 506bcced704SSubhransu S. Prusty cvt->params.channels_max = chans; 507bcced704SSubhransu S. Prusty if (chans > hdmi->chmap.channels_max) 508bcced704SSubhransu S. Prusty hdmi->chmap.channels_max = chans; 50918382eadSSubhransu S. Prusty 51018382eadSSubhransu S. Prusty err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 51118382eadSSubhransu S. Prusty &cvt->params.rates, 51218382eadSSubhransu S. Prusty &cvt->params.formats, 51318382eadSSubhransu S. Prusty &cvt->params.maxbps); 51418382eadSSubhransu S. Prusty if (err < 0) 51518382eadSSubhransu S. Prusty dev_err(&hdac->dev, 51618382eadSSubhransu S. Prusty "Failed to query pcm params for nid %d: %d\n", 51718382eadSSubhransu S. Prusty cvt->nid, err); 51818382eadSSubhransu S. Prusty 51918382eadSSubhransu S. Prusty return err; 52018382eadSSubhransu S. Prusty } 52118382eadSSubhransu S. Prusty 52279f4e922SSubhransu S. Prusty static int hdac_hdmi_fill_widget_info(struct device *dev, 523*c9bfb5d7SJeeja KP struct snd_soc_dapm_widget *w, enum snd_soc_dapm_type id, 524*c9bfb5d7SJeeja KP void *priv, const char *wname, const char *stream, 525*c9bfb5d7SJeeja KP struct snd_kcontrol_new *wc, int numkc, 526*c9bfb5d7SJeeja KP int (*event)(struct snd_soc_dapm_widget *, 527*c9bfb5d7SJeeja KP struct snd_kcontrol *, int), unsigned short event_flags) 52818382eadSSubhransu S. Prusty { 52918382eadSSubhransu S. Prusty w->id = id; 53079f4e922SSubhransu S. Prusty w->name = devm_kstrdup(dev, wname, GFP_KERNEL); 53179f4e922SSubhransu S. Prusty if (!w->name) 53279f4e922SSubhransu S. Prusty return -ENOMEM; 53379f4e922SSubhransu S. Prusty 53418382eadSSubhransu S. Prusty w->sname = stream; 53518382eadSSubhransu S. Prusty w->reg = SND_SOC_NOPM; 53618382eadSSubhransu S. Prusty w->shift = 0; 53779f4e922SSubhransu S. Prusty w->kcontrol_news = wc; 53879f4e922SSubhransu S. Prusty w->num_kcontrols = numkc; 53979f4e922SSubhransu S. Prusty w->priv = priv; 540*c9bfb5d7SJeeja KP w->event = event; 541*c9bfb5d7SJeeja KP w->event_flags = event_flags; 54279f4e922SSubhransu S. Prusty 54379f4e922SSubhransu S. Prusty return 0; 54418382eadSSubhransu S. Prusty } 54518382eadSSubhransu S. Prusty 54618382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 54779f4e922SSubhransu S. Prusty const char *sink, const char *control, const char *src, 54879f4e922SSubhransu S. Prusty int (*handler)(struct snd_soc_dapm_widget *src, 54979f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *sink)) 55018382eadSSubhransu S. Prusty { 55118382eadSSubhransu S. Prusty route->sink = sink; 55218382eadSSubhransu S. Prusty route->source = src; 55318382eadSSubhransu S. Prusty route->control = control; 55479f4e922SSubhransu S. Prusty route->connected = handler; 55518382eadSSubhransu S. Prusty } 55618382eadSSubhransu S. Prusty 5574a3478deSJeeja KP static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, 5584a3478deSJeeja KP struct hdac_hdmi_pin *pin) 5594a3478deSJeeja KP { 5604a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 5614a3478deSJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 5624a3478deSJeeja KP 5634a3478deSJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 5644a3478deSJeeja KP if (pcm->pin == pin) 5654a3478deSJeeja KP return pcm; 5664a3478deSJeeja KP } 5674a3478deSJeeja KP 5684a3478deSJeeja KP return NULL; 5694a3478deSJeeja KP } 5704a3478deSJeeja KP 571*c9bfb5d7SJeeja KP static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, 572*c9bfb5d7SJeeja KP hda_nid_t nid, unsigned int pwr_state) 573*c9bfb5d7SJeeja KP { 574*c9bfb5d7SJeeja KP if (get_wcaps(&edev->hdac, nid) & AC_WCAP_POWER) { 575*c9bfb5d7SJeeja KP if (!snd_hdac_check_power_state(&edev->hdac, nid, pwr_state)) 576*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, nid, 0, 577*c9bfb5d7SJeeja KP AC_VERB_SET_POWER_STATE, pwr_state); 578*c9bfb5d7SJeeja KP } 579*c9bfb5d7SJeeja KP } 580*c9bfb5d7SJeeja KP 581*c9bfb5d7SJeeja KP static void hdac_hdmi_set_amp(struct hdac_ext_device *edev, 582*c9bfb5d7SJeeja KP hda_nid_t nid, int val) 583*c9bfb5d7SJeeja KP { 584*c9bfb5d7SJeeja KP if (get_wcaps(&edev->hdac, nid) & AC_WCAP_OUT_AMP) 585*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, nid, 0, 586*c9bfb5d7SJeeja KP AC_VERB_SET_AMP_GAIN_MUTE, val); 587*c9bfb5d7SJeeja KP } 588*c9bfb5d7SJeeja KP 589*c9bfb5d7SJeeja KP 590*c9bfb5d7SJeeja KP static int hdac_hdmi_pin_output_widget_event(struct snd_soc_dapm_widget *w, 591*c9bfb5d7SJeeja KP struct snd_kcontrol *kc, int event) 592*c9bfb5d7SJeeja KP { 593*c9bfb5d7SJeeja KP struct hdac_hdmi_pin *pin = w->priv; 594*c9bfb5d7SJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); 595*c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 596*c9bfb5d7SJeeja KP 597*c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", 598*c9bfb5d7SJeeja KP __func__, w->name, event); 599*c9bfb5d7SJeeja KP 600*c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm(edev, pin); 601*c9bfb5d7SJeeja KP if (!pcm) 602*c9bfb5d7SJeeja KP return -EIO; 603*c9bfb5d7SJeeja KP 604*c9bfb5d7SJeeja KP switch (event) { 605*c9bfb5d7SJeeja KP case SND_SOC_DAPM_PRE_PMU: 606*c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D0); 607*c9bfb5d7SJeeja KP 608*c9bfb5d7SJeeja KP /* Enable out path for this pin widget */ 609*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 610*c9bfb5d7SJeeja KP AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 611*c9bfb5d7SJeeja KP 612*c9bfb5d7SJeeja KP hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_UNMUTE); 613*c9bfb5d7SJeeja KP 614*c9bfb5d7SJeeja KP return hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, 615*c9bfb5d7SJeeja KP pin->nid); 616*c9bfb5d7SJeeja KP 617*c9bfb5d7SJeeja KP case SND_SOC_DAPM_POST_PMD: 618*c9bfb5d7SJeeja KP hdac_hdmi_set_amp(edev, pin->nid, AMP_OUT_MUTE); 619*c9bfb5d7SJeeja KP 620*c9bfb5d7SJeeja KP /* Disable out path for this pin widget */ 621*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 622*c9bfb5d7SJeeja KP AC_VERB_SET_PIN_WIDGET_CONTROL, 0); 623*c9bfb5d7SJeeja KP 624*c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, pin->nid, AC_PWRST_D3); 625*c9bfb5d7SJeeja KP break; 626*c9bfb5d7SJeeja KP 627*c9bfb5d7SJeeja KP } 628*c9bfb5d7SJeeja KP 629*c9bfb5d7SJeeja KP return 0; 630*c9bfb5d7SJeeja KP } 631*c9bfb5d7SJeeja KP 632*c9bfb5d7SJeeja KP static int hdac_hdmi_cvt_output_widget_event(struct snd_soc_dapm_widget *w, 633*c9bfb5d7SJeeja KP struct snd_kcontrol *kc, int event) 634*c9bfb5d7SJeeja KP { 635*c9bfb5d7SJeeja KP struct hdac_hdmi_cvt *cvt = w->priv; 636*c9bfb5d7SJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); 637*c9bfb5d7SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 638*c9bfb5d7SJeeja KP struct hdac_hdmi_pcm *pcm; 639*c9bfb5d7SJeeja KP 640*c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", 641*c9bfb5d7SJeeja KP __func__, w->name, event); 642*c9bfb5d7SJeeja KP 643*c9bfb5d7SJeeja KP pcm = hdac_hdmi_get_pcm_from_cvt(hdmi, cvt); 644*c9bfb5d7SJeeja KP if (!pcm) 645*c9bfb5d7SJeeja KP return -EIO; 646*c9bfb5d7SJeeja KP 647*c9bfb5d7SJeeja KP switch (event) { 648*c9bfb5d7SJeeja KP case SND_SOC_DAPM_PRE_PMU: 649*c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D0); 650*c9bfb5d7SJeeja KP 651*c9bfb5d7SJeeja KP /* Enable transmission */ 652*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 653*c9bfb5d7SJeeja KP AC_VERB_SET_DIGI_CONVERT_1, 1); 654*c9bfb5d7SJeeja KP 655*c9bfb5d7SJeeja KP /* Category Code (CC) to zero */ 656*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 657*c9bfb5d7SJeeja KP AC_VERB_SET_DIGI_CONVERT_2, 0); 658*c9bfb5d7SJeeja KP 659*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 660*c9bfb5d7SJeeja KP AC_VERB_SET_CHANNEL_STREAMID, pcm->stream_tag); 661*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 662*c9bfb5d7SJeeja KP AC_VERB_SET_STREAM_FORMAT, pcm->format); 663*c9bfb5d7SJeeja KP break; 664*c9bfb5d7SJeeja KP 665*c9bfb5d7SJeeja KP case SND_SOC_DAPM_POST_PMD: 666*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 667*c9bfb5d7SJeeja KP AC_VERB_SET_CHANNEL_STREAMID, 0); 668*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 669*c9bfb5d7SJeeja KP AC_VERB_SET_STREAM_FORMAT, 0); 670*c9bfb5d7SJeeja KP 671*c9bfb5d7SJeeja KP hdac_hdmi_set_power_state(edev, cvt->nid, AC_PWRST_D3); 672*c9bfb5d7SJeeja KP break; 673*c9bfb5d7SJeeja KP 674*c9bfb5d7SJeeja KP } 675*c9bfb5d7SJeeja KP 676*c9bfb5d7SJeeja KP return 0; 677*c9bfb5d7SJeeja KP } 678*c9bfb5d7SJeeja KP 679*c9bfb5d7SJeeja KP static int hdac_hdmi_pin_mux_widget_event(struct snd_soc_dapm_widget *w, 680*c9bfb5d7SJeeja KP struct snd_kcontrol *kc, int event) 681*c9bfb5d7SJeeja KP { 682*c9bfb5d7SJeeja KP struct hdac_hdmi_pin *pin = w->priv; 683*c9bfb5d7SJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(w->dapm->dev); 684*c9bfb5d7SJeeja KP int mux_idx; 685*c9bfb5d7SJeeja KP 686*c9bfb5d7SJeeja KP dev_dbg(&edev->hdac.dev, "%s: widget: %s event: %x\n", 687*c9bfb5d7SJeeja KP __func__, w->name, event); 688*c9bfb5d7SJeeja KP 689*c9bfb5d7SJeeja KP if (!kc) 690*c9bfb5d7SJeeja KP kc = w->kcontrols[0]; 691*c9bfb5d7SJeeja KP 692*c9bfb5d7SJeeja KP mux_idx = dapm_kcontrol_get_value(kc); 693*c9bfb5d7SJeeja KP if (mux_idx > 0) { 694*c9bfb5d7SJeeja KP snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 695*c9bfb5d7SJeeja KP AC_VERB_SET_CONNECT_SEL, (mux_idx - 1)); 696*c9bfb5d7SJeeja KP } 697*c9bfb5d7SJeeja KP 698*c9bfb5d7SJeeja KP return 0; 699*c9bfb5d7SJeeja KP } 700*c9bfb5d7SJeeja KP 7014a3478deSJeeja KP /* 7024a3478deSJeeja KP * Based on user selection, map the PINs with the PCMs. 7034a3478deSJeeja KP */ 7044a3478deSJeeja KP static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, 7054a3478deSJeeja KP struct snd_ctl_elem_value *ucontrol) 7064a3478deSJeeja KP { 7074a3478deSJeeja KP int ret; 7084a3478deSJeeja KP struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 7094a3478deSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 7104a3478deSJeeja KP struct snd_soc_dapm_context *dapm = w->dapm; 7114a3478deSJeeja KP struct hdac_hdmi_pin *pin = w->priv; 7124a3478deSJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 7134a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 7144a3478deSJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 7154a3478deSJeeja KP const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; 7164a3478deSJeeja KP 7174a3478deSJeeja KP ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); 7184a3478deSJeeja KP if (ret < 0) 7194a3478deSJeeja KP return ret; 7204a3478deSJeeja KP 7214a3478deSJeeja KP mutex_lock(&hdmi->pin_mutex); 7224a3478deSJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 7234a3478deSJeeja KP if (pcm->pin == pin) 7244a3478deSJeeja KP pcm->pin = NULL; 7254a3478deSJeeja KP 7264a3478deSJeeja KP /* 7274a3478deSJeeja KP * Jack status is not reported during device probe as the 7284a3478deSJeeja KP * PCMs are not registered by then. So report it here. 7294a3478deSJeeja KP */ 7304a3478deSJeeja KP if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { 7314a3478deSJeeja KP pcm->pin = pin; 7324a3478deSJeeja KP if (pin->eld.monitor_present && pin->eld.eld_valid) { 7334a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 7344a3478deSJeeja KP "jack report for pcm=%d\n", 7354a3478deSJeeja KP pcm->pcm_id); 7364a3478deSJeeja KP 7374a3478deSJeeja KP snd_jack_report(pcm->jack, SND_JACK_AVOUT); 7384a3478deSJeeja KP } 7394a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 7404a3478deSJeeja KP return ret; 7414a3478deSJeeja KP } 7424a3478deSJeeja KP } 7434a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 7444a3478deSJeeja KP 7454a3478deSJeeja KP return ret; 7464a3478deSJeeja KP } 7474a3478deSJeeja KP 74879f4e922SSubhransu S. Prusty /* 74979f4e922SSubhransu S. Prusty * Ideally the Mux inputs should be based on the num_muxs enumerated, but 75079f4e922SSubhransu S. Prusty * the display driver seem to be programming the connection list for the pin 75179f4e922SSubhransu S. Prusty * widget runtime. 75279f4e922SSubhransu S. Prusty * 75379f4e922SSubhransu S. Prusty * So programming all the possible inputs for the mux, the user has to take 75479f4e922SSubhransu S. Prusty * care of selecting the right one and leaving all other inputs selected to 75579f4e922SSubhransu S. Prusty * "NONE" 75679f4e922SSubhransu S. Prusty */ 75779f4e922SSubhransu S. Prusty static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, 75879f4e922SSubhransu S. Prusty struct hdac_hdmi_pin *pin, 75979f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widget, 76079f4e922SSubhransu S. Prusty const char *widget_name) 76118382eadSSubhransu S. Prusty { 76279f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 76379f4e922SSubhransu S. Prusty struct snd_kcontrol_new *kc; 76479f4e922SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 76579f4e922SSubhransu S. Prusty struct soc_enum *se; 76679f4e922SSubhransu S. Prusty char kc_name[NAME_SIZE]; 76779f4e922SSubhransu S. Prusty char mux_items[NAME_SIZE]; 76879f4e922SSubhransu S. Prusty /* To hold inputs to the Pin mux */ 76979f4e922SSubhransu S. Prusty char *items[HDA_MAX_CONNECTIONS]; 77079f4e922SSubhransu S. Prusty int i = 0; 77179f4e922SSubhransu S. Prusty int num_items = hdmi->num_cvt + 1; 77218382eadSSubhransu S. Prusty 77379f4e922SSubhransu S. Prusty kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL); 77479f4e922SSubhransu S. Prusty if (!kc) 77579f4e922SSubhransu S. Prusty return -ENOMEM; 77618382eadSSubhransu S. Prusty 77779f4e922SSubhransu S. Prusty se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL); 77879f4e922SSubhransu S. Prusty if (!se) 77979f4e922SSubhransu S. Prusty return -ENOMEM; 78018382eadSSubhransu S. Prusty 78179f4e922SSubhransu S. Prusty sprintf(kc_name, "Pin %d Input", pin->nid); 78279f4e922SSubhransu S. Prusty kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); 78379f4e922SSubhransu S. Prusty if (!kc->name) 78479f4e922SSubhransu S. Prusty return -ENOMEM; 78518382eadSSubhransu S. Prusty 78679f4e922SSubhransu S. Prusty kc->private_value = (long)se; 78779f4e922SSubhransu S. Prusty kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 78879f4e922SSubhransu S. Prusty kc->access = 0; 78979f4e922SSubhransu S. Prusty kc->info = snd_soc_info_enum_double; 7904a3478deSJeeja KP kc->put = hdac_hdmi_set_pin_mux; 79179f4e922SSubhransu S. Prusty kc->get = snd_soc_dapm_get_enum_double; 79279f4e922SSubhransu S. Prusty 79379f4e922SSubhransu S. Prusty se->reg = SND_SOC_NOPM; 79479f4e922SSubhransu S. Prusty 79579f4e922SSubhransu S. Prusty /* enum texts: ["NONE", "cvt #", "cvt #", ...] */ 79679f4e922SSubhransu S. Prusty se->items = num_items; 79779f4e922SSubhransu S. Prusty se->mask = roundup_pow_of_two(se->items) - 1; 79879f4e922SSubhransu S. Prusty 79979f4e922SSubhransu S. Prusty sprintf(mux_items, "NONE"); 80079f4e922SSubhransu S. Prusty items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); 80179f4e922SSubhransu S. Prusty if (!items[i]) 80279f4e922SSubhransu S. Prusty return -ENOMEM; 80379f4e922SSubhransu S. Prusty 80479f4e922SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 80579f4e922SSubhransu S. Prusty i++; 80679f4e922SSubhransu S. Prusty sprintf(mux_items, "cvt %d", cvt->nid); 80779f4e922SSubhransu S. Prusty items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); 80879f4e922SSubhransu S. Prusty if (!items[i]) 80979f4e922SSubhransu S. Prusty return -ENOMEM; 81079f4e922SSubhransu S. Prusty } 81179f4e922SSubhransu S. Prusty 81279f4e922SSubhransu S. Prusty se->texts = devm_kmemdup(&edev->hdac.dev, items, 81379f4e922SSubhransu S. Prusty (num_items * sizeof(char *)), GFP_KERNEL); 81479f4e922SSubhransu S. Prusty if (!se->texts) 81579f4e922SSubhransu S. Prusty return -ENOMEM; 81679f4e922SSubhransu S. Prusty 81779f4e922SSubhransu S. Prusty return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, 818*c9bfb5d7SJeeja KP snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1, 819*c9bfb5d7SJeeja KP hdac_hdmi_pin_mux_widget_event, 820*c9bfb5d7SJeeja KP SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_REG); 82179f4e922SSubhransu S. Prusty } 82279f4e922SSubhransu S. Prusty 82379f4e922SSubhransu S. Prusty /* Add cvt <- input <- mux route map */ 82479f4e922SSubhransu S. Prusty static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, 82579f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widgets, 82679f4e922SSubhransu S. Prusty struct snd_soc_dapm_route *route, int rindex) 82779f4e922SSubhransu S. Prusty { 82879f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 82979f4e922SSubhransu S. Prusty const struct snd_kcontrol_new *kc; 83079f4e922SSubhransu S. Prusty struct soc_enum *se; 83179f4e922SSubhransu S. Prusty int mux_index = hdmi->num_cvt + hdmi->num_pin; 83279f4e922SSubhransu S. Prusty int i, j; 83379f4e922SSubhransu S. Prusty 83479f4e922SSubhransu S. Prusty for (i = 0; i < hdmi->num_pin; i++) { 83579f4e922SSubhransu S. Prusty kc = widgets[mux_index].kcontrol_news; 83679f4e922SSubhransu S. Prusty se = (struct soc_enum *)kc->private_value; 83779f4e922SSubhransu S. Prusty for (j = 0; j < hdmi->num_cvt; j++) { 83879f4e922SSubhransu S. Prusty hdac_hdmi_fill_route(&route[rindex], 83979f4e922SSubhransu S. Prusty widgets[mux_index].name, 84079f4e922SSubhransu S. Prusty se->texts[j + 1], 84179f4e922SSubhransu S. Prusty widgets[j].name, NULL); 84279f4e922SSubhransu S. Prusty 84379f4e922SSubhransu S. Prusty rindex++; 84479f4e922SSubhransu S. Prusty } 84579f4e922SSubhransu S. Prusty 84679f4e922SSubhransu S. Prusty mux_index++; 84779f4e922SSubhransu S. Prusty } 84879f4e922SSubhransu S. Prusty } 84979f4e922SSubhransu S. Prusty 85079f4e922SSubhransu S. Prusty /* 85179f4e922SSubhransu S. Prusty * Widgets are added in the below sequence 85279f4e922SSubhransu S. Prusty * Converter widgets for num converters enumerated 85379f4e922SSubhransu S. Prusty * Pin widgets for num pins enumerated 85479f4e922SSubhransu S. Prusty * Pin mux widgets to represent connenction list of pin widget 85579f4e922SSubhransu S. Prusty * 85679f4e922SSubhransu S. Prusty * Total widgets elements = num_cvt + num_pin + num_pin; 85779f4e922SSubhransu S. Prusty * 85879f4e922SSubhransu S. Prusty * Routes are added as below: 85979f4e922SSubhransu S. Prusty * pin mux -> pin (based on num_pins) 86079f4e922SSubhransu S. Prusty * cvt -> "Input sel control" -> pin_mux 86179f4e922SSubhransu S. Prusty * 86279f4e922SSubhransu S. Prusty * Total route elements: 86379f4e922SSubhransu S. Prusty * num_pins + (pin_muxes * num_cvt) 86479f4e922SSubhransu S. Prusty */ 86579f4e922SSubhransu S. Prusty static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) 86679f4e922SSubhransu S. Prusty { 86779f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widgets; 86879f4e922SSubhransu S. Prusty struct snd_soc_dapm_route *route; 86979f4e922SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 87079f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 87179f4e922SSubhransu S. Prusty struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; 87279f4e922SSubhransu S. Prusty char widget_name[NAME_SIZE]; 87379f4e922SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 87479f4e922SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 87579f4e922SSubhransu S. Prusty int ret, i = 0, num_routes = 0; 87679f4e922SSubhransu S. Prusty 87779f4e922SSubhransu S. Prusty if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) 87879f4e922SSubhransu S. Prusty return -EINVAL; 87979f4e922SSubhransu S. Prusty 88079f4e922SSubhransu S. Prusty widgets = devm_kzalloc(dapm->dev, 88179f4e922SSubhransu S. Prusty (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), 88279f4e922SSubhransu S. Prusty GFP_KERNEL); 88379f4e922SSubhransu S. Prusty 88479f4e922SSubhransu S. Prusty if (!widgets) 88579f4e922SSubhransu S. Prusty return -ENOMEM; 88679f4e922SSubhransu S. Prusty 88779f4e922SSubhransu S. Prusty /* DAPM widgets to represent each converter widget */ 88879f4e922SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 88979f4e922SSubhransu S. Prusty sprintf(widget_name, "Converter %d", cvt->nid); 89079f4e922SSubhransu S. Prusty ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], 891*c9bfb5d7SJeeja KP snd_soc_dapm_aif_in, cvt, 892*c9bfb5d7SJeeja KP widget_name, dai_drv[i].playback.stream_name, NULL, 0, 893*c9bfb5d7SJeeja KP hdac_hdmi_cvt_output_widget_event, 894*c9bfb5d7SJeeja KP SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); 89579f4e922SSubhransu S. Prusty if (ret < 0) 89679f4e922SSubhransu S. Prusty return ret; 89779f4e922SSubhransu S. Prusty i++; 89879f4e922SSubhransu S. Prusty } 89979f4e922SSubhransu S. Prusty 90079f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 90179f4e922SSubhransu S. Prusty sprintf(widget_name, "hif%d Output", pin->nid); 90279f4e922SSubhransu S. Prusty ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], 903*c9bfb5d7SJeeja KP snd_soc_dapm_output, pin, 904*c9bfb5d7SJeeja KP widget_name, NULL, NULL, 0, 905*c9bfb5d7SJeeja KP hdac_hdmi_pin_output_widget_event, 906*c9bfb5d7SJeeja KP SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); 90779f4e922SSubhransu S. Prusty if (ret < 0) 90879f4e922SSubhransu S. Prusty return ret; 90979f4e922SSubhransu S. Prusty i++; 91079f4e922SSubhransu S. Prusty } 91179f4e922SSubhransu S. Prusty 91279f4e922SSubhransu S. Prusty /* DAPM widgets to represent the connection list to pin widget */ 91379f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 91479f4e922SSubhransu S. Prusty sprintf(widget_name, "Pin %d Mux", pin->nid); 91579f4e922SSubhransu S. Prusty ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], 91679f4e922SSubhransu S. Prusty widget_name); 91779f4e922SSubhransu S. Prusty if (ret < 0) 91879f4e922SSubhransu S. Prusty return ret; 91979f4e922SSubhransu S. Prusty i++; 92079f4e922SSubhransu S. Prusty 92179f4e922SSubhransu S. Prusty /* For cvt to pin_mux mapping */ 92279f4e922SSubhransu S. Prusty num_routes += hdmi->num_cvt; 92379f4e922SSubhransu S. Prusty 92479f4e922SSubhransu S. Prusty /* For pin_mux to pin mapping */ 92579f4e922SSubhransu S. Prusty num_routes++; 92679f4e922SSubhransu S. Prusty } 92779f4e922SSubhransu S. Prusty 92879f4e922SSubhransu S. Prusty route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), 92979f4e922SSubhransu S. Prusty GFP_KERNEL); 93079f4e922SSubhransu S. Prusty if (!route) 93179f4e922SSubhransu S. Prusty return -ENOMEM; 93279f4e922SSubhransu S. Prusty 93379f4e922SSubhransu S. Prusty i = 0; 93479f4e922SSubhransu S. Prusty /* Add pin <- NULL <- mux route map */ 93579f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 93679f4e922SSubhransu S. Prusty int sink_index = i + hdmi->num_cvt; 93779f4e922SSubhransu S. Prusty int src_index = sink_index + hdmi->num_pin; 93879f4e922SSubhransu S. Prusty 93979f4e922SSubhransu S. Prusty hdac_hdmi_fill_route(&route[i], 94079f4e922SSubhransu S. Prusty widgets[sink_index].name, NULL, 94179f4e922SSubhransu S. Prusty widgets[src_index].name, NULL); 94279f4e922SSubhransu S. Prusty i++; 94379f4e922SSubhransu S. Prusty 94479f4e922SSubhransu S. Prusty } 94579f4e922SSubhransu S. Prusty 94679f4e922SSubhransu S. Prusty hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i); 94779f4e922SSubhransu S. Prusty 94879f4e922SSubhransu S. Prusty snd_soc_dapm_new_controls(dapm, widgets, 94979f4e922SSubhransu S. Prusty ((2 * hdmi->num_pin) + hdmi->num_cvt)); 95079f4e922SSubhransu S. Prusty 95179f4e922SSubhransu S. Prusty snd_soc_dapm_add_routes(dapm, route, num_routes); 95279f4e922SSubhransu S. Prusty snd_soc_dapm_new_widgets(dapm->card); 95379f4e922SSubhransu S. Prusty 95479f4e922SSubhransu S. Prusty return 0; 95579f4e922SSubhransu S. Prusty 95618382eadSSubhransu S. Prusty } 95718382eadSSubhransu S. Prusty 95815b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) 95918382eadSSubhransu S. Prusty { 96015b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 961148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 96215b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 963148569fdSSubhransu S. Prusty int dai_id = 0; 96418382eadSSubhransu S. Prusty 965148569fdSSubhransu S. Prusty if (list_empty(&hdmi->cvt_list)) 96615b91447SSubhransu S. Prusty return -EINVAL; 96718382eadSSubhransu S. Prusty 968148569fdSSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 969148569fdSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai_id]; 970148569fdSSubhransu S. Prusty dai_map->dai_id = dai_id; 97115b91447SSubhransu S. Prusty dai_map->cvt = cvt; 97218382eadSSubhransu S. Prusty 973148569fdSSubhransu S. Prusty dai_id++; 974148569fdSSubhransu S. Prusty 975148569fdSSubhransu S. Prusty if (dai_id == HDA_MAX_CVTS) { 976148569fdSSubhransu S. Prusty dev_warn(&edev->hdac.dev, 977148569fdSSubhransu S. Prusty "Max dais supported: %d\n", dai_id); 978148569fdSSubhransu S. Prusty break; 979148569fdSSubhransu S. Prusty } 980148569fdSSubhransu S. Prusty } 98118382eadSSubhransu S. Prusty 98215b91447SSubhransu S. Prusty return 0; 98315b91447SSubhransu S. Prusty } 98415b91447SSubhransu S. Prusty 98515b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) 98615b91447SSubhransu S. Prusty { 98715b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 98815b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 9894a3478deSJeeja KP char name[NAME_SIZE]; 99015b91447SSubhransu S. Prusty 99115b91447SSubhransu S. Prusty cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); 99215b91447SSubhransu S. Prusty if (!cvt) 99315b91447SSubhransu S. Prusty return -ENOMEM; 99415b91447SSubhransu S. Prusty 99515b91447SSubhransu S. Prusty cvt->nid = nid; 9964a3478deSJeeja KP sprintf(name, "cvt %d", cvt->nid); 9974a3478deSJeeja KP cvt->name = kstrdup(name, GFP_KERNEL); 99815b91447SSubhransu S. Prusty 99915b91447SSubhransu S. Prusty list_add_tail(&cvt->head, &hdmi->cvt_list); 100015b91447SSubhransu S. Prusty hdmi->num_cvt++; 100115b91447SSubhransu S. Prusty 100215b91447SSubhransu S. Prusty return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); 100315b91447SSubhransu S. Prusty } 100415b91447SSubhransu S. Prusty 1005f6fa11a3SSandeep Tayal static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, 1006b7756edeSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 1007b7756edeSSubhransu S. Prusty { 1008f6fa11a3SSandeep Tayal unsigned int ver, mnl; 1009f6fa11a3SSandeep Tayal 1010f6fa11a3SSandeep Tayal ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) 1011f6fa11a3SSandeep Tayal >> DRM_ELD_VER_SHIFT; 1012f6fa11a3SSandeep Tayal 1013f6fa11a3SSandeep Tayal if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { 1014f6fa11a3SSandeep Tayal dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); 1015f6fa11a3SSandeep Tayal return -EINVAL; 1016b7756edeSSubhransu S. Prusty } 1017b7756edeSSubhransu S. Prusty 1018f6fa11a3SSandeep Tayal mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & 1019f6fa11a3SSandeep Tayal DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; 1020f6fa11a3SSandeep Tayal 1021f6fa11a3SSandeep Tayal if (mnl > ELD_MAX_MNL) { 1022f6fa11a3SSandeep Tayal dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); 1023f6fa11a3SSandeep Tayal return -EINVAL; 1024f6fa11a3SSandeep Tayal } 1025f6fa11a3SSandeep Tayal 1026f6fa11a3SSandeep Tayal pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; 1027f6fa11a3SSandeep Tayal 1028f6fa11a3SSandeep Tayal return 0; 1029f6fa11a3SSandeep Tayal } 1030f6fa11a3SSandeep Tayal 1031f6fa11a3SSandeep Tayal static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) 1032b8a54545SSubhransu S. Prusty { 1033b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = pin->edev; 10344a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 10354a3478deSJeeja KP struct hdac_hdmi_pcm *pcm; 1036f6fa11a3SSandeep Tayal int size; 10374a3478deSJeeja KP 10384a3478deSJeeja KP mutex_lock(&hdmi->pin_mutex); 1039f6fa11a3SSandeep Tayal pin->eld.monitor_present = false; 1040f6fa11a3SSandeep Tayal 1041f6fa11a3SSandeep Tayal size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, 1042f6fa11a3SSandeep Tayal &pin->eld.monitor_present, pin->eld.eld_buffer, 1043f6fa11a3SSandeep Tayal ELD_MAX_SIZE); 1044f6fa11a3SSandeep Tayal 1045f6fa11a3SSandeep Tayal if (size > 0) { 1046f6fa11a3SSandeep Tayal size = min(size, ELD_MAX_SIZE); 1047f6fa11a3SSandeep Tayal if (hdac_hdmi_parse_eld(edev, pin) < 0) 1048f6fa11a3SSandeep Tayal size = -EINVAL; 1049f6fa11a3SSandeep Tayal } 1050f6fa11a3SSandeep Tayal 1051f6fa11a3SSandeep Tayal if (size > 0) { 1052f6fa11a3SSandeep Tayal pin->eld.eld_valid = true; 1053f6fa11a3SSandeep Tayal pin->eld.eld_size = size; 1054f6fa11a3SSandeep Tayal } else { 1055f6fa11a3SSandeep Tayal pin->eld.eld_valid = false; 1056f6fa11a3SSandeep Tayal pin->eld.eld_size = 0; 1057f6fa11a3SSandeep Tayal } 1058b8a54545SSubhransu S. Prusty 10594a3478deSJeeja KP pcm = hdac_hdmi_get_pcm(edev, pin); 10604a3478deSJeeja KP 1061b8a54545SSubhransu S. Prusty if (!pin->eld.monitor_present || !pin->eld.eld_valid) { 1062b8a54545SSubhransu S. Prusty 1063b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", 1064b8a54545SSubhransu S. Prusty __func__, pin->nid); 10654a3478deSJeeja KP 10664a3478deSJeeja KP /* 10674a3478deSJeeja KP * PCMs are not registered during device probe, so don't 10684a3478deSJeeja KP * report jack here. It will be done in usermode mux 10694a3478deSJeeja KP * control select. 10704a3478deSJeeja KP */ 10714a3478deSJeeja KP if (pcm) { 10724a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 10734a3478deSJeeja KP "jack report for pcm=%d\n", pcm->pcm_id); 10744a3478deSJeeja KP 10754a3478deSJeeja KP snd_jack_report(pcm->jack, 0); 10764a3478deSJeeja KP } 10774a3478deSJeeja KP 10784a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 1079f6fa11a3SSandeep Tayal return; 1080b8a54545SSubhransu S. Prusty } 1081b8a54545SSubhransu S. Prusty 1082b8a54545SSubhransu S. Prusty if (pin->eld.monitor_present && pin->eld.eld_valid) { 10834a3478deSJeeja KP if (pcm) { 10844a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 10854a3478deSJeeja KP "jack report for pcm=%d\n", 10864a3478deSJeeja KP pcm->pcm_id); 10874a3478deSJeeja KP 10884a3478deSJeeja KP snd_jack_report(pcm->jack, SND_JACK_AVOUT); 10894a3478deSJeeja KP } 10904a3478deSJeeja KP 1091f6fa11a3SSandeep Tayal print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, 1092f6fa11a3SSandeep Tayal pin->eld.eld_buffer, pin->eld.eld_size, false); 10934a3478deSJeeja KP } 10944a3478deSJeeja KP 10954a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 1096b8a54545SSubhransu S. Prusty } 1097b8a54545SSubhransu S. Prusty 109815b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) 109915b91447SSubhransu S. Prusty { 110015b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 110115b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 110215b91447SSubhransu S. Prusty 110315b91447SSubhransu S. Prusty pin = kzalloc(sizeof(*pin), GFP_KERNEL); 110415b91447SSubhransu S. Prusty if (!pin) 110515b91447SSubhransu S. Prusty return -ENOMEM; 110615b91447SSubhransu S. Prusty 110715b91447SSubhransu S. Prusty pin->nid = nid; 110815b91447SSubhransu S. Prusty 110915b91447SSubhransu S. Prusty list_add_tail(&pin->head, &hdmi->pin_list); 111015b91447SSubhransu S. Prusty hdmi->num_pin++; 111115b91447SSubhransu S. Prusty 1112b8a54545SSubhransu S. Prusty pin->edev = edev; 1113bcced704SSubhransu S. Prusty mutex_init(&pin->lock); 1114b8a54545SSubhransu S. Prusty 111515b91447SSubhransu S. Prusty return 0; 111618382eadSSubhransu S. Prusty } 111718382eadSSubhransu S. Prusty 1118211caab7SSubhransu S. Prusty #define INTEL_VENDOR_NID 0x08 1119211caab7SSubhransu S. Prusty #define INTEL_GET_VENDOR_VERB 0xf81 1120211caab7SSubhransu S. Prusty #define INTEL_SET_VENDOR_VERB 0x781 1121211caab7SSubhransu S. Prusty #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ 1122211caab7SSubhransu S. Prusty #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ 1123211caab7SSubhransu S. Prusty 1124211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) 1125211caab7SSubhransu S. Prusty { 1126211caab7SSubhransu S. Prusty unsigned int vendor_param; 1127211caab7SSubhransu S. Prusty 1128211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1129211caab7SSubhransu S. Prusty INTEL_GET_VENDOR_VERB, 0); 1130211caab7SSubhransu S. Prusty if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) 1131211caab7SSubhransu S. Prusty return; 1132211caab7SSubhransu S. Prusty 1133211caab7SSubhransu S. Prusty vendor_param |= INTEL_EN_ALL_PIN_CVTS; 1134211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1135211caab7SSubhransu S. Prusty INTEL_SET_VENDOR_VERB, vendor_param); 1136211caab7SSubhransu S. Prusty if (vendor_param == -1) 1137211caab7SSubhransu S. Prusty return; 1138211caab7SSubhransu S. Prusty } 1139211caab7SSubhransu S. Prusty 1140211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) 1141211caab7SSubhransu S. Prusty { 1142211caab7SSubhransu S. Prusty unsigned int vendor_param; 1143211caab7SSubhransu S. Prusty 1144211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1145211caab7SSubhransu S. Prusty INTEL_GET_VENDOR_VERB, 0); 1146211caab7SSubhransu S. Prusty if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) 1147211caab7SSubhransu S. Prusty return; 1148211caab7SSubhransu S. Prusty 1149211caab7SSubhransu S. Prusty /* enable DP1.2 mode */ 1150211caab7SSubhransu S. Prusty vendor_param |= INTEL_EN_DP12; 1151211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1152211caab7SSubhransu S. Prusty INTEL_SET_VENDOR_VERB, vendor_param); 1153211caab7SSubhransu S. Prusty if (vendor_param == -1) 1154211caab7SSubhransu S. Prusty return; 1155211caab7SSubhransu S. Prusty 1156211caab7SSubhransu S. Prusty } 1157211caab7SSubhransu S. Prusty 115817a42c45SSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = { 115917a42c45SSubhransu S. Prusty .startup = hdac_hdmi_pcm_open, 116017a42c45SSubhransu S. Prusty .shutdown = hdac_hdmi_pcm_close, 116117a42c45SSubhransu S. Prusty .hw_params = hdac_hdmi_set_hw_params, 1162*c9bfb5d7SJeeja KP .set_tdm_slot = hdac_hdmi_set_tdm_slot, 116317a42c45SSubhransu S. Prusty }; 116417a42c45SSubhransu S. Prusty 116517a42c45SSubhransu S. Prusty /* 116617a42c45SSubhransu S. Prusty * Each converter can support a stream independently. So a dai is created 116717a42c45SSubhransu S. Prusty * based on the number of converter queried. 116817a42c45SSubhransu S. Prusty */ 116917a42c45SSubhransu S. Prusty static int hdac_hdmi_create_dais(struct hdac_device *hdac, 117017a42c45SSubhransu S. Prusty struct snd_soc_dai_driver **dais, 117117a42c45SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi, int num_dais) 117217a42c45SSubhransu S. Prusty { 117317a42c45SSubhransu S. Prusty struct snd_soc_dai_driver *hdmi_dais; 117417a42c45SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 117517a42c45SSubhransu S. Prusty char name[NAME_SIZE], dai_name[NAME_SIZE]; 117617a42c45SSubhransu S. Prusty int i = 0; 117717a42c45SSubhransu S. Prusty u32 rates, bps; 117817a42c45SSubhransu S. Prusty unsigned int rate_max = 384000, rate_min = 8000; 117917a42c45SSubhransu S. Prusty u64 formats; 118017a42c45SSubhransu S. Prusty int ret; 118117a42c45SSubhransu S. Prusty 118217a42c45SSubhransu S. Prusty hdmi_dais = devm_kzalloc(&hdac->dev, 118317a42c45SSubhransu S. Prusty (sizeof(*hdmi_dais) * num_dais), 118417a42c45SSubhransu S. Prusty GFP_KERNEL); 118517a42c45SSubhransu S. Prusty if (!hdmi_dais) 118617a42c45SSubhransu S. Prusty return -ENOMEM; 118717a42c45SSubhransu S. Prusty 118817a42c45SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 118917a42c45SSubhransu S. Prusty ret = snd_hdac_query_supported_pcm(hdac, cvt->nid, 119017a42c45SSubhransu S. Prusty &rates, &formats, &bps); 119117a42c45SSubhransu S. Prusty if (ret) 119217a42c45SSubhransu S. Prusty return ret; 119317a42c45SSubhransu S. Prusty 119417a42c45SSubhransu S. Prusty sprintf(dai_name, "intel-hdmi-hifi%d", i+1); 119517a42c45SSubhransu S. Prusty hdmi_dais[i].name = devm_kstrdup(&hdac->dev, 119617a42c45SSubhransu S. Prusty dai_name, GFP_KERNEL); 119717a42c45SSubhransu S. Prusty 119817a42c45SSubhransu S. Prusty if (!hdmi_dais[i].name) 119917a42c45SSubhransu S. Prusty return -ENOMEM; 120017a42c45SSubhransu S. Prusty 120117a42c45SSubhransu S. Prusty snprintf(name, sizeof(name), "hifi%d", i+1); 120217a42c45SSubhransu S. Prusty hdmi_dais[i].playback.stream_name = 120317a42c45SSubhransu S. Prusty devm_kstrdup(&hdac->dev, name, GFP_KERNEL); 120417a42c45SSubhransu S. Prusty if (!hdmi_dais[i].playback.stream_name) 120517a42c45SSubhransu S. Prusty return -ENOMEM; 120617a42c45SSubhransu S. Prusty 120717a42c45SSubhransu S. Prusty /* 120817a42c45SSubhransu S. Prusty * Set caps based on capability queried from the converter. 120917a42c45SSubhransu S. Prusty * It will be constrained runtime based on ELD queried. 121017a42c45SSubhransu S. Prusty */ 121117a42c45SSubhransu S. Prusty hdmi_dais[i].playback.formats = formats; 121217a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rates = rates; 121317a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rate_max = rate_max; 121417a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rate_min = rate_min; 121517a42c45SSubhransu S. Prusty hdmi_dais[i].playback.channels_min = 2; 121617a42c45SSubhransu S. Prusty hdmi_dais[i].playback.channels_max = 2; 121717a42c45SSubhransu S. Prusty hdmi_dais[i].ops = &hdmi_dai_ops; 121817a42c45SSubhransu S. Prusty 121917a42c45SSubhransu S. Prusty i++; 122017a42c45SSubhransu S. Prusty } 122117a42c45SSubhransu S. Prusty 122217a42c45SSubhransu S. Prusty *dais = hdmi_dais; 122317a42c45SSubhransu S. Prusty 122417a42c45SSubhransu S. Prusty return 0; 122517a42c45SSubhransu S. Prusty } 122617a42c45SSubhransu S. Prusty 122718382eadSSubhransu S. Prusty /* 122818382eadSSubhransu S. Prusty * Parse all nodes and store the cvt/pin nids in array 122918382eadSSubhransu S. Prusty * Add one time initialization for pin and cvt widgets 123018382eadSSubhransu S. Prusty */ 123117a42c45SSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, 123217a42c45SSubhransu S. Prusty struct snd_soc_dai_driver **dais, int *num_dais) 123318382eadSSubhransu S. Prusty { 123418382eadSSubhransu S. Prusty hda_nid_t nid; 12353c83ac23SSudip Mukherjee int i, num_nodes; 123618382eadSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 123718382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 123815b91447SSubhransu S. Prusty int ret; 123918382eadSSubhransu S. Prusty 1240211caab7SSubhransu S. Prusty hdac_hdmi_skl_enable_all_pins(hdac); 1241211caab7SSubhransu S. Prusty hdac_hdmi_skl_enable_dp12(hdac); 1242211caab7SSubhransu S. Prusty 12433c83ac23SSudip Mukherjee num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); 1244541140d4SSubhransu S. Prusty if (!nid || num_nodes <= 0) { 124518382eadSSubhransu S. Prusty dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 124618382eadSSubhransu S. Prusty return -EINVAL; 124718382eadSSubhransu S. Prusty } 124818382eadSSubhransu S. Prusty 12493c83ac23SSudip Mukherjee hdac->num_nodes = num_nodes; 125018382eadSSubhransu S. Prusty hdac->start_nid = nid; 125118382eadSSubhransu S. Prusty 125218382eadSSubhransu S. Prusty for (i = 0; i < hdac->num_nodes; i++, nid++) { 125318382eadSSubhransu S. Prusty unsigned int caps; 125418382eadSSubhransu S. Prusty unsigned int type; 125518382eadSSubhransu S. Prusty 125618382eadSSubhransu S. Prusty caps = get_wcaps(hdac, nid); 125718382eadSSubhransu S. Prusty type = get_wcaps_type(caps); 125818382eadSSubhransu S. Prusty 125918382eadSSubhransu S. Prusty if (!(caps & AC_WCAP_DIGITAL)) 126018382eadSSubhransu S. Prusty continue; 126118382eadSSubhransu S. Prusty 126218382eadSSubhransu S. Prusty switch (type) { 126318382eadSSubhransu S. Prusty 126418382eadSSubhransu S. Prusty case AC_WID_AUD_OUT: 126515b91447SSubhransu S. Prusty ret = hdac_hdmi_add_cvt(edev, nid); 126615b91447SSubhransu S. Prusty if (ret < 0) 126715b91447SSubhransu S. Prusty return ret; 126818382eadSSubhransu S. Prusty break; 126918382eadSSubhransu S. Prusty 127018382eadSSubhransu S. Prusty case AC_WID_PIN: 127115b91447SSubhransu S. Prusty ret = hdac_hdmi_add_pin(edev, nid); 127215b91447SSubhransu S. Prusty if (ret < 0) 127315b91447SSubhransu S. Prusty return ret; 127418382eadSSubhransu S. Prusty break; 127518382eadSSubhransu S. Prusty } 127618382eadSSubhransu S. Prusty } 127718382eadSSubhransu S. Prusty 127818382eadSSubhransu S. Prusty hdac->end_nid = nid; 127918382eadSSubhransu S. Prusty 128015b91447SSubhransu S. Prusty if (!hdmi->num_pin || !hdmi->num_cvt) 128118382eadSSubhransu S. Prusty return -EIO; 128218382eadSSubhransu S. Prusty 128317a42c45SSubhransu S. Prusty ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt); 128417a42c45SSubhransu S. Prusty if (ret) { 128517a42c45SSubhransu S. Prusty dev_err(&hdac->dev, "Failed to create dais with err: %d\n", 128617a42c45SSubhransu S. Prusty ret); 128717a42c45SSubhransu S. Prusty return ret; 128817a42c45SSubhransu S. Prusty } 128917a42c45SSubhransu S. Prusty 129017a42c45SSubhransu S. Prusty *num_dais = hdmi->num_cvt; 129117a42c45SSubhransu S. Prusty 129215b91447SSubhransu S. Prusty return hdac_hdmi_init_dai_map(edev); 129318382eadSSubhransu S. Prusty } 129418382eadSSubhransu S. Prusty 1295f9318941SPandiyan, Dhinakaran static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe) 1296b8a54545SSubhransu S. Prusty { 1297b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = aptr; 1298b8a54545SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 1299b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 1300b8a54545SSubhransu S. Prusty struct snd_soc_codec *codec = edev->scodec; 1301b8a54545SSubhransu S. Prusty 1302b8a54545SSubhransu S. Prusty /* Don't know how this mapping is derived */ 1303b8a54545SSubhransu S. Prusty hda_nid_t pin_nid = port + 0x04; 1304b8a54545SSubhransu S. Prusty 1305b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); 1306b8a54545SSubhransu S. Prusty 1307b8a54545SSubhransu S. Prusty /* 1308b8a54545SSubhransu S. Prusty * skip notification during system suspend (but not in runtime PM); 1309b8a54545SSubhransu S. Prusty * the state will be updated at resume. Also since the ELD and 1310b8a54545SSubhransu S. Prusty * connection states are updated in anyway at the end of the resume, 1311b8a54545SSubhransu S. Prusty * we can skip it when received during PM process. 1312b8a54545SSubhransu S. Prusty */ 1313b8a54545SSubhransu S. Prusty if (snd_power_get_state(codec->component.card->snd_card) != 1314b8a54545SSubhransu S. Prusty SNDRV_CTL_POWER_D0) 1315b8a54545SSubhransu S. Prusty return; 1316b8a54545SSubhransu S. Prusty 1317b8a54545SSubhransu S. Prusty if (atomic_read(&edev->hdac.in_pm)) 1318b8a54545SSubhransu S. Prusty return; 1319b8a54545SSubhransu S. Prusty 1320b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 1321b8a54545SSubhransu S. Prusty if (pin->nid == pin_nid) 1322f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1323b8a54545SSubhransu S. Prusty } 1324b8a54545SSubhransu S. Prusty } 1325b8a54545SSubhransu S. Prusty 1326b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = { 1327b8a54545SSubhransu S. Prusty .pin_eld_notify = hdac_hdmi_eld_notify_cb, 1328b8a54545SSubhransu S. Prusty }; 1329b8a54545SSubhransu S. Prusty 13302889099eSSubhransu S. Prusty static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, 13312889099eSSubhransu S. Prusty int device) 13322889099eSSubhransu S. Prusty { 13332889099eSSubhransu S. Prusty struct snd_soc_pcm_runtime *rtd; 13342889099eSSubhransu S. Prusty 13352889099eSSubhransu S. Prusty list_for_each_entry(rtd, &card->rtd_list, list) { 13362889099eSSubhransu S. Prusty if (rtd->pcm && (rtd->pcm->device == device)) 13372889099eSSubhransu S. Prusty return rtd->pcm; 13382889099eSSubhransu S. Prusty } 13392889099eSSubhransu S. Prusty 13402889099eSSubhransu S. Prusty return NULL; 13412889099eSSubhransu S. Prusty } 13422889099eSSubhransu S. Prusty 13434a3478deSJeeja KP int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) 13444a3478deSJeeja KP { 13454a3478deSJeeja KP char jack_name[NAME_SIZE]; 13464a3478deSJeeja KP struct snd_soc_codec *codec = dai->codec; 13474a3478deSJeeja KP struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 13484a3478deSJeeja KP struct snd_soc_dapm_context *dapm = 13494a3478deSJeeja KP snd_soc_component_get_dapm(&codec->component); 13504a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 13514a3478deSJeeja KP struct hdac_hdmi_pcm *pcm; 13522889099eSSubhransu S. Prusty struct snd_pcm *snd_pcm; 13532889099eSSubhransu S. Prusty int err; 13544a3478deSJeeja KP 13554a3478deSJeeja KP /* 13564a3478deSJeeja KP * this is a new PCM device, create new pcm and 13574a3478deSJeeja KP * add to the pcm list 13584a3478deSJeeja KP */ 13594a3478deSJeeja KP pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); 13604a3478deSJeeja KP if (!pcm) 13614a3478deSJeeja KP return -ENOMEM; 13624a3478deSJeeja KP pcm->pcm_id = device; 13634a3478deSJeeja KP pcm->cvt = hdmi->dai_map[dai->id].cvt; 13644a3478deSJeeja KP 13652889099eSSubhransu S. Prusty snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); 13662889099eSSubhransu S. Prusty if (snd_pcm) { 13672889099eSSubhransu S. Prusty err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); 13682889099eSSubhransu S. Prusty if (err < 0) { 13692889099eSSubhransu S. Prusty dev_err(&edev->hdac.dev, 13702889099eSSubhransu S. Prusty "chmap control add failed with err: %d for pcm: %d\n", 13712889099eSSubhransu S. Prusty err, device); 13722889099eSSubhransu S. Prusty kfree(pcm); 13732889099eSSubhransu S. Prusty return err; 13742889099eSSubhransu S. Prusty } 13752889099eSSubhransu S. Prusty } 13762889099eSSubhransu S. Prusty 13774a3478deSJeeja KP list_add_tail(&pcm->head, &hdmi->pcm_list); 13784a3478deSJeeja KP 13794a3478deSJeeja KP sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); 13804a3478deSJeeja KP 13814a3478deSJeeja KP return snd_jack_new(dapm->card->snd_card, jack_name, 13824a3478deSJeeja KP SND_JACK_AVOUT, &pcm->jack, true, false); 13834a3478deSJeeja KP } 13844a3478deSJeeja KP EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); 13854a3478deSJeeja KP 138618382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec) 138718382eadSSubhransu S. Prusty { 138818382eadSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 138918382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 139018382eadSSubhransu S. Prusty struct snd_soc_dapm_context *dapm = 139118382eadSSubhransu S. Prusty snd_soc_component_get_dapm(&codec->component); 1392b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 1393b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 1394b8a54545SSubhransu S. Prusty int ret; 139518382eadSSubhransu S. Prusty 139618382eadSSubhransu S. Prusty edev->scodec = codec; 139718382eadSSubhransu S. Prusty 1398b2047e99SVinod Koul /* 1399b2047e99SVinod Koul * hold the ref while we probe, also no need to drop the ref on 1400b2047e99SVinod Koul * exit, we call pm_runtime_suspend() so that will do for us 1401b2047e99SVinod Koul */ 1402b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); 1403500e06b9SVinod Koul if (!hlink) { 1404500e06b9SVinod Koul dev_err(&edev->hdac.dev, "hdac link not found\n"); 1405500e06b9SVinod Koul return -EIO; 1406500e06b9SVinod Koul } 1407500e06b9SVinod Koul 1408b2047e99SVinod Koul snd_hdac_ext_bus_link_get(edev->ebus, hlink); 1409b2047e99SVinod Koul 141079f4e922SSubhransu S. Prusty ret = create_fill_widget_route_map(dapm); 141179f4e922SSubhransu S. Prusty if (ret < 0) 141279f4e922SSubhransu S. Prusty return ret; 141318382eadSSubhransu S. Prusty 1414b8a54545SSubhransu S. Prusty aops.audio_ptr = edev; 1415b8a54545SSubhransu S. Prusty ret = snd_hdac_i915_register_notifier(&aops); 1416b8a54545SSubhransu S. Prusty if (ret < 0) { 1417b8a54545SSubhransu S. Prusty dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n", 1418b8a54545SSubhransu S. Prusty ret); 1419b8a54545SSubhransu S. Prusty return ret; 1420b8a54545SSubhransu S. Prusty } 1421b8a54545SSubhransu S. Prusty 1422b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) 1423f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1424b8a54545SSubhransu S. Prusty 142518382eadSSubhransu S. Prusty /* Imp: Store the card pointer in hda_codec */ 142618382eadSSubhransu S. Prusty edev->card = dapm->card->snd_card; 142718382eadSSubhransu S. Prusty 1428e342ac08SSubhransu S. Prusty /* 1429e342ac08SSubhransu S. Prusty * hdac_device core already sets the state to active and calls 1430e342ac08SSubhransu S. Prusty * get_noresume. So enable runtime and set the device to suspend. 1431e342ac08SSubhransu S. Prusty */ 1432e342ac08SSubhransu S. Prusty pm_runtime_enable(&edev->hdac.dev); 1433e342ac08SSubhransu S. Prusty pm_runtime_put(&edev->hdac.dev); 1434e342ac08SSubhransu S. Prusty pm_runtime_suspend(&edev->hdac.dev); 1435e342ac08SSubhransu S. Prusty 1436e342ac08SSubhransu S. Prusty return 0; 1437e342ac08SSubhransu S. Prusty } 1438e342ac08SSubhransu S. Prusty 1439e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec) 1440e342ac08SSubhransu S. Prusty { 1441e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 1442e342ac08SSubhransu S. Prusty 1443e342ac08SSubhransu S. Prusty pm_runtime_disable(&edev->hdac.dev); 144418382eadSSubhransu S. Prusty return 0; 144518382eadSSubhransu S. Prusty } 144618382eadSSubhransu S. Prusty 1447571d5078SJeeja KP #ifdef CONFIG_PM 14481b377ccdSSubhransu S. Prusty static int hdmi_codec_prepare(struct device *dev) 14491b377ccdSSubhransu S. Prusty { 14501b377ccdSSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 14511b377ccdSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 14521b377ccdSSubhransu S. Prusty 14531b377ccdSSubhransu S. Prusty pm_runtime_get_sync(&edev->hdac.dev); 14541b377ccdSSubhransu S. Prusty 14551b377ccdSSubhransu S. Prusty /* 14561b377ccdSSubhransu S. Prusty * Power down afg. 14571b377ccdSSubhransu S. Prusty * codec_read is preferred over codec_write to set the power state. 14581b377ccdSSubhransu S. Prusty * This way verb is send to set the power state and response 14591b377ccdSSubhransu S. Prusty * is received. So setting power state is ensured without using loop 14601b377ccdSSubhransu S. Prusty * to read the state. 14611b377ccdSSubhransu S. Prusty */ 14621b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 14631b377ccdSSubhransu S. Prusty AC_PWRST_D3); 14641b377ccdSSubhransu S. Prusty 14651b377ccdSSubhransu S. Prusty return 0; 14661b377ccdSSubhransu S. Prusty } 14671b377ccdSSubhransu S. Prusty 14680fee1798SSubhransu S. Prusty static void hdmi_codec_complete(struct device *dev) 1469571d5078SJeeja KP { 14700fee1798SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1471571d5078SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 1472571d5078SJeeja KP struct hdac_hdmi_pin *pin; 1473571d5078SJeeja KP struct hdac_device *hdac = &edev->hdac; 14741b377ccdSSubhransu S. Prusty 14751b377ccdSSubhransu S. Prusty /* Power up afg */ 14761b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 14771b377ccdSSubhransu S. Prusty AC_PWRST_D0); 1478571d5078SJeeja KP 1479571d5078SJeeja KP hdac_hdmi_skl_enable_all_pins(&edev->hdac); 1480571d5078SJeeja KP hdac_hdmi_skl_enable_dp12(&edev->hdac); 1481571d5078SJeeja KP 1482571d5078SJeeja KP /* 1483571d5078SJeeja KP * As the ELD notify callback request is not entertained while the 1484571d5078SJeeja KP * device is in suspend state. Need to manually check detection of 1485571d5078SJeeja KP * all pins here. 1486571d5078SJeeja KP */ 1487571d5078SJeeja KP list_for_each_entry(pin, &hdmi->pin_list, head) 1488f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1489571d5078SJeeja KP 14901b377ccdSSubhransu S. Prusty pm_runtime_put_sync(&edev->hdac.dev); 1491571d5078SJeeja KP } 1492571d5078SJeeja KP #else 14931b377ccdSSubhransu S. Prusty #define hdmi_codec_prepare NULL 14940fee1798SSubhransu S. Prusty #define hdmi_codec_complete NULL 1495571d5078SJeeja KP #endif 1496571d5078SJeeja KP 149718382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = { 149818382eadSSubhransu S. Prusty .probe = hdmi_codec_probe, 1499e342ac08SSubhransu S. Prusty .remove = hdmi_codec_remove, 150018382eadSSubhransu S. Prusty .idle_bias_off = true, 150118382eadSSubhransu S. Prusty }; 150218382eadSSubhransu S. Prusty 15032889099eSSubhransu S. Prusty static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, 15042889099eSSubhransu S. Prusty unsigned char *chmap) 15052889099eSSubhransu S. Prusty { 15062889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15072889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15082889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15092889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15102889099eSSubhransu S. Prusty 15112889099eSSubhransu S. Prusty /* chmap is already set to 0 in caller */ 15122889099eSSubhransu S. Prusty if (!pin) 15132889099eSSubhransu S. Prusty return; 15142889099eSSubhransu S. Prusty 15152889099eSSubhransu S. Prusty memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); 15162889099eSSubhransu S. Prusty } 15172889099eSSubhransu S. Prusty 15182889099eSSubhransu S. Prusty static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, 15192889099eSSubhransu S. Prusty unsigned char *chmap, int prepared) 15202889099eSSubhransu S. Prusty { 15212889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15222889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15232889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15242889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15252889099eSSubhransu S. Prusty 15262889099eSSubhransu S. Prusty mutex_lock(&pin->lock); 15272889099eSSubhransu S. Prusty pin->chmap_set = true; 15282889099eSSubhransu S. Prusty memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); 15292889099eSSubhransu S. Prusty if (prepared) 15302889099eSSubhransu S. Prusty hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); 15312889099eSSubhransu S. Prusty mutex_unlock(&pin->lock); 15322889099eSSubhransu S. Prusty } 15332889099eSSubhransu S. Prusty 15342889099eSSubhransu S. Prusty static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) 15352889099eSSubhransu S. Prusty { 15362889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15372889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15382889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15392889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15402889099eSSubhransu S. Prusty 15412889099eSSubhransu S. Prusty return pin ? true:false; 15422889099eSSubhransu S. Prusty } 15432889099eSSubhransu S. Prusty 15442889099eSSubhransu S. Prusty static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) 15452889099eSSubhransu S. Prusty { 15462889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15472889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15482889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15492889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15502889099eSSubhransu S. Prusty 15518f658815SDan Carpenter if (!pin || !pin->eld.eld_valid) 15522889099eSSubhransu S. Prusty return 0; 15532889099eSSubhransu S. Prusty 15542889099eSSubhransu S. Prusty return pin->eld.info.spk_alloc; 15552889099eSSubhransu S. Prusty } 15562889099eSSubhransu S. Prusty 155718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) 155818382eadSSubhransu S. Prusty { 155918382eadSSubhransu S. Prusty struct hdac_device *codec = &edev->hdac; 156018382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi_priv; 156117a42c45SSubhransu S. Prusty struct snd_soc_dai_driver *hdmi_dais = NULL; 1562b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 156317a42c45SSubhransu S. Prusty int num_dais = 0; 156418382eadSSubhransu S. Prusty int ret = 0; 156518382eadSSubhransu S. Prusty 1566b2047e99SVinod Koul /* hold the ref while we probe */ 1567b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); 1568500e06b9SVinod Koul if (!hlink) { 1569500e06b9SVinod Koul dev_err(&edev->hdac.dev, "hdac link not found\n"); 1570500e06b9SVinod Koul return -EIO; 1571500e06b9SVinod Koul } 1572500e06b9SVinod Koul 1573b2047e99SVinod Koul snd_hdac_ext_bus_link_get(edev->ebus, hlink); 1574b2047e99SVinod Koul 157518382eadSSubhransu S. Prusty hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 157618382eadSSubhransu S. Prusty if (hdmi_priv == NULL) 157718382eadSSubhransu S. Prusty return -ENOMEM; 157818382eadSSubhransu S. Prusty 157918382eadSSubhransu S. Prusty edev->private_data = hdmi_priv; 1580bcced704SSubhransu S. Prusty snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); 15812889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; 15822889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; 15832889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; 15842889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; 158518382eadSSubhransu S. Prusty 158618382eadSSubhransu S. Prusty dev_set_drvdata(&codec->dev, edev); 158718382eadSSubhransu S. Prusty 158815b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->pin_list); 158915b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->cvt_list); 15904a3478deSJeeja KP INIT_LIST_HEAD(&hdmi_priv->pcm_list); 15914a3478deSJeeja KP mutex_init(&hdmi_priv->pin_mutex); 159215b91447SSubhransu S. Prusty 1593aeaccef0SRamesh Babu /* 1594aeaccef0SRamesh Babu * Turned off in the runtime_suspend during the first explicit 1595aeaccef0SRamesh Babu * pm_runtime_suspend call. 1596aeaccef0SRamesh Babu */ 1597aeaccef0SRamesh Babu ret = snd_hdac_display_power(edev->hdac.bus, true); 1598aeaccef0SRamesh Babu if (ret < 0) { 1599aeaccef0SRamesh Babu dev_err(&edev->hdac.dev, 1600aeaccef0SRamesh Babu "Cannot turn on display power on i915 err: %d\n", 1601aeaccef0SRamesh Babu ret); 1602aeaccef0SRamesh Babu return ret; 1603aeaccef0SRamesh Babu } 1604aeaccef0SRamesh Babu 160517a42c45SSubhransu S. Prusty ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); 160617a42c45SSubhransu S. Prusty if (ret < 0) { 160717a42c45SSubhransu S. Prusty dev_err(&codec->dev, 160817a42c45SSubhransu S. Prusty "Failed in parse and map nid with err: %d\n", ret); 160918382eadSSubhransu S. Prusty return ret; 161017a42c45SSubhransu S. Prusty } 161118382eadSSubhransu S. Prusty 161218382eadSSubhransu S. Prusty /* ASoC specific initialization */ 1613b2047e99SVinod Koul ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 161417a42c45SSubhransu S. Prusty hdmi_dais, num_dais); 1615b2047e99SVinod Koul 1616b2047e99SVinod Koul snd_hdac_ext_bus_link_put(edev->ebus, hlink); 1617b2047e99SVinod Koul 1618b2047e99SVinod Koul return ret; 161918382eadSSubhransu S. Prusty } 162018382eadSSubhransu S. Prusty 162118382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) 162218382eadSSubhransu S. Prusty { 162315b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 162415b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin, *pin_next; 162515b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt, *cvt_next; 16264a3478deSJeeja KP struct hdac_hdmi_pcm *pcm, *pcm_next; 162715b91447SSubhransu S. Prusty 162818382eadSSubhransu S. Prusty snd_soc_unregister_codec(&edev->hdac.dev); 162918382eadSSubhransu S. Prusty 16304a3478deSJeeja KP list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { 16314a3478deSJeeja KP pcm->cvt = NULL; 16324a3478deSJeeja KP pcm->pin = NULL; 16334a3478deSJeeja KP list_del(&pcm->head); 16344a3478deSJeeja KP kfree(pcm); 16354a3478deSJeeja KP } 16364a3478deSJeeja KP 163715b91447SSubhransu S. Prusty list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { 163815b91447SSubhransu S. Prusty list_del(&cvt->head); 16394a3478deSJeeja KP kfree(cvt->name); 164015b91447SSubhransu S. Prusty kfree(cvt); 164115b91447SSubhransu S. Prusty } 164215b91447SSubhransu S. Prusty 164315b91447SSubhransu S. Prusty list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { 164415b91447SSubhransu S. Prusty list_del(&pin->head); 164515b91447SSubhransu S. Prusty kfree(pin); 164615b91447SSubhransu S. Prusty } 164715b91447SSubhransu S. Prusty 164818382eadSSubhransu S. Prusty return 0; 164918382eadSSubhransu S. Prusty } 165018382eadSSubhransu S. Prusty 1651e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM 1652e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev) 1653e342ac08SSubhransu S. Prusty { 1654e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1655e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 165607f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 1657b2047e99SVinod Koul struct hdac_ext_bus *ebus = hbus_to_ebus(bus); 1658b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 165907f083abSSubhransu S. Prusty int err; 1660e342ac08SSubhransu S. Prusty 1661e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 1662e342ac08SSubhransu S. Prusty 166307f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 166407f083abSSubhransu S. Prusty if (!bus) 166507f083abSSubhransu S. Prusty return 0; 166607f083abSSubhransu S. Prusty 16671b377ccdSSubhransu S. Prusty /* 16681b377ccdSSubhransu S. Prusty * Power down afg. 16691b377ccdSSubhransu S. Prusty * codec_read is preferred over codec_write to set the power state. 16701b377ccdSSubhransu S. Prusty * This way verb is send to set the power state and response 16711b377ccdSSubhransu S. Prusty * is received. So setting power state is ensured without using loop 16721b377ccdSSubhransu S. Prusty * to read the state. 16731b377ccdSSubhransu S. Prusty */ 16741b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 16751b377ccdSSubhransu S. Prusty AC_PWRST_D3); 167607f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, false); 167707f083abSSubhransu S. Prusty if (err < 0) { 167807f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 167907f083abSSubhransu S. Prusty return err; 168007f083abSSubhransu S. Prusty } 168107f083abSSubhransu S. Prusty 1682b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); 1683500e06b9SVinod Koul if (!hlink) { 1684500e06b9SVinod Koul dev_err(dev, "hdac link not found\n"); 1685500e06b9SVinod Koul return -EIO; 1686500e06b9SVinod Koul } 1687500e06b9SVinod Koul 1688b2047e99SVinod Koul snd_hdac_ext_bus_link_put(ebus, hlink); 1689b2047e99SVinod Koul 1690e342ac08SSubhransu S. Prusty return 0; 1691e342ac08SSubhransu S. Prusty } 1692e342ac08SSubhransu S. Prusty 1693e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev) 1694e342ac08SSubhransu S. Prusty { 1695e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1696e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 169707f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 1698b2047e99SVinod Koul struct hdac_ext_bus *ebus = hbus_to_ebus(bus); 1699b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 170007f083abSSubhransu S. Prusty int err; 1701e342ac08SSubhransu S. Prusty 1702e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 1703e342ac08SSubhransu S. Prusty 170407f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 170507f083abSSubhransu S. Prusty if (!bus) 170607f083abSSubhransu S. Prusty return 0; 170707f083abSSubhransu S. Prusty 1708b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); 1709500e06b9SVinod Koul if (!hlink) { 1710500e06b9SVinod Koul dev_err(dev, "hdac link not found\n"); 1711500e06b9SVinod Koul return -EIO; 1712500e06b9SVinod Koul } 1713500e06b9SVinod Koul 1714b2047e99SVinod Koul snd_hdac_ext_bus_link_get(ebus, hlink); 1715b2047e99SVinod Koul 171607f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, true); 171707f083abSSubhransu S. Prusty if (err < 0) { 171807f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 171907f083abSSubhransu S. Prusty return err; 172007f083abSSubhransu S. Prusty } 172107f083abSSubhransu S. Prusty 1722ab85f5b3SSubhransu S. Prusty hdac_hdmi_skl_enable_all_pins(&edev->hdac); 1723ab85f5b3SSubhransu S. Prusty hdac_hdmi_skl_enable_dp12(&edev->hdac); 1724ab85f5b3SSubhransu S. Prusty 1725e342ac08SSubhransu S. Prusty /* Power up afg */ 17261b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 17271b377ccdSSubhransu S. Prusty AC_PWRST_D0); 1728e342ac08SSubhransu S. Prusty 1729e342ac08SSubhransu S. Prusty return 0; 1730e342ac08SSubhransu S. Prusty } 1731e342ac08SSubhransu S. Prusty #else 1732e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL 1733e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL 1734e342ac08SSubhransu S. Prusty #endif 1735e342ac08SSubhransu S. Prusty 1736e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = { 1737e342ac08SSubhransu S. Prusty SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) 17381b377ccdSSubhransu S. Prusty .prepare = hdmi_codec_prepare, 17390fee1798SSubhransu S. Prusty .complete = hdmi_codec_complete, 1740e342ac08SSubhransu S. Prusty }; 1741e342ac08SSubhransu S. Prusty 174218382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = { 174318382eadSSubhransu S. Prusty HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), 1744e2304803SJeeja KP HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), 1745cc216887SShreyas NC HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), 174618382eadSSubhransu S. Prusty {} 174718382eadSSubhransu S. Prusty }; 174818382eadSSubhransu S. Prusty 174918382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list); 175018382eadSSubhransu S. Prusty 175118382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = { 175218382eadSSubhransu S. Prusty . hdac = { 175318382eadSSubhransu S. Prusty .driver = { 175418382eadSSubhransu S. Prusty .name = "HDMI HDA Codec", 1755e342ac08SSubhransu S. Prusty .pm = &hdac_hdmi_pm, 175618382eadSSubhransu S. Prusty }, 175718382eadSSubhransu S. Prusty .id_table = hdmi_list, 175818382eadSSubhransu S. Prusty }, 175918382eadSSubhransu S. Prusty .probe = hdac_hdmi_dev_probe, 176018382eadSSubhransu S. Prusty .remove = hdac_hdmi_dev_remove, 176118382eadSSubhransu S. Prusty }; 176218382eadSSubhransu S. Prusty 176318382eadSSubhransu S. Prusty static int __init hdmi_init(void) 176418382eadSSubhransu S. Prusty { 176518382eadSSubhransu S. Prusty return snd_hda_ext_driver_register(&hdmi_driver); 176618382eadSSubhransu S. Prusty } 176718382eadSSubhransu S. Prusty 176818382eadSSubhransu S. Prusty static void __exit hdmi_exit(void) 176918382eadSSubhransu S. Prusty { 177018382eadSSubhransu S. Prusty snd_hda_ext_driver_unregister(&hdmi_driver); 177118382eadSSubhransu S. Prusty } 177218382eadSSubhransu S. Prusty 177318382eadSSubhransu S. Prusty module_init(hdmi_init); 177418382eadSSubhransu S. Prusty module_exit(hdmi_exit); 177518382eadSSubhransu S. Prusty 177618382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 177718382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec"); 177818382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); 177918382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); 1780