~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // MediaTek ALSA SoC Audio DAI TDM Control
  4 //
  5 // Copyright (c) 2018 MediaTek Inc.
  6 // Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com>
  7 
  8 #include <linux/regmap.h>
  9 #include <sound/pcm_params.h>
 10 #include "mt8183-afe-clk.h"
 11 #include "mt8183-afe-common.h"
 12 #include "mt8183-interconnection.h"
 13 #include "mt8183-reg.h"
 14 
 15 struct mtk_afe_tdm_priv {
 16         int bck_id;
 17         int bck_rate;
 18         int tdm_out_mode;
 19         int bck_invert;
 20         int lck_invert;
 21         int mclk_id;
 22         int mclk_multiple; /* according to sample rate */
 23         int mclk_rate;
 24         int mclk_apll;
 25 };
 26 
 27 enum {
 28         TDM_OUT_I2S = 0,
 29         TDM_OUT_TDM = 1,
 30 };
 31 
 32 enum {
 33         TDM_BCK_NON_INV = 0,
 34         TDM_BCK_INV = 1,
 35 };
 36 
 37 enum {
 38         TDM_LCK_NON_INV = 0,
 39         TDM_LCK_INV = 1,
 40 };
 41 
 42 enum {
 43         TDM_WLEN_16_BIT = 1,
 44         TDM_WLEN_32_BIT = 2,
 45 };
 46 
 47 enum {
 48         TDM_CHANNEL_BCK_16 = 0,
 49         TDM_CHANNEL_BCK_24 = 1,
 50         TDM_CHANNEL_BCK_32 = 2,
 51 };
 52 
 53 enum {
 54         TDM_CHANNEL_NUM_2 = 0,
 55         TDM_CHANNEL_NUM_4 = 1,
 56         TDM_CHANNEL_NUM_8 = 2,
 57 };
 58 
 59 enum  {
 60         TDM_CH_START_O30_O31 = 0,
 61         TDM_CH_START_O32_O33,
 62         TDM_CH_START_O34_O35,
 63         TDM_CH_START_O36_O37,
 64         TDM_CH_ZERO,
 65 };
 66 
 67 enum {
 68         HDMI_BIT_WIDTH_16_BIT = 0,
 69         HDMI_BIT_WIDTH_32_BIT = 1,
 70 };
 71 
 72 static unsigned int get_hdmi_wlen(snd_pcm_format_t format)
 73 {
 74         return snd_pcm_format_physical_width(format) <= 16 ?
 75                HDMI_BIT_WIDTH_16_BIT : HDMI_BIT_WIDTH_32_BIT;
 76 }
 77 
 78 static unsigned int get_tdm_wlen(snd_pcm_format_t format)
 79 {
 80         return snd_pcm_format_physical_width(format) <= 16 ?
 81                TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
 82 }
 83 
 84 static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
 85 {
 86         return snd_pcm_format_physical_width(format) <= 16 ?
 87                TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
 88 }
 89 
 90 static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
 91 {
 92         return snd_pcm_format_physical_width(format) - 1;
 93 }
 94 
 95 static unsigned int get_tdm_ch(unsigned int ch)
 96 {
 97         switch (ch) {
 98         case 1:
 99         case 2:
100                 return TDM_CHANNEL_NUM_2;
101         case 3:
102         case 4:
103                 return TDM_CHANNEL_NUM_4;
104         case 5:
105         case 6:
106         case 7:
107         case 8:
108         default:
109                 return TDM_CHANNEL_NUM_8;
110         }
111 }
112 
113 static unsigned int get_tdm_ch_fixup(unsigned int channels)
114 {
115         if (channels > 4)
116                 return 8;
117         else if (channels > 2)
118                 return 4;
119         else
120                 return 2;
121 }
122 
123 static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
124                                          unsigned int channels)
125 {
126         if (mode == TDM_OUT_TDM)
127                 return get_tdm_ch_fixup(channels);
128         else
129                 return 2;
130 }
131 
132 /* interconnection */
133 enum {
134         HDMI_CONN_CH0 = 0,
135         HDMI_CONN_CH1,
136         HDMI_CONN_CH2,
137         HDMI_CONN_CH3,
138         HDMI_CONN_CH4,
139         HDMI_CONN_CH5,
140         HDMI_CONN_CH6,
141         HDMI_CONN_CH7,
142 };
143 
144 static const char *const hdmi_conn_mux_map[] = {
145         "CH0", "CH1", "CH2", "CH3",
146         "CH4", "CH5", "CH6", "CH7",
147 };
148 
149 static int hdmi_conn_mux_map_value[] = {
150         HDMI_CONN_CH0,
151         HDMI_CONN_CH1,
152         HDMI_CONN_CH2,
153         HDMI_CONN_CH3,
154         HDMI_CONN_CH4,
155         HDMI_CONN_CH5,
156         HDMI_CONN_CH6,
157         HDMI_CONN_CH7,
158 };
159 
160 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
161                                   AFE_HDMI_CONN0,
162                                   HDMI_O_0_SFT,
163                                   HDMI_O_0_MASK,
164                                   hdmi_conn_mux_map,
165                                   hdmi_conn_mux_map_value);
166 
167 static const struct snd_kcontrol_new hdmi_ch0_mux_control =
168         SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
169 
170 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
171                                   AFE_HDMI_CONN0,
172                                   HDMI_O_1_SFT,
173                                   HDMI_O_1_MASK,
174                                   hdmi_conn_mux_map,
175                                   hdmi_conn_mux_map_value);
176 
177 static const struct snd_kcontrol_new hdmi_ch1_mux_control =
178         SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
179 
180 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
181                                   AFE_HDMI_CONN0,
182                                   HDMI_O_2_SFT,
183                                   HDMI_O_2_MASK,
184                                   hdmi_conn_mux_map,
185                                   hdmi_conn_mux_map_value);
186 
187 static const struct snd_kcontrol_new hdmi_ch2_mux_control =
188         SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
189 
190 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
191                                   AFE_HDMI_CONN0,
192                                   HDMI_O_3_SFT,
193                                   HDMI_O_3_MASK,
194                                   hdmi_conn_mux_map,
195                                   hdmi_conn_mux_map_value);
196 
197 static const struct snd_kcontrol_new hdmi_ch3_mux_control =
198         SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
199 
200 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
201                                   AFE_HDMI_CONN0,
202                                   HDMI_O_4_SFT,
203                                   HDMI_O_4_MASK,
204                                   hdmi_conn_mux_map,
205                                   hdmi_conn_mux_map_value);
206 
207 static const struct snd_kcontrol_new hdmi_ch4_mux_control =
208         SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
209 
210 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
211                                   AFE_HDMI_CONN0,
212                                   HDMI_O_5_SFT,
213                                   HDMI_O_5_MASK,
214                                   hdmi_conn_mux_map,
215                                   hdmi_conn_mux_map_value);
216 
217 static const struct snd_kcontrol_new hdmi_ch5_mux_control =
218         SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
219 
220 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
221                                   AFE_HDMI_CONN0,
222                                   HDMI_O_6_SFT,
223                                   HDMI_O_6_MASK,
224                                   hdmi_conn_mux_map,
225                                   hdmi_conn_mux_map_value);
226 
227 static const struct snd_kcontrol_new hdmi_ch6_mux_control =
228         SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
229 
230 static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
231                                   AFE_HDMI_CONN0,
232                                   HDMI_O_7_SFT,
233                                   HDMI_O_7_MASK,
234                                   hdmi_conn_mux_map,
235                                   hdmi_conn_mux_map_value);
236 
237 static const struct snd_kcontrol_new hdmi_ch7_mux_control =
238         SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
239 
240 enum {
241         SUPPLY_SEQ_APLL,
242         SUPPLY_SEQ_TDM_MCK_EN,
243         SUPPLY_SEQ_TDM_BCK_EN,
244 };
245 
246 static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
247                                 struct snd_kcontrol *kcontrol,
248                                 int event)
249 {
250         struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
251         struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
252         struct mt8183_afe_private *afe_priv = afe->platform_priv;
253         struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
254 
255         dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
256                  __func__, w->name, event);
257 
258         switch (event) {
259         case SND_SOC_DAPM_PRE_PMU:
260                 mt8183_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
261                 break;
262         case SND_SOC_DAPM_POST_PMD:
263                 mt8183_mck_disable(afe, tdm_priv->bck_id);
264                 break;
265         default:
266                 break;
267         }
268 
269         return 0;
270 }
271 
272 static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
273                                 struct snd_kcontrol *kcontrol,
274                                 int event)
275 {
276         struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
277         struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
278         struct mt8183_afe_private *afe_priv = afe->platform_priv;
279         struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
280 
281         dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
282                  __func__, w->name, event);
283 
284         switch (event) {
285         case SND_SOC_DAPM_PRE_PMU:
286                 mt8183_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
287                 break;
288         case SND_SOC_DAPM_POST_PMD:
289                 tdm_priv->mclk_rate = 0;
290                 mt8183_mck_disable(afe, tdm_priv->mclk_id);
291                 break;
292         default:
293                 break;
294         }
295 
296         return 0;
297 }
298 
299 static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
300         SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,
301                          &hdmi_ch0_mux_control),
302         SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,
303                          &hdmi_ch1_mux_control),
304         SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,
305                          &hdmi_ch2_mux_control),
306         SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,
307                          &hdmi_ch3_mux_control),
308         SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,
309                          &hdmi_ch4_mux_control),
310         SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,
311                          &hdmi_ch5_mux_control),
312         SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,
313                          &hdmi_ch6_mux_control),
314         SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,
315                          &hdmi_ch7_mux_control),
316 
317         SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
318 
319         SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
320                               SND_SOC_NOPM, 0, 0,
321                               mtk_tdm_bck_en_event,
322                               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
323 
324         SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
325                               SND_SOC_NOPM, 0, 0,
326                               mtk_tdm_mck_en_event,
327                               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
328 };
329 
330 static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
331                                     struct snd_soc_dapm_widget *sink)
332 {
333         struct snd_soc_dapm_widget *w = sink;
334         struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
335         struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
336         struct mt8183_afe_private *afe_priv = afe->platform_priv;
337         struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
338         int cur_apll;
339 
340         /* which apll */
341         cur_apll = mt8183_get_apll_by_name(afe, source->name);
342 
343         return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
344 }
345 
346 static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
347         {"HDMI_CH0_MUX", "CH0", "HDMI"},
348         {"HDMI_CH0_MUX", "CH1", "HDMI"},
349         {"HDMI_CH0_MUX", "CH2", "HDMI"},
350         {"HDMI_CH0_MUX", "CH3", "HDMI"},
351         {"HDMI_CH0_MUX", "CH4", "HDMI"},
352         {"HDMI_CH0_MUX", "CH5", "HDMI"},
353         {"HDMI_CH0_MUX", "CH6", "HDMI"},
354         {"HDMI_CH0_MUX", "CH7", "HDMI"},
355 
356         {"HDMI_CH1_MUX", "CH0", "HDMI"},
357         {"HDMI_CH1_MUX", "CH1", "HDMI"},
358         {"HDMI_CH1_MUX", "CH2", "HDMI"},
359         {"HDMI_CH1_MUX", "CH3", "HDMI"},
360         {"HDMI_CH1_MUX", "CH4", "HDMI"},
361         {"HDMI_CH1_MUX", "CH5", "HDMI"},
362         {"HDMI_CH1_MUX", "CH6", "HDMI"},
363         {"HDMI_CH1_MUX", "CH7", "HDMI"},
364 
365         {"HDMI_CH2_MUX", "CH0", "HDMI"},
366         {"HDMI_CH2_MUX", "CH1", "HDMI"},
367         {"HDMI_CH2_MUX", "CH2", "HDMI"},
368         {"HDMI_CH2_MUX", "CH3", "HDMI"},
369         {"HDMI_CH2_MUX", "CH4", "HDMI"},
370         {"HDMI_CH2_MUX", "CH5", "HDMI"},
371         {"HDMI_CH2_MUX", "CH6", "HDMI"},
372         {"HDMI_CH2_MUX", "CH7", "HDMI"},
373 
374         {"HDMI_CH3_MUX", "CH0", "HDMI"},
375         {"HDMI_CH3_MUX", "CH1", "HDMI"},
376         {"HDMI_CH3_MUX", "CH2", "HDMI"},
377         {"HDMI_CH3_MUX", "CH3", "HDMI"},
378         {"HDMI_CH3_MUX", "CH4", "HDMI"},
379         {"HDMI_CH3_MUX", "CH5", "HDMI"},
380         {"HDMI_CH3_MUX", "CH6", "HDMI"},
381         {"HDMI_CH3_MUX", "CH7", "HDMI"},
382 
383         {"HDMI_CH4_MUX", "CH0", "HDMI"},
384         {"HDMI_CH4_MUX", "CH1", "HDMI"},
385         {"HDMI_CH4_MUX", "CH2", "HDMI"},
386         {"HDMI_CH4_MUX", "CH3", "HDMI"},
387         {"HDMI_CH4_MUX", "CH4", "HDMI"},
388         {"HDMI_CH4_MUX", "CH5", "HDMI"},
389         {"HDMI_CH4_MUX", "CH6", "HDMI"},
390         {"HDMI_CH4_MUX", "CH7", "HDMI"},
391 
392         {"HDMI_CH5_MUX", "CH0", "HDMI"},
393         {"HDMI_CH5_MUX", "CH1", "HDMI"},
394         {"HDMI_CH5_MUX", "CH2", "HDMI"},
395         {"HDMI_CH5_MUX", "CH3", "HDMI"},
396         {"HDMI_CH5_MUX", "CH4", "HDMI"},
397         {"HDMI_CH5_MUX", "CH5", "HDMI"},
398         {"HDMI_CH5_MUX", "CH6", "HDMI"},
399         {"HDMI_CH5_MUX", "CH7", "HDMI"},
400 
401         {"HDMI_CH6_MUX", "CH0", "HDMI"},
402         {"HDMI_CH6_MUX", "CH1", "HDMI"},
403         {"HDMI_CH6_MUX", "CH2", "HDMI"},
404         {"HDMI_CH6_MUX", "CH3", "HDMI"},
405         {"HDMI_CH6_MUX", "CH4", "HDMI"},
406         {"HDMI_CH6_MUX", "CH5", "HDMI"},
407         {"HDMI_CH6_MUX", "CH6", "HDMI"},
408         {"HDMI_CH6_MUX", "CH7", "HDMI"},
409 
410         {"HDMI_CH7_MUX", "CH0", "HDMI"},
411         {"HDMI_CH7_MUX", "CH1", "HDMI"},
412         {"HDMI_CH7_MUX", "CH2", "HDMI"},
413         {"HDMI_CH7_MUX", "CH3", "HDMI"},
414         {"HDMI_CH7_MUX", "CH4", "HDMI"},
415         {"HDMI_CH7_MUX", "CH5", "HDMI"},
416         {"HDMI_CH7_MUX", "CH6", "HDMI"},
417         {"HDMI_CH7_MUX", "CH7", "HDMI"},
418 
419         {"TDM", NULL, "HDMI_CH0_MUX"},
420         {"TDM", NULL, "HDMI_CH1_MUX"},
421         {"TDM", NULL, "HDMI_CH2_MUX"},
422         {"TDM", NULL, "HDMI_CH3_MUX"},
423         {"TDM", NULL, "HDMI_CH4_MUX"},
424         {"TDM", NULL, "HDMI_CH5_MUX"},
425         {"TDM", NULL, "HDMI_CH6_MUX"},
426         {"TDM", NULL, "HDMI_CH7_MUX"},
427 
428         {"TDM", NULL, "aud_tdm_clk"},
429         {"TDM", NULL, "TDM_BCK"},
430         {"TDM_BCK", NULL, "TDM_MCK"},
431         {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
432         {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
433 };
434 
435 /* dai ops */
436 static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
437                                 struct mtk_afe_tdm_priv *tdm_priv,
438                                 int freq)
439 {
440         int apll;
441         int apll_rate;
442 
443         apll = mt8183_get_apll_by_rate(afe, freq);
444         apll_rate = mt8183_get_apll_rate(afe, apll);
445 
446         if (!freq || freq > apll_rate) {
447                 dev_warn(afe->dev,
448                          "%s(), freq(%d Hz) invalid\n", __func__, freq);
449                 return -EINVAL;
450         }
451 
452         if (apll_rate % freq != 0) {
453                 dev_warn(afe->dev,
454                          "%s(), APLL cannot generate %d Hz", __func__, freq);
455                 return -EINVAL;
456         }
457 
458         tdm_priv->mclk_rate = freq;
459         tdm_priv->mclk_apll = apll;
460 
461         return 0;
462 }
463 
464 static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
465                                  struct snd_pcm_hw_params *params,
466                                  struct snd_soc_dai *dai)
467 {
468         struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
469         struct mt8183_afe_private *afe_priv = afe->platform_priv;
470         int tdm_id = dai->id;
471         struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
472         unsigned int tdm_out_mode = tdm_priv->tdm_out_mode;
473         unsigned int rate = params_rate(params);
474         unsigned int channels = params_channels(params);
475         unsigned int out_channels_per_sdata =
476                 get_tdm_ch_per_sdata(tdm_out_mode, channels);
477         snd_pcm_format_t format = params_format(params);
478         unsigned int tdm_con = 0;
479 
480         /* calculate mclk_rate, if not set explicitly */
481         if (!tdm_priv->mclk_rate) {
482                 tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
483                 mtk_dai_tdm_cal_mclk(afe,
484                                      tdm_priv,
485                                      tdm_priv->mclk_rate);
486         }
487 
488         /* calculate bck */
489         tdm_priv->bck_rate = rate *
490                              out_channels_per_sdata *
491                              snd_pcm_format_physical_width(format);
492 
493         if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
494                 dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__);
495 
496         if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
497                 dev_warn(afe->dev, "%s(), bck cannot generate", __func__);
498 
499         dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n",
500                  __func__,
501                  tdm_id, rate, channels, format,
502                  tdm_priv->mclk_rate, tdm_priv->bck_rate);
503         dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n",
504                  __func__, out_channels_per_sdata);
505 
506         /* set tdm */
507         if (tdm_priv->bck_invert)
508                 regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
509                                    BCK_INVERSE_MASK_SFT,
510                                    0x1 << BCK_INVERSE_SFT);
511 
512         if (tdm_priv->lck_invert)
513                 tdm_con |= 1 << LRCK_INVERSE_SFT;
514 
515         if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) {
516                 tdm_con |= 1 << DELAY_DATA_SFT;
517                 tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
518         } else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) {
519                 tdm_con |= 0 << DELAY_DATA_SFT;
520                 tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
521         }
522 
523         tdm_con |= 1 << LEFT_ALIGN_SFT;
524         tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
525         tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT;
526         tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
527         regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
528 
529         if (out_channels_per_sdata == 2) {
530                 switch (channels) {
531                 case 1:
532                 case 2:
533                         tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
534                         tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
535                         tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
536                         tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
537                         break;
538                 case 3:
539                 case 4:
540                         tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
541                         tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
542                         tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
543                         tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
544                         break;
545                 case 5:
546                 case 6:
547                         tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
548                         tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
549                         tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
550                         tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
551                         break;
552                 case 7:
553                 case 8:
554                         tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
555                         tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
556                         tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
557                         tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
558                         break;
559                 default:
560                         tdm_con = 0;
561                 }
562         } else {
563                 tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
564                 tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
565                 tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
566                 tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
567         }
568 
569         regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
570 
571         regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
572                            AFE_HDMI_OUT_CH_NUM_MASK_SFT,
573                            channels << AFE_HDMI_OUT_CH_NUM_SFT);
574 
575         regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
576                            AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT,
577                            get_hdmi_wlen(format) << AFE_HDMI_OUT_BIT_WIDTH_SFT);
578         return 0;
579 }
580 
581 static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
582                                int cmd,
583                                struct snd_soc_dai *dai)
584 {
585         struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
586 
587         switch (cmd) {
588         case SNDRV_PCM_TRIGGER_START:
589         case SNDRV_PCM_TRIGGER_RESUME:
590                 /* enable Out control */
591                 regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
592                                    AFE_HDMI_OUT_ON_MASK_SFT,
593                                    0x1 << AFE_HDMI_OUT_ON_SFT);
594                 /* enable tdm */
595                 regmap_update_bits(afe->regmap, AFE_TDM_CON1,
596                                    TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
597                 break;
598         case SNDRV_PCM_TRIGGER_STOP:
599         case SNDRV_PCM_TRIGGER_SUSPEND:
600                 /* disable tdm */
601                 regmap_update_bits(afe->regmap, AFE_TDM_CON1,
602                                    TDM_EN_MASK_SFT, 0);
603                 /* disable Out control */
604                 regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
605                                    AFE_HDMI_OUT_ON_MASK_SFT,
606                                    0);
607                 break;
608         default:
609                 return -EINVAL;
610         }
611 
612         return 0;
613 }
614 
615 static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
616                                   int clk_id, unsigned int freq, int dir)
617 {
618         struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
619         struct mt8183_afe_private *afe_priv = afe->platform_priv;
620         struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
621 
622         if (!tdm_priv) {
623                 dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
624                 return -EINVAL;
625         }
626 
627         if (dir != SND_SOC_CLOCK_OUT) {
628                 dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
629                 return -EINVAL;
630         }
631 
632         dev_info(afe->dev, "%s(), freq %d\n", __func__, freq);
633 
634         return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
635 }
636 
637 static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
638 {
639         struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
640         struct mt8183_afe_private *afe_priv = afe->platform_priv;
641         struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
642 
643         if (!tdm_priv) {
644                 dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
645                 return -EINVAL;
646         }
647 
648         /* DAI mode*/
649         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
650         case SND_SOC_DAIFMT_I2S:
651                 tdm_priv->tdm_out_mode = TDM_OUT_I2S;
652                 break;
653         case SND_SOC_DAIFMT_DSP_A:
654                 tdm_priv->tdm_out_mode = TDM_OUT_TDM;
655                 break;
656         default:
657                 tdm_priv->tdm_out_mode = TDM_OUT_I2S;
658         }
659 
660         /* DAI clock inversion*/
661         switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
662         case SND_SOC_DAIFMT_NB_NF:
663                 tdm_priv->bck_invert = TDM_BCK_NON_INV;
664                 tdm_priv->lck_invert = TDM_LCK_NON_INV;
665                 break;
666         case SND_SOC_DAIFMT_NB_IF:
667                 tdm_priv->bck_invert = TDM_BCK_NON_INV;
668                 tdm_priv->lck_invert = TDM_LCK_INV;
669                 break;
670         case SND_SOC_DAIFMT_IB_NF:
671                 tdm_priv->bck_invert = TDM_BCK_INV;
672                 tdm_priv->lck_invert = TDM_LCK_NON_INV;
673                 break;
674         case SND_SOC_DAIFMT_IB_IF:
675         default:
676                 tdm_priv->bck_invert = TDM_BCK_INV;
677                 tdm_priv->lck_invert = TDM_LCK_INV;
678                 break;
679         }
680 
681         return 0;
682 }
683 
684 static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
685         .hw_params = mtk_dai_tdm_hw_params,
686         .trigger = mtk_dai_tdm_trigger,
687         .set_sysclk = mtk_dai_tdm_set_sysclk,
688         .set_fmt = mtk_dai_tdm_set_fmt,
689 };
690 
691 /* dai driver */
692 #define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
693                        SNDRV_PCM_RATE_88200 |\
694                        SNDRV_PCM_RATE_96000 |\
695                        SNDRV_PCM_RATE_176400 |\
696                        SNDRV_PCM_RATE_192000)
697 
698 #define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
699                          SNDRV_PCM_FMTBIT_S24_LE |\
700                          SNDRV_PCM_FMTBIT_S32_LE)
701 
702 static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
703         {
704                 .name = "TDM",
705                 .id = MT8183_DAI_TDM,
706                 .playback = {
707                         .stream_name = "TDM",
708                         .channels_min = 2,
709                         .channels_max = 8,
710                         .rates = MTK_TDM_RATES,
711                         .formats = MTK_TDM_FORMATS,
712                 },
713                 .ops = &mtk_dai_tdm_ops,
714         },
715 };
716 
717 int mt8183_dai_tdm_register(struct mtk_base_afe *afe)
718 {
719         struct mt8183_afe_private *afe_priv = afe->platform_priv;
720         struct mtk_afe_tdm_priv *tdm_priv;
721         struct mtk_base_afe_dai *dai;
722 
723         dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
724         if (!dai)
725                 return -ENOMEM;
726 
727         list_add(&dai->list, &afe->sub_dais);
728 
729         dai->dai_drivers = mtk_dai_tdm_driver;
730         dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
731 
732         dai->dapm_widgets = mtk_dai_tdm_widgets;
733         dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
734         dai->dapm_routes = mtk_dai_tdm_routes;
735         dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
736 
737         tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
738                                 GFP_KERNEL);
739         if (!tdm_priv)
740                 return -ENOMEM;
741 
742         tdm_priv->mclk_multiple = 128;
743         tdm_priv->bck_id = MT8183_I2S4_BCK;
744         tdm_priv->mclk_id = MT8183_I2S4_MCK;
745 
746         afe_priv->dai_priv[MT8183_DAI_TDM] = tdm_priv;
747         return 0;
748 }
749 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php