hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/sound/soc/sunxi/sun8i-codec.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * This driver supports the digital controls for the internal codec
34 * found in Allwinner's A33 SoCs.
....@@ -6,24 +7,16 @@
67 * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
78 * huangxin <huangxin@Reuuimllatech.com>
89 * Mylène Josserand <mylene.josserand@free-electrons.com>
9
- *
10
- * This program is free software; you can redistribute it and/or modify
11
- * it under the terms of the GNU General Public License as published by
12
- * the Free Software Foundation; either version 2 of the License, or
13
- * (at your option) any later version.
14
- *
15
- * This program is distributed in the hope that it will be useful,
16
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
- * GNU General Public License for more details.
1910 */
2011
2112 #include <linux/module.h>
2213 #include <linux/delay.h>
2314 #include <linux/clk.h>
2415 #include <linux/io.h>
16
+#include <linux/of_device.h>
2517 #include <linux/pm_runtime.h>
2618 #include <linux/regmap.h>
19
+#include <linux/log2.h>
2720
2821 #include <sound/pcm_params.h>
2922 #include <sound/soc.h>
....@@ -31,10 +24,13 @@
3124
3225 #define SUN8I_SYSCLK_CTL 0x00c
3326 #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
34
-#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL 9
35
-#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC 8
27
+#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL (0x2 << 8)
28
+#define SUN8I_SYSCLK_CTL_AIF2CLK_ENA 7
29
+#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL (0x2 << 4)
3630 #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3
3731 #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0
32
+#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK (0x0 << 0)
33
+#define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0)
3834 #define SUN8I_MOD_CLK_ENA 0x010
3935 #define SUN8I_MOD_CLK_ENA_AIF1 15
4036 #define SUN8I_MOD_CLK_ENA_ADC 3
....@@ -52,53 +48,62 @@
5248 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13
5349 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9
5450 #define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6
55
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6)
5651 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4
5752 #define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4)
5853 #define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2
5954 #define SUN8I_AIF1_ADCDAT_CTRL 0x044
60
-#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA 15
61
-#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA 14
55
+#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15
56
+#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14
57
+#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC 10
58
+#define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC 8
6259 #define SUN8I_AIF1_DACDAT_CTRL 0x048
6360 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
6461 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
62
+#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC 10
63
+#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC 8
6564 #define SUN8I_AIF1_MXR_SRC 0x04c
66
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L 15
67
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL 14
68
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL 13
69
-#define SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR 12
65
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15
66
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14
67
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13
68
+#define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12
7069 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11
7170 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10
7271 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9
7372 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8
7473 #define SUN8I_ADC_DIG_CTRL 0x100
75
-#define SUN8I_ADC_DIG_CTRL_ENDA 15
74
+#define SUN8I_ADC_DIG_CTRL_ENAD 15
7675 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2
7776 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1
7877 #define SUN8I_DAC_DIG_CTRL 0x120
79
-#define SUN8I_DAC_DIG_CTRL_ENDA 15
78
+#define SUN8I_DAC_DIG_CTRL_ENDA 15
8079 #define SUN8I_DAC_MXR_SRC 0x130
81
-#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
82
-#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
83
-#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
80
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
81
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
82
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
8483 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12
85
-#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
86
-#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
87
-#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
84
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
85
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
86
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
8887 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8
8988
89
+#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8)
90
+#define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4)
9091 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12)
9192 #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
92
-#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2)
93
-#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
94
-#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
9593 #define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK GENMASK(12, 9)
94
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
95
+#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
96
+#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT_MASK GENMASK(3, 2)
97
+
98
+struct sun8i_codec_quirks {
99
+ bool legacy_widgets : 1;
100
+ bool lrck_inversion : 1;
101
+};
96102
97103 struct sun8i_codec {
98
- struct device *dev;
99
- struct regmap *regmap;
100
- struct clk *clk_module;
101
- struct clk *clk_bus;
104
+ struct regmap *regmap;
105
+ struct clk *clk_module;
106
+ const struct sun8i_codec_quirks *quirks;
102107 };
103108
104109 static int sun8i_codec_runtime_resume(struct device *dev)
....@@ -106,35 +111,15 @@
106111 struct sun8i_codec *scodec = dev_get_drvdata(dev);
107112 int ret;
108113
109
- ret = clk_prepare_enable(scodec->clk_module);
110
- if (ret) {
111
- dev_err(dev, "Failed to enable the module clock\n");
112
- return ret;
113
- }
114
-
115
- ret = clk_prepare_enable(scodec->clk_bus);
116
- if (ret) {
117
- dev_err(dev, "Failed to enable the bus clock\n");
118
- goto err_disable_modclk;
119
- }
120
-
121114 regcache_cache_only(scodec->regmap, false);
122115
123116 ret = regcache_sync(scodec->regmap);
124117 if (ret) {
125118 dev_err(dev, "Failed to sync regmap cache\n");
126
- goto err_disable_clk;
119
+ return ret;
127120 }
128121
129122 return 0;
130
-
131
-err_disable_clk:
132
- clk_disable_unprepare(scodec->clk_bus);
133
-
134
-err_disable_modclk:
135
- clk_disable_unprepare(scodec->clk_module);
136
-
137
- return ret;
138123 }
139124
140125 static int sun8i_codec_runtime_suspend(struct device *dev)
....@@ -143,9 +128,6 @@
143128
144129 regcache_cache_only(scodec->regmap, true);
145130 regcache_mark_dirty(scodec->regmap);
146
-
147
- clk_disable_unprepare(scodec->clk_module);
148
- clk_disable_unprepare(scodec->clk_bus);
149131
150132 return 0;
151133 }
....@@ -185,7 +167,7 @@
185167
186168 static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
187169 {
188
- struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
170
+ struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
189171 u32 value;
190172
191173 /* clock masters */
....@@ -219,18 +201,19 @@
219201 value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
220202
221203 /*
222
- * It appears that the DAI and the codec don't share the same
223
- * polarity for the LRCK signal when they mean 'normal' and
224
- * 'inverted' in the datasheet.
204
+ * It appears that the DAI and the codec in the A33 SoC don't
205
+ * share the same polarity for the LRCK signal when they mean
206
+ * 'normal' and 'inverted' in the datasheet.
225207 *
226208 * Since the DAI here is our regular i2s driver that have been
227209 * tested with way more codecs than just this one, it means
228210 * that the codec probably gets it backward, and we have to
229211 * invert the value here.
230212 */
213
+ value ^= scodec->quirks->lrck_inversion;
231214 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
232215 BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
233
- !value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
216
+ value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
234217
235218 /* DAI format */
236219 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
....@@ -301,12 +284,23 @@
301284 return best_val;
302285 }
303286
287
+static int sun8i_codec_get_lrck_div(unsigned int channels,
288
+ unsigned int word_size)
289
+{
290
+ unsigned int div = word_size * channels;
291
+
292
+ if (div < 16 || div > 256)
293
+ return -EINVAL;
294
+
295
+ return ilog2(div) - 4;
296
+}
297
+
304298 static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
305299 struct snd_pcm_hw_params *params,
306300 struct snd_soc_dai *dai)
307301 {
308
- struct sun8i_codec *scodec = snd_soc_component_get_drvdata(dai->component);
309
- int sample_rate;
302
+ struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
303
+ int sample_rate, lrck_div;
310304 u8 bclk_div;
311305
312306 /*
....@@ -322,9 +316,14 @@
322316 SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV_MASK,
323317 bclk_div << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV);
324318
319
+ lrck_div = sun8i_codec_get_lrck_div(params_channels(params),
320
+ params_physical_width(params));
321
+ if (lrck_div < 0)
322
+ return lrck_div;
323
+
325324 regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
326325 SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
327
- SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
326
+ lrck_div << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV);
328327
329328 sample_rate = sun8i_codec_get_hw_rate(params);
330329 if (sample_rate < 0)
....@@ -333,12 +332,52 @@
333332 regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
334333 SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
335334 sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
336
- regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
337
- SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
338
- sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
339335
340336 return 0;
341337 }
338
+
339
+static const char *const sun8i_aif_stereo_mux_enum_values[] = {
340
+ "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
341
+};
342
+
343
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
344
+ SUN8I_AIF1_ADCDAT_CTRL,
345
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
346
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
347
+ sun8i_aif_stereo_mux_enum_values);
348
+
349
+static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
350
+ SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
351
+ sun8i_aif1_ad0_stereo_mux_enum);
352
+
353
+static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
354
+ SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
355
+ SUN8I_AIF1_MXR_SRC,
356
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
357
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
358
+ SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
359
+ SUN8I_AIF1_MXR_SRC,
360
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
361
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
362
+ SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
363
+ SUN8I_AIF1_MXR_SRC,
364
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
365
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
366
+ SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
367
+ SUN8I_AIF1_MXR_SRC,
368
+ SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
369
+ SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
370
+};
371
+
372
+static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
373
+ SUN8I_AIF1_DACDAT_CTRL,
374
+ SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
375
+ SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
376
+ sun8i_aif_stereo_mux_enum_values);
377
+
378
+static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
379
+ SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
380
+ sun8i_aif1_da0_stereo_mux_enum);
342381
343382 static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
344383 SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
....@@ -357,125 +396,233 @@
357396 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
358397 };
359398
360
-static const struct snd_kcontrol_new sun8i_input_mixer_controls[] = {
361
- SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
362
- SUN8I_AIF1_MXR_SRC,
363
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF1DA0L,
364
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
365
- SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch", SUN8I_AIF1_MXR_SRC,
366
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACL,
367
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
368
- SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
369
- SUN8I_AIF1_MXR_SRC,
370
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_ADCL,
371
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
372
- SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
373
- SUN8I_AIF1_MXR_SRC,
374
- SUN8I_AIF1_MXR_SRC_AD0L_MXL_SRC_AIF2DACR,
375
- SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
376
-};
377
-
378399 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
379
- /* Digital parts of the DACs and ADC */
380
- SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA,
381
- 0, NULL, 0),
382
- SND_SOC_DAPM_SUPPLY("ADC", SUN8I_ADC_DIG_CTRL, SUN8I_ADC_DIG_CTRL_ENDA,
383
- 0, NULL, 0),
400
+ /* System Clocks */
401
+ SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
384402
385
- /* Analog DAC AIF */
386
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left", "Playback", 0,
403
+ SND_SOC_DAPM_SUPPLY("AIF1CLK",
404
+ SUN8I_SYSCLK_CTL,
405
+ SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
406
+ SND_SOC_DAPM_SUPPLY("SYSCLK",
407
+ SUN8I_SYSCLK_CTL,
408
+ SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
409
+
410
+ /* Module Clocks */
411
+ SND_SOC_DAPM_SUPPLY("CLK AIF1",
412
+ SUN8I_MOD_CLK_ENA,
413
+ SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
414
+ SND_SOC_DAPM_SUPPLY("CLK ADC",
415
+ SUN8I_MOD_CLK_ENA,
416
+ SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
417
+ SND_SOC_DAPM_SUPPLY("CLK DAC",
418
+ SUN8I_MOD_CLK_ENA,
419
+ SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
420
+
421
+ /* Module Resets */
422
+ SND_SOC_DAPM_SUPPLY("RST AIF1",
423
+ SUN8I_MOD_RST_CTL,
424
+ SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
425
+ SND_SOC_DAPM_SUPPLY("RST ADC",
426
+ SUN8I_MOD_RST_CTL,
427
+ SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
428
+ SND_SOC_DAPM_SUPPLY("RST DAC",
429
+ SUN8I_MOD_RST_CTL,
430
+ SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
431
+
432
+ /* Module Supplies */
433
+ SND_SOC_DAPM_SUPPLY("ADC",
434
+ SUN8I_ADC_DIG_CTRL,
435
+ SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
436
+ SND_SOC_DAPM_SUPPLY("DAC",
437
+ SUN8I_DAC_DIG_CTRL,
438
+ SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
439
+
440
+ /* AIF "ADC" Outputs */
441
+ SND_SOC_DAPM_AIF_OUT("AIF1 AD0L", "Capture", 0,
442
+ SUN8I_AIF1_ADCDAT_CTRL,
443
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0),
444
+ SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "Capture", 1,
445
+ SUN8I_AIF1_ADCDAT_CTRL,
446
+ SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
447
+
448
+ /* AIF "ADC" Mono/Stereo Muxes */
449
+ SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
450
+ &sun8i_aif1_ad0_stereo_mux_control),
451
+ SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
452
+ &sun8i_aif1_ad0_stereo_mux_control),
453
+
454
+ /* AIF "ADC" Mixers */
455
+ SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
456
+ sun8i_aif1_ad0_mixer_controls),
457
+ SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
458
+ sun8i_aif1_ad0_mixer_controls),
459
+
460
+ /* AIF "DAC" Mono/Stereo Muxes */
461
+ SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
462
+ &sun8i_aif1_da0_stereo_mux_control),
463
+ SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
464
+ &sun8i_aif1_da0_stereo_mux_control),
465
+
466
+ /* AIF "DAC" Inputs */
467
+ SND_SOC_DAPM_AIF_IN("AIF1 DA0L", "Playback", 0,
387468 SUN8I_AIF1_DACDAT_CTRL,
388469 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
389
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right", "Playback", 0,
470
+ SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "Playback", 1,
390471 SUN8I_AIF1_DACDAT_CTRL,
391472 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
392473
393
- /* Analog ADC AIF */
394
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Left ADC", "Capture", 0,
395
- SUN8I_AIF1_ADCDAT_CTRL,
396
- SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0L_ENA, 0),
397
- SND_SOC_DAPM_AIF_IN("AIF1 Slot 0 Right ADC", "Capture", 0,
398
- SUN8I_AIF1_ADCDAT_CTRL,
399
- SUN8I_AIF1_ADCDAT_CTRL_AIF1_DA0R_ENA, 0),
474
+ /* ADC Inputs (connected to analog codec DAPM context) */
475
+ SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
476
+ SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
400477
401
- /* DAC and ADC Mixers */
402
- SOC_MIXER_ARRAY("Left Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
478
+ /* DAC Outputs (connected to analog codec DAPM context) */
479
+ SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
480
+ SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
481
+
482
+ /* DAC Mixers */
483
+ SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
403484 sun8i_dac_mixer_controls),
404
- SOC_MIXER_ARRAY("Right Digital DAC Mixer", SND_SOC_NOPM, 0, 0,
485
+ SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
405486 sun8i_dac_mixer_controls),
406
- SOC_MIXER_ARRAY("Left Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
407
- sun8i_input_mixer_controls),
408
- SOC_MIXER_ARRAY("Right Digital ADC Mixer", SND_SOC_NOPM, 0, 0,
409
- sun8i_input_mixer_controls),
410
-
411
- /* Clocks */
412
- SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA,
413
- SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
414
- SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA,
415
- SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
416
- SND_SOC_DAPM_SUPPLY("MODCLK ADC", SUN8I_MOD_CLK_ENA,
417
- SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
418
- SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL,
419
- SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
420
- SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL,
421
- SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
422
-
423
- SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL,
424
- SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0),
425
- /* Inversion as 0=AIF1, 1=AIF2 */
426
- SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL,
427
- SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0),
428
-
429
- /* Module reset */
430
- SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL,
431
- SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
432
- SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL,
433
- SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
434
- SND_SOC_DAPM_SUPPLY("RST ADC", SUN8I_MOD_RST_CTL,
435
- SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
436
-
437
- SND_SOC_DAPM_MIC("Headset Mic", NULL),
438
- SND_SOC_DAPM_MIC("Mic", NULL),
439
-
440487 };
441488
442489 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
443490 /* Clock Routes */
444
- { "AIF1", NULL, "SYSCLK AIF1" },
445
- { "AIF1 PLL", NULL, "AIF1" },
446
- { "RST AIF1", NULL, "AIF1 PLL" },
447
- { "MODCLK AFI1", NULL, "RST AIF1" },
448
- { "DAC", NULL, "MODCLK AFI1" },
449
- { "ADC", NULL, "MODCLK AFI1" },
491
+ { "AIF1CLK", NULL, "mod" },
450492
451
- { "RST DAC", NULL, "SYSCLK" },
452
- { "MODCLK DAC", NULL, "RST DAC" },
453
- { "DAC", NULL, "MODCLK DAC" },
493
+ { "SYSCLK", NULL, "AIF1CLK" },
454494
455
- { "RST ADC", NULL, "SYSCLK" },
456
- { "MODCLK ADC", NULL, "RST ADC" },
457
- { "ADC", NULL, "MODCLK ADC" },
495
+ { "CLK AIF1", NULL, "AIF1CLK" },
496
+ { "CLK AIF1", NULL, "SYSCLK" },
497
+ { "RST AIF1", NULL, "CLK AIF1" },
498
+ { "AIF1 AD0L", NULL, "RST AIF1" },
499
+ { "AIF1 AD0R", NULL, "RST AIF1" },
500
+ { "AIF1 DA0L", NULL, "RST AIF1" },
501
+ { "AIF1 DA0R", NULL, "RST AIF1" },
458502
459
- /* DAC Routes */
460
- { "AIF1 Slot 0 Right", NULL, "DAC" },
461
- { "AIF1 Slot 0 Left", NULL, "DAC" },
503
+ { "CLK ADC", NULL, "SYSCLK" },
504
+ { "RST ADC", NULL, "CLK ADC" },
505
+ { "ADC", NULL, "RST ADC" },
506
+ { "ADCL", NULL, "ADC" },
507
+ { "ADCR", NULL, "ADC" },
508
+
509
+ { "CLK DAC", NULL, "SYSCLK" },
510
+ { "RST DAC", NULL, "CLK DAC" },
511
+ { "DAC", NULL, "RST DAC" },
512
+ { "DACL", NULL, "DAC" },
513
+ { "DACR", NULL, "DAC" },
514
+
515
+ /* AIF "ADC" Output Routes */
516
+ { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
517
+ { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
518
+
519
+ /* AIF "ADC" Mono/Stereo Mux Routes */
520
+ { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
521
+ { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
522
+ { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
523
+ { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
524
+ { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
525
+ { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
526
+
527
+ { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
528
+ { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
529
+ { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
530
+ { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
531
+ { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
532
+ { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
533
+
534
+ /* AIF "ADC" Mixer Routes */
535
+ { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
536
+ { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
537
+
538
+ { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
539
+ { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
540
+
541
+ /* AIF "DAC" Mono/Stereo Mux Routes */
542
+ { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
543
+ { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
544
+ { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
545
+ { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
546
+ { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
547
+ { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
548
+
549
+ { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
550
+ { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
551
+ { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
552
+ { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
553
+ { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
554
+ { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
555
+
556
+ /* DAC Output Routes */
557
+ { "DACL", NULL, "DACL Mixer" },
558
+ { "DACR", NULL, "DACR Mixer" },
462559
463560 /* DAC Mixer Routes */
464
- { "Left Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
465
- "AIF1 Slot 0 Left"},
466
- { "Right Digital DAC Mixer", "AIF1 Slot 0 Digital DAC Playback Switch",
467
- "AIF1 Slot 0 Right"},
561
+ { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
562
+ { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
468563
469
- /* ADC Routes */
470
- { "AIF1 Slot 0 Right ADC", NULL, "ADC" },
471
- { "AIF1 Slot 0 Left ADC", NULL, "ADC" },
472
-
473
- /* ADC Mixer Routes */
474
- { "Left Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
475
- "AIF1 Slot 0 Left ADC" },
476
- { "Right Digital ADC Mixer", "AIF1 Data Digital ADC Capture Switch",
477
- "AIF1 Slot 0 Right ADC" },
564
+ { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
565
+ { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
478566 };
567
+
568
+static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
569
+ /* Legacy ADC Inputs (connected to analog codec DAPM context) */
570
+ SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
571
+ SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
572
+
573
+ /* Legacy DAC Outputs (connected to analog codec DAPM context) */
574
+ SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
575
+ SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
576
+};
577
+
578
+static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
579
+ /* Legacy ADC Routes */
580
+ { "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
581
+ { "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
582
+
583
+ /* Legacy DAC Routes */
584
+ { "AIF1 Slot 0 Left", NULL, "DACL" },
585
+ { "AIF1 Slot 0 Right", NULL, "DACR" },
586
+};
587
+
588
+static int sun8i_codec_component_probe(struct snd_soc_component *component)
589
+{
590
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
591
+ struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
592
+ int ret;
593
+
594
+ /* Add widgets for backward compatibility with old device trees. */
595
+ if (scodec->quirks->legacy_widgets) {
596
+ ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
597
+ ARRAY_SIZE(sun8i_codec_legacy_widgets));
598
+ if (ret)
599
+ return ret;
600
+
601
+ ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
602
+ ARRAY_SIZE(sun8i_codec_legacy_routes));
603
+ if (ret)
604
+ return ret;
605
+ }
606
+
607
+ /*
608
+ * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
609
+ * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
610
+ * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
611
+ * directly to simplify the clock tree.
612
+ */
613
+ regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
614
+ SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
615
+ SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
616
+ SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
617
+ SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
618
+
619
+ /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
620
+ regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
621
+ BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
622
+ SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
623
+
624
+ return 0;
625
+}
479626
480627 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
481628 .hw_params = sun8i_codec_hw_params,
....@@ -510,6 +657,7 @@
510657 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
511658 .dapm_routes = sun8i_codec_dapm_routes,
512659 .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
660
+ .probe = sun8i_codec_component_probe,
513661 .idle_bias_on = 1,
514662 .use_pmdown_time = 1,
515663 .endianness = 1,
....@@ -527,7 +675,6 @@
527675
528676 static int sun8i_codec_probe(struct platform_device *pdev)
529677 {
530
- struct resource *res_base;
531678 struct sun8i_codec *scodec;
532679 void __iomem *base;
533680 int ret;
....@@ -536,33 +683,26 @@
536683 if (!scodec)
537684 return -ENOMEM;
538685
539
- scodec->dev = &pdev->dev;
540
-
541686 scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
542687 if (IS_ERR(scodec->clk_module)) {
543688 dev_err(&pdev->dev, "Failed to get the module clock\n");
544689 return PTR_ERR(scodec->clk_module);
545690 }
546691
547
- scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
548
- if (IS_ERR(scodec->clk_bus)) {
549
- dev_err(&pdev->dev, "Failed to get the bus clock\n");
550
- return PTR_ERR(scodec->clk_bus);
551
- }
552
-
553
- res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
554
- base = devm_ioremap_resource(&pdev->dev, res_base);
692
+ base = devm_platform_ioremap_resource(pdev, 0);
555693 if (IS_ERR(base)) {
556694 dev_err(&pdev->dev, "Failed to map the registers\n");
557695 return PTR_ERR(base);
558696 }
559697
560
- scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
561
- &sun8i_codec_regmap_config);
698
+ scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
699
+ &sun8i_codec_regmap_config);
562700 if (IS_ERR(scodec->regmap)) {
563701 dev_err(&pdev->dev, "Failed to create our regmap\n");
564702 return PTR_ERR(scodec->regmap);
565703 }
704
+
705
+ scodec->quirks = of_device_get_match_data(&pdev->dev);
566706
567707 platform_set_drvdata(pdev, scodec);
568708
....@@ -601,8 +741,17 @@
601741 return 0;
602742 }
603743
744
+static const struct sun8i_codec_quirks sun8i_a33_quirks = {
745
+ .legacy_widgets = true,
746
+ .lrck_inversion = true,
747
+};
748
+
749
+static const struct sun8i_codec_quirks sun50i_a64_quirks = {
750
+};
751
+
604752 static const struct of_device_id sun8i_codec_of_match[] = {
605
- { .compatible = "allwinner,sun8i-a33-codec" },
753
+ { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
754
+ { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
606755 {}
607756 };
608757 MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);