118382eadSSubhransu S. Prusty /* 218382eadSSubhransu S. Prusty * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms 318382eadSSubhransu S. Prusty * 418382eadSSubhransu S. Prusty * Copyright (C) 2014-2015 Intel Corp 518382eadSSubhransu S. Prusty * Author: Samreen Nilofer <samreen.nilofer@intel.com> 618382eadSSubhransu S. Prusty * Subhransu S. Prusty <subhransu.s.prusty@intel.com> 718382eadSSubhransu S. Prusty * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 818382eadSSubhransu S. Prusty * 918382eadSSubhransu S. Prusty * This program is free software; you can redistribute it and/or modify 1018382eadSSubhransu S. Prusty * it under the terms of the GNU General Public License as published by 1118382eadSSubhransu S. Prusty * the Free Software Foundation; version 2 of the License. 1218382eadSSubhransu S. Prusty * 1318382eadSSubhransu S. Prusty * This program is distributed in the hope that it will be useful, but 1418382eadSSubhransu S. Prusty * WITHOUT ANY WARRANTY; without even the implied warranty of 1518382eadSSubhransu S. Prusty * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1618382eadSSubhransu S. Prusty * General Public License for more details. 1718382eadSSubhransu S. Prusty * 1818382eadSSubhransu S. Prusty * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1918382eadSSubhransu S. Prusty */ 2018382eadSSubhransu S. Prusty #include <linux/init.h> 2118382eadSSubhransu S. Prusty #include <linux/delay.h> 2218382eadSSubhransu S. Prusty #include <linux/module.h> 2318382eadSSubhransu S. Prusty #include <linux/pm_runtime.h> 24a657f1d0SSubhransu S. Prusty #include <linux/hdmi.h> 2518382eadSSubhransu S. Prusty #include <sound/pcm_params.h> 2618382eadSSubhransu S. Prusty #include <sound/soc.h> 2718382eadSSubhransu S. Prusty #include <sound/hdaudio_ext.h> 2807f083abSSubhransu S. Prusty #include <sound/hda_i915.h> 2918382eadSSubhransu S. Prusty #include "../../hda/local.h" 3018382eadSSubhransu S. Prusty 31b0362adbSSubhransu S. Prusty #define AMP_OUT_MUTE 0xb080 32b0362adbSSubhransu S. Prusty #define AMP_OUT_UNMUTE 0xb000 3318382eadSSubhransu S. Prusty #define PIN_OUT (AC_PINCTL_OUT_EN) 34b0362adbSSubhransu S. Prusty 3518382eadSSubhransu S. Prusty #define HDA_MAX_CONNECTIONS 32 3618382eadSSubhransu S. Prusty 37*b8a54545SSubhransu S. Prusty #define ELD_MAX_SIZE 256 38*b8a54545SSubhransu S. Prusty #define ELD_FIXED_BYTES 20 39*b8a54545SSubhransu S. Prusty 4018382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params { 4118382eadSSubhransu S. Prusty unsigned int channels_min; 4218382eadSSubhransu S. Prusty unsigned int channels_max; 4318382eadSSubhransu S. Prusty u32 rates; 4418382eadSSubhransu S. Prusty u64 formats; 4518382eadSSubhransu S. Prusty unsigned int maxbps; 4618382eadSSubhransu S. Prusty }; 4718382eadSSubhransu S. Prusty 4818382eadSSubhransu S. Prusty struct hdac_hdmi_cvt { 4915b91447SSubhransu S. Prusty struct list_head head; 5018382eadSSubhransu S. Prusty hda_nid_t nid; 5118382eadSSubhransu S. Prusty struct hdac_hdmi_cvt_params params; 5218382eadSSubhransu S. Prusty }; 5318382eadSSubhransu S. Prusty 54*b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld { 55*b8a54545SSubhransu S. Prusty bool monitor_present; 56*b8a54545SSubhransu S. Prusty bool eld_valid; 57*b8a54545SSubhransu S. Prusty int eld_size; 58*b8a54545SSubhransu S. Prusty char eld_buffer[ELD_MAX_SIZE]; 59*b8a54545SSubhransu S. Prusty }; 60*b8a54545SSubhransu S. Prusty 6118382eadSSubhransu S. Prusty struct hdac_hdmi_pin { 6215b91447SSubhransu S. Prusty struct list_head head; 6318382eadSSubhransu S. Prusty hda_nid_t nid; 6418382eadSSubhransu S. Prusty int num_mux_nids; 6518382eadSSubhransu S. Prusty hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; 66*b8a54545SSubhransu S. Prusty struct hdac_hdmi_eld eld; 67*b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev; 68*b8a54545SSubhransu S. Prusty int repoll_count; 69*b8a54545SSubhransu S. Prusty struct delayed_work work; 7018382eadSSubhransu S. Prusty }; 7118382eadSSubhransu S. Prusty 7218382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map { 7318382eadSSubhransu S. Prusty int dai_id; 7415b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 7515b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 7618382eadSSubhransu S. Prusty }; 7718382eadSSubhransu S. Prusty 7818382eadSSubhransu S. Prusty struct hdac_hdmi_priv { 7918382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map dai_map[3]; 8015b91447SSubhransu S. Prusty struct list_head pin_list; 8115b91447SSubhransu S. Prusty struct list_head cvt_list; 8215b91447SSubhransu S. Prusty int num_pin; 8315b91447SSubhransu S. Prusty int num_cvt; 8418382eadSSubhransu S. Prusty }; 8518382eadSSubhransu S. Prusty 86e342ac08SSubhransu S. Prusty static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) 87e342ac08SSubhransu S. Prusty { 8851b2c425SGeliang Tang struct hdac_device *hdac = dev_to_hdac_dev(dev); 89e342ac08SSubhransu S. Prusty 9051b2c425SGeliang Tang return to_ehdac_device(hdac); 91e342ac08SSubhransu S. Prusty } 92e342ac08SSubhransu S. Prusty 93*b8a54545SSubhransu S. Prusty /* HDMI ELD routines */ 94*b8a54545SSubhransu S. Prusty static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec, 95*b8a54545SSubhransu S. Prusty hda_nid_t nid, int byte_index) 96*b8a54545SSubhransu S. Prusty { 97*b8a54545SSubhransu S. Prusty unsigned int val; 98*b8a54545SSubhransu S. Prusty 99*b8a54545SSubhransu S. Prusty val = snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, 100*b8a54545SSubhransu S. Prusty byte_index); 101*b8a54545SSubhransu S. Prusty 102*b8a54545SSubhransu S. Prusty dev_dbg(&codec->dev, "HDMI: ELD data byte %d: 0x%x\n", 103*b8a54545SSubhransu S. Prusty byte_index, val); 104*b8a54545SSubhransu S. Prusty 105*b8a54545SSubhransu S. Prusty return val; 106*b8a54545SSubhransu S. Prusty } 107*b8a54545SSubhransu S. Prusty 108*b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld_size(struct hdac_device *codec, hda_nid_t nid) 109*b8a54545SSubhransu S. Prusty { 110*b8a54545SSubhransu S. Prusty return snd_hdac_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, 111*b8a54545SSubhransu S. Prusty AC_DIPSIZE_ELD_BUF); 112*b8a54545SSubhransu S. Prusty } 113*b8a54545SSubhransu S. Prusty 114*b8a54545SSubhransu S. Prusty /* 115*b8a54545SSubhransu S. Prusty * This function queries the ELD size and ELD data and fills in the buffer 116*b8a54545SSubhransu S. Prusty * passed by user 117*b8a54545SSubhransu S. Prusty */ 118*b8a54545SSubhransu S. Prusty static int hdac_hdmi_get_eld(struct hdac_device *codec, hda_nid_t nid, 119*b8a54545SSubhransu S. Prusty unsigned char *buf, int *eld_size) 120*b8a54545SSubhransu S. Prusty { 121*b8a54545SSubhransu S. Prusty int i, size, ret = 0; 122*b8a54545SSubhransu S. Prusty 123*b8a54545SSubhransu S. Prusty /* 124*b8a54545SSubhransu S. Prusty * ELD size is initialized to zero in caller function. If no errors and 125*b8a54545SSubhransu S. Prusty * ELD is valid, actual eld_size is assigned. 126*b8a54545SSubhransu S. Prusty */ 127*b8a54545SSubhransu S. Prusty 128*b8a54545SSubhransu S. Prusty size = hdac_hdmi_get_eld_size(codec, nid); 129*b8a54545SSubhransu S. Prusty if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { 130*b8a54545SSubhransu S. Prusty dev_err(&codec->dev, "HDMI: invalid ELD buf size %d\n", size); 131*b8a54545SSubhransu S. Prusty return -ERANGE; 132*b8a54545SSubhransu S. Prusty } 133*b8a54545SSubhransu S. Prusty 134*b8a54545SSubhransu S. Prusty /* set ELD buffer */ 135*b8a54545SSubhransu S. Prusty for (i = 0; i < size; i++) { 136*b8a54545SSubhransu S. Prusty unsigned int val = hdac_hdmi_get_eld_data(codec, nid, i); 137*b8a54545SSubhransu S. Prusty /* 138*b8a54545SSubhransu S. Prusty * Graphics driver might be writing to ELD buffer right now. 139*b8a54545SSubhransu S. Prusty * Just abort. The caller will repoll after a while. 140*b8a54545SSubhransu S. Prusty */ 141*b8a54545SSubhransu S. Prusty if (!(val & AC_ELDD_ELD_VALID)) { 142*b8a54545SSubhransu S. Prusty dev_err(&codec->dev, 143*b8a54545SSubhransu S. Prusty "HDMI: invalid ELD data byte %d\n", i); 144*b8a54545SSubhransu S. Prusty ret = -EINVAL; 145*b8a54545SSubhransu S. Prusty goto error; 146*b8a54545SSubhransu S. Prusty } 147*b8a54545SSubhransu S. Prusty val &= AC_ELDD_ELD_DATA; 148*b8a54545SSubhransu S. Prusty /* 149*b8a54545SSubhransu S. Prusty * The first byte cannot be zero. This can happen on some DVI 150*b8a54545SSubhransu S. Prusty * connections. Some Intel chips may also need some 250ms delay 151*b8a54545SSubhransu S. Prusty * to return non-zero ELD data, even when the graphics driver 152*b8a54545SSubhransu S. Prusty * correctly writes ELD content before setting ELD_valid bit. 153*b8a54545SSubhransu S. Prusty */ 154*b8a54545SSubhransu S. Prusty if (!val && !i) { 155*b8a54545SSubhransu S. Prusty dev_err(&codec->dev, "HDMI: 0 ELD data\n"); 156*b8a54545SSubhransu S. Prusty ret = -EINVAL; 157*b8a54545SSubhransu S. Prusty goto error; 158*b8a54545SSubhransu S. Prusty } 159*b8a54545SSubhransu S. Prusty buf[i] = val; 160*b8a54545SSubhransu S. Prusty } 161*b8a54545SSubhransu S. Prusty 162*b8a54545SSubhransu S. Prusty *eld_size = size; 163*b8a54545SSubhransu S. Prusty error: 164*b8a54545SSubhransu S. Prusty return ret; 165*b8a54545SSubhransu S. Prusty } 166*b8a54545SSubhransu S. Prusty 167b0362adbSSubhransu S. Prusty static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, 168b0362adbSSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid, 169b0362adbSSubhransu S. Prusty u32 stream_tag, int format) 170b0362adbSSubhransu S. Prusty { 171b0362adbSSubhransu S. Prusty unsigned int val; 172b0362adbSSubhransu S. Prusty 173b0362adbSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", 174b0362adbSSubhransu S. Prusty cvt_nid, pin_nid, stream_tag, format); 175b0362adbSSubhransu S. Prusty 176b0362adbSSubhransu S. Prusty val = (stream_tag << 4); 177b0362adbSSubhransu S. Prusty 178b0362adbSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 179b0362adbSSubhransu S. Prusty AC_VERB_SET_CHANNEL_STREAMID, val); 180b0362adbSSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 181b0362adbSSubhransu S. Prusty AC_VERB_SET_STREAM_FORMAT, format); 182b0362adbSSubhransu S. Prusty 183b0362adbSSubhransu S. Prusty return 0; 184b0362adbSSubhransu S. Prusty } 185b0362adbSSubhransu S. Prusty 186a657f1d0SSubhransu S. Prusty static void 187a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, 188a657f1d0SSubhransu S. Prusty int packet_index, int byte_index) 189a657f1d0SSubhransu S. Prusty { 190a657f1d0SSubhransu S. Prusty int val; 191a657f1d0SSubhransu S. Prusty 192a657f1d0SSubhransu S. Prusty val = (packet_index << 5) | (byte_index & 0x1f); 193a657f1d0SSubhransu S. Prusty 194a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 195a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_INDEX, val); 196a657f1d0SSubhransu S. Prusty } 197a657f1d0SSubhransu S. Prusty 198a657f1d0SSubhransu S. Prusty static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, 199a657f1d0SSubhransu S. Prusty hda_nid_t cvt_nid, hda_nid_t pin_nid) 200a657f1d0SSubhransu S. Prusty { 201a657f1d0SSubhransu S. Prusty uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; 202a657f1d0SSubhransu S. Prusty struct hdmi_audio_infoframe frame; 203a657f1d0SSubhransu S. Prusty u8 *dip = (u8 *)&frame; 204a657f1d0SSubhransu S. Prusty int ret; 205a657f1d0SSubhransu S. Prusty int i; 206a657f1d0SSubhransu S. Prusty 207a657f1d0SSubhransu S. Prusty hdmi_audio_infoframe_init(&frame); 208a657f1d0SSubhransu S. Prusty 209a657f1d0SSubhransu S. Prusty /* Default stereo for now */ 210a657f1d0SSubhransu S. Prusty frame.channels = 2; 211a657f1d0SSubhransu S. Prusty 212a657f1d0SSubhransu S. Prusty /* setup channel count */ 213a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, 214a657f1d0SSubhransu S. Prusty AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1); 215a657f1d0SSubhransu S. Prusty 216a657f1d0SSubhransu S. Prusty ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); 217a657f1d0SSubhransu S. Prusty if (ret < 0) 218a657f1d0SSubhransu S. Prusty return ret; 219a657f1d0SSubhransu S. Prusty 220a657f1d0SSubhransu S. Prusty /* stop infoframe transmission */ 221a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 222a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 223a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); 224a657f1d0SSubhransu S. Prusty 225a657f1d0SSubhransu S. Prusty 226a657f1d0SSubhransu S. Prusty /* Fill infoframe. Index auto-incremented */ 227a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 228a657f1d0SSubhransu S. Prusty for (i = 0; i < sizeof(frame); i++) 229a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 230a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_DATA, dip[i]); 231a657f1d0SSubhransu S. Prusty 232a657f1d0SSubhransu S. Prusty /* Start infoframe */ 233a657f1d0SSubhransu S. Prusty hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); 234a657f1d0SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, 235a657f1d0SSubhransu S. Prusty AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); 236a657f1d0SSubhransu S. Prusty 237a657f1d0SSubhransu S. Prusty return 0; 238a657f1d0SSubhransu S. Prusty } 239a657f1d0SSubhransu S. Prusty 240b0362adbSSubhransu S. Prusty static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, 241b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) 242b0362adbSSubhransu S. Prusty { 243b0362adbSSubhransu S. Prusty /* Power up pin widget */ 24415b91447SSubhransu S. Prusty if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, 24515b91447SSubhransu S. Prusty pwr_state)) 24615b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, 247b0362adbSSubhransu S. Prusty AC_VERB_SET_POWER_STATE, pwr_state); 248b0362adbSSubhransu S. Prusty 249b0362adbSSubhransu S. Prusty /* Power up converter */ 25015b91447SSubhransu S. Prusty if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, 25115b91447SSubhransu S. Prusty pwr_state)) 25215b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 253b0362adbSSubhransu S. Prusty AC_VERB_SET_POWER_STATE, pwr_state); 254b0362adbSSubhransu S. Prusty } 255b0362adbSSubhransu S. Prusty 256b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, 257b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 258b0362adbSSubhransu S. Prusty { 259b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 260b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 261b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 262b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 263a657f1d0SSubhransu S. Prusty int ret; 264b0362adbSSubhransu S. Prusty 265b0362adbSSubhransu S. Prusty if (dai->id > 0) { 266b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 267b0362adbSSubhransu S. Prusty return -ENODEV; 268b0362adbSSubhransu S. Prusty } 269b0362adbSSubhransu S. Prusty 270b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 271b0362adbSSubhransu S. Prusty 272b0362adbSSubhransu S. Prusty dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 273b0362adbSSubhransu S. Prusty dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", 274b0362adbSSubhransu S. Prusty dd->stream_tag, dd->format); 275b0362adbSSubhransu S. Prusty 27615b91447SSubhransu S. Prusty ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, 27715b91447SSubhransu S. Prusty dai_map->pin->nid); 278a657f1d0SSubhransu S. Prusty if (ret < 0) 279a657f1d0SSubhransu S. Prusty return ret; 280a657f1d0SSubhransu S. Prusty 28115b91447SSubhransu S. Prusty return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, 28215b91447SSubhransu S. Prusty dai_map->pin->nid, dd->stream_tag, dd->format); 283b0362adbSSubhransu S. Prusty } 284b0362adbSSubhransu S. Prusty 285b0362adbSSubhransu S. Prusty static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, 286b0362adbSSubhransu S. Prusty struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) 287b0362adbSSubhransu S. Prusty { 288b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 289b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 290b0362adbSSubhransu S. Prusty 291b0362adbSSubhransu S. Prusty if (dai->id > 0) { 292b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 293b0362adbSSubhransu S. Prusty return -ENODEV; 294b0362adbSSubhransu S. Prusty } 295b0362adbSSubhransu S. Prusty 296b0362adbSSubhransu S. Prusty dd = kzalloc(sizeof(*dd), GFP_KERNEL); 2978d33ab24SSudip Mukherjee if (!dd) 2988d33ab24SSudip Mukherjee return -ENOMEM; 299b0362adbSSubhransu S. Prusty dd->format = snd_hdac_calc_stream_format(params_rate(hparams), 300b0362adbSSubhransu S. Prusty params_channels(hparams), params_format(hparams), 301b0362adbSSubhransu S. Prusty 24, 0); 302b0362adbSSubhransu S. Prusty 303b0362adbSSubhransu S. Prusty snd_soc_dai_set_dma_data(dai, substream, (void *)dd); 304b0362adbSSubhransu S. Prusty 305b0362adbSSubhransu S. Prusty return 0; 306b0362adbSSubhransu S. Prusty } 307b0362adbSSubhransu S. Prusty 308b0362adbSSubhransu S. Prusty static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, 309b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 310b0362adbSSubhransu S. Prusty { 311b0362adbSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); 312b0362adbSSubhransu S. Prusty struct hdac_ext_dma_params *dd; 313b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 314b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 315b0362adbSSubhransu S. Prusty 316b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 317b0362adbSSubhransu S. Prusty 31815b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 319b0362adbSSubhransu S. Prusty AC_VERB_SET_CHANNEL_STREAMID, 0); 32015b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, 321b0362adbSSubhransu S. Prusty AC_VERB_SET_STREAM_FORMAT, 0); 322b0362adbSSubhransu S. Prusty 323b0362adbSSubhransu S. Prusty dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); 324b0362adbSSubhransu S. Prusty snd_soc_dai_set_dma_data(dai, substream, NULL); 325b0362adbSSubhransu S. Prusty 326b0362adbSSubhransu S. Prusty kfree(dd); 327b0362adbSSubhransu S. Prusty 328b0362adbSSubhransu S. Prusty return 0; 329b0362adbSSubhransu S. Prusty } 330b0362adbSSubhransu S. Prusty 331b0362adbSSubhransu S. Prusty static int hdac_hdmi_pcm_open(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; 337b0362adbSSubhransu S. Prusty 338b0362adbSSubhransu S. Prusty if (dai->id > 0) { 339b0362adbSSubhransu S. Prusty dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); 340b0362adbSSubhransu S. Prusty return -ENODEV; 341b0362adbSSubhransu S. Prusty } 342b0362adbSSubhransu S. Prusty 343b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 344b0362adbSSubhransu S. Prusty 345*b8a54545SSubhransu S. Prusty if ((!dai_map->pin->eld.monitor_present) || 346*b8a54545SSubhransu S. Prusty (!dai_map->pin->eld.eld_valid)) { 347b0362adbSSubhransu S. Prusty 348*b8a54545SSubhransu S. Prusty dev_err(&hdac->hdac.dev, 349*b8a54545SSubhransu S. Prusty "Failed: montior present? %d ELD valid?: %d\n", 350*b8a54545SSubhransu S. Prusty dai_map->pin->eld.monitor_present, 351*b8a54545SSubhransu S. Prusty dai_map->pin->eld.eld_valid); 352*b8a54545SSubhransu S. Prusty 353b0362adbSSubhransu S. Prusty return -ENODEV; 354b0362adbSSubhransu S. Prusty } 355b0362adbSSubhransu S. Prusty 356b0362adbSSubhransu S. Prusty hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); 357b0362adbSSubhransu S. Prusty 35815b91447SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, 359b0362adbSSubhransu S. Prusty AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); 360b0362adbSSubhransu S. Prusty 361b0362adbSSubhransu S. Prusty snd_pcm_hw_constraint_step(substream->runtime, 0, 362b0362adbSSubhransu S. Prusty SNDRV_PCM_HW_PARAM_CHANNELS, 2); 363b0362adbSSubhransu S. Prusty 364b0362adbSSubhransu S. Prusty return 0; 365b0362adbSSubhransu S. Prusty } 366b0362adbSSubhransu S. Prusty 367b0362adbSSubhransu S. Prusty static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, 368b0362adbSSubhransu S. Prusty struct snd_soc_dai *dai) 369b0362adbSSubhransu S. Prusty { 370b0362adbSSubhransu S. Prusty struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); 371b0362adbSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = hdac->private_data; 372b0362adbSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map; 373b0362adbSSubhransu S. Prusty 374b0362adbSSubhransu S. Prusty dai_map = &hdmi->dai_map[dai->id]; 375b0362adbSSubhransu S. Prusty 376b0362adbSSubhransu S. Prusty hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); 377b0362adbSSubhransu S. Prusty 37815b91447SSubhransu S. Prusty snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, 379b0362adbSSubhransu S. Prusty AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); 380b0362adbSSubhransu S. Prusty } 381b0362adbSSubhransu S. Prusty 38218382eadSSubhransu S. Prusty static int 38318382eadSSubhransu S. Prusty hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) 38418382eadSSubhransu S. Prusty { 38518382eadSSubhransu S. Prusty int err; 38618382eadSSubhransu S. Prusty 38718382eadSSubhransu S. Prusty /* Only stereo supported as of now */ 38818382eadSSubhransu S. Prusty cvt->params.channels_min = cvt->params.channels_max = 2; 38918382eadSSubhransu S. Prusty 39018382eadSSubhransu S. Prusty err = snd_hdac_query_supported_pcm(hdac, cvt->nid, 39118382eadSSubhransu S. Prusty &cvt->params.rates, 39218382eadSSubhransu S. Prusty &cvt->params.formats, 39318382eadSSubhransu S. Prusty &cvt->params.maxbps); 39418382eadSSubhransu S. Prusty if (err < 0) 39518382eadSSubhransu S. Prusty dev_err(&hdac->dev, 39618382eadSSubhransu S. Prusty "Failed to query pcm params for nid %d: %d\n", 39718382eadSSubhransu S. Prusty cvt->nid, err); 39818382eadSSubhransu S. Prusty 39918382eadSSubhransu S. Prusty return err; 40018382eadSSubhransu S. Prusty } 40118382eadSSubhransu S. Prusty 40218382eadSSubhransu S. Prusty static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, 40318382eadSSubhransu S. Prusty enum snd_soc_dapm_type id, 40418382eadSSubhransu S. Prusty const char *wname, const char *stream) 40518382eadSSubhransu S. Prusty { 40618382eadSSubhransu S. Prusty w->id = id; 40718382eadSSubhransu S. Prusty w->name = wname; 40818382eadSSubhransu S. Prusty w->sname = stream; 40918382eadSSubhransu S. Prusty w->reg = SND_SOC_NOPM; 41018382eadSSubhransu S. Prusty w->shift = 0; 41118382eadSSubhransu S. Prusty w->kcontrol_news = NULL; 41218382eadSSubhransu S. Prusty w->num_kcontrols = 0; 41318382eadSSubhransu S. Prusty w->priv = NULL; 41418382eadSSubhransu S. Prusty } 41518382eadSSubhransu S. Prusty 41618382eadSSubhransu S. Prusty static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, 41718382eadSSubhransu S. Prusty const char *sink, const char *control, const char *src) 41818382eadSSubhransu S. Prusty { 41918382eadSSubhransu S. Prusty route->sink = sink; 42018382eadSSubhransu S. Prusty route->source = src; 42118382eadSSubhransu S. Prusty route->control = control; 42218382eadSSubhransu S. Prusty route->connected = NULL; 42318382eadSSubhransu S. Prusty } 42418382eadSSubhransu S. Prusty 42518382eadSSubhransu S. Prusty static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, 42618382eadSSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map) 42718382eadSSubhransu S. Prusty { 42818382eadSSubhransu S. Prusty struct snd_soc_dapm_route route[1]; 42918382eadSSubhransu S. Prusty struct snd_soc_dapm_widget widgets[2] = { {0} }; 43018382eadSSubhransu S. Prusty 43118382eadSSubhransu S. Prusty memset(&route, 0, sizeof(route)); 43218382eadSSubhransu S. Prusty 43318382eadSSubhransu S. Prusty hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, 43418382eadSSubhransu S. Prusty "hif1 Output", NULL); 43518382eadSSubhransu S. Prusty hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, 43618382eadSSubhransu S. Prusty "Coverter 1", "hif1"); 43718382eadSSubhransu S. Prusty 43818382eadSSubhransu S. Prusty hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); 43918382eadSSubhransu S. Prusty 44018382eadSSubhransu S. Prusty snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); 44118382eadSSubhransu S. Prusty snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); 44218382eadSSubhransu S. Prusty } 44318382eadSSubhransu S. Prusty 44415b91447SSubhransu S. Prusty static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) 44518382eadSSubhransu S. Prusty { 44615b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 44715b91447SSubhransu S. Prusty struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0]; 44815b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 44915b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 45018382eadSSubhransu S. Prusty 45115b91447SSubhransu S. Prusty if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) 45215b91447SSubhransu S. Prusty return -EINVAL; 45318382eadSSubhransu S. Prusty 45415b91447SSubhransu S. Prusty /* 45515b91447SSubhransu S. Prusty * Currently on board only 1 pin and 1 converter is enabled for 45615b91447SSubhransu S. Prusty * simplification, more will be added eventually 45715b91447SSubhransu S. Prusty * So using fixed map for dai_id:pin:cvt 45815b91447SSubhransu S. Prusty */ 45915b91447SSubhransu S. Prusty cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head); 46015b91447SSubhransu S. Prusty pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head); 46118382eadSSubhransu S. Prusty 46215b91447SSubhransu S. Prusty dai_map->dai_id = 0; 46315b91447SSubhransu S. Prusty dai_map->pin = pin; 46415b91447SSubhransu S. Prusty 46515b91447SSubhransu S. Prusty dai_map->cvt = cvt; 46618382eadSSubhransu S. Prusty 46718382eadSSubhransu S. Prusty /* Enable out path for this pin widget */ 46815b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 46918382eadSSubhransu S. Prusty AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); 47018382eadSSubhransu S. Prusty 47118382eadSSubhransu S. Prusty /* Enable transmission */ 47215b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 47318382eadSSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_1, 1); 47418382eadSSubhransu S. Prusty 47518382eadSSubhransu S. Prusty /* Category Code (CC) to zero */ 47615b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, 47718382eadSSubhransu S. Prusty AC_VERB_SET_DIGI_CONVERT_2, 0); 47818382eadSSubhransu S. Prusty 47915b91447SSubhransu S. Prusty snd_hdac_codec_write(&edev->hdac, pin->nid, 0, 48018382eadSSubhransu S. Prusty AC_VERB_SET_CONNECT_SEL, 0); 48118382eadSSubhransu S. Prusty 48215b91447SSubhransu S. Prusty return 0; 48315b91447SSubhransu S. Prusty } 48415b91447SSubhransu S. Prusty 48515b91447SSubhransu S. Prusty static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) 48615b91447SSubhransu S. Prusty { 48715b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 48815b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt; 48915b91447SSubhransu S. Prusty 49015b91447SSubhransu S. Prusty cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); 49115b91447SSubhransu S. Prusty if (!cvt) 49215b91447SSubhransu S. Prusty return -ENOMEM; 49315b91447SSubhransu S. Prusty 49415b91447SSubhransu S. Prusty cvt->nid = nid; 49515b91447SSubhransu S. Prusty 49615b91447SSubhransu S. Prusty list_add_tail(&cvt->head, &hdmi->cvt_list); 49715b91447SSubhransu S. Prusty hdmi->num_cvt++; 49815b91447SSubhransu S. Prusty 49915b91447SSubhransu S. Prusty return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); 50015b91447SSubhransu S. Prusty } 50115b91447SSubhransu S. Prusty 502*b8a54545SSubhransu S. Prusty static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) 503*b8a54545SSubhransu S. Prusty { 504*b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = pin->edev; 505*b8a54545SSubhransu S. Prusty int val; 506*b8a54545SSubhransu S. Prusty 507*b8a54545SSubhransu S. Prusty if (!edev) 508*b8a54545SSubhransu S. Prusty return; 509*b8a54545SSubhransu S. Prusty 510*b8a54545SSubhransu S. Prusty pin->repoll_count = repoll; 511*b8a54545SSubhransu S. Prusty 512*b8a54545SSubhransu S. Prusty pm_runtime_get_sync(&edev->hdac.dev); 513*b8a54545SSubhransu S. Prusty val = snd_hdac_codec_read(&edev->hdac, pin->nid, 0, 514*b8a54545SSubhransu S. Prusty AC_VERB_GET_PIN_SENSE, 0); 515*b8a54545SSubhransu S. Prusty 516*b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "Pin sense val %x for pin: %d\n", 517*b8a54545SSubhransu S. Prusty val, pin->nid); 518*b8a54545SSubhransu S. Prusty 519*b8a54545SSubhransu S. Prusty pin->eld.monitor_present = !!(val & AC_PINSENSE_PRESENCE); 520*b8a54545SSubhransu S. Prusty pin->eld.eld_valid = !!(val & AC_PINSENSE_ELDV); 521*b8a54545SSubhransu S. Prusty 522*b8a54545SSubhransu S. Prusty if (!pin->eld.monitor_present || !pin->eld.eld_valid) { 523*b8a54545SSubhransu S. Prusty 524*b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: disconnect for pin %d\n", 525*b8a54545SSubhransu S. Prusty __func__, pin->nid); 526*b8a54545SSubhransu S. Prusty goto put_hdac_device; 527*b8a54545SSubhransu S. Prusty } 528*b8a54545SSubhransu S. Prusty 529*b8a54545SSubhransu S. Prusty if (pin->eld.monitor_present && pin->eld.eld_valid) { 530*b8a54545SSubhransu S. Prusty /* TODO: use i915 component for reading ELD later */ 531*b8a54545SSubhransu S. Prusty if (hdac_hdmi_get_eld(&edev->hdac, pin->nid, 532*b8a54545SSubhransu S. Prusty pin->eld.eld_buffer, 533*b8a54545SSubhransu S. Prusty &pin->eld.eld_size) == 0) { 534*b8a54545SSubhransu S. Prusty 535*b8a54545SSubhransu S. Prusty print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, 536*b8a54545SSubhransu S. Prusty pin->eld.eld_buffer, pin->eld.eld_size); 537*b8a54545SSubhransu S. Prusty } else { 538*b8a54545SSubhransu S. Prusty pin->eld.monitor_present = false; 539*b8a54545SSubhransu S. Prusty pin->eld.eld_valid = false; 540*b8a54545SSubhransu S. Prusty } 541*b8a54545SSubhransu S. Prusty } 542*b8a54545SSubhransu S. Prusty 543*b8a54545SSubhransu S. Prusty /* 544*b8a54545SSubhransu S. Prusty * Sometimes the pin_sense may present invalid monitor 545*b8a54545SSubhransu S. Prusty * present and eld_valid. If ELD data is not valid, loop few 546*b8a54545SSubhransu S. Prusty * more times to get correct pin sense and valid ELD. 547*b8a54545SSubhransu S. Prusty */ 548*b8a54545SSubhransu S. Prusty if ((!pin->eld.monitor_present || !pin->eld.eld_valid) && repoll) 549*b8a54545SSubhransu S. Prusty schedule_delayed_work(&pin->work, msecs_to_jiffies(300)); 550*b8a54545SSubhransu S. Prusty 551*b8a54545SSubhransu S. Prusty put_hdac_device: 552*b8a54545SSubhransu S. Prusty pm_runtime_put_sync(&edev->hdac.dev); 553*b8a54545SSubhransu S. Prusty } 554*b8a54545SSubhransu S. Prusty 555*b8a54545SSubhransu S. Prusty static void hdac_hdmi_repoll_eld(struct work_struct *work) 556*b8a54545SSubhransu S. Prusty { 557*b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin = 558*b8a54545SSubhransu S. Prusty container_of(to_delayed_work(work), struct hdac_hdmi_pin, work); 559*b8a54545SSubhransu S. Prusty 560*b8a54545SSubhransu S. Prusty /* picked from legacy HDA driver */ 561*b8a54545SSubhransu S. Prusty if (pin->repoll_count++ > 6) 562*b8a54545SSubhransu S. Prusty pin->repoll_count = 0; 563*b8a54545SSubhransu S. Prusty 564*b8a54545SSubhransu S. Prusty hdac_hdmi_present_sense(pin, pin->repoll_count); 565*b8a54545SSubhransu S. Prusty } 566*b8a54545SSubhransu S. Prusty 56715b91447SSubhransu S. Prusty static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) 56815b91447SSubhransu S. Prusty { 56915b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 57015b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 57115b91447SSubhransu S. Prusty 57215b91447SSubhransu S. Prusty pin = kzalloc(sizeof(*pin), GFP_KERNEL); 57315b91447SSubhransu S. Prusty if (!pin) 57415b91447SSubhransu S. Prusty return -ENOMEM; 57515b91447SSubhransu S. Prusty 57615b91447SSubhransu S. Prusty pin->nid = nid; 57715b91447SSubhransu S. Prusty 57815b91447SSubhransu S. Prusty list_add_tail(&pin->head, &hdmi->pin_list); 57915b91447SSubhransu S. Prusty hdmi->num_pin++; 58015b91447SSubhransu S. Prusty 581*b8a54545SSubhransu S. Prusty pin->edev = edev; 582*b8a54545SSubhransu S. Prusty INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); 583*b8a54545SSubhransu S. Prusty 58415b91447SSubhransu S. Prusty return 0; 58518382eadSSubhransu S. Prusty } 58618382eadSSubhransu S. Prusty 58718382eadSSubhransu S. Prusty /* 58818382eadSSubhransu S. Prusty * Parse all nodes and store the cvt/pin nids in array 58918382eadSSubhransu S. Prusty * Add one time initialization for pin and cvt widgets 59018382eadSSubhransu S. Prusty */ 59118382eadSSubhransu S. Prusty static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) 59218382eadSSubhransu S. Prusty { 59318382eadSSubhransu S. Prusty hda_nid_t nid; 5943c83ac23SSudip Mukherjee int i, num_nodes; 59518382eadSSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 59618382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 59715b91447SSubhransu S. Prusty int ret; 59818382eadSSubhransu S. Prusty 5993c83ac23SSudip Mukherjee num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); 600541140d4SSubhransu S. Prusty if (!nid || num_nodes <= 0) { 60118382eadSSubhransu S. Prusty dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); 60218382eadSSubhransu S. Prusty return -EINVAL; 60318382eadSSubhransu S. Prusty } 60418382eadSSubhransu S. Prusty 6053c83ac23SSudip Mukherjee hdac->num_nodes = num_nodes; 60618382eadSSubhransu S. Prusty hdac->start_nid = nid; 60718382eadSSubhransu S. Prusty 60818382eadSSubhransu S. Prusty for (i = 0; i < hdac->num_nodes; i++, nid++) { 60918382eadSSubhransu S. Prusty unsigned int caps; 61018382eadSSubhransu S. Prusty unsigned int type; 61118382eadSSubhransu S. Prusty 61218382eadSSubhransu S. Prusty caps = get_wcaps(hdac, nid); 61318382eadSSubhransu S. Prusty type = get_wcaps_type(caps); 61418382eadSSubhransu S. Prusty 61518382eadSSubhransu S. Prusty if (!(caps & AC_WCAP_DIGITAL)) 61618382eadSSubhransu S. Prusty continue; 61718382eadSSubhransu S. Prusty 61818382eadSSubhransu S. Prusty switch (type) { 61918382eadSSubhransu S. Prusty 62018382eadSSubhransu S. Prusty case AC_WID_AUD_OUT: 62115b91447SSubhransu S. Prusty ret = hdac_hdmi_add_cvt(edev, nid); 62215b91447SSubhransu S. Prusty if (ret < 0) 62315b91447SSubhransu S. Prusty return ret; 62418382eadSSubhransu S. Prusty break; 62518382eadSSubhransu S. Prusty 62618382eadSSubhransu S. Prusty case AC_WID_PIN: 62715b91447SSubhransu S. Prusty ret = hdac_hdmi_add_pin(edev, nid); 62815b91447SSubhransu S. Prusty if (ret < 0) 62915b91447SSubhransu S. Prusty return ret; 63018382eadSSubhransu S. Prusty break; 63118382eadSSubhransu S. Prusty } 63218382eadSSubhransu S. Prusty } 63318382eadSSubhransu S. Prusty 63418382eadSSubhransu S. Prusty hdac->end_nid = nid; 63518382eadSSubhransu S. Prusty 63615b91447SSubhransu S. Prusty if (!hdmi->num_pin || !hdmi->num_cvt) 63718382eadSSubhransu S. Prusty return -EIO; 63818382eadSSubhransu S. Prusty 63915b91447SSubhransu S. Prusty return hdac_hdmi_init_dai_map(edev); 64018382eadSSubhransu S. Prusty } 64118382eadSSubhransu S. Prusty 642*b8a54545SSubhransu S. Prusty static void hdac_hdmi_eld_notify_cb(void *aptr, int port) 643*b8a54545SSubhransu S. Prusty { 644*b8a54545SSubhransu S. Prusty struct hdac_ext_device *edev = aptr; 645*b8a54545SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 646*b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 647*b8a54545SSubhransu S. Prusty struct snd_soc_codec *codec = edev->scodec; 648*b8a54545SSubhransu S. Prusty 649*b8a54545SSubhransu S. Prusty /* Don't know how this mapping is derived */ 650*b8a54545SSubhransu S. Prusty hda_nid_t pin_nid = port + 0x04; 651*b8a54545SSubhransu S. Prusty 652*b8a54545SSubhransu S. Prusty dev_dbg(&edev->hdac.dev, "%s: for pin: %d\n", __func__, pin_nid); 653*b8a54545SSubhransu S. Prusty 654*b8a54545SSubhransu S. Prusty /* 655*b8a54545SSubhransu S. Prusty * skip notification during system suspend (but not in runtime PM); 656*b8a54545SSubhransu S. Prusty * the state will be updated at resume. Also since the ELD and 657*b8a54545SSubhransu S. Prusty * connection states are updated in anyway at the end of the resume, 658*b8a54545SSubhransu S. Prusty * we can skip it when received during PM process. 659*b8a54545SSubhransu S. Prusty */ 660*b8a54545SSubhransu S. Prusty if (snd_power_get_state(codec->component.card->snd_card) != 661*b8a54545SSubhransu S. Prusty SNDRV_CTL_POWER_D0) 662*b8a54545SSubhransu S. Prusty return; 663*b8a54545SSubhransu S. Prusty 664*b8a54545SSubhransu S. Prusty if (atomic_read(&edev->hdac.in_pm)) 665*b8a54545SSubhransu S. Prusty return; 666*b8a54545SSubhransu S. Prusty 667*b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) { 668*b8a54545SSubhransu S. Prusty if (pin->nid == pin_nid) 669*b8a54545SSubhransu S. Prusty hdac_hdmi_present_sense(pin, 1); 670*b8a54545SSubhransu S. Prusty } 671*b8a54545SSubhransu S. Prusty } 672*b8a54545SSubhransu S. Prusty 673*b8a54545SSubhransu S. Prusty static struct i915_audio_component_audio_ops aops = { 674*b8a54545SSubhransu S. Prusty .pin_eld_notify = hdac_hdmi_eld_notify_cb, 675*b8a54545SSubhransu S. Prusty }; 676*b8a54545SSubhransu S. Prusty 67718382eadSSubhransu S. Prusty static int hdmi_codec_probe(struct snd_soc_codec *codec) 67818382eadSSubhransu S. Prusty { 67918382eadSSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 68018382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 68118382eadSSubhransu S. Prusty struct snd_soc_dapm_context *dapm = 68218382eadSSubhransu S. Prusty snd_soc_component_get_dapm(&codec->component); 683*b8a54545SSubhransu S. Prusty struct hdac_hdmi_pin *pin; 684*b8a54545SSubhransu S. Prusty int ret; 68518382eadSSubhransu S. Prusty 68618382eadSSubhransu S. Prusty edev->scodec = codec; 68718382eadSSubhransu S. Prusty 68818382eadSSubhransu S. Prusty create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); 68918382eadSSubhransu S. Prusty 690*b8a54545SSubhransu S. Prusty aops.audio_ptr = edev; 691*b8a54545SSubhransu S. Prusty ret = snd_hdac_i915_register_notifier(&aops); 692*b8a54545SSubhransu S. Prusty if (ret < 0) { 693*b8a54545SSubhransu S. Prusty dev_err(&edev->hdac.dev, "notifier register failed: err: %d\n", 694*b8a54545SSubhransu S. Prusty ret); 695*b8a54545SSubhransu S. Prusty return ret; 696*b8a54545SSubhransu S. Prusty } 697*b8a54545SSubhransu S. Prusty 698*b8a54545SSubhransu S. Prusty list_for_each_entry(pin, &hdmi->pin_list, head) 699*b8a54545SSubhransu S. Prusty hdac_hdmi_present_sense(pin, 1); 700*b8a54545SSubhransu S. Prusty 70118382eadSSubhransu S. Prusty /* Imp: Store the card pointer in hda_codec */ 70218382eadSSubhransu S. Prusty edev->card = dapm->card->snd_card; 70318382eadSSubhransu S. Prusty 704e342ac08SSubhransu S. Prusty /* 705e342ac08SSubhransu S. Prusty * hdac_device core already sets the state to active and calls 706e342ac08SSubhransu S. Prusty * get_noresume. So enable runtime and set the device to suspend. 707e342ac08SSubhransu S. Prusty */ 708e342ac08SSubhransu S. Prusty pm_runtime_enable(&edev->hdac.dev); 709e342ac08SSubhransu S. Prusty pm_runtime_put(&edev->hdac.dev); 710e342ac08SSubhransu S. Prusty pm_runtime_suspend(&edev->hdac.dev); 711e342ac08SSubhransu S. Prusty 712e342ac08SSubhransu S. Prusty return 0; 713e342ac08SSubhransu S. Prusty } 714e342ac08SSubhransu S. Prusty 715e342ac08SSubhransu S. Prusty static int hdmi_codec_remove(struct snd_soc_codec *codec) 716e342ac08SSubhransu S. Prusty { 717e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); 718e342ac08SSubhransu S. Prusty 719e342ac08SSubhransu S. Prusty pm_runtime_disable(&edev->hdac.dev); 72018382eadSSubhransu S. Prusty return 0; 72118382eadSSubhransu S. Prusty } 72218382eadSSubhransu S. Prusty 72318382eadSSubhransu S. Prusty static struct snd_soc_codec_driver hdmi_hda_codec = { 72418382eadSSubhransu S. Prusty .probe = hdmi_codec_probe, 725e342ac08SSubhransu S. Prusty .remove = hdmi_codec_remove, 72618382eadSSubhransu S. Prusty .idle_bias_off = true, 72718382eadSSubhransu S. Prusty }; 72818382eadSSubhransu S. Prusty 729b0362adbSSubhransu S. Prusty static struct snd_soc_dai_ops hdmi_dai_ops = { 730b0362adbSSubhransu S. Prusty .startup = hdac_hdmi_pcm_open, 731b0362adbSSubhransu S. Prusty .shutdown = hdac_hdmi_pcm_close, 732b0362adbSSubhransu S. Prusty .hw_params = hdac_hdmi_set_hw_params, 733b0362adbSSubhransu S. Prusty .prepare = hdac_hdmi_playback_prepare, 734b0362adbSSubhransu S. Prusty .hw_free = hdac_hdmi_playback_cleanup, 735b0362adbSSubhransu S. Prusty }; 736b0362adbSSubhransu S. Prusty 73718382eadSSubhransu S. Prusty static struct snd_soc_dai_driver hdmi_dais[] = { 73818382eadSSubhransu S. Prusty { .name = "intel-hdmi-hif1", 73918382eadSSubhransu S. Prusty .playback = { 74018382eadSSubhransu S. Prusty .stream_name = "hif1", 74118382eadSSubhransu S. Prusty .channels_min = 2, 74218382eadSSubhransu S. Prusty .channels_max = 2, 74318382eadSSubhransu S. Prusty .rates = SNDRV_PCM_RATE_32000 | 74418382eadSSubhransu S. Prusty SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | 74518382eadSSubhransu S. Prusty SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | 74618382eadSSubhransu S. Prusty SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, 74718382eadSSubhransu S. Prusty .formats = SNDRV_PCM_FMTBIT_S16_LE | 74818382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S20_3LE | 74918382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S24_LE | 75018382eadSSubhransu S. Prusty SNDRV_PCM_FMTBIT_S32_LE, 75118382eadSSubhransu S. Prusty 75218382eadSSubhransu S. Prusty }, 753b0362adbSSubhransu S. Prusty .ops = &hdmi_dai_ops, 75418382eadSSubhransu S. Prusty }, 75518382eadSSubhransu S. Prusty }; 75618382eadSSubhransu S. Prusty 75718382eadSSubhransu S. Prusty static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) 75818382eadSSubhransu S. Prusty { 75918382eadSSubhransu S. Prusty struct hdac_device *codec = &edev->hdac; 76018382eadSSubhransu S. Prusty struct hdac_hdmi_priv *hdmi_priv; 76118382eadSSubhransu S. Prusty int ret = 0; 76218382eadSSubhransu S. Prusty 76318382eadSSubhransu S. Prusty hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); 76418382eadSSubhransu S. Prusty if (hdmi_priv == NULL) 76518382eadSSubhransu S. Prusty return -ENOMEM; 76618382eadSSubhransu S. Prusty 76718382eadSSubhransu S. Prusty edev->private_data = hdmi_priv; 76818382eadSSubhransu S. Prusty 76918382eadSSubhransu S. Prusty dev_set_drvdata(&codec->dev, edev); 77018382eadSSubhransu S. Prusty 77115b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->pin_list); 77215b91447SSubhransu S. Prusty INIT_LIST_HEAD(&hdmi_priv->cvt_list); 77315b91447SSubhransu S. Prusty 77418382eadSSubhransu S. Prusty ret = hdac_hdmi_parse_and_map_nid(edev); 77518382eadSSubhransu S. Prusty if (ret < 0) 77618382eadSSubhransu S. Prusty return ret; 77718382eadSSubhransu S. Prusty 77818382eadSSubhransu S. Prusty /* ASoC specific initialization */ 77918382eadSSubhransu S. Prusty return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, 78018382eadSSubhransu S. Prusty hdmi_dais, ARRAY_SIZE(hdmi_dais)); 78118382eadSSubhransu S. Prusty } 78218382eadSSubhransu S. Prusty 78318382eadSSubhransu S. Prusty static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) 78418382eadSSubhransu S. Prusty { 78515b91447SSubhransu S. Prusty struct hdac_hdmi_priv *hdmi = edev->private_data; 78615b91447SSubhransu S. Prusty struct hdac_hdmi_pin *pin, *pin_next; 78715b91447SSubhransu S. Prusty struct hdac_hdmi_cvt *cvt, *cvt_next; 78815b91447SSubhransu S. Prusty 78918382eadSSubhransu S. Prusty snd_soc_unregister_codec(&edev->hdac.dev); 79018382eadSSubhransu S. Prusty 79115b91447SSubhransu S. Prusty list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { 79215b91447SSubhransu S. Prusty list_del(&cvt->head); 79315b91447SSubhransu S. Prusty kfree(cvt); 79415b91447SSubhransu S. Prusty } 79515b91447SSubhransu S. Prusty 79615b91447SSubhransu S. Prusty list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { 79715b91447SSubhransu S. Prusty list_del(&pin->head); 79815b91447SSubhransu S. Prusty kfree(pin); 79915b91447SSubhransu S. Prusty } 80015b91447SSubhransu S. Prusty 80118382eadSSubhransu S. Prusty return 0; 80218382eadSSubhransu S. Prusty } 80318382eadSSubhransu S. Prusty 804e342ac08SSubhransu S. Prusty #ifdef CONFIG_PM 805e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_suspend(struct device *dev) 806e342ac08SSubhransu S. Prusty { 807e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 808e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 80907f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 81007f083abSSubhransu S. Prusty int err; 811e342ac08SSubhransu S. Prusty 812e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 813e342ac08SSubhransu S. Prusty 81407f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 81507f083abSSubhransu S. Prusty if (!bus) 81607f083abSSubhransu S. Prusty return 0; 81707f083abSSubhransu S. Prusty 818e342ac08SSubhransu S. Prusty /* Power down afg */ 819e342ac08SSubhransu S. Prusty if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) 820e342ac08SSubhransu S. Prusty snd_hdac_codec_write(hdac, hdac->afg, 0, 821e342ac08SSubhransu S. Prusty AC_VERB_SET_POWER_STATE, AC_PWRST_D3); 822e342ac08SSubhransu S. Prusty 82307f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, false); 82407f083abSSubhransu S. Prusty if (err < 0) { 82507f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 82607f083abSSubhransu S. Prusty return err; 82707f083abSSubhransu S. Prusty } 82807f083abSSubhransu S. Prusty 829e342ac08SSubhransu S. Prusty return 0; 830e342ac08SSubhransu S. Prusty } 831e342ac08SSubhransu S. Prusty 832e342ac08SSubhransu S. Prusty static int hdac_hdmi_runtime_resume(struct device *dev) 833e342ac08SSubhransu S. Prusty { 834e342ac08SSubhransu S. Prusty struct hdac_ext_device *edev = to_hda_ext_device(dev); 835e342ac08SSubhransu S. Prusty struct hdac_device *hdac = &edev->hdac; 83607f083abSSubhransu S. Prusty struct hdac_bus *bus = hdac->bus; 83707f083abSSubhransu S. Prusty int err; 838e342ac08SSubhransu S. Prusty 839e342ac08SSubhransu S. Prusty dev_dbg(dev, "Enter: %s\n", __func__); 840e342ac08SSubhransu S. Prusty 84107f083abSSubhransu S. Prusty /* controller may not have been initialized for the first time */ 84207f083abSSubhransu S. Prusty if (!bus) 84307f083abSSubhransu S. Prusty return 0; 84407f083abSSubhransu S. Prusty 84507f083abSSubhransu S. Prusty err = snd_hdac_display_power(bus, true); 84607f083abSSubhransu S. Prusty if (err < 0) { 84707f083abSSubhransu S. Prusty dev_err(bus->dev, "Cannot turn on display power on i915\n"); 84807f083abSSubhransu S. Prusty return err; 84907f083abSSubhransu S. Prusty } 85007f083abSSubhransu S. Prusty 851e342ac08SSubhransu S. Prusty /* Power up afg */ 852e342ac08SSubhransu S. Prusty if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) 853e342ac08SSubhransu S. Prusty snd_hdac_codec_write(hdac, hdac->afg, 0, 854e342ac08SSubhransu S. Prusty AC_VERB_SET_POWER_STATE, AC_PWRST_D0); 855e342ac08SSubhransu S. Prusty 856e342ac08SSubhransu S. Prusty return 0; 857e342ac08SSubhransu S. Prusty } 858e342ac08SSubhransu S. Prusty #else 859e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_suspend NULL 860e342ac08SSubhransu S. Prusty #define hdac_hdmi_runtime_resume NULL 861e342ac08SSubhransu S. Prusty #endif 862e342ac08SSubhransu S. Prusty 863e342ac08SSubhransu S. Prusty static const struct dev_pm_ops hdac_hdmi_pm = { 864e342ac08SSubhransu S. Prusty SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) 865e342ac08SSubhransu S. Prusty }; 866e342ac08SSubhransu S. Prusty 86718382eadSSubhransu S. Prusty static const struct hda_device_id hdmi_list[] = { 86818382eadSSubhransu S. Prusty HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), 86918382eadSSubhransu S. Prusty {} 87018382eadSSubhransu S. Prusty }; 87118382eadSSubhransu S. Prusty 87218382eadSSubhransu S. Prusty MODULE_DEVICE_TABLE(hdaudio, hdmi_list); 87318382eadSSubhransu S. Prusty 87418382eadSSubhransu S. Prusty static struct hdac_ext_driver hdmi_driver = { 87518382eadSSubhransu S. Prusty . hdac = { 87618382eadSSubhransu S. Prusty .driver = { 87718382eadSSubhransu S. Prusty .name = "HDMI HDA Codec", 878e342ac08SSubhransu S. Prusty .pm = &hdac_hdmi_pm, 87918382eadSSubhransu S. Prusty }, 88018382eadSSubhransu S. Prusty .id_table = hdmi_list, 88118382eadSSubhransu S. Prusty }, 88218382eadSSubhransu S. Prusty .probe = hdac_hdmi_dev_probe, 88318382eadSSubhransu S. Prusty .remove = hdac_hdmi_dev_remove, 88418382eadSSubhransu S. Prusty }; 88518382eadSSubhransu S. Prusty 88618382eadSSubhransu S. Prusty static int __init hdmi_init(void) 88718382eadSSubhransu S. Prusty { 88818382eadSSubhransu S. Prusty return snd_hda_ext_driver_register(&hdmi_driver); 88918382eadSSubhransu S. Prusty } 89018382eadSSubhransu S. Prusty 89118382eadSSubhransu S. Prusty static void __exit hdmi_exit(void) 89218382eadSSubhransu S. Prusty { 89318382eadSSubhransu S. Prusty snd_hda_ext_driver_unregister(&hdmi_driver); 89418382eadSSubhransu S. Prusty } 89518382eadSSubhransu S. Prusty 89618382eadSSubhransu S. Prusty module_init(hdmi_init); 89718382eadSSubhransu S. Prusty module_exit(hdmi_exit); 89818382eadSSubhransu S. Prusty 89918382eadSSubhransu S. Prusty MODULE_LICENSE("GPL v2"); 90018382eadSSubhransu S. Prusty MODULE_DESCRIPTION("HDMI HD codec"); 90118382eadSSubhransu S. Prusty MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); 90218382eadSSubhransu S. Prusty MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); 903