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 49*f6fa11a3SSandeep Tayal #define ELD_VER_CEA_861D 2 50*f6fa11a3SSandeep Tayal #define ELD_VER_PARTIAL 31 51*f6fa11a3SSandeep Tayal #define ELD_MAX_MNL 16 52*f6fa11a3SSandeep 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; 1004a3478deSJeeja KP }; 1014a3478deSJeeja KP 10218382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map { 10318382eadSSubhransu S. Prusty int dai_id; 10415b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 10515b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 10618382eadSSubhransu S. Prusty }; 10718382eadSSubhransu S. Prusty 10818382eadSSubhransu S. Prusty struct hdac_hdmi_priv { 109148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map dai_map[HDA_MAX_CVTS]; 11015b91447SSubhransu S. Prusty struct list_head pin_list; 11115b91447SSubhransu S. Prusty struct list_head cvt_list; 1124a3478deSJeeja KP struct list_head pcm_list; 11315b91447SSubhransu S. Prusty int num_pin; 11415b91447SSubhransu S. Prusty int num_cvt; 1154a3478deSJeeja KP struct mutex pin_mutex; 116bcced704SSubhransu S. Prusty struct hdac_chmap chmap; 11718382eadSSubhransu S. Prusty }; 11818382eadSSubhransu S. Prusty 1191de777feSJeeja KP static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, 1201de777feSJeeja KP struct hdac_hdmi_dai_pin_map *dai_map); 1211de777feSJeeja KP 1221de777feSJeeja KP static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, 1231de777feSJeeja KP struct hdac_hdmi_dai_pin_map *dai_map); 1241de777feSJeeja KP 1252889099eSSubhransu S. Prusty static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, 1262889099eSSubhransu S. Prusty int pcm_idx) 1272889099eSSubhransu S. Prusty { 1282889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm; 1292889099eSSubhransu S. Prusty 1302889099eSSubhransu S. Prusty list_for_each_entry(pcm, &hdmi->pcm_list, head) { 1312889099eSSubhransu S. Prusty if (pcm->pcm_id == pcm_idx) 1322889099eSSubhransu S. Prusty return pcm; 1332889099eSSubhransu S. Prusty } 1342889099eSSubhransu S. Prusty 1352889099eSSubhransu S. Prusty return NULL; 1362889099eSSubhransu S. Prusty } 1372889099eSSubhransu S. Prusty 138e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 139e342ac08SSubhransu S. Prusty { 14051b2c425SGeliang Tang struct hdac_device *hdac = dev_to_hdac_dev(dev); 141e342ac08SSubhransu S. Prusty 14251b2c425SGeliang Tang return to_ehdac_device(hdac); 143e342ac08SSubhransu S. Prusty } 144e342ac08SSubhransu S. Prusty 1452428bca3SSubhransu S. Prusty static unsigned int sad_format(const u8 *sad) 1462428bca3SSubhransu S. Prusty { 1472428bca3SSubhransu S. Prusty return ((sad[0] >> 0x3) & 0x1f); 1482428bca3SSubhransu S. Prusty } 1492428bca3SSubhransu S. Prusty 1502428bca3SSubhransu S. Prusty static unsigned int sad_sample_bits_lpcm(const u8 *sad) 1512428bca3SSubhransu S. Prusty { 1522428bca3SSubhransu S. Prusty return (sad[2] & 7); 1532428bca3SSubhransu S. Prusty } 1542428bca3SSubhransu S. Prusty 1552428bca3SSubhransu S. Prusty static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime, 1562428bca3SSubhransu S. Prusty void *eld) 1572428bca3SSubhransu S. Prusty { 1582428bca3SSubhransu S. Prusty u64 formats = SNDRV_PCM_FMTBIT_S16; 1592428bca3SSubhransu S. Prusty int i; 1602428bca3SSubhransu S. Prusty const u8 *sad, *eld_buf = eld; 1612428bca3SSubhransu S. Prusty 1622428bca3SSubhransu S. Prusty sad = drm_eld_sad(eld_buf); 1632428bca3SSubhransu S. Prusty if (!sad) 1642428bca3SSubhransu S. Prusty goto format_constraint; 1652428bca3SSubhransu S. Prusty 1662428bca3SSubhransu S. Prusty for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) { 1672428bca3SSubhransu S. Prusty if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */ 1682428bca3SSubhransu S. Prusty 1692428bca3SSubhransu S. Prusty /* 1702428bca3SSubhransu S. Prusty * the controller support 20 and 24 bits in 32 bit 1712428bca3SSubhransu S. Prusty * container so we set S32 1722428bca3SSubhransu S. Prusty */ 1732428bca3SSubhransu S. Prusty if (sad_sample_bits_lpcm(sad) & 0x6) 1742428bca3SSubhransu S. Prusty formats |= SNDRV_PCM_FMTBIT_S32; 1752428bca3SSubhransu S. Prusty } 1762428bca3SSubhransu S. Prusty } 1772428bca3SSubhransu S. Prusty 1782428bca3SSubhransu S. Prusty format_constraint: 1792428bca3SSubhransu S. Prusty return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, 1802428bca3SSubhransu S. Prusty formats); 1812428bca3SSubhransu S. Prusty 1822428bca3SSubhransu S. Prusty } 1832428bca3SSubhransu S. Prusty 184b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, 185b0362adbSSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid, 186b0362adbSSubhransu S. Prusty u32 stream_tag, int format) 187b0362adbSSubhransu S. Prusty { 188b0362adbSSubhransu S. Prusty unsigned int val; 189b0362adbSSubhransu S. Prusty 190b0362adbSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", 191b0362adbSSubhransu S. Prusty cvt_nid, pin_nid, stream_tag, format); 192b0362adbSSubhransu S. Prusty 193b0362adbSSubhransu S. Prusty val = (stream_tag << 4); 194b0362adbSSubhransu S. Prusty 195b0362adbSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 196b0362adbSSubhransu S. Prusty AC_VERB_SET_CHANNEL_STREAMID, val); 197b0362adbSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 198b0362adbSSubhransu S. Prusty AC_VERB_SET_STREAM_FORMAT, format); 199b0362adbSSubhransu S. Prusty 200b0362adbSSubhransu S. Prusty return 0; 201b0362adbSSubhransu S. Prusty } 202b0362adbSSubhransu S. Prusty 203a657f1d0SSubhransu S. Prusty static void 204a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, 205a657f1d0SSubhransu S. Prusty int packet_index, int byte_index) 206a657f1d0SSubhransu S. Prusty { 207a657f1d0SSubhransu S. Prusty int val; 208a657f1d0SSubhransu S. Prusty 209a657f1d0SSubhransu S. Prusty val = (packet_index << 5) | (byte_index & 0x1f); 210a657f1d0SSubhransu S. Prusty 211a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 212a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_INDEX, val); 213a657f1d0SSubhransu S. Prusty } 214a657f1d0SSubhransu S. Prusty 215478f544eSSubhransu S. Prusty struct dp_audio_infoframe { 216478f544eSSubhransu S. Prusty u8 type; /* 0x84 */ 217478f544eSSubhransu S. Prusty u8 len; /* 0x1b */ 218478f544eSSubhransu S. Prusty u8 ver; /* 0x11 << 2 */ 219478f544eSSubhransu S. Prusty 220478f544eSSubhransu S. Prusty u8 CC02_CT47; /* match with HDMI infoframe from this on */ 221478f544eSSubhransu S. Prusty u8 SS01_SF24; 222478f544eSSubhransu S. Prusty u8 CXT04; 223478f544eSSubhransu S. Prusty u8 CA; 224478f544eSSubhransu S. Prusty u8 LFEPBL01_LSV36_DM_INH7; 225478f544eSSubhransu S. Prusty }; 226478f544eSSubhransu S. Prusty 227a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, 228a657f1d0SSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid) 229a657f1d0SSubhransu S. Prusty { 230a657f1d0SSubhransu S. Prusty uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; 231a657f1d0SSubhransu S. Prusty struct hdmi_audio_infoframe frame; 232478f544eSSubhransu S. Prusty struct dp_audio_infoframe dp_ai; 233478f544eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 234478f544eSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 235478f544eSSubhransu S. Prusty u8 *dip; 236a657f1d0SSubhransu S. Prusty int ret; 237a657f1d0SSubhransu S. Prusty int i; 238478f544eSSubhransu S. Prusty const u8 *eld_buf; 239478f544eSSubhransu S. Prusty u8 conn_type; 240bcced704SSubhransu S. Prusty int channels, ca; 241a657f1d0SSubhransu S. Prusty 242478f544eSSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 243478f544eSSubhransu S. Prusty if (pin->nid == pin_nid) 244478f544eSSubhransu S. Prusty break; 245478f544eSSubhransu S. Prusty } 246a657f1d0SSubhransu S. Prusty 247bcced704SSubhransu S. Prusty ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, 248bcced704SSubhransu S. Prusty pin->channels, pin->chmap_set, true, pin->chmap); 249bcced704SSubhransu S. Prusty 250bcced704SSubhransu S. Prusty channels = snd_hdac_get_active_channels(ca); 251bcced704SSubhransu S. Prusty hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); 252bcced704SSubhransu S. Prusty 253bcced704SSubhransu S. Prusty snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, 254bcced704SSubhransu S. Prusty pin->channels, pin->chmap, pin->chmap_set); 255bcced704SSubhransu S. Prusty 256478f544eSSubhransu S. Prusty eld_buf = pin->eld.eld_buffer; 257478f544eSSubhransu S. Prusty conn_type = drm_eld_get_conn_type(eld_buf); 258a657f1d0SSubhransu S. Prusty 259478f544eSSubhransu S. Prusty switch (conn_type) { 260478f544eSSubhransu S. Prusty case DRM_ELD_CONN_TYPE_HDMI: 261478f544eSSubhransu S. Prusty hdmi_audio_infoframe_init(&frame); 262478f544eSSubhransu S. Prusty 263478f544eSSubhransu S. Prusty frame.channels = channels; 264bcced704SSubhransu S. Prusty frame.channel_allocation = ca; 265a657f1d0SSubhransu S. Prusty 266a657f1d0SSubhransu S. Prusty ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); 267a657f1d0SSubhransu S. Prusty if (ret < 0) 268a657f1d0SSubhransu S. Prusty return ret; 269a657f1d0SSubhransu S. Prusty 270478f544eSSubhransu S. Prusty break; 271478f544eSSubhransu S. Prusty 272478f544eSSubhransu S. Prusty case DRM_ELD_CONN_TYPE_DP: 273478f544eSSubhransu S. Prusty memset(&dp_ai, 0, sizeof(dp_ai)); 274478f544eSSubhransu S. Prusty dp_ai.type = 0x84; 275478f544eSSubhransu S. Prusty dp_ai.len = 0x1b; 276478f544eSSubhransu S. Prusty dp_ai.ver = 0x11 << 2; 277478f544eSSubhransu S. Prusty dp_ai.CC02_CT47 = channels - 1; 278bcced704SSubhransu S. Prusty dp_ai.CA = ca; 279478f544eSSubhransu S. Prusty 280478f544eSSubhransu S. Prusty dip = (u8 *)&dp_ai; 281478f544eSSubhransu S. Prusty break; 282478f544eSSubhransu S. Prusty 283478f544eSSubhransu S. Prusty default: 284478f544eSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Invalid connection type: %d\n", 285478f544eSSubhransu S. Prusty conn_type); 286478f544eSSubhransu S. Prusty return -EIO; 287478f544eSSubhransu S. Prusty } 288478f544eSSubhransu S. Prusty 289a657f1d0SSubhransu S. Prusty /* stop infoframe transmission */ 290a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 291a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 292a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); 293a657f1d0SSubhransu S. Prusty 294a657f1d0SSubhransu S. Prusty 295a657f1d0SSubhransu S. Prusty /* Fill infoframe. Index auto-incremented */ 296a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 297478f544eSSubhransu S. Prusty if (conn_type == DRM_ELD_CONN_TYPE_HDMI) { 298391005e8SSubhransu S. Prusty for (i = 0; i < sizeof(buffer); i++) 299a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 300391005e8SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, buffer[i]); 301478f544eSSubhransu S. Prusty } else { 302478f544eSSubhransu S. Prusty for (i = 0; i < sizeof(dp_ai); i++) 303478f544eSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 304478f544eSSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, dip[i]); 305478f544eSSubhransu S. Prusty } 306a657f1d0SSubhransu S. Prusty 307a657f1d0SSubhransu S. Prusty /* Start infoframe */ 308a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 309a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 310a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); 311a657f1d0SSubhransu S. Prusty 312a657f1d0SSubhransu S. Prusty return 0; 313a657f1d0SSubhransu S. Prusty } 314a657f1d0SSubhransu S. Prusty 315b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, 316b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) 317b0362adbSSubhransu S. Prusty { 318b0362adbSSubhransu S. Prusty /* Power up pin widget */ 31915b91447SSubhransu S. Prusty if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, 32015b91447SSubhransu S. Prusty pwr_state)) 32115b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, 322b0362adbSSubhransu S. Prusty AC_VERB_SET_POWER_STATE, pwr_state); 323b0362adbSSubhransu S. Prusty 324b0362adbSSubhransu S. Prusty /* Power up converter */ 32515b91447SSubhransu S. Prusty if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, 32615b91447SSubhransu S. Prusty pwr_state)) 32715b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 328b0362adbSSubhransu S. Prusty AC_VERB_SET_POWER_STATE, pwr_state); 329b0362adbSSubhransu S. Prusty } 330b0362adbSSubhransu S. Prusty 331b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, 332b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 333b0362adbSSubhransu S. Prusty { 334b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 335b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 336b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 337bcced704SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 338b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 339a657f1d0SSubhransu S. Prusty int ret; 340b0362adbSSubhransu S. Prusty 341b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 342bcced704SSubhransu S. Prusty pin = dai_map->pin; 343b0362adbSSubhransu S. Prusty 344b0362adbSSubhransu S. Prusty dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 345b0362adbSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", 346b0362adbSSubhransu S. Prusty dd->stream_tag, dd->format); 347b0362adbSSubhransu S. Prusty 3481de777feSJeeja KP hdac_hdmi_enable_cvt(hdac, dai_map); 3491de777feSJeeja KP ret = hdac_hdmi_enable_pin(hdac, dai_map); 3501de777feSJeeja KP if (ret < 0) 3511de777feSJeeja KP return ret; 352bcced704SSubhransu S. Prusty mutex_lock(&pin->lock); 353bcced704SSubhransu S. Prusty pin->channels = substream->runtime->channels; 354bcced704SSubhransu S. Prusty 35515b91447SSubhransu S. Prusty ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, 35615b91447SSubhransu S. Prusty dai_map->pin->nid); 357bcced704SSubhransu S. Prusty mutex_unlock(&pin->lock); 358a657f1d0SSubhransu S. Prusty if (ret < 0) 359a657f1d0SSubhransu S. Prusty return ret; 360a657f1d0SSubhransu S. Prusty 36115b91447SSubhransu S. Prusty return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, 36215b91447SSubhransu S. Prusty dai_map->pin->nid, dd->stream_tag, dd->format); 363b0362adbSSubhransu S. Prusty } 364b0362adbSSubhransu S. Prusty 365b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, 366b0362adbSSubhransu S. Prusty struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) 367b0362adbSSubhransu S. Prusty { 368b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 36954dfa1eaSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 37054dfa1eaSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 37154dfa1eaSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 372b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 373b0362adbSSubhransu S. Prusty 37454dfa1eaSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 37554dfa1eaSSubhransu S. Prusty pin = dai_map->pin; 37654dfa1eaSSubhransu S. Prusty 37754dfa1eaSSubhransu S. Prusty if (!pin) 37854dfa1eaSSubhransu S. Prusty return -ENODEV; 37954dfa1eaSSubhransu S. Prusty 38054dfa1eaSSubhransu S. Prusty if ((!pin->eld.monitor_present) || (!pin->eld.eld_valid)) { 38154dfa1eaSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "device is not configured for this pin: %d\n", 38254dfa1eaSSubhransu S. Prusty pin->nid); 383b0362adbSSubhransu S. Prusty return -ENODEV; 384b0362adbSSubhransu S. Prusty } 385b0362adbSSubhransu S. Prusty 3866793a3d7SSubhransu S. Prusty dd = snd_soc_dai_get_dma_data(dai, substream); 3876793a3d7SSubhransu S. Prusty if (!dd) { 388b0362adbSSubhransu S. Prusty dd = kzalloc(sizeof(*dd), GFP_KERNEL); 3898d33ab24SSudip Mukherjee if (!dd) 3908d33ab24SSudip Mukherjee return -ENOMEM; 3916793a3d7SSubhransu S. Prusty } 3926793a3d7SSubhransu S. Prusty 393b0362adbSSubhransu S. Prusty dd->format = snd_hdac_calc_stream_format(params_rate(hparams), 394b0362adbSSubhransu S. Prusty params_channels(hparams), params_format(hparams), 395b0362adbSSubhransu S. Prusty 24, 0); 396b0362adbSSubhransu S. Prusty 397b0362adbSSubhransu S. Prusty snd_soc_dai_set_dma_data(dai, substream, (void *)dd); 398b0362adbSSubhransu S. Prusty 399b0362adbSSubhransu S. Prusty return 0; 400b0362adbSSubhransu S. Prusty } 401b0362adbSSubhransu S. Prusty 402b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, 403b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 404b0362adbSSubhransu S. Prusty { 405b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 406b0362adbSSubhransu S. Prusty 407b0362adbSSubhransu S. Prusty dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 408b0362adbSSubhransu S. Prusty 4096793a3d7SSubhransu S. Prusty if (dd) { 4106793a3d7SSubhransu S. Prusty snd_soc_dai_set_dma_data(dai, substream, NULL); 411b0362adbSSubhransu S. Prusty kfree(dd); 4126793a3d7SSubhransu S. Prusty } 413b0362adbSSubhransu S. Prusty 414b0362adbSSubhransu S. Prusty return 0; 415b0362adbSSubhransu S. Prusty } 416b0362adbSSubhransu S. Prusty 417ab85f5b3SSubhransu S. Prusty static void hdac_hdmi_enable_cvt(struct hdac_ext_device *edev, 418ab85f5b3SSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map) 419ab85f5b3SSubhransu S. Prusty { 420ab85f5b3SSubhransu S. Prusty /* Enable transmission */ 421ab85f5b3SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 422ab85f5b3SSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_1, 1); 423ab85f5b3SSubhransu S. Prusty 424ab85f5b3SSubhransu S. Prusty /* Category Code (CC) to zero */ 425ab85f5b3SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 426ab85f5b3SSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_2, 0); 427ab85f5b3SSubhransu S. Prusty } 428ab85f5b3SSubhransu S. Prusty 429148569fdSSubhransu S. Prusty static int hdac_hdmi_enable_pin(struct hdac_ext_device *hdac, 430148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map) 431148569fdSSubhransu S. Prusty { 432148569fdSSubhransu S. Prusty int mux_idx; 433148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin = dai_map->pin; 434148569fdSSubhransu S. Prusty 435148569fdSSubhransu S. Prusty for (mux_idx = 0; mux_idx < pin->num_mux_nids; mux_idx++) { 436148569fdSSubhransu S. Prusty if (pin->mux_nids[mux_idx] == dai_map->cvt->nid) { 437148569fdSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 438148569fdSSubhransu S. Prusty AC_VERB_SET_CONNECT_SEL, mux_idx); 439148569fdSSubhransu S. Prusty break; 440148569fdSSubhransu S. Prusty } 441148569fdSSubhransu S. Prusty } 442148569fdSSubhransu S. Prusty 443148569fdSSubhransu S. Prusty if (mux_idx == pin->num_mux_nids) 444148569fdSSubhransu S. Prusty return -EIO; 445148569fdSSubhransu S. Prusty 446148569fdSSubhransu S. Prusty /* Enable out path for this pin widget */ 447148569fdSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 448148569fdSSubhransu S. Prusty AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 449148569fdSSubhransu S. Prusty 450148569fdSSubhransu S. Prusty hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); 451148569fdSSubhransu S. Prusty 452148569fdSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin->nid, 0, 453148569fdSSubhransu S. Prusty AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 454148569fdSSubhransu S. Prusty 455148569fdSSubhransu S. Prusty return 0; 456148569fdSSubhransu S. Prusty } 457148569fdSSubhransu S. Prusty 458148569fdSSubhransu S. Prusty static int hdac_hdmi_query_pin_connlist(struct hdac_ext_device *hdac, 459148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 460148569fdSSubhransu S. Prusty { 461148569fdSSubhransu S. Prusty if (!(get_wcaps(&hdac->hdac, pin->nid) & AC_WCAP_CONN_LIST)) { 462148569fdSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 463148569fdSSubhransu S. Prusty "HDMI: pin %d wcaps %#x does not support connection list\n", 464148569fdSSubhransu S. Prusty pin->nid, get_wcaps(&hdac->hdac, pin->nid)); 465148569fdSSubhransu S. Prusty return -EINVAL; 466148569fdSSubhransu S. Prusty } 467148569fdSSubhransu S. Prusty 468148569fdSSubhransu S. Prusty pin->num_mux_nids = snd_hdac_get_connections(&hdac->hdac, pin->nid, 469148569fdSSubhransu S. Prusty pin->mux_nids, HDA_MAX_CONNECTIONS); 470148569fdSSubhransu S. Prusty if (pin->num_mux_nids == 0) 471148569fdSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, "No connections found for pin: %d\n", 472148569fdSSubhransu S. Prusty pin->nid); 473148569fdSSubhransu S. Prusty 474148569fdSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "num_mux_nids %d for pin: %d\n", 475148569fdSSubhransu S. Prusty pin->num_mux_nids, pin->nid); 476148569fdSSubhransu S. Prusty 477148569fdSSubhransu S. Prusty return pin->num_mux_nids; 478148569fdSSubhransu S. Prusty } 479148569fdSSubhransu S. Prusty 480148569fdSSubhransu S. Prusty /* 481148569fdSSubhransu S. Prusty * Query pcm list and return pin widget to which stream is routed. 482148569fdSSubhransu S. Prusty * 483148569fdSSubhransu S. Prusty * Also query connection list of the pin, to validate the cvt to pin map. 484148569fdSSubhransu S. Prusty * 485148569fdSSubhransu S. Prusty * Same stream rendering to multiple pins simultaneously can be done 486148569fdSSubhransu S. Prusty * possibly, but not supported for now in driver. So return the first pin 487148569fdSSubhransu S. Prusty * connected. 488148569fdSSubhransu S. Prusty */ 489148569fdSSubhransu S. Prusty static struct hdac_hdmi_pin *hdac_hdmi_get_pin_from_cvt( 490148569fdSSubhransu S. Prusty struct hdac_ext_device *edev, 491148569fdSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi, 492148569fdSSubhransu S. Prusty struct hdac_hdmi_cvt *cvt) 493148569fdSSubhransu S. Prusty { 494148569fdSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm; 495148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin = NULL; 496148569fdSSubhransu S. Prusty int ret, i; 497148569fdSSubhransu S. Prusty 498148569fdSSubhransu S. Prusty list_for_each_entry(pcm, &hdmi->pcm_list, head) { 499148569fdSSubhransu S. Prusty if (pcm->cvt == cvt) { 500148569fdSSubhransu S. Prusty pin = pcm->pin; 501148569fdSSubhransu S. Prusty break; 502148569fdSSubhransu S. Prusty } 503148569fdSSubhransu S. Prusty } 504148569fdSSubhransu S. Prusty 505148569fdSSubhransu S. Prusty if (pin) { 506148569fdSSubhransu S. Prusty ret = hdac_hdmi_query_pin_connlist(edev, pin); 507148569fdSSubhransu S. Prusty if (ret < 0) 508148569fdSSubhransu S. Prusty return NULL; 509148569fdSSubhransu S. Prusty 510148569fdSSubhransu S. Prusty for (i = 0; i < pin->num_mux_nids; i++) { 511148569fdSSubhransu S. Prusty if (pin->mux_nids[i] == cvt->nid) 512148569fdSSubhransu S. Prusty return pin; 513148569fdSSubhransu S. Prusty } 514148569fdSSubhransu S. Prusty } 515148569fdSSubhransu S. Prusty 516148569fdSSubhransu S. Prusty return NULL; 517148569fdSSubhransu S. Prusty } 518148569fdSSubhransu S. Prusty 51954dfa1eaSSubhransu S. Prusty /* 52054dfa1eaSSubhransu S. Prusty * This tries to get a valid pin and set the HW constraints based on the 52154dfa1eaSSubhransu S. Prusty * ELD. Even if a valid pin is not found return success so that device open 52254dfa1eaSSubhransu S. Prusty * doesn't fail. 52354dfa1eaSSubhransu S. Prusty */ 524b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, 525b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 526b0362adbSSubhransu S. Prusty { 527b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 528b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 529b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 530148569fdSSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 531148569fdSSubhransu S. Prusty struct hdac_hdmi_pin *pin; 5322428bca3SSubhransu S. Prusty int ret; 533b0362adbSSubhransu S. Prusty 534b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 535b0362adbSSubhransu S. Prusty 536148569fdSSubhransu S. Prusty cvt = dai_map->cvt; 537148569fdSSubhransu S. Prusty pin = hdac_hdmi_get_pin_from_cvt(hdac, hdmi, cvt); 53854dfa1eaSSubhransu S. Prusty 53954dfa1eaSSubhransu S. Prusty /* 54054dfa1eaSSubhransu S. Prusty * To make PA and other userland happy. 54154dfa1eaSSubhransu S. Prusty * userland scans devices so returning error does not help. 54254dfa1eaSSubhransu S. Prusty */ 543148569fdSSubhransu S. Prusty if (!pin) 54454dfa1eaSSubhransu S. Prusty return 0; 545148569fdSSubhransu S. Prusty 546148569fdSSubhransu S. Prusty if ((!pin->eld.monitor_present) || 547148569fdSSubhransu S. Prusty (!pin->eld.eld_valid)) { 548b0362adbSSubhransu S. Prusty 54954dfa1eaSSubhransu S. Prusty dev_warn(&hdac->hdac.dev, 5503fb7b4e4SColin Ian King "Failed: monitor present? %d ELD valid?: %d for pin: %d\n", 551148569fdSSubhransu S. Prusty pin->eld.monitor_present, pin->eld.eld_valid, pin->nid); 552b8a54545SSubhransu S. Prusty 55354dfa1eaSSubhransu S. Prusty return 0; 554b0362adbSSubhransu S. Prusty } 555b0362adbSSubhransu S. Prusty 556148569fdSSubhransu S. Prusty dai_map->pin = pin; 557b0362adbSSubhransu S. Prusty 5582428bca3SSubhransu S. Prusty ret = hdac_hdmi_eld_limit_formats(substream->runtime, 559148569fdSSubhransu S. Prusty pin->eld.eld_buffer); 5602428bca3SSubhransu S. Prusty if (ret < 0) 5612428bca3SSubhransu S. Prusty return ret; 562b0362adbSSubhransu S. Prusty 5632428bca3SSubhransu S. Prusty return snd_pcm_hw_constraint_eld(substream->runtime, 564148569fdSSubhransu S. Prusty pin->eld.eld_buffer); 565b0362adbSSubhransu S. Prusty } 566b0362adbSSubhransu S. Prusty 567571d5078SJeeja KP static int hdac_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, 568571d5078SJeeja KP struct snd_soc_dai *dai) 569571d5078SJeeja KP { 570571d5078SJeeja KP 5711de777feSJeeja KP switch (cmd) { 5721de777feSJeeja KP case SNDRV_PCM_TRIGGER_RESUME: 5731de777feSJeeja KP case SNDRV_PCM_TRIGGER_START: 5741de777feSJeeja KP case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 575571d5078SJeeja KP return hdac_hdmi_playback_prepare(substream, dai); 5761de777feSJeeja KP 5771de777feSJeeja KP default: 5781de777feSJeeja KP return 0; 579571d5078SJeeja KP } 580571d5078SJeeja KP 581571d5078SJeeja KP return 0; 582571d5078SJeeja KP } 583571d5078SJeeja KP 584b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, 585b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 586b0362adbSSubhransu S. Prusty { 587b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 588b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 589b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 590b0362adbSSubhransu S. Prusty 591b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 592b0362adbSSubhransu S. Prusty 59354dfa1eaSSubhransu S. Prusty if (dai_map->pin) { 59454dfa1eaSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, 59554dfa1eaSSubhransu S. Prusty AC_VERB_SET_CHANNEL_STREAMID, 0); 59654dfa1eaSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->cvt->nid, 0, 59754dfa1eaSSubhransu S. Prusty AC_VERB_SET_STREAM_FORMAT, 0); 59854dfa1eaSSubhransu S. Prusty 599b0362adbSSubhransu S. Prusty hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); 600b0362adbSSubhransu S. Prusty 60115b91447SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, 602b0362adbSSubhransu S. Prusty AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 603148569fdSSubhransu S. Prusty 604bcced704SSubhransu S. Prusty mutex_lock(&dai_map->pin->lock); 6052889099eSSubhransu S. Prusty dai_map->pin->chmap_set = false; 6062889099eSSubhransu S. Prusty memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); 607bcced704SSubhransu S. Prusty dai_map->pin->channels = 0; 608bcced704SSubhransu S. Prusty mutex_unlock(&dai_map->pin->lock); 609bcced704SSubhransu S. Prusty 610148569fdSSubhransu S. Prusty dai_map->pin = NULL; 611b0362adbSSubhransu S. Prusty } 61254dfa1eaSSubhransu S. Prusty } 613b0362adbSSubhransu S. Prusty 61418382eadSSubhransu S. Prusty static int 61518382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 61618382eadSSubhransu S. Prusty { 617bcced704SSubhransu S. Prusty unsigned int chans; 618bcced704SSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 619bcced704SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 62018382eadSSubhransu S. Prusty int err; 62118382eadSSubhransu S. Prusty 622bcced704SSubhransu S. Prusty chans = get_wcaps(hdac, cvt->nid); 623bcced704SSubhransu S. Prusty chans = get_wcaps_channels(chans); 624bcced704SSubhransu S. Prusty 625bcced704SSubhransu S. Prusty cvt->params.channels_min = 2; 626bcced704SSubhransu S. Prusty 627bcced704SSubhransu S. Prusty cvt->params.channels_max = chans; 628bcced704SSubhransu S. Prusty if (chans > hdmi->chmap.channels_max) 629bcced704SSubhransu S. Prusty hdmi->chmap.channels_max = chans; 63018382eadSSubhransu S. Prusty 63118382eadSSubhransu S. Prusty err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 63218382eadSSubhransu S. Prusty &cvt->params.rates, 63318382eadSSubhransu S. Prusty &cvt->params.formats, 63418382eadSSubhransu S. Prusty &cvt->params.maxbps); 63518382eadSSubhransu S. Prusty if (err < 0) 63618382eadSSubhransu S. Prusty dev_err(&hdac->dev, 63718382eadSSubhransu S. Prusty "Failed to query pcm params for nid %d: %d\n", 63818382eadSSubhransu S. Prusty cvt->nid, err); 63918382eadSSubhransu S. Prusty 64018382eadSSubhransu S. Prusty return err; 64118382eadSSubhransu S. Prusty } 64218382eadSSubhransu S. Prusty 64379f4e922SSubhransu S. Prusty static int hdac_hdmi_fill_widget_info(struct device *dev, 64479f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *w, 64579f4e922SSubhransu S. Prusty enum snd_soc_dapm_type id, void *priv, 64679f4e922SSubhransu S. Prusty const char *wname, const char *stream, 64779f4e922SSubhransu S. Prusty struct snd_kcontrol_new *wc, int numkc) 64818382eadSSubhransu S. Prusty { 64918382eadSSubhransu S. Prusty w->id = id; 65079f4e922SSubhransu S. Prusty w->name = devm_kstrdup(dev, wname, GFP_KERNEL); 65179f4e922SSubhransu S. Prusty if (!w->name) 65279f4e922SSubhransu S. Prusty return -ENOMEM; 65379f4e922SSubhransu S. Prusty 65418382eadSSubhransu S. Prusty w->sname = stream; 65518382eadSSubhransu S. Prusty w->reg = SND_SOC_NOPM; 65618382eadSSubhransu S. Prusty w->shift = 0; 65779f4e922SSubhransu S. Prusty w->kcontrol_news = wc; 65879f4e922SSubhransu S. Prusty w->num_kcontrols = numkc; 65979f4e922SSubhransu S. Prusty w->priv = priv; 66079f4e922SSubhransu S. Prusty 66179f4e922SSubhransu S. Prusty return 0; 66218382eadSSubhransu S. Prusty } 66318382eadSSubhransu S. Prusty 66418382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 66579f4e922SSubhransu S. Prusty const char *sink, const char *control, const char *src, 66679f4e922SSubhransu S. Prusty int (*handler)(struct snd_soc_dapm_widget *src, 66779f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *sink)) 66818382eadSSubhransu S. Prusty { 66918382eadSSubhransu S. Prusty route->sink = sink; 67018382eadSSubhransu S. Prusty route->source = src; 67118382eadSSubhransu S. Prusty route->control = control; 67279f4e922SSubhransu S. Prusty route->connected = handler; 67318382eadSSubhransu S. Prusty } 67418382eadSSubhransu S. Prusty 6754a3478deSJeeja KP static struct hdac_hdmi_pcm *hdac_hdmi_get_pcm(struct hdac_ext_device *edev, 6764a3478deSJeeja KP struct hdac_hdmi_pin *pin) 6774a3478deSJeeja KP { 6784a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 6794a3478deSJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 6804a3478deSJeeja KP 6814a3478deSJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 6824a3478deSJeeja KP if (pcm->pin == pin) 6834a3478deSJeeja KP return pcm; 6844a3478deSJeeja KP } 6854a3478deSJeeja KP 6864a3478deSJeeja KP return NULL; 6874a3478deSJeeja KP } 6884a3478deSJeeja KP 6894a3478deSJeeja KP /* 6904a3478deSJeeja KP * Based on user selection, map the PINs with the PCMs. 6914a3478deSJeeja KP */ 6924a3478deSJeeja KP static int hdac_hdmi_set_pin_mux(struct snd_kcontrol *kcontrol, 6934a3478deSJeeja KP struct snd_ctl_elem_value *ucontrol) 6944a3478deSJeeja KP { 6954a3478deSJeeja KP int ret; 6964a3478deSJeeja KP struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 6974a3478deSJeeja KP struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); 6984a3478deSJeeja KP struct snd_soc_dapm_context *dapm = w->dapm; 6994a3478deSJeeja KP struct hdac_hdmi_pin *pin = w->priv; 7004a3478deSJeeja KP struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 7014a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 7024a3478deSJeeja KP struct hdac_hdmi_pcm *pcm = NULL; 7034a3478deSJeeja KP const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0]]; 7044a3478deSJeeja KP 7054a3478deSJeeja KP ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); 7064a3478deSJeeja KP if (ret < 0) 7074a3478deSJeeja KP return ret; 7084a3478deSJeeja KP 7094a3478deSJeeja KP mutex_lock(&hdmi->pin_mutex); 7104a3478deSJeeja KP list_for_each_entry(pcm, &hdmi->pcm_list, head) { 7114a3478deSJeeja KP if (pcm->pin == pin) 7124a3478deSJeeja KP pcm->pin = NULL; 7134a3478deSJeeja KP 7144a3478deSJeeja KP /* 7154a3478deSJeeja KP * Jack status is not reported during device probe as the 7164a3478deSJeeja KP * PCMs are not registered by then. So report it here. 7174a3478deSJeeja KP */ 7184a3478deSJeeja KP if (!strcmp(cvt_name, pcm->cvt->name) && !pcm->pin) { 7194a3478deSJeeja KP pcm->pin = pin; 7204a3478deSJeeja KP if (pin->eld.monitor_present && pin->eld.eld_valid) { 7214a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 7224a3478deSJeeja KP "jack report for pcm=%d\n", 7234a3478deSJeeja KP pcm->pcm_id); 7244a3478deSJeeja KP 7254a3478deSJeeja KP snd_jack_report(pcm->jack, SND_JACK_AVOUT); 7264a3478deSJeeja KP } 7274a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 7284a3478deSJeeja KP return ret; 7294a3478deSJeeja KP } 7304a3478deSJeeja KP } 7314a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 7324a3478deSJeeja KP 7334a3478deSJeeja KP return ret; 7344a3478deSJeeja KP } 7354a3478deSJeeja KP 73679f4e922SSubhransu S. Prusty /* 73779f4e922SSubhransu S. Prusty * Ideally the Mux inputs should be based on the num_muxs enumerated, but 73879f4e922SSubhransu S. Prusty * the display driver seem to be programming the connection list for the pin 73979f4e922SSubhransu S. Prusty * widget runtime. 74079f4e922SSubhransu S. Prusty * 74179f4e922SSubhransu S. Prusty * So programming all the possible inputs for the mux, the user has to take 74279f4e922SSubhransu S. Prusty * care of selecting the right one and leaving all other inputs selected to 74379f4e922SSubhransu S. Prusty * "NONE" 74479f4e922SSubhransu S. Prusty */ 74579f4e922SSubhransu S. Prusty static int hdac_hdmi_create_pin_muxs(struct hdac_ext_device *edev, 74679f4e922SSubhransu S. Prusty struct hdac_hdmi_pin *pin, 74779f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widget, 74879f4e922SSubhransu S. Prusty const char *widget_name) 74918382eadSSubhransu S. Prusty { 75079f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 75179f4e922SSubhransu S. Prusty struct snd_kcontrol_new *kc; 75279f4e922SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 75379f4e922SSubhransu S. Prusty struct soc_enum *se; 75479f4e922SSubhransu S. Prusty char kc_name[NAME_SIZE]; 75579f4e922SSubhransu S. Prusty char mux_items[NAME_SIZE]; 75679f4e922SSubhransu S. Prusty /* To hold inputs to the Pin mux */ 75779f4e922SSubhransu S. Prusty char *items[HDA_MAX_CONNECTIONS]; 75879f4e922SSubhransu S. Prusty int i = 0; 75979f4e922SSubhransu S. Prusty int num_items = hdmi->num_cvt + 1; 76018382eadSSubhransu S. Prusty 76179f4e922SSubhransu S. Prusty kc = devm_kzalloc(&edev->hdac.dev, sizeof(*kc), GFP_KERNEL); 76279f4e922SSubhransu S. Prusty if (!kc) 76379f4e922SSubhransu S. Prusty return -ENOMEM; 76418382eadSSubhransu S. Prusty 76579f4e922SSubhransu S. Prusty se = devm_kzalloc(&edev->hdac.dev, sizeof(*se), GFP_KERNEL); 76679f4e922SSubhransu S. Prusty if (!se) 76779f4e922SSubhransu S. Prusty return -ENOMEM; 76818382eadSSubhransu S. Prusty 76979f4e922SSubhransu S. Prusty sprintf(kc_name, "Pin %d Input", pin->nid); 77079f4e922SSubhransu S. Prusty kc->name = devm_kstrdup(&edev->hdac.dev, kc_name, GFP_KERNEL); 77179f4e922SSubhransu S. Prusty if (!kc->name) 77279f4e922SSubhransu S. Prusty return -ENOMEM; 77318382eadSSubhransu S. Prusty 77479f4e922SSubhransu S. Prusty kc->private_value = (long)se; 77579f4e922SSubhransu S. Prusty kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; 77679f4e922SSubhransu S. Prusty kc->access = 0; 77779f4e922SSubhransu S. Prusty kc->info = snd_soc_info_enum_double; 7784a3478deSJeeja KP kc->put = hdac_hdmi_set_pin_mux; 77979f4e922SSubhransu S. Prusty kc->get = snd_soc_dapm_get_enum_double; 78079f4e922SSubhransu S. Prusty 78179f4e922SSubhransu S. Prusty se->reg = SND_SOC_NOPM; 78279f4e922SSubhransu S. Prusty 78379f4e922SSubhransu S. Prusty /* enum texts: ["NONE", "cvt #", "cvt #", ...] */ 78479f4e922SSubhransu S. Prusty se->items = num_items; 78579f4e922SSubhransu S. Prusty se->mask = roundup_pow_of_two(se->items) - 1; 78679f4e922SSubhransu S. Prusty 78779f4e922SSubhransu S. Prusty sprintf(mux_items, "NONE"); 78879f4e922SSubhransu S. Prusty items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); 78979f4e922SSubhransu S. Prusty if (!items[i]) 79079f4e922SSubhransu S. Prusty return -ENOMEM; 79179f4e922SSubhransu S. Prusty 79279f4e922SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 79379f4e922SSubhransu S. Prusty i++; 79479f4e922SSubhransu S. Prusty sprintf(mux_items, "cvt %d", cvt->nid); 79579f4e922SSubhransu S. Prusty items[i] = devm_kstrdup(&edev->hdac.dev, mux_items, GFP_KERNEL); 79679f4e922SSubhransu S. Prusty if (!items[i]) 79779f4e922SSubhransu S. Prusty return -ENOMEM; 79879f4e922SSubhransu S. Prusty } 79979f4e922SSubhransu S. Prusty 80079f4e922SSubhransu S. Prusty se->texts = devm_kmemdup(&edev->hdac.dev, items, 80179f4e922SSubhransu S. Prusty (num_items * sizeof(char *)), GFP_KERNEL); 80279f4e922SSubhransu S. Prusty if (!se->texts) 80379f4e922SSubhransu S. Prusty return -ENOMEM; 80479f4e922SSubhransu S. Prusty 80579f4e922SSubhransu S. Prusty return hdac_hdmi_fill_widget_info(&edev->hdac.dev, widget, 8064a3478deSJeeja KP snd_soc_dapm_mux, pin, widget_name, NULL, kc, 1); 80779f4e922SSubhransu S. Prusty } 80879f4e922SSubhransu S. Prusty 80979f4e922SSubhransu S. Prusty /* Add cvt <- input <- mux route map */ 81079f4e922SSubhransu S. Prusty static void hdac_hdmi_add_pinmux_cvt_route(struct hdac_ext_device *edev, 81179f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widgets, 81279f4e922SSubhransu S. Prusty struct snd_soc_dapm_route *route, int rindex) 81379f4e922SSubhransu S. Prusty { 81479f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 81579f4e922SSubhransu S. Prusty const struct snd_kcontrol_new *kc; 81679f4e922SSubhransu S. Prusty struct soc_enum *se; 81779f4e922SSubhransu S. Prusty int mux_index = hdmi->num_cvt + hdmi->num_pin; 81879f4e922SSubhransu S. Prusty int i, j; 81979f4e922SSubhransu S. Prusty 82079f4e922SSubhransu S. Prusty for (i = 0; i < hdmi->num_pin; i++) { 82179f4e922SSubhransu S. Prusty kc = widgets[mux_index].kcontrol_news; 82279f4e922SSubhransu S. Prusty se = (struct soc_enum *)kc->private_value; 82379f4e922SSubhransu S. Prusty for (j = 0; j < hdmi->num_cvt; j++) { 82479f4e922SSubhransu S. Prusty hdac_hdmi_fill_route(&route[rindex], 82579f4e922SSubhransu S. Prusty widgets[mux_index].name, 82679f4e922SSubhransu S. Prusty se->texts[j + 1], 82779f4e922SSubhransu S. Prusty widgets[j].name, NULL); 82879f4e922SSubhransu S. Prusty 82979f4e922SSubhransu S. Prusty rindex++; 83079f4e922SSubhransu S. Prusty } 83179f4e922SSubhransu S. Prusty 83279f4e922SSubhransu S. Prusty mux_index++; 83379f4e922SSubhransu S. Prusty } 83479f4e922SSubhransu S. Prusty } 83579f4e922SSubhransu S. Prusty 83679f4e922SSubhransu S. Prusty /* 83779f4e922SSubhransu S. Prusty * Widgets are added in the below sequence 83879f4e922SSubhransu S. Prusty * Converter widgets for num converters enumerated 83979f4e922SSubhransu S. Prusty * Pin widgets for num pins enumerated 84079f4e922SSubhransu S. Prusty * Pin mux widgets to represent connenction list of pin widget 84179f4e922SSubhransu S. Prusty * 84279f4e922SSubhransu S. Prusty * Total widgets elements = num_cvt + num_pin + num_pin; 84379f4e922SSubhransu S. Prusty * 84479f4e922SSubhransu S. Prusty * Routes are added as below: 84579f4e922SSubhransu S. Prusty * pin mux -> pin (based on num_pins) 84679f4e922SSubhransu S. Prusty * cvt -> "Input sel control" -> pin_mux 84779f4e922SSubhransu S. Prusty * 84879f4e922SSubhransu S. Prusty * Total route elements: 84979f4e922SSubhransu S. Prusty * num_pins + (pin_muxes * num_cvt) 85079f4e922SSubhransu S. Prusty */ 85179f4e922SSubhransu S. Prusty static int create_fill_widget_route_map(struct snd_soc_dapm_context *dapm) 85279f4e922SSubhransu S. Prusty { 85379f4e922SSubhransu S. Prusty struct snd_soc_dapm_widget *widgets; 85479f4e922SSubhransu S. Prusty struct snd_soc_dapm_route *route; 85579f4e922SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dapm->dev); 85679f4e922SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 85779f4e922SSubhransu S. Prusty struct snd_soc_dai_driver *dai_drv = dapm->component->dai_drv; 85879f4e922SSubhransu S. Prusty char widget_name[NAME_SIZE]; 85979f4e922SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 86079f4e922SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 86179f4e922SSubhransu S. Prusty int ret, i = 0, num_routes = 0; 86279f4e922SSubhransu S. Prusty 86379f4e922SSubhransu S. Prusty if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) 86479f4e922SSubhransu S. Prusty return -EINVAL; 86579f4e922SSubhransu S. Prusty 86679f4e922SSubhransu S. Prusty widgets = devm_kzalloc(dapm->dev, 86779f4e922SSubhransu S. Prusty (sizeof(*widgets) * ((2 * hdmi->num_pin) + hdmi->num_cvt)), 86879f4e922SSubhransu S. Prusty GFP_KERNEL); 86979f4e922SSubhransu S. Prusty 87079f4e922SSubhransu S. Prusty if (!widgets) 87179f4e922SSubhransu S. Prusty return -ENOMEM; 87279f4e922SSubhransu S. Prusty 87379f4e922SSubhransu S. Prusty /* DAPM widgets to represent each converter widget */ 87479f4e922SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 87579f4e922SSubhransu S. Prusty sprintf(widget_name, "Converter %d", cvt->nid); 87679f4e922SSubhransu S. Prusty ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], 87779f4e922SSubhransu S. Prusty snd_soc_dapm_aif_in, &cvt->nid, 87879f4e922SSubhransu S. Prusty widget_name, dai_drv[i].playback.stream_name, NULL, 0); 87979f4e922SSubhransu S. Prusty if (ret < 0) 88079f4e922SSubhransu S. Prusty return ret; 88179f4e922SSubhransu S. Prusty i++; 88279f4e922SSubhransu S. Prusty } 88379f4e922SSubhransu S. Prusty 88479f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 88579f4e922SSubhransu S. Prusty sprintf(widget_name, "hif%d Output", pin->nid); 88679f4e922SSubhransu S. Prusty ret = hdac_hdmi_fill_widget_info(dapm->dev, &widgets[i], 88779f4e922SSubhransu S. Prusty snd_soc_dapm_output, &pin->nid, 88879f4e922SSubhransu S. Prusty widget_name, NULL, NULL, 0); 88979f4e922SSubhransu S. Prusty if (ret < 0) 89079f4e922SSubhransu S. Prusty return ret; 89179f4e922SSubhransu S. Prusty i++; 89279f4e922SSubhransu S. Prusty } 89379f4e922SSubhransu S. Prusty 89479f4e922SSubhransu S. Prusty /* DAPM widgets to represent the connection list to pin widget */ 89579f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 89679f4e922SSubhransu S. Prusty sprintf(widget_name, "Pin %d Mux", pin->nid); 89779f4e922SSubhransu S. Prusty ret = hdac_hdmi_create_pin_muxs(edev, pin, &widgets[i], 89879f4e922SSubhransu S. Prusty widget_name); 89979f4e922SSubhransu S. Prusty if (ret < 0) 90079f4e922SSubhransu S. Prusty return ret; 90179f4e922SSubhransu S. Prusty i++; 90279f4e922SSubhransu S. Prusty 90379f4e922SSubhransu S. Prusty /* For cvt to pin_mux mapping */ 90479f4e922SSubhransu S. Prusty num_routes += hdmi->num_cvt; 90579f4e922SSubhransu S. Prusty 90679f4e922SSubhransu S. Prusty /* For pin_mux to pin mapping */ 90779f4e922SSubhransu S. Prusty num_routes++; 90879f4e922SSubhransu S. Prusty } 90979f4e922SSubhransu S. Prusty 91079f4e922SSubhransu S. Prusty route = devm_kzalloc(dapm->dev, (sizeof(*route) * num_routes), 91179f4e922SSubhransu S. Prusty GFP_KERNEL); 91279f4e922SSubhransu S. Prusty if (!route) 91379f4e922SSubhransu S. Prusty return -ENOMEM; 91479f4e922SSubhransu S. Prusty 91579f4e922SSubhransu S. Prusty i = 0; 91679f4e922SSubhransu S. Prusty /* Add pin <- NULL <- mux route map */ 91779f4e922SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 91879f4e922SSubhransu S. Prusty int sink_index = i + hdmi->num_cvt; 91979f4e922SSubhransu S. Prusty int src_index = sink_index + hdmi->num_pin; 92079f4e922SSubhransu S. Prusty 92179f4e922SSubhransu S. Prusty hdac_hdmi_fill_route(&route[i], 92279f4e922SSubhransu S. Prusty widgets[sink_index].name, NULL, 92379f4e922SSubhransu S. Prusty widgets[src_index].name, NULL); 92479f4e922SSubhransu S. Prusty i++; 92579f4e922SSubhransu S. Prusty 92679f4e922SSubhransu S. Prusty } 92779f4e922SSubhransu S. Prusty 92879f4e922SSubhransu S. Prusty hdac_hdmi_add_pinmux_cvt_route(edev, widgets, route, i); 92979f4e922SSubhransu S. Prusty 93079f4e922SSubhransu S. Prusty snd_soc_dapm_new_controls(dapm, widgets, 93179f4e922SSubhransu S. Prusty ((2 * hdmi->num_pin) + hdmi->num_cvt)); 93279f4e922SSubhransu S. Prusty 93379f4e922SSubhransu S. Prusty snd_soc_dapm_add_routes(dapm, route, num_routes); 93479f4e922SSubhransu S. Prusty snd_soc_dapm_new_widgets(dapm->card); 93579f4e922SSubhransu S. Prusty 93679f4e922SSubhransu S. Prusty return 0; 93779f4e922SSubhransu S. Prusty 93818382eadSSubhransu S. Prusty } 93918382eadSSubhransu S. Prusty 94015b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) 94118382eadSSubhransu S. Prusty { 94215b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 943148569fdSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 94415b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 945148569fdSSubhransu S. Prusty int dai_id = 0; 94618382eadSSubhransu S. Prusty 947148569fdSSubhransu S. Prusty if (list_empty(&hdmi->cvt_list)) 94815b91447SSubhransu S. Prusty return -EINVAL; 94918382eadSSubhransu S. Prusty 950148569fdSSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 951148569fdSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai_id]; 952148569fdSSubhransu S. Prusty dai_map->dai_id = dai_id; 95315b91447SSubhransu S. Prusty dai_map->cvt = cvt; 95418382eadSSubhransu S. Prusty 955148569fdSSubhransu S. Prusty dai_id++; 956148569fdSSubhransu S. Prusty 957148569fdSSubhransu S. Prusty if (dai_id == HDA_MAX_CVTS) { 958148569fdSSubhransu S. Prusty dev_warn(&edev->hdac.dev, 959148569fdSSubhransu S. Prusty "Max dais supported: %d\n", dai_id); 960148569fdSSubhransu S. Prusty break; 961148569fdSSubhransu S. Prusty } 962148569fdSSubhransu S. Prusty } 96318382eadSSubhransu S. Prusty 96415b91447SSubhransu S. Prusty return 0; 96515b91447SSubhransu S. Prusty } 96615b91447SSubhransu S. Prusty 96715b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) 96815b91447SSubhransu S. Prusty { 96915b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 97015b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 9714a3478deSJeeja KP char name[NAME_SIZE]; 97215b91447SSubhransu S. Prusty 97315b91447SSubhransu S. Prusty cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); 97415b91447SSubhransu S. Prusty if (!cvt) 97515b91447SSubhransu S. Prusty return -ENOMEM; 97615b91447SSubhransu S. Prusty 97715b91447SSubhransu S. Prusty cvt->nid = nid; 9784a3478deSJeeja KP sprintf(name, "cvt %d", cvt->nid); 9794a3478deSJeeja KP cvt->name = kstrdup(name, GFP_KERNEL); 98015b91447SSubhransu S. Prusty 98115b91447SSubhransu S. Prusty list_add_tail(&cvt->head, &hdmi->cvt_list); 98215b91447SSubhransu S. Prusty hdmi->num_cvt++; 98315b91447SSubhransu S. Prusty 98415b91447SSubhransu S. Prusty return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); 98515b91447SSubhransu S. Prusty } 98615b91447SSubhransu S. Prusty 987*f6fa11a3SSandeep Tayal static int hdac_hdmi_parse_eld(struct hdac_ext_device *edev, 988b7756edeSSubhransu S. Prusty struct hdac_hdmi_pin *pin) 989b7756edeSSubhransu S. Prusty { 990*f6fa11a3SSandeep Tayal unsigned int ver, mnl; 991*f6fa11a3SSandeep Tayal 992*f6fa11a3SSandeep Tayal ver = (pin->eld.eld_buffer[DRM_ELD_VER] & DRM_ELD_VER_MASK) 993*f6fa11a3SSandeep Tayal >> DRM_ELD_VER_SHIFT; 994*f6fa11a3SSandeep Tayal 995*f6fa11a3SSandeep Tayal if (ver != ELD_VER_CEA_861D && ver != ELD_VER_PARTIAL) { 996*f6fa11a3SSandeep Tayal dev_err(&edev->hdac.dev, "HDMI: Unknown ELD version %d\n", ver); 997*f6fa11a3SSandeep Tayal return -EINVAL; 998b7756edeSSubhransu S. Prusty } 999b7756edeSSubhransu S. Prusty 1000*f6fa11a3SSandeep Tayal mnl = (pin->eld.eld_buffer[DRM_ELD_CEA_EDID_VER_MNL] & 1001*f6fa11a3SSandeep Tayal DRM_ELD_MNL_MASK) >> DRM_ELD_MNL_SHIFT; 1002*f6fa11a3SSandeep Tayal 1003*f6fa11a3SSandeep Tayal if (mnl > ELD_MAX_MNL) { 1004*f6fa11a3SSandeep Tayal dev_err(&edev->hdac.dev, "HDMI: MNL Invalid %d\n", mnl); 1005*f6fa11a3SSandeep Tayal return -EINVAL; 1006*f6fa11a3SSandeep Tayal } 1007*f6fa11a3SSandeep Tayal 1008*f6fa11a3SSandeep Tayal pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; 1009*f6fa11a3SSandeep Tayal 1010*f6fa11a3SSandeep Tayal return 0; 1011*f6fa11a3SSandeep Tayal } 1012*f6fa11a3SSandeep Tayal 1013*f6fa11a3SSandeep Tayal static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin) 1014b8a54545SSubhransu S. Prusty { 1015b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = pin->edev; 10164a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 10174a3478deSJeeja KP struct hdac_hdmi_pcm *pcm; 1018*f6fa11a3SSandeep Tayal int size; 10194a3478deSJeeja KP 10204a3478deSJeeja KP mutex_lock(&hdmi->pin_mutex); 1021*f6fa11a3SSandeep Tayal pin->eld.monitor_present = false; 1022*f6fa11a3SSandeep Tayal 1023*f6fa11a3SSandeep Tayal size = snd_hdac_acomp_get_eld(&edev->hdac, pin->nid, -1, 1024*f6fa11a3SSandeep Tayal &pin->eld.monitor_present, pin->eld.eld_buffer, 1025*f6fa11a3SSandeep Tayal ELD_MAX_SIZE); 1026*f6fa11a3SSandeep Tayal 1027*f6fa11a3SSandeep Tayal if (size > 0) { 1028*f6fa11a3SSandeep Tayal size = min(size, ELD_MAX_SIZE); 1029*f6fa11a3SSandeep Tayal if (hdac_hdmi_parse_eld(edev, pin) < 0) 1030*f6fa11a3SSandeep Tayal size = -EINVAL; 1031*f6fa11a3SSandeep Tayal } 1032*f6fa11a3SSandeep Tayal 1033*f6fa11a3SSandeep Tayal if (size > 0) { 1034*f6fa11a3SSandeep Tayal pin->eld.eld_valid = true; 1035*f6fa11a3SSandeep Tayal pin->eld.eld_size = size; 1036*f6fa11a3SSandeep Tayal } else { 1037*f6fa11a3SSandeep Tayal pin->eld.eld_valid = false; 1038*f6fa11a3SSandeep Tayal pin->eld.eld_size = 0; 1039*f6fa11a3SSandeep Tayal } 1040b8a54545SSubhransu S. Prusty 10414a3478deSJeeja KP pcm = hdac_hdmi_get_pcm(edev, pin); 10424a3478deSJeeja KP 1043b8a54545SSubhransu S. Prusty if (!pin->eld.monitor_present || !pin->eld.eld_valid) { 1044b8a54545SSubhransu S. Prusty 1045b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", 1046b8a54545SSubhransu S. Prusty __func__, pin->nid); 10474a3478deSJeeja KP 10484a3478deSJeeja KP /* 10494a3478deSJeeja KP * PCMs are not registered during device probe, so don't 10504a3478deSJeeja KP * report jack here. It will be done in usermode mux 10514a3478deSJeeja KP * control select. 10524a3478deSJeeja KP */ 10534a3478deSJeeja KP if (pcm) { 10544a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 10554a3478deSJeeja KP "jack report for pcm=%d\n", pcm->pcm_id); 10564a3478deSJeeja KP 10574a3478deSJeeja KP snd_jack_report(pcm->jack, 0); 10584a3478deSJeeja KP } 10594a3478deSJeeja KP 10604a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 1061*f6fa11a3SSandeep Tayal return; 1062b8a54545SSubhransu S. Prusty } 1063b8a54545SSubhransu S. Prusty 1064b8a54545SSubhransu S. Prusty if (pin->eld.monitor_present && pin->eld.eld_valid) { 10654a3478deSJeeja KP if (pcm) { 10664a3478deSJeeja KP dev_dbg(&edev->hdac.dev, 10674a3478deSJeeja KP "jack report for pcm=%d\n", 10684a3478deSJeeja KP pcm->pcm_id); 10694a3478deSJeeja KP 10704a3478deSJeeja KP snd_jack_report(pcm->jack, SND_JACK_AVOUT); 10714a3478deSJeeja KP } 10724a3478deSJeeja KP 1073*f6fa11a3SSandeep Tayal print_hex_dump_debug("ELD: ", DUMP_PREFIX_OFFSET, 16, 1, 1074*f6fa11a3SSandeep Tayal pin->eld.eld_buffer, pin->eld.eld_size, false); 10754a3478deSJeeja KP } 10764a3478deSJeeja KP 10774a3478deSJeeja KP mutex_unlock(&hdmi->pin_mutex); 1078b8a54545SSubhransu S. Prusty } 1079b8a54545SSubhransu S. Prusty 108015b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) 108115b91447SSubhransu S. Prusty { 108215b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 108315b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 108415b91447SSubhransu S. Prusty 108515b91447SSubhransu S. Prusty pin = kzalloc(sizeof(*pin), GFP_KERNEL); 108615b91447SSubhransu S. Prusty if (!pin) 108715b91447SSubhransu S. Prusty return -ENOMEM; 108815b91447SSubhransu S. Prusty 108915b91447SSubhransu S. Prusty pin->nid = nid; 109015b91447SSubhransu S. Prusty 109115b91447SSubhransu S. Prusty list_add_tail(&pin->head, &hdmi->pin_list); 109215b91447SSubhransu S. Prusty hdmi->num_pin++; 109315b91447SSubhransu S. Prusty 1094b8a54545SSubhransu S. Prusty pin->edev = edev; 1095bcced704SSubhransu S. Prusty mutex_init(&pin->lock); 1096b8a54545SSubhransu S. Prusty 109715b91447SSubhransu S. Prusty return 0; 109818382eadSSubhransu S. Prusty } 109918382eadSSubhransu S. Prusty 1100211caab7SSubhransu S. Prusty #define INTEL_VENDOR_NID 0x08 1101211caab7SSubhransu S. Prusty #define INTEL_GET_VENDOR_VERB 0xf81 1102211caab7SSubhransu S. Prusty #define INTEL_SET_VENDOR_VERB 0x781 1103211caab7SSubhransu S. Prusty #define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ 1104211caab7SSubhransu S. Prusty #define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ 1105211caab7SSubhransu S. Prusty 1106211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_all_pins(struct hdac_device *hdac) 1107211caab7SSubhransu S. Prusty { 1108211caab7SSubhransu S. Prusty unsigned int vendor_param; 1109211caab7SSubhransu S. Prusty 1110211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1111211caab7SSubhransu S. Prusty INTEL_GET_VENDOR_VERB, 0); 1112211caab7SSubhransu S. Prusty if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) 1113211caab7SSubhransu S. Prusty return; 1114211caab7SSubhransu S. Prusty 1115211caab7SSubhransu S. Prusty vendor_param |= INTEL_EN_ALL_PIN_CVTS; 1116211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1117211caab7SSubhransu S. Prusty INTEL_SET_VENDOR_VERB, vendor_param); 1118211caab7SSubhransu S. Prusty if (vendor_param == -1) 1119211caab7SSubhransu S. Prusty return; 1120211caab7SSubhransu S. Prusty } 1121211caab7SSubhransu S. Prusty 1122211caab7SSubhransu S. Prusty static void hdac_hdmi_skl_enable_dp12(struct hdac_device *hdac) 1123211caab7SSubhransu S. Prusty { 1124211caab7SSubhransu S. Prusty unsigned int vendor_param; 1125211caab7SSubhransu S. Prusty 1126211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1127211caab7SSubhransu S. Prusty INTEL_GET_VENDOR_VERB, 0); 1128211caab7SSubhransu S. Prusty if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) 1129211caab7SSubhransu S. Prusty return; 1130211caab7SSubhransu S. Prusty 1131211caab7SSubhransu S. Prusty /* enable DP1.2 mode */ 1132211caab7SSubhransu S. Prusty vendor_param |= INTEL_EN_DP12; 1133211caab7SSubhransu S. Prusty vendor_param = snd_hdac_codec_read(hdac, INTEL_VENDOR_NID, 0, 1134211caab7SSubhransu S. Prusty INTEL_SET_VENDOR_VERB, vendor_param); 1135211caab7SSubhransu S. Prusty if (vendor_param == -1) 1136211caab7SSubhransu S. Prusty return; 1137211caab7SSubhransu S. Prusty 1138211caab7SSubhransu S. Prusty } 1139211caab7SSubhransu S. Prusty 114017a42c45SSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = { 114117a42c45SSubhransu S. Prusty .startup = hdac_hdmi_pcm_open, 114217a42c45SSubhransu S. Prusty .shutdown = hdac_hdmi_pcm_close, 114317a42c45SSubhransu S. Prusty .hw_params = hdac_hdmi_set_hw_params, 114417a42c45SSubhransu S. Prusty .prepare = hdac_hdmi_playback_prepare, 1145571d5078SJeeja KP .trigger = hdac_hdmi_trigger, 114617a42c45SSubhransu S. Prusty .hw_free = hdac_hdmi_playback_cleanup, 114717a42c45SSubhransu S. Prusty }; 114817a42c45SSubhransu S. Prusty 114917a42c45SSubhransu S. Prusty /* 115017a42c45SSubhransu S. Prusty * Each converter can support a stream independently. So a dai is created 115117a42c45SSubhransu S. Prusty * based on the number of converter queried. 115217a42c45SSubhransu S. Prusty */ 115317a42c45SSubhransu S. Prusty static int hdac_hdmi_create_dais(struct hdac_device *hdac, 115417a42c45SSubhransu S. Prusty struct snd_soc_dai_driver **dais, 115517a42c45SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi, int num_dais) 115617a42c45SSubhransu S. Prusty { 115717a42c45SSubhransu S. Prusty struct snd_soc_dai_driver *hdmi_dais; 115817a42c45SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 115917a42c45SSubhransu S. Prusty char name[NAME_SIZE], dai_name[NAME_SIZE]; 116017a42c45SSubhransu S. Prusty int i = 0; 116117a42c45SSubhransu S. Prusty u32 rates, bps; 116217a42c45SSubhransu S. Prusty unsigned int rate_max = 384000, rate_min = 8000; 116317a42c45SSubhransu S. Prusty u64 formats; 116417a42c45SSubhransu S. Prusty int ret; 116517a42c45SSubhransu S. Prusty 116617a42c45SSubhransu S. Prusty hdmi_dais = devm_kzalloc(&hdac->dev, 116717a42c45SSubhransu S. Prusty (sizeof(*hdmi_dais) * num_dais), 116817a42c45SSubhransu S. Prusty GFP_KERNEL); 116917a42c45SSubhransu S. Prusty if (!hdmi_dais) 117017a42c45SSubhransu S. Prusty return -ENOMEM; 117117a42c45SSubhransu S. Prusty 117217a42c45SSubhransu S. Prusty list_for_each_entry(cvt, &hdmi->cvt_list, head) { 117317a42c45SSubhransu S. Prusty ret = snd_hdac_query_supported_pcm(hdac, cvt->nid, 117417a42c45SSubhransu S. Prusty &rates, &formats, &bps); 117517a42c45SSubhransu S. Prusty if (ret) 117617a42c45SSubhransu S. Prusty return ret; 117717a42c45SSubhransu S. Prusty 117817a42c45SSubhransu S. Prusty sprintf(dai_name, "intel-hdmi-hifi%d", i+1); 117917a42c45SSubhransu S. Prusty hdmi_dais[i].name = devm_kstrdup(&hdac->dev, 118017a42c45SSubhransu S. Prusty dai_name, GFP_KERNEL); 118117a42c45SSubhransu S. Prusty 118217a42c45SSubhransu S. Prusty if (!hdmi_dais[i].name) 118317a42c45SSubhransu S. Prusty return -ENOMEM; 118417a42c45SSubhransu S. Prusty 118517a42c45SSubhransu S. Prusty snprintf(name, sizeof(name), "hifi%d", i+1); 118617a42c45SSubhransu S. Prusty hdmi_dais[i].playback.stream_name = 118717a42c45SSubhransu S. Prusty devm_kstrdup(&hdac->dev, name, GFP_KERNEL); 118817a42c45SSubhransu S. Prusty if (!hdmi_dais[i].playback.stream_name) 118917a42c45SSubhransu S. Prusty return -ENOMEM; 119017a42c45SSubhransu S. Prusty 119117a42c45SSubhransu S. Prusty /* 119217a42c45SSubhransu S. Prusty * Set caps based on capability queried from the converter. 119317a42c45SSubhransu S. Prusty * It will be constrained runtime based on ELD queried. 119417a42c45SSubhransu S. Prusty */ 119517a42c45SSubhransu S. Prusty hdmi_dais[i].playback.formats = formats; 119617a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rates = rates; 119717a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rate_max = rate_max; 119817a42c45SSubhransu S. Prusty hdmi_dais[i].playback.rate_min = rate_min; 119917a42c45SSubhransu S. Prusty hdmi_dais[i].playback.channels_min = 2; 120017a42c45SSubhransu S. Prusty hdmi_dais[i].playback.channels_max = 2; 120117a42c45SSubhransu S. Prusty hdmi_dais[i].ops = &hdmi_dai_ops; 120217a42c45SSubhransu S. Prusty 120317a42c45SSubhransu S. Prusty i++; 120417a42c45SSubhransu S. Prusty } 120517a42c45SSubhransu S. Prusty 120617a42c45SSubhransu S. Prusty *dais = hdmi_dais; 120717a42c45SSubhransu S. Prusty 120817a42c45SSubhransu S. Prusty return 0; 120917a42c45SSubhransu S. Prusty } 121017a42c45SSubhransu S. Prusty 121118382eadSSubhransu S. Prusty /* 121218382eadSSubhransu S. Prusty * Parse all nodes and store the cvt/pin nids in array 121318382eadSSubhransu S. Prusty * Add one time initialization for pin and cvt widgets 121418382eadSSubhransu S. Prusty */ 121517a42c45SSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev, 121617a42c45SSubhransu S. Prusty struct snd_soc_dai_driver **dais, int *num_dais) 121718382eadSSubhransu S. Prusty { 121818382eadSSubhransu S. Prusty hda_nid_t nid; 12193c83ac23SSudip Mukherjee int i, num_nodes; 122018382eadSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 122118382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 122215b91447SSubhransu S. Prusty int ret; 122318382eadSSubhransu S. Prusty 1224211caab7SSubhransu S. Prusty hdac_hdmi_skl_enable_all_pins(hdac); 1225211caab7SSubhransu S. Prusty hdac_hdmi_skl_enable_dp12(hdac); 1226211caab7SSubhransu S. Prusty 12273c83ac23SSudip Mukherjee num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); 1228541140d4SSubhransu S. Prusty if (!nid || num_nodes <= 0) { 122918382eadSSubhransu S. Prusty dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 123018382eadSSubhransu S. Prusty return -EINVAL; 123118382eadSSubhransu S. Prusty } 123218382eadSSubhransu S. Prusty 12333c83ac23SSudip Mukherjee hdac->num_nodes = num_nodes; 123418382eadSSubhransu S. Prusty hdac->start_nid = nid; 123518382eadSSubhransu S. Prusty 123618382eadSSubhransu S. Prusty for (i = 0; i < hdac->num_nodes; i++, nid++) { 123718382eadSSubhransu S. Prusty unsigned int caps; 123818382eadSSubhransu S. Prusty unsigned int type; 123918382eadSSubhransu S. Prusty 124018382eadSSubhransu S. Prusty caps = get_wcaps(hdac, nid); 124118382eadSSubhransu S. Prusty type = get_wcaps_type(caps); 124218382eadSSubhransu S. Prusty 124318382eadSSubhransu S. Prusty if (!(caps & AC_WCAP_DIGITAL)) 124418382eadSSubhransu S. Prusty continue; 124518382eadSSubhransu S. Prusty 124618382eadSSubhransu S. Prusty switch (type) { 124718382eadSSubhransu S. Prusty 124818382eadSSubhransu S. Prusty case AC_WID_AUD_OUT: 124915b91447SSubhransu S. Prusty ret = hdac_hdmi_add_cvt(edev, nid); 125015b91447SSubhransu S. Prusty if (ret < 0) 125115b91447SSubhransu S. Prusty return ret; 125218382eadSSubhransu S. Prusty break; 125318382eadSSubhransu S. Prusty 125418382eadSSubhransu S. Prusty case AC_WID_PIN: 125515b91447SSubhransu S. Prusty ret = hdac_hdmi_add_pin(edev, nid); 125615b91447SSubhransu S. Prusty if (ret < 0) 125715b91447SSubhransu S. Prusty return ret; 125818382eadSSubhransu S. Prusty break; 125918382eadSSubhransu S. Prusty } 126018382eadSSubhransu S. Prusty } 126118382eadSSubhransu S. Prusty 126218382eadSSubhransu S. Prusty hdac->end_nid = nid; 126318382eadSSubhransu S. Prusty 126415b91447SSubhransu S. Prusty if (!hdmi->num_pin || !hdmi->num_cvt) 126518382eadSSubhransu S. Prusty return -EIO; 126618382eadSSubhransu S. Prusty 126717a42c45SSubhransu S. Prusty ret = hdac_hdmi_create_dais(hdac, dais, hdmi, hdmi->num_cvt); 126817a42c45SSubhransu S. Prusty if (ret) { 126917a42c45SSubhransu S. Prusty dev_err(&hdac->dev, "Failed to create dais with err: %d\n", 127017a42c45SSubhransu S. Prusty ret); 127117a42c45SSubhransu S. Prusty return ret; 127217a42c45SSubhransu S. Prusty } 127317a42c45SSubhransu S. Prusty 127417a42c45SSubhransu S. Prusty *num_dais = hdmi->num_cvt; 127517a42c45SSubhransu S. Prusty 127615b91447SSubhransu S. Prusty return hdac_hdmi_init_dai_map(edev); 127718382eadSSubhransu S. Prusty } 127818382eadSSubhransu S. Prusty 1279b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port) 1280b8a54545SSubhransu S. Prusty { 1281b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = aptr; 1282b8a54545SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 1283b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 1284b8a54545SSubhransu S. Prusty struct snd_soc_codec *codec = edev->scodec; 1285b8a54545SSubhransu S. Prusty 1286b8a54545SSubhransu S. Prusty /* Don't know how this mapping is derived */ 1287b8a54545SSubhransu S. Prusty hda_nid_t pin_nid = port + 0x04; 1288b8a54545SSubhransu S. Prusty 1289b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); 1290b8a54545SSubhransu S. Prusty 1291b8a54545SSubhransu S. Prusty /* 1292b8a54545SSubhransu S. Prusty * skip notification during system suspend (but not in runtime PM); 1293b8a54545SSubhransu S. Prusty * the state will be updated at resume. Also since the ELD and 1294b8a54545SSubhransu S. Prusty * connection states are updated in anyway at the end of the resume, 1295b8a54545SSubhransu S. Prusty * we can skip it when received during PM process. 1296b8a54545SSubhransu S. Prusty */ 1297b8a54545SSubhransu S. Prusty if (snd_power_get_state(codec->component.card->snd_card) != 1298b8a54545SSubhransu S. Prusty SNDRV_CTL_POWER_D0) 1299b8a54545SSubhransu S. Prusty return; 1300b8a54545SSubhransu S. Prusty 1301b8a54545SSubhransu S. Prusty if (atomic_read(&edev->hdac.in_pm)) 1302b8a54545SSubhransu S. Prusty return; 1303b8a54545SSubhransu S. Prusty 1304b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 1305b8a54545SSubhransu S. Prusty if (pin->nid == pin_nid) 1306*f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1307b8a54545SSubhransu S. Prusty } 1308b8a54545SSubhransu S. Prusty } 1309b8a54545SSubhransu S. Prusty 1310b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = { 1311b8a54545SSubhransu S. Prusty .pin_eld_notify = hdac_hdmi_eld_notify_cb, 1312b8a54545SSubhransu S. Prusty }; 1313b8a54545SSubhransu S. Prusty 13142889099eSSubhransu S. Prusty static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, 13152889099eSSubhransu S. Prusty int device) 13162889099eSSubhransu S. Prusty { 13172889099eSSubhransu S. Prusty struct snd_soc_pcm_runtime *rtd; 13182889099eSSubhransu S. Prusty 13192889099eSSubhransu S. Prusty list_for_each_entry(rtd, &card->rtd_list, list) { 13202889099eSSubhransu S. Prusty if (rtd->pcm && (rtd->pcm->device == device)) 13212889099eSSubhransu S. Prusty return rtd->pcm; 13222889099eSSubhransu S. Prusty } 13232889099eSSubhransu S. Prusty 13242889099eSSubhransu S. Prusty return NULL; 13252889099eSSubhransu S. Prusty } 13262889099eSSubhransu S. Prusty 13274a3478deSJeeja KP int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) 13284a3478deSJeeja KP { 13294a3478deSJeeja KP char jack_name[NAME_SIZE]; 13304a3478deSJeeja KP struct snd_soc_codec *codec = dai->codec; 13314a3478deSJeeja KP struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 13324a3478deSJeeja KP struct snd_soc_dapm_context *dapm = 13334a3478deSJeeja KP snd_soc_component_get_dapm(&codec->component); 13344a3478deSJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 13354a3478deSJeeja KP struct hdac_hdmi_pcm *pcm; 13362889099eSSubhransu S. Prusty struct snd_pcm *snd_pcm; 13372889099eSSubhransu S. Prusty int err; 13384a3478deSJeeja KP 13394a3478deSJeeja KP /* 13404a3478deSJeeja KP * this is a new PCM device, create new pcm and 13414a3478deSJeeja KP * add to the pcm list 13424a3478deSJeeja KP */ 13434a3478deSJeeja KP pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); 13444a3478deSJeeja KP if (!pcm) 13454a3478deSJeeja KP return -ENOMEM; 13464a3478deSJeeja KP pcm->pcm_id = device; 13474a3478deSJeeja KP pcm->cvt = hdmi->dai_map[dai->id].cvt; 13484a3478deSJeeja KP 13492889099eSSubhransu S. Prusty snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); 13502889099eSSubhransu S. Prusty if (snd_pcm) { 13512889099eSSubhransu S. Prusty err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); 13522889099eSSubhransu S. Prusty if (err < 0) { 13532889099eSSubhransu S. Prusty dev_err(&edev->hdac.dev, 13542889099eSSubhransu S. Prusty "chmap control add failed with err: %d for pcm: %d\n", 13552889099eSSubhransu S. Prusty err, device); 13562889099eSSubhransu S. Prusty kfree(pcm); 13572889099eSSubhransu S. Prusty return err; 13582889099eSSubhransu S. Prusty } 13592889099eSSubhransu S. Prusty } 13602889099eSSubhransu S. Prusty 13614a3478deSJeeja KP list_add_tail(&pcm->head, &hdmi->pcm_list); 13624a3478deSJeeja KP 13634a3478deSJeeja KP sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); 13644a3478deSJeeja KP 13654a3478deSJeeja KP return snd_jack_new(dapm->card->snd_card, jack_name, 13664a3478deSJeeja KP SND_JACK_AVOUT, &pcm->jack, true, false); 13674a3478deSJeeja KP } 13684a3478deSJeeja KP EXPORT_SYMBOL_GPL(hdac_hdmi_jack_init); 13694a3478deSJeeja KP 137018382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec) 137118382eadSSubhransu S. Prusty { 137218382eadSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 137318382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 137418382eadSSubhransu S. Prusty struct snd_soc_dapm_context *dapm = 137518382eadSSubhransu S. Prusty snd_soc_component_get_dapm(&codec->component); 1376b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 1377b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 1378b8a54545SSubhransu S. Prusty int ret; 137918382eadSSubhransu S. Prusty 138018382eadSSubhransu S. Prusty edev->scodec = codec; 138118382eadSSubhransu S. Prusty 1382b2047e99SVinod Koul /* 1383b2047e99SVinod Koul * hold the ref while we probe, also no need to drop the ref on 1384b2047e99SVinod Koul * exit, we call pm_runtime_suspend() so that will do for us 1385b2047e99SVinod Koul */ 1386b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); 1387500e06b9SVinod Koul if (!hlink) { 1388500e06b9SVinod Koul dev_err(&edev->hdac.dev, "hdac link not found\n"); 1389500e06b9SVinod Koul return -EIO; 1390500e06b9SVinod Koul } 1391500e06b9SVinod Koul 1392b2047e99SVinod Koul snd_hdac_ext_bus_link_get(edev->ebus, hlink); 1393b2047e99SVinod Koul 139479f4e922SSubhransu S. Prusty ret = create_fill_widget_route_map(dapm); 139579f4e922SSubhransu S. Prusty if (ret < 0) 139679f4e922SSubhransu S. Prusty return ret; 139718382eadSSubhransu S. Prusty 1398b8a54545SSubhransu S. Prusty aops.audio_ptr = edev; 1399b8a54545SSubhransu S. Prusty ret = snd_hdac_i915_register_notifier(&aops); 1400b8a54545SSubhransu S. Prusty if (ret < 0) { 1401b8a54545SSubhransu S. Prusty dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n", 1402b8a54545SSubhransu S. Prusty ret); 1403b8a54545SSubhransu S. Prusty return ret; 1404b8a54545SSubhransu S. Prusty } 1405b8a54545SSubhransu S. Prusty 1406b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) 1407*f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1408b8a54545SSubhransu S. Prusty 140918382eadSSubhransu S. Prusty /* Imp: Store the card pointer in hda_codec */ 141018382eadSSubhransu S. Prusty edev->card = dapm->card->snd_card; 141118382eadSSubhransu S. Prusty 1412e342ac08SSubhransu S. Prusty /* 1413e342ac08SSubhransu S. Prusty * hdac_device core already sets the state to active and calls 1414e342ac08SSubhransu S. Prusty * get_noresume. So enable runtime and set the device to suspend. 1415e342ac08SSubhransu S. Prusty */ 1416e342ac08SSubhransu S. Prusty pm_runtime_enable(&edev->hdac.dev); 1417e342ac08SSubhransu S. Prusty pm_runtime_put(&edev->hdac.dev); 1418e342ac08SSubhransu S. Prusty pm_runtime_suspend(&edev->hdac.dev); 1419e342ac08SSubhransu S. Prusty 1420e342ac08SSubhransu S. Prusty return 0; 1421e342ac08SSubhransu S. Prusty } 1422e342ac08SSubhransu S. Prusty 1423e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec) 1424e342ac08SSubhransu S. Prusty { 1425e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 1426e342ac08SSubhransu S. Prusty 1427e342ac08SSubhransu S. Prusty pm_runtime_disable(&edev->hdac.dev); 142818382eadSSubhransu S. Prusty return 0; 142918382eadSSubhransu S. Prusty } 143018382eadSSubhransu S. Prusty 1431571d5078SJeeja KP #ifdef CONFIG_PM 14321b377ccdSSubhransu S. Prusty static int hdmi_codec_prepare(struct device *dev) 14331b377ccdSSubhransu S. Prusty { 14341b377ccdSSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 14351b377ccdSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 14361b377ccdSSubhransu S. Prusty 14371b377ccdSSubhransu S. Prusty pm_runtime_get_sync(&edev->hdac.dev); 14381b377ccdSSubhransu S. Prusty 14391b377ccdSSubhransu S. Prusty /* 14401b377ccdSSubhransu S. Prusty * Power down afg. 14411b377ccdSSubhransu S. Prusty * codec_read is preferred over codec_write to set the power state. 14421b377ccdSSubhransu S. Prusty * This way verb is send to set the power state and response 14431b377ccdSSubhransu S. Prusty * is received. So setting power state is ensured without using loop 14441b377ccdSSubhransu S. Prusty * to read the state. 14451b377ccdSSubhransu S. Prusty */ 14461b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 14471b377ccdSSubhransu S. Prusty AC_PWRST_D3); 14481b377ccdSSubhransu S. Prusty 14491b377ccdSSubhransu S. Prusty return 0; 14501b377ccdSSubhransu S. Prusty } 14511b377ccdSSubhransu S. Prusty 14520fee1798SSubhransu S. Prusty static void hdmi_codec_complete(struct device *dev) 1453571d5078SJeeja KP { 14540fee1798SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1455571d5078SJeeja KP struct hdac_hdmi_priv *hdmi = edev->private_data; 1456571d5078SJeeja KP struct hdac_hdmi_pin *pin; 1457571d5078SJeeja KP struct hdac_device *hdac = &edev->hdac; 14581b377ccdSSubhransu S. Prusty 14591b377ccdSSubhransu S. Prusty /* Power up afg */ 14601b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 14611b377ccdSSubhransu S. Prusty AC_PWRST_D0); 1462571d5078SJeeja KP 1463571d5078SJeeja KP hdac_hdmi_skl_enable_all_pins(&edev->hdac); 1464571d5078SJeeja KP hdac_hdmi_skl_enable_dp12(&edev->hdac); 1465571d5078SJeeja KP 1466571d5078SJeeja KP /* 1467571d5078SJeeja KP * As the ELD notify callback request is not entertained while the 1468571d5078SJeeja KP * device is in suspend state. Need to manually check detection of 1469571d5078SJeeja KP * all pins here. 1470571d5078SJeeja KP */ 1471571d5078SJeeja KP list_for_each_entry(pin, &hdmi->pin_list, head) 1472*f6fa11a3SSandeep Tayal hdac_hdmi_present_sense(pin); 1473571d5078SJeeja KP 14741b377ccdSSubhransu S. Prusty pm_runtime_put_sync(&edev->hdac.dev); 1475571d5078SJeeja KP } 1476571d5078SJeeja KP #else 14771b377ccdSSubhransu S. Prusty #define hdmi_codec_prepare NULL 14780fee1798SSubhransu S. Prusty #define hdmi_codec_complete NULL 1479571d5078SJeeja KP #endif 1480571d5078SJeeja KP 148118382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = { 148218382eadSSubhransu S. Prusty .probe = hdmi_codec_probe, 1483e342ac08SSubhransu S. Prusty .remove = hdmi_codec_remove, 148418382eadSSubhransu S. Prusty .idle_bias_off = true, 148518382eadSSubhransu S. Prusty }; 148618382eadSSubhransu S. Prusty 14872889099eSSubhransu S. Prusty static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, 14882889099eSSubhransu S. Prusty unsigned char *chmap) 14892889099eSSubhransu S. Prusty { 14902889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 14912889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 14922889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 14932889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 14942889099eSSubhransu S. Prusty 14952889099eSSubhransu S. Prusty /* chmap is already set to 0 in caller */ 14962889099eSSubhransu S. Prusty if (!pin) 14972889099eSSubhransu S. Prusty return; 14982889099eSSubhransu S. Prusty 14992889099eSSubhransu S. Prusty memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); 15002889099eSSubhransu S. Prusty } 15012889099eSSubhransu S. Prusty 15022889099eSSubhransu S. Prusty static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, 15032889099eSSubhransu S. Prusty unsigned char *chmap, int prepared) 15042889099eSSubhransu S. Prusty { 15052889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15062889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15072889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15082889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15092889099eSSubhransu S. Prusty 15102889099eSSubhransu S. Prusty mutex_lock(&pin->lock); 15112889099eSSubhransu S. Prusty pin->chmap_set = true; 15122889099eSSubhransu S. Prusty memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); 15132889099eSSubhransu S. Prusty if (prepared) 15142889099eSSubhransu S. Prusty hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); 15152889099eSSubhransu S. Prusty mutex_unlock(&pin->lock); 15162889099eSSubhransu S. Prusty } 15172889099eSSubhransu S. Prusty 15182889099eSSubhransu S. Prusty static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) 15192889099eSSubhransu S. Prusty { 15202889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15212889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15222889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15232889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15242889099eSSubhransu S. Prusty 15252889099eSSubhransu S. Prusty return pin ? true:false; 15262889099eSSubhransu S. Prusty } 15272889099eSSubhransu S. Prusty 15282889099eSSubhransu S. Prusty static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) 15292889099eSSubhransu S. Prusty { 15302889099eSSubhransu S. Prusty struct hdac_ext_device *edev = to_ehdac_device(hdac); 15312889099eSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 15322889099eSSubhransu S. Prusty struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); 15332889099eSSubhransu S. Prusty struct hdac_hdmi_pin *pin = pcm->pin; 15342889099eSSubhransu S. Prusty 15358f658815SDan Carpenter if (!pin || !pin->eld.eld_valid) 15362889099eSSubhransu S. Prusty return 0; 15372889099eSSubhransu S. Prusty 15382889099eSSubhransu S. Prusty return pin->eld.info.spk_alloc; 15392889099eSSubhransu S. Prusty } 15402889099eSSubhransu S. Prusty 154118382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) 154218382eadSSubhransu S. Prusty { 154318382eadSSubhransu S. Prusty struct hdac_device *codec = &edev->hdac; 154418382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi_priv; 154517a42c45SSubhransu S. Prusty struct snd_soc_dai_driver *hdmi_dais = NULL; 1546b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 154717a42c45SSubhransu S. Prusty int num_dais = 0; 154818382eadSSubhransu S. Prusty int ret = 0; 154918382eadSSubhransu S. Prusty 1550b2047e99SVinod Koul /* hold the ref while we probe */ 1551b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); 1552500e06b9SVinod Koul if (!hlink) { 1553500e06b9SVinod Koul dev_err(&edev->hdac.dev, "hdac link not found\n"); 1554500e06b9SVinod Koul return -EIO; 1555500e06b9SVinod Koul } 1556500e06b9SVinod Koul 1557b2047e99SVinod Koul snd_hdac_ext_bus_link_get(edev->ebus, hlink); 1558b2047e99SVinod Koul 155918382eadSSubhransu S. Prusty hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 156018382eadSSubhransu S. Prusty if (hdmi_priv == NULL) 156118382eadSSubhransu S. Prusty return -ENOMEM; 156218382eadSSubhransu S. Prusty 156318382eadSSubhransu S. Prusty edev->private_data = hdmi_priv; 1564bcced704SSubhransu S. Prusty snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); 15652889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; 15662889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; 15672889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; 15682889099eSSubhransu S. Prusty hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; 156918382eadSSubhransu S. Prusty 157018382eadSSubhransu S. Prusty dev_set_drvdata(&codec->dev, edev); 157118382eadSSubhransu S. Prusty 157215b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->pin_list); 157315b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->cvt_list); 15744a3478deSJeeja KP INIT_LIST_HEAD(&hdmi_priv->pcm_list); 15754a3478deSJeeja KP mutex_init(&hdmi_priv->pin_mutex); 157615b91447SSubhransu S. Prusty 1577aeaccef0SRamesh Babu /* 1578aeaccef0SRamesh Babu * Turned off in the runtime_suspend during the first explicit 1579aeaccef0SRamesh Babu * pm_runtime_suspend call. 1580aeaccef0SRamesh Babu */ 1581aeaccef0SRamesh Babu ret = snd_hdac_display_power(edev->hdac.bus, true); 1582aeaccef0SRamesh Babu if (ret < 0) { 1583aeaccef0SRamesh Babu dev_err(&edev->hdac.dev, 1584aeaccef0SRamesh Babu "Cannot turn on display power on i915 err: %d\n", 1585aeaccef0SRamesh Babu ret); 1586aeaccef0SRamesh Babu return ret; 1587aeaccef0SRamesh Babu } 1588aeaccef0SRamesh Babu 158917a42c45SSubhransu S. Prusty ret = hdac_hdmi_parse_and_map_nid(edev, &hdmi_dais, &num_dais); 159017a42c45SSubhransu S. Prusty if (ret < 0) { 159117a42c45SSubhransu S. Prusty dev_err(&codec->dev, 159217a42c45SSubhransu S. Prusty "Failed in parse and map nid with err: %d\n", ret); 159318382eadSSubhransu S. Prusty return ret; 159417a42c45SSubhransu S. Prusty } 159518382eadSSubhransu S. Prusty 159618382eadSSubhransu S. Prusty /* ASoC specific initialization */ 1597b2047e99SVinod Koul ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 159817a42c45SSubhransu S. Prusty hdmi_dais, num_dais); 1599b2047e99SVinod Koul 1600b2047e99SVinod Koul snd_hdac_ext_bus_link_put(edev->ebus, hlink); 1601b2047e99SVinod Koul 1602b2047e99SVinod Koul return ret; 160318382eadSSubhransu S. Prusty } 160418382eadSSubhransu S. Prusty 160518382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) 160618382eadSSubhransu S. Prusty { 160715b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 160815b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin, *pin_next; 160915b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt, *cvt_next; 16104a3478deSJeeja KP struct hdac_hdmi_pcm *pcm, *pcm_next; 161115b91447SSubhransu S. Prusty 161218382eadSSubhransu S. Prusty snd_soc_unregister_codec(&edev->hdac.dev); 161318382eadSSubhransu S. Prusty 16144a3478deSJeeja KP list_for_each_entry_safe(pcm, pcm_next, &hdmi->pcm_list, head) { 16154a3478deSJeeja KP pcm->cvt = NULL; 16164a3478deSJeeja KP pcm->pin = NULL; 16174a3478deSJeeja KP list_del(&pcm->head); 16184a3478deSJeeja KP kfree(pcm); 16194a3478deSJeeja KP } 16204a3478deSJeeja KP 162115b91447SSubhransu S. Prusty list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { 162215b91447SSubhransu S. Prusty list_del(&cvt->head); 16234a3478deSJeeja KP kfree(cvt->name); 162415b91447SSubhransu S. Prusty kfree(cvt); 162515b91447SSubhransu S. Prusty } 162615b91447SSubhransu S. Prusty 162715b91447SSubhransu S. Prusty list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { 162815b91447SSubhransu S. Prusty list_del(&pin->head); 162915b91447SSubhransu S. Prusty kfree(pin); 163015b91447SSubhransu S. Prusty } 163115b91447SSubhransu S. Prusty 163218382eadSSubhransu S. Prusty return 0; 163318382eadSSubhransu S. Prusty } 163418382eadSSubhransu S. Prusty 1635e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM 1636e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev) 1637e342ac08SSubhransu S. Prusty { 1638e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1639e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 164007f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 1641b2047e99SVinod Koul struct hdac_ext_bus *ebus = hbus_to_ebus(bus); 1642b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 164307f083abSSubhransu S. Prusty int err; 1644e342ac08SSubhransu S. Prusty 1645e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 1646e342ac08SSubhransu S. Prusty 164707f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 164807f083abSSubhransu S. Prusty if (!bus) 164907f083abSSubhransu S. Prusty return 0; 165007f083abSSubhransu S. Prusty 16511b377ccdSSubhransu S. Prusty /* 16521b377ccdSSubhransu S. Prusty * Power down afg. 16531b377ccdSSubhransu S. Prusty * codec_read is preferred over codec_write to set the power state. 16541b377ccdSSubhransu S. Prusty * This way verb is send to set the power state and response 16551b377ccdSSubhransu S. Prusty * is received. So setting power state is ensured without using loop 16561b377ccdSSubhransu S. Prusty * to read the state. 16571b377ccdSSubhransu S. Prusty */ 16581b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 16591b377ccdSSubhransu S. Prusty AC_PWRST_D3); 166007f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, false); 166107f083abSSubhransu S. Prusty if (err < 0) { 166207f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 166307f083abSSubhransu S. Prusty return err; 166407f083abSSubhransu S. Prusty } 166507f083abSSubhransu S. Prusty 1666b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); 1667500e06b9SVinod Koul if (!hlink) { 1668500e06b9SVinod Koul dev_err(dev, "hdac link not found\n"); 1669500e06b9SVinod Koul return -EIO; 1670500e06b9SVinod Koul } 1671500e06b9SVinod Koul 1672b2047e99SVinod Koul snd_hdac_ext_bus_link_put(ebus, hlink); 1673b2047e99SVinod Koul 1674e342ac08SSubhransu S. Prusty return 0; 1675e342ac08SSubhransu S. Prusty } 1676e342ac08SSubhransu S. Prusty 1677e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev) 1678e342ac08SSubhransu S. Prusty { 1679e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 1680e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 168107f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 1682b2047e99SVinod Koul struct hdac_ext_bus *ebus = hbus_to_ebus(bus); 1683b2047e99SVinod Koul struct hdac_ext_link *hlink = NULL; 168407f083abSSubhransu S. Prusty int err; 1685e342ac08SSubhransu S. Prusty 1686e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 1687e342ac08SSubhransu S. Prusty 168807f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 168907f083abSSubhransu S. Prusty if (!bus) 169007f083abSSubhransu S. Prusty return 0; 169107f083abSSubhransu S. Prusty 1692b2047e99SVinod Koul hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); 1693500e06b9SVinod Koul if (!hlink) { 1694500e06b9SVinod Koul dev_err(dev, "hdac link not found\n"); 1695500e06b9SVinod Koul return -EIO; 1696500e06b9SVinod Koul } 1697500e06b9SVinod Koul 1698b2047e99SVinod Koul snd_hdac_ext_bus_link_get(ebus, hlink); 1699b2047e99SVinod Koul 170007f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, true); 170107f083abSSubhransu S. Prusty if (err < 0) { 170207f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 170307f083abSSubhransu S. Prusty return err; 170407f083abSSubhransu S. Prusty } 170507f083abSSubhransu S. Prusty 1706ab85f5b3SSubhransu S. Prusty hdac_hdmi_skl_enable_all_pins(&edev->hdac); 1707ab85f5b3SSubhransu S. Prusty hdac_hdmi_skl_enable_dp12(&edev->hdac); 1708ab85f5b3SSubhransu S. Prusty 1709e342ac08SSubhransu S. Prusty /* Power up afg */ 17101b377ccdSSubhransu S. Prusty snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, 17111b377ccdSSubhransu S. Prusty AC_PWRST_D0); 1712e342ac08SSubhransu S. Prusty 1713e342ac08SSubhransu S. Prusty return 0; 1714e342ac08SSubhransu S. Prusty } 1715e342ac08SSubhransu S. Prusty #else 1716e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL 1717e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL 1718e342ac08SSubhransu S. Prusty #endif 1719e342ac08SSubhransu S. Prusty 1720e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = { 1721e342ac08SSubhransu S. Prusty SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) 17221b377ccdSSubhransu S. Prusty .prepare = hdmi_codec_prepare, 17230fee1798SSubhransu S. Prusty .complete = hdmi_codec_complete, 1724e342ac08SSubhransu S. Prusty }; 1725e342ac08SSubhransu S. Prusty 172618382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = { 172718382eadSSubhransu S. Prusty HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), 1728e2304803SJeeja KP HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), 1729cc216887SShreyas NC HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), 173018382eadSSubhransu S. Prusty {} 173118382eadSSubhransu S. Prusty }; 173218382eadSSubhransu S. Prusty 173318382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list); 173418382eadSSubhransu S. Prusty 173518382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = { 173618382eadSSubhransu S. Prusty . hdac = { 173718382eadSSubhransu S. Prusty .driver = { 173818382eadSSubhransu S. Prusty .name = "HDMI HDA Codec", 1739e342ac08SSubhransu S. Prusty .pm = &hdac_hdmi_pm, 174018382eadSSubhransu S. Prusty }, 174118382eadSSubhransu S. Prusty .id_table = hdmi_list, 174218382eadSSubhransu S. Prusty }, 174318382eadSSubhransu S. Prusty .probe = hdac_hdmi_dev_probe, 174418382eadSSubhransu S. Prusty .remove = hdac_hdmi_dev_remove, 174518382eadSSubhransu S. Prusty }; 174618382eadSSubhransu S. Prusty 174718382eadSSubhransu S. Prusty static int __init hdmi_init(void) 174818382eadSSubhransu S. Prusty { 174918382eadSSubhransu S. Prusty return snd_hda_ext_driver_register(&hdmi_driver); 175018382eadSSubhransu S. Prusty } 175118382eadSSubhransu S. Prusty 175218382eadSSubhransu S. Prusty static void __exit hdmi_exit(void) 175318382eadSSubhransu S. Prusty { 175418382eadSSubhransu S. Prusty snd_hda_ext_driver_unregister(&hdmi_driver); 175518382eadSSubhransu S. Prusty } 175618382eadSSubhransu S. Prusty 175718382eadSSubhransu S. Prusty module_init(hdmi_init); 175818382eadSSubhransu S. Prusty module_exit(hdmi_exit); 175918382eadSSubhransu S. Prusty 176018382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 176118382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec"); 176218382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); 176318382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); 1764