1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2020 The Linux Foundation. All rights reserved. 4 * 5 * lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI 6 */ 7 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <sound/pcm_params.h> 12 #include <linux/regmap.h> 13 #include <sound/soc.h> 14 #include <sound/soc-dai.h> 15 #include <dt-bindings/sound/sc7180-lpass.h> 16 #include "lpass-lpaif-reg.h" 17 #include "lpass.h" 18 19 static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream, 20 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 21 { 22 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 23 snd_pcm_format_t format = params_format(params); 24 unsigned int rate = params_rate(params); 25 unsigned int channels = params_channels(params); 26 unsigned int ret; 27 int bitwidth; 28 unsigned int word_length; 29 unsigned int ch_sts_buf0; 30 unsigned int ch_sts_buf1; 31 unsigned int data_format; 32 unsigned int sampling_freq; 33 unsigned int ch = 0; 34 struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl; 35 struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl; 36 37 bitwidth = snd_pcm_format_width(format); 38 if (bitwidth < 0) { 39 dev_err(dai->dev, "%s invalid bit width given : %d\n", 40 __func__, bitwidth); 41 return bitwidth; 42 } 43 44 switch (bitwidth) { 45 case 16: 46 word_length = LPASS_DP_AUDIO_BITWIDTH16; 47 break; 48 case 24: 49 word_length = LPASS_DP_AUDIO_BITWIDTH24; 50 break; 51 default: 52 dev_err(dai->dev, "%s invalid bit width given : %d\n", 53 __func__, bitwidth); 54 return -EINVAL; 55 } 56 57 switch (rate) { 58 case 32000: 59 sampling_freq = LPASS_SAMPLING_FREQ32; 60 break; 61 case 44100: 62 sampling_freq = LPASS_SAMPLING_FREQ44; 63 break; 64 case 48000: 65 sampling_freq = LPASS_SAMPLING_FREQ48; 66 break; 67 default: 68 dev_err(dai->dev, "%s invalid bit width given : %d\n", 69 __func__, bitwidth); 70 return -EINVAL; 71 } 72 data_format = LPASS_DATA_FORMAT_LINEAR; 73 ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & LPASS_DATA_FORMAT_MASK) 74 | ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & LPASS_FREQ_BIT_MASK)); 75 ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK; 76 77 ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_RESET); 78 if (ret) 79 return ret; 80 81 ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_CLEAR); 82 if (ret) 83 return ret; 84 85 ret = regmap_field_write(drvdata->hdmitx_legacy_en, LPASS_HDMITX_LEGACY_DISABLE); 86 if (ret) 87 return ret; 88 89 ret = regmap_field_write(drvdata->hdmitx_parity_calc_en, HDMITX_PARITY_CALC_EN); 90 if (ret) 91 return ret; 92 93 ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit, REPLACE_VBIT); 94 if (ret) 95 return ret; 96 97 ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream, LINEAR_PCM_DATA); 98 if (ret) 99 return ret; 100 101 ret = regmap_field_write(drvdata->hdmitx_ch_msb[0], ch_sts_buf1); 102 if (ret) 103 return ret; 104 105 ret = regmap_field_write(drvdata->hdmitx_ch_lsb[0], ch_sts_buf0); 106 if (ret) 107 return ret; 108 109 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs, HW_MODE); 110 if (ret) 111 return ret; 112 113 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel, SW_MODE); 114 if (ret) 115 return ret; 116 117 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr, HW_MODE); 118 if (ret) 119 return ret; 120 121 ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel, SW_MODE); 122 if (ret) 123 return ret; 124 125 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE); 126 if (ret) 127 return ret; 128 129 ret = regmap_field_write(meta_ctl->as_sdp_cc, channels - 1); 130 if (ret) 131 return ret; 132 133 ret = regmap_field_write(meta_ctl->as_sdp_ct, LPASS_META_DEFAULT_VAL); 134 if (ret) 135 return ret; 136 137 ret = regmap_field_write(meta_ctl->aif_db4, LPASS_META_DEFAULT_VAL); 138 if (ret) 139 return ret; 140 141 ret = regmap_field_write(meta_ctl->frequency, sampling_freq); 142 if (ret) 143 return ret; 144 145 ret = regmap_field_write(meta_ctl->mst_index, LPASS_META_DEFAULT_VAL); 146 if (ret) 147 return ret; 148 149 ret = regmap_field_write(meta_ctl->dptx_index, LPASS_META_DEFAULT_VAL); 150 if (ret) 151 return ret; 152 153 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE); 154 if (ret) 155 return ret; 156 157 ret = regmap_field_write(sstream_ctl->dma_sel, ch); 158 if (ret) 159 return ret; 160 161 ret = regmap_field_write(sstream_ctl->auto_bbit_en, LPASS_SSTREAM_DEFAULT_ENABLE); 162 if (ret) 163 return ret; 164 165 ret = regmap_field_write(sstream_ctl->layout, LPASS_SSTREAM_DEFAULT_DISABLE); 166 if (ret) 167 return ret; 168 169 ret = regmap_field_write(sstream_ctl->layout_sp, LPASS_LAYOUT_SP_DEFAULT); 170 if (ret) 171 return ret; 172 173 ret = regmap_field_write(sstream_ctl->dp_audio, LPASS_SSTREAM_DEFAULT_ENABLE); 174 if (ret) 175 return ret; 176 177 ret = regmap_field_write(sstream_ctl->set_sp_on_en, LPASS_SSTREAM_DEFAULT_ENABLE); 178 if (ret) 179 return ret; 180 181 ret = regmap_field_write(sstream_ctl->dp_sp_b_hw_en, LPASS_SSTREAM_DEFAULT_ENABLE); 182 if (ret) 183 return ret; 184 185 ret = regmap_field_write(sstream_ctl->dp_staffing_en, LPASS_SSTREAM_DEFAULT_ENABLE); 186 187 return ret; 188 } 189 190 static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream, 191 struct snd_soc_dai *dai) 192 { 193 int ret; 194 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 195 196 ret = regmap_field_write(drvdata->sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE); 197 if (ret) 198 return ret; 199 200 ret = regmap_field_write(drvdata->meta_ctl->mute, LPASS_MUTE_DISABLE); 201 202 return ret; 203 } 204 205 static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream, 206 int cmd, struct snd_soc_dai *dai) 207 { 208 struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai); 209 struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl; 210 struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl; 211 int ret = -EINVAL; 212 213 switch (cmd) { 214 case SNDRV_PCM_TRIGGER_START: 215 case SNDRV_PCM_TRIGGER_RESUME: 216 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 217 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE); 218 if (ret) 219 return ret; 220 221 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_DISABLE); 222 if (ret) 223 return ret; 224 225 break; 226 case SNDRV_PCM_TRIGGER_STOP: 227 case SNDRV_PCM_TRIGGER_SUSPEND: 228 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 229 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE); 230 if (ret) 231 return ret; 232 233 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE); 234 if (ret) 235 return ret; 236 237 ret = regmap_field_write(sstream_ctl->dp_audio, 0); 238 if (ret) 239 return ret; 240 241 break; 242 } 243 return ret; 244 } 245 246 const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = { 247 .hw_params = lpass_hdmi_daiops_hw_params, 248 .prepare = lpass_hdmi_daiops_prepare, 249 .trigger = lpass_hdmi_daiops_trigger, 250 }; 251 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops); 252 253 MODULE_DESCRIPTION("QTi LPASS HDMI Driver"); 254 MODULE_LICENSE("GPL v2"); 255