GNU Linux-libre 5.10.76-gnu1
[releases.git] / sound / soc / qcom / lpass-hdmi.c
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         if (ret)
187                 return ret;
188
189         return ret;
190 }
191
192 static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream,
193                 struct snd_soc_dai *dai)
194 {
195         int ret;
196         struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
197
198         ret = regmap_field_write(drvdata->sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);
199         if (ret)
200                 return ret;
201
202         ret = regmap_field_write(drvdata->meta_ctl->mute, LPASS_MUTE_DISABLE);
203         if (ret)
204                 return ret;
205
206         return ret;
207 }
208
209 static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream,
210                 int cmd, struct snd_soc_dai *dai)
211 {
212         struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
213         struct lpass_dp_metadata_ctl *meta_ctl = drvdata->meta_ctl;
214         struct lpass_sstream_ctl *sstream_ctl = drvdata->sstream_ctl;
215         int ret = -EINVAL;
216
217         switch (cmd) {
218         case SNDRV_PCM_TRIGGER_START:
219         case SNDRV_PCM_TRIGGER_RESUME:
220         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
221                 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_ENABLE);
222                 if (ret)
223                         return ret;
224
225                 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_DISABLE);
226                 if (ret)
227                         return ret;
228
229                 break;
230         case SNDRV_PCM_TRIGGER_STOP:
231         case SNDRV_PCM_TRIGGER_SUSPEND:
232         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
233                 ret = regmap_field_write(sstream_ctl->sstream_en, LPASS_SSTREAM_DISABLE);
234                 if (ret)
235                         return ret;
236
237                 ret = regmap_field_write(meta_ctl->mute, LPASS_MUTE_ENABLE);
238                 if (ret)
239                         return ret;
240
241                 ret = regmap_field_write(sstream_ctl->dp_audio, 0);
242                 if (ret)
243                         return ret;
244
245                 break;
246         }
247         return ret;
248 }
249
250 const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
251         .hw_params      = lpass_hdmi_daiops_hw_params,
252         .prepare        = lpass_hdmi_daiops_prepare,
253         .trigger        = lpass_hdmi_daiops_trigger,
254 };
255 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
256
257 MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
258 MODULE_LICENSE("GPL v2");