arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / sound / soc / meson / aiu-encoder-i2s.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // Copyright (c) 2020 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
5
6 #include <linux/bitfield.h>
7 #include <linux/clk.h>
8 #include <sound/pcm_params.h>
9 #include <sound/soc.h>
10 #include <sound/soc-dai.h>
11
12 #include "aiu.h"
13
14 #define AIU_I2S_SOURCE_DESC_MODE_8CH    BIT(0)
15 #define AIU_I2S_SOURCE_DESC_MODE_24BIT  BIT(5)
16 #define AIU_I2S_SOURCE_DESC_MODE_32BIT  BIT(9)
17 #define AIU_I2S_SOURCE_DESC_MODE_SPLIT  BIT(11)
18 #define AIU_RST_SOFT_I2S_FAST           BIT(0)
19
20 #define AIU_I2S_DAC_CFG_MSB_FIRST       BIT(2)
21 #define AIU_CLK_CTRL_I2S_DIV_EN         BIT(0)
22 #define AIU_CLK_CTRL_I2S_DIV            GENMASK(3, 2)
23 #define AIU_CLK_CTRL_AOCLK_INVERT       BIT(6)
24 #define AIU_CLK_CTRL_LRCLK_INVERT       BIT(7)
25 #define AIU_CLK_CTRL_LRCLK_SKEW         GENMASK(9, 8)
26 #define AIU_CLK_CTRL_MORE_HDMI_AMCLK    BIT(6)
27 #define AIU_CLK_CTRL_MORE_I2S_DIV       GENMASK(5, 0)
28 #define AIU_CODEC_DAC_LRCLK_CTRL_DIV    GENMASK(11, 0)
29
30 static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
31                                            bool enable)
32 {
33         snd_soc_component_update_bits(component, AIU_CLK_CTRL,
34                                       AIU_CLK_CTRL_I2S_DIV_EN,
35                                       enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
36 }
37
38 static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
39                                       struct snd_pcm_hw_params *params)
40 {
41         /* Always operate in split (classic interleaved) mode */
42         unsigned int desc = AIU_I2S_SOURCE_DESC_MODE_SPLIT;
43
44         /* Reset required to update the pipeline */
45         snd_soc_component_write(component, AIU_RST_SOFT, AIU_RST_SOFT_I2S_FAST);
46         snd_soc_component_read(component, AIU_I2S_SYNC);
47
48         switch (params_physical_width(params)) {
49         case 16: /* Nothing to do */
50                 break;
51
52         case 32:
53                 desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
54                          AIU_I2S_SOURCE_DESC_MODE_32BIT);
55                 break;
56
57         default:
58                 return -EINVAL;
59         }
60
61         switch (params_channels(params)) {
62         case 2: /* Nothing to do */
63                 break;
64         case 8:
65                 desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
66                 break;
67         default:
68                 return -EINVAL;
69         }
70
71         snd_soc_component_update_bits(component, AIU_I2S_SOURCE_DESC,
72                                       AIU_I2S_SOURCE_DESC_MODE_8CH |
73                                       AIU_I2S_SOURCE_DESC_MODE_24BIT |
74                                       AIU_I2S_SOURCE_DESC_MODE_32BIT |
75                                       AIU_I2S_SOURCE_DESC_MODE_SPLIT,
76                                       desc);
77
78         return 0;
79 }
80
81 static int aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component,
82                                           struct snd_pcm_hw_params *params,
83                                           unsigned int bs)
84 {
85         switch (bs) {
86         case 1:
87         case 2:
88         case 4:
89         case 8:
90                 /* These are the only valid legacy dividers */
91                 break;
92
93         default:
94                 dev_err(component->dev, "Unsupported i2s divider: %u\n", bs);
95                 return -EINVAL;
96         }
97
98         snd_soc_component_update_bits(component, AIU_CLK_CTRL,
99                                       AIU_CLK_CTRL_I2S_DIV,
100                                       FIELD_PREP(AIU_CLK_CTRL_I2S_DIV,
101                                                  __ffs(bs)));
102
103         snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
104                                       AIU_CLK_CTRL_MORE_I2S_DIV,
105                                       FIELD_PREP(AIU_CLK_CTRL_MORE_I2S_DIV,
106                                                  0));
107
108         return 0;
109 }
110
111 static int aiu_encoder_i2s_set_more_div(struct snd_soc_component *component,
112                                         struct snd_pcm_hw_params *params,
113                                         unsigned int bs)
114 {
115         /*
116          * NOTE: this HW is odd.
117          * In most configuration, the i2s divider is 'mclk / blck'.
118          * However, in 16 bits - 8ch mode, this factor needs to be
119          * increased by 50% to get the correct output rate.
120          * No idea why !
121          */
122         if (params_width(params) == 16 && params_channels(params) == 8) {
123                 if (bs % 2) {
124                         dev_err(component->dev,
125                                 "Cannot increase i2s divider by 50%%\n");
126                         return -EINVAL;
127                 }
128                 bs += bs / 2;
129         }
130
131         /* Use CLK_MORE for mclk to bclk divider */
132         snd_soc_component_update_bits(component, AIU_CLK_CTRL,
133                                       AIU_CLK_CTRL_I2S_DIV,
134                                       FIELD_PREP(AIU_CLK_CTRL_I2S_DIV, 0));
135
136         snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
137                                       AIU_CLK_CTRL_MORE_I2S_DIV,
138                                       FIELD_PREP(AIU_CLK_CTRL_MORE_I2S_DIV,
139                                                  bs - 1));
140
141         return 0;
142 }
143
144 static int aiu_encoder_i2s_set_clocks(struct snd_soc_component *component,
145                                       struct snd_pcm_hw_params *params)
146 {
147         struct aiu *aiu = snd_soc_component_get_drvdata(component);
148         unsigned int srate = params_rate(params);
149         unsigned int fs, bs;
150         int ret;
151
152         /* Get the oversampling factor */
153         fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate);
154
155         if (fs % 64)
156                 return -EINVAL;
157
158         /* Send data MSB first */
159         snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
160                                       AIU_I2S_DAC_CFG_MSB_FIRST,
161                                       AIU_I2S_DAC_CFG_MSB_FIRST);
162
163         /* Set bclk to lrlck ratio */
164         snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
165                                       AIU_CODEC_DAC_LRCLK_CTRL_DIV,
166                                       FIELD_PREP(AIU_CODEC_DAC_LRCLK_CTRL_DIV,
167                                                  64 - 1));
168
169         bs = fs / 64;
170
171         if (aiu->platform->has_clk_ctrl_more_i2s_div)
172                 ret = aiu_encoder_i2s_set_more_div(component, params, bs);
173         else
174                 ret = aiu_encoder_i2s_set_legacy_div(component, params, bs);
175
176         if (ret)
177                 return ret;
178
179         /* Make sure amclk is used for HDMI i2s as well */
180         snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
181                                       AIU_CLK_CTRL_MORE_HDMI_AMCLK,
182                                       AIU_CLK_CTRL_MORE_HDMI_AMCLK);
183
184         return 0;
185 }
186
187 static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
188                                      struct snd_pcm_hw_params *params,
189                                      struct snd_soc_dai *dai)
190 {
191         struct snd_soc_component *component = dai->component;
192         int ret;
193
194         /* Disable the clock while changing the settings */
195         aiu_encoder_i2s_divider_enable(component, false);
196
197         ret = aiu_encoder_i2s_setup_desc(component, params);
198         if (ret) {
199                 dev_err(dai->dev, "setting i2s desc failed\n");
200                 return ret;
201         }
202
203         ret = aiu_encoder_i2s_set_clocks(component, params);
204         if (ret) {
205                 dev_err(dai->dev, "setting i2s clocks failed\n");
206                 return ret;
207         }
208
209         aiu_encoder_i2s_divider_enable(component, true);
210
211         return 0;
212 }
213
214 static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
215                                    struct snd_soc_dai *dai)
216 {
217         struct snd_soc_component *component = dai->component;
218
219         aiu_encoder_i2s_divider_enable(component, false);
220
221         return 0;
222 }
223
224 static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
225 {
226         struct snd_soc_component *component = dai->component;
227         unsigned int inv = fmt & SND_SOC_DAIFMT_INV_MASK;
228         unsigned int val = 0;
229         unsigned int skew;
230
231         /* Only CPU Master / Codec Slave supported ATM */
232         if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP)
233                 return -EINVAL;
234
235         if (inv == SND_SOC_DAIFMT_NB_IF ||
236             inv == SND_SOC_DAIFMT_IB_IF)
237                 val |= AIU_CLK_CTRL_LRCLK_INVERT;
238
239         if (inv == SND_SOC_DAIFMT_IB_NF ||
240             inv == SND_SOC_DAIFMT_IB_IF)
241                 val |= AIU_CLK_CTRL_AOCLK_INVERT;
242
243         /* Signal skew */
244         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
245         case SND_SOC_DAIFMT_I2S:
246                 /* Invert sample clock for i2s */
247                 val ^= AIU_CLK_CTRL_LRCLK_INVERT;
248                 skew = 1;
249                 break;
250         case SND_SOC_DAIFMT_LEFT_J:
251                 skew = 0;
252                 break;
253         default:
254                 return -EINVAL;
255         }
256
257         val |= FIELD_PREP(AIU_CLK_CTRL_LRCLK_SKEW, skew);
258         snd_soc_component_update_bits(component, AIU_CLK_CTRL,
259                                       AIU_CLK_CTRL_LRCLK_INVERT |
260                                       AIU_CLK_CTRL_AOCLK_INVERT |
261                                       AIU_CLK_CTRL_LRCLK_SKEW,
262                                       val);
263
264         return 0;
265 }
266
267 static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
268                                       unsigned int freq, int dir)
269 {
270         struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
271         int ret;
272
273         if (WARN_ON(clk_id != 0))
274                 return -EINVAL;
275
276         if (dir == SND_SOC_CLOCK_IN)
277                 return 0;
278
279         ret = clk_set_rate(aiu->i2s.clks[MCLK].clk, freq);
280         if (ret)
281                 dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
282
283         return ret;
284 }
285
286 static const unsigned int hw_channels[] = {2, 8};
287 static const struct snd_pcm_hw_constraint_list hw_channel_constraints = {
288         .list = hw_channels,
289         .count = ARRAY_SIZE(hw_channels),
290         .mask = 0,
291 };
292
293 static int aiu_encoder_i2s_startup(struct snd_pcm_substream *substream,
294                                    struct snd_soc_dai *dai)
295 {
296         struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
297         int ret;
298
299         /* Make sure the encoder gets either 2 or 8 channels */
300         ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
301                                          SNDRV_PCM_HW_PARAM_CHANNELS,
302                                          &hw_channel_constraints);
303         if (ret) {
304                 dev_err(dai->dev, "adding channels constraints failed\n");
305                 return ret;
306         }
307
308         ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks);
309         if (ret)
310                 dev_err(dai->dev, "failed to enable i2s clocks\n");
311
312         return ret;
313 }
314
315 static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
316                                      struct snd_soc_dai *dai)
317 {
318         struct aiu *aiu = snd_soc_component_get_drvdata(dai->component);
319
320         clk_bulk_disable_unprepare(aiu->i2s.clk_num, aiu->i2s.clks);
321 }
322
323 const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
324         .hw_params      = aiu_encoder_i2s_hw_params,
325         .hw_free        = aiu_encoder_i2s_hw_free,
326         .set_fmt        = aiu_encoder_i2s_set_fmt,
327         .set_sysclk     = aiu_encoder_i2s_set_sysclk,
328         .startup        = aiu_encoder_i2s_startup,
329         .shutdown       = aiu_encoder_i2s_shutdown,
330 };
331