1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * This driver supports the digital controls for the internal codec
4 * found in Allwinner's A33 SoCs.
6 * (C) Copyright 2010-2016
7 * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
8 * huangxin <huangxin@Reuuimllatech.com>
9 * Mylène Josserand <mylene.josserand@free-electrons.com>
12 #include <linux/module.h>
13 #include <linux/delay.h>
14 #include <linux/clk.h>
16 #include <linux/of_device.h>
17 #include <linux/pm_runtime.h>
18 #include <linux/regmap.h>
19 #include <linux/log2.h>
21 #include <sound/pcm_params.h>
22 #include <sound/soc.h>
23 #include <sound/soc-dapm.h>
25 #define SUN8I_SYSCLK_CTL 0x00c
26 #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
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)
30 #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3
31 #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)
34 #define SUN8I_MOD_CLK_ENA 0x010
35 #define SUN8I_MOD_CLK_ENA_AIF1 15
36 #define SUN8I_MOD_CLK_ENA_ADC 3
37 #define SUN8I_MOD_CLK_ENA_DAC 2
38 #define SUN8I_MOD_RST_CTL 0x014
39 #define SUN8I_MOD_RST_CTL_AIF1 15
40 #define SUN8I_MOD_RST_CTL_ADC 3
41 #define SUN8I_MOD_RST_CTL_DAC 2
42 #define SUN8I_SYS_SR_CTRL 0x018
43 #define SUN8I_SYS_SR_CTRL_AIF1_FS 12
44 #define SUN8I_SYS_SR_CTRL_AIF2_FS 8
45 #define SUN8I_AIF_CLK_CTRL(n) (0x040 * (1 + (n)))
46 #define SUN8I_AIF_CLK_CTRL_MSTR_MOD 15
47 #define SUN8I_AIF_CLK_CTRL_CLK_INV 13
48 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV 9
49 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV 6
50 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ 4
51 #define SUN8I_AIF_CLK_CTRL_DATA_FMT 2
52 #define SUN8I_AIF1_ADCDAT_CTRL 0x044
53 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15
54 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14
55 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC 10
56 #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC 8
57 #define SUN8I_AIF1_DACDAT_CTRL 0x048
58 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
59 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
60 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC 10
61 #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC 8
62 #define SUN8I_AIF1_MXR_SRC 0x04c
63 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15
64 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14
65 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13
66 #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12
67 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11
68 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10
69 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9
70 #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8
71 #define SUN8I_ADC_DIG_CTRL 0x100
72 #define SUN8I_ADC_DIG_CTRL_ENAD 15
73 #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2
74 #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1
75 #define SUN8I_DAC_DIG_CTRL 0x120
76 #define SUN8I_DAC_DIG_CTRL_ENDA 15
77 #define SUN8I_DAC_MXR_SRC 0x130
78 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
79 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
80 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
81 #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12
82 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
83 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
84 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
85 #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8
87 #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8)
88 #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4)
89 #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12)
90 #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
91 #define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK GENMASK(14, 13)
92 #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK GENMASK(12, 9)
93 #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK GENMASK(8, 6)
94 #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4)
95 #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2)
97 #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
99 #define SUN8I_CODEC_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\
100 SNDRV_PCM_FMTBIT_S16_LE |\
101 SNDRV_PCM_FMTBIT_S20_LE |\
102 SNDRV_PCM_FMTBIT_S24_LE |\
103 SNDRV_PCM_FMTBIT_S20_3LE|\
104 SNDRV_PCM_FMTBIT_S24_3LE)
106 #define SUN8I_CODEC_PCM_RATES (SNDRV_PCM_RATE_8000_48000|\
107 SNDRV_PCM_RATE_88200 |\
108 SNDRV_PCM_RATE_96000 |\
109 SNDRV_PCM_RATE_176400 |\
110 SNDRV_PCM_RATE_192000 |\
118 struct sun8i_codec_aif {
119 unsigned int sample_rate;
121 unsigned int slot_width;
122 unsigned int active_streams : 2;
123 unsigned int open_streams : 2;
126 struct sun8i_codec_quirks {
127 bool legacy_widgets : 1;
128 bool lrck_inversion : 1;
132 struct regmap *regmap;
133 struct clk *clk_module;
134 const struct sun8i_codec_quirks *quirks;
135 struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS];
136 unsigned int sysclk_rate;
140 static int sun8i_codec_runtime_resume(struct device *dev)
142 struct sun8i_codec *scodec = dev_get_drvdata(dev);
145 regcache_cache_only(scodec->regmap, false);
147 ret = regcache_sync(scodec->regmap);
149 dev_err(dev, "Failed to sync regmap cache\n");
156 static int sun8i_codec_runtime_suspend(struct device *dev)
158 struct sun8i_codec *scodec = dev_get_drvdata(dev);
160 regcache_cache_only(scodec->regmap, true);
161 regcache_mark_dirty(scodec->regmap);
166 static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
168 switch (sample_rate) {
201 static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
203 unsigned int max_rate = 0;
206 for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
207 struct sun8i_codec_aif *aif = &scodec->aifs[i];
209 if (aif->active_streams)
210 max_rate = max(max_rate, aif->sample_rate);
213 /* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
215 max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
217 hw_rate = sun8i_codec_get_hw_rate(max_rate);
221 regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
222 SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
223 hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
228 static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
230 struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
231 u32 dsp_format, format, invert, value;
234 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
235 case SND_SOC_DAIFMT_CBS_CFS: /* Codec slave, DAI master */
238 case SND_SOC_DAIFMT_CBM_CFM: /* Codec Master, DAI slave */
245 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
246 BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
247 value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
250 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
251 case SND_SOC_DAIFMT_I2S:
254 case SND_SOC_DAIFMT_LEFT_J:
257 case SND_SOC_DAIFMT_RIGHT_J:
260 case SND_SOC_DAIFMT_DSP_A:
262 dsp_format = 0x0; /* Set LRCK_INV to 0 */
264 case SND_SOC_DAIFMT_DSP_B:
266 dsp_format = 0x1; /* Set LRCK_INV to 1 */
272 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
273 SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
274 format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
276 /* clock inversion */
277 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
278 case SND_SOC_DAIFMT_NB_NF: /* Normal */
281 case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
284 case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
287 case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
295 /* Inverted LRCK is not available in DSP mode. */
299 /* Instead, the bit selects between DSP A/B formats. */
300 invert |= dsp_format;
303 * It appears that the DAI and the codec in the A33 SoC don't
304 * share the same polarity for the LRCK signal when they mean
305 * 'normal' and 'inverted' in the datasheet.
307 * Since the DAI here is our regular i2s driver that have been
308 * tested with way more codecs than just this one, it means
309 * that the codec probably gets it backward, and we have to
310 * invert the value here.
312 invert ^= scodec->quirks->lrck_inversion;
315 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
316 SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
317 invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
322 static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
323 unsigned int tx_mask, unsigned int rx_mask,
324 int slots, int slot_width)
326 struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
327 struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
329 if (slot_width && !is_power_of_2(slot_width))
333 aif->slot_width = slot_width;
338 static const unsigned int sun8i_codec_rates[] = {
339 7350, 8000, 11025, 12000, 14700, 16000, 22050, 24000,
340 29400, 32000, 44100, 48000, 88200, 96000, 176400, 192000,
343 static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
344 .list = sun8i_codec_rates,
345 .count = ARRAY_SIZE(sun8i_codec_rates),
348 static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
349 .list = sun8i_codec_rates,
350 .count = ARRAY_SIZE(sun8i_codec_rates),
354 static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
355 .list = sun8i_codec_rates,
356 .count = ARRAY_SIZE(sun8i_codec_rates),
360 static int sun8i_codec_startup(struct snd_pcm_substream *substream,
361 struct snd_soc_dai *dai)
363 struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
364 const struct snd_pcm_hw_constraint_list *list;
366 if (!scodec->sysclk_refcnt)
367 list = &sun8i_codec_all_rates;
368 else if (scodec->sysclk_rate == 22579200)
369 list = &sun8i_codec_22M_rates;
370 else if (scodec->sysclk_rate == 24576000)
371 list = &sun8i_codec_24M_rates;
375 return snd_pcm_hw_constraint_list(substream->runtime, 0,
376 SNDRV_PCM_HW_PARAM_RATE, list);
379 struct sun8i_codec_clk_div {
384 static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
385 { .div = 1, .val = 0 },
386 { .div = 2, .val = 1 },
387 { .div = 4, .val = 2 },
388 { .div = 6, .val = 3 },
389 { .div = 8, .val = 4 },
390 { .div = 12, .val = 5 },
391 { .div = 16, .val = 6 },
392 { .div = 24, .val = 7 },
393 { .div = 32, .val = 8 },
394 { .div = 48, .val = 9 },
395 { .div = 64, .val = 10 },
396 { .div = 96, .val = 11 },
397 { .div = 128, .val = 12 },
398 { .div = 192, .val = 13 },
401 static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
402 unsigned int lrck_div_order,
403 unsigned int sample_rate)
405 unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
408 for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
409 const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
411 if (bdiv->div == div)
418 static int sun8i_codec_get_lrck_div_order(unsigned int slots,
419 unsigned int slot_width)
421 unsigned int div = slots * slot_width;
423 if (div < 16 || div > 256)
426 return order_base_2(div);
429 static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
431 return sample_rate % 4000 ? 22579200 : 24576000;
434 static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
435 struct snd_pcm_hw_params *params,
436 struct snd_soc_dai *dai)
438 struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
439 struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
440 unsigned int sample_rate = params_rate(params);
441 unsigned int slots = aif->slots ?: params_channels(params);
442 unsigned int slot_width = aif->slot_width ?: params_width(params);
443 unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
444 int bclk_div, lrck_div_order, ret, word_size;
447 switch (params_width(params)) {
464 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
465 SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
466 word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
468 /* LRCK divider (BCLK/LRCK ratio) */
469 lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
470 if (lrck_div_order < 0)
471 return lrck_div_order;
473 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
474 SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
475 (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
477 /* BCLK divider (SYSCLK/BCLK ratio) */
478 bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
482 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
483 SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
484 bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
489 * Clock rate protection is reference counted; but hw_params may be
490 * called many times per substream, without matching calls to hw_free.
491 * Protect the clock rate once per AIF, on the first hw_params call
492 * for the first substream. clk_set_rate() will allow clock rate
493 * changes on subsequent calls if only one AIF has open streams.
495 ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
499 "%s sample rate (%u Hz) conflicts with other audio streams\n",
500 dai->name, sample_rate);
504 if (!aif->open_streams)
505 scodec->sysclk_refcnt++;
506 scodec->sysclk_rate = sysclk_rate;
508 aif->sample_rate = sample_rate;
509 aif->open_streams |= BIT(substream->stream);
511 return sun8i_codec_update_sample_rate(scodec);
514 static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
515 struct snd_soc_dai *dai)
517 struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
518 struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
520 /* Drop references when the last substream for the AIF is freed. */
521 if (aif->open_streams != BIT(substream->stream))
524 clk_rate_exclusive_put(scodec->clk_module);
525 scodec->sysclk_refcnt--;
526 aif->sample_rate = 0;
529 aif->open_streams &= ~BIT(substream->stream);
533 static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
534 .set_fmt = sun8i_codec_set_fmt,
535 .set_tdm_slot = sun8i_codec_set_tdm_slot,
536 .startup = sun8i_codec_startup,
537 .hw_params = sun8i_codec_hw_params,
538 .hw_free = sun8i_codec_hw_free,
541 static struct snd_soc_dai_driver sun8i_codec_dais[] = {
543 .name = "sun8i-codec-aif1",
544 .id = SUN8I_CODEC_AIF1,
545 .ops = &sun8i_codec_dai_ops,
546 /* capture capabilities */
548 .stream_name = "AIF1 Capture",
551 .rates = SUN8I_CODEC_PCM_RATES,
552 .formats = SUN8I_CODEC_PCM_FORMATS,
555 /* playback capabilities */
557 .stream_name = "AIF1 Playback",
560 .rates = SUN8I_CODEC_PCM_RATES,
561 .formats = SUN8I_CODEC_PCM_FORMATS,
563 .symmetric_rates = true,
564 .symmetric_channels = true,
565 .symmetric_samplebits = true,
569 static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
570 struct snd_kcontrol *kcontrol, int event)
572 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
573 struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
574 struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
575 int stream = w->id == snd_soc_dapm_aif_out;
577 if (SND_SOC_DAPM_EVENT_ON(event))
578 aif->active_streams |= BIT(stream);
580 aif->active_streams &= ~BIT(stream);
582 return sun8i_codec_update_sample_rate(scodec);
585 static const char *const sun8i_aif_stereo_mux_enum_values[] = {
586 "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
589 static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
590 SUN8I_AIF1_ADCDAT_CTRL,
591 SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
592 SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
593 sun8i_aif_stereo_mux_enum_values);
595 static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
596 SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
597 sun8i_aif1_ad0_stereo_mux_enum);
599 static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
600 SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
602 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
603 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
604 SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
606 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
607 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
608 SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
610 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
611 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
612 SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
614 SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
615 SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
618 static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
619 SUN8I_AIF1_DACDAT_CTRL,
620 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
621 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
622 sun8i_aif_stereo_mux_enum_values);
624 static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
625 SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
626 sun8i_aif1_da0_stereo_mux_enum);
628 static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
629 SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
631 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
632 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
633 SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
635 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
636 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
637 SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
638 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
639 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
640 SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
641 SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
642 SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
645 static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
647 SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
649 SND_SOC_DAPM_SUPPLY("AIF1CLK",
651 SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
652 SND_SOC_DAPM_SUPPLY("SYSCLK",
654 SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
657 SND_SOC_DAPM_SUPPLY("CLK AIF1",
659 SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
660 SND_SOC_DAPM_SUPPLY("CLK ADC",
662 SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
663 SND_SOC_DAPM_SUPPLY("CLK DAC",
665 SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
668 SND_SOC_DAPM_SUPPLY("RST AIF1",
670 SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
671 SND_SOC_DAPM_SUPPLY("RST ADC",
673 SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
674 SND_SOC_DAPM_SUPPLY("RST DAC",
676 SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
678 /* Module Supplies */
679 SND_SOC_DAPM_SUPPLY("ADC",
681 SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
682 SND_SOC_DAPM_SUPPLY("DAC",
684 SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
686 /* AIF "ADC" Outputs */
687 SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
688 SUN8I_AIF1_ADCDAT_CTRL,
689 SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
690 sun8i_codec_aif_event,
691 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
692 SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
693 SUN8I_AIF1_ADCDAT_CTRL,
694 SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
696 /* AIF "ADC" Mono/Stereo Muxes */
697 SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
698 &sun8i_aif1_ad0_stereo_mux_control),
699 SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
700 &sun8i_aif1_ad0_stereo_mux_control),
702 /* AIF "ADC" Mixers */
703 SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
704 sun8i_aif1_ad0_mixer_controls),
705 SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
706 sun8i_aif1_ad0_mixer_controls),
708 /* AIF "DAC" Mono/Stereo Muxes */
709 SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
710 &sun8i_aif1_da0_stereo_mux_control),
711 SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
712 &sun8i_aif1_da0_stereo_mux_control),
714 /* AIF "DAC" Inputs */
715 SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
716 SUN8I_AIF1_DACDAT_CTRL,
717 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
718 sun8i_codec_aif_event,
719 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
720 SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
721 SUN8I_AIF1_DACDAT_CTRL,
722 SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
724 /* ADC Inputs (connected to analog codec DAPM context) */
725 SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
726 SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
728 /* DAC Outputs (connected to analog codec DAPM context) */
729 SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
730 SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
733 SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
734 sun8i_dac_mixer_controls),
735 SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
736 sun8i_dac_mixer_controls),
739 static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
741 { "AIF1CLK", NULL, "mod" },
743 { "SYSCLK", NULL, "AIF1CLK" },
745 { "CLK AIF1", NULL, "AIF1CLK" },
746 { "CLK AIF1", NULL, "SYSCLK" },
747 { "RST AIF1", NULL, "CLK AIF1" },
748 { "AIF1 AD0L", NULL, "RST AIF1" },
749 { "AIF1 AD0R", NULL, "RST AIF1" },
750 { "AIF1 DA0L", NULL, "RST AIF1" },
751 { "AIF1 DA0R", NULL, "RST AIF1" },
753 { "CLK ADC", NULL, "SYSCLK" },
754 { "RST ADC", NULL, "CLK ADC" },
755 { "ADC", NULL, "RST ADC" },
756 { "ADCL", NULL, "ADC" },
757 { "ADCR", NULL, "ADC" },
759 { "CLK DAC", NULL, "SYSCLK" },
760 { "RST DAC", NULL, "CLK DAC" },
761 { "DAC", NULL, "RST DAC" },
762 { "DACL", NULL, "DAC" },
763 { "DACR", NULL, "DAC" },
765 /* AIF "ADC" Output Routes */
766 { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
767 { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
769 /* AIF "ADC" Mono/Stereo Mux Routes */
770 { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
771 { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
772 { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
773 { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
774 { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
775 { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
777 { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
778 { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
779 { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
780 { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
781 { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
782 { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
784 /* AIF "ADC" Mixer Routes */
785 { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
786 { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
788 { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
789 { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
791 /* AIF "DAC" Mono/Stereo Mux Routes */
792 { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
793 { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
794 { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
795 { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
796 { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
797 { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
799 { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
800 { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
801 { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
802 { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
803 { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
804 { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
806 /* DAC Output Routes */
807 { "DACL", NULL, "DACL Mixer" },
808 { "DACR", NULL, "DACR Mixer" },
810 /* DAC Mixer Routes */
811 { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
812 { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
814 { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
815 { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
818 static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
819 /* Legacy ADC Inputs (connected to analog codec DAPM context) */
820 SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
821 SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
823 /* Legacy DAC Outputs (connected to analog codec DAPM context) */
824 SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
825 SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
828 static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
829 /* Legacy ADC Routes */
830 { "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
831 { "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
833 /* Legacy DAC Routes */
834 { "AIF1 Slot 0 Left", NULL, "DACL" },
835 { "AIF1 Slot 0 Right", NULL, "DACR" },
838 static int sun8i_codec_component_probe(struct snd_soc_component *component)
840 struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
841 struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
844 /* Add widgets for backward compatibility with old device trees. */
845 if (scodec->quirks->legacy_widgets) {
846 ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
847 ARRAY_SIZE(sun8i_codec_legacy_widgets));
851 ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
852 ARRAY_SIZE(sun8i_codec_legacy_routes));
858 * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
859 * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
860 * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
861 * directly to simplify the clock tree.
863 regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
864 SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
865 SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
866 SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
867 SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
869 /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
870 regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
871 BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
872 SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
874 /* Program the default sample rate. */
875 sun8i_codec_update_sample_rate(scodec);
880 static const struct snd_soc_component_driver sun8i_soc_component = {
881 .dapm_widgets = sun8i_codec_dapm_widgets,
882 .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
883 .dapm_routes = sun8i_codec_dapm_routes,
884 .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
885 .probe = sun8i_codec_component_probe,
888 .non_legacy_dai_naming = 1,
891 static const struct regmap_config sun8i_codec_regmap_config = {
895 .max_register = SUN8I_DAC_MXR_SRC,
897 .cache_type = REGCACHE_FLAT,
900 static int sun8i_codec_probe(struct platform_device *pdev)
902 struct sun8i_codec *scodec;
906 scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
910 scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
911 if (IS_ERR(scodec->clk_module)) {
912 dev_err(&pdev->dev, "Failed to get the module clock\n");
913 return PTR_ERR(scodec->clk_module);
916 base = devm_platform_ioremap_resource(pdev, 0);
918 dev_err(&pdev->dev, "Failed to map the registers\n");
919 return PTR_ERR(base);
922 scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
923 &sun8i_codec_regmap_config);
924 if (IS_ERR(scodec->regmap)) {
925 dev_err(&pdev->dev, "Failed to create our regmap\n");
926 return PTR_ERR(scodec->regmap);
929 scodec->quirks = of_device_get_match_data(&pdev->dev);
931 platform_set_drvdata(pdev, scodec);
933 pm_runtime_enable(&pdev->dev);
934 if (!pm_runtime_enabled(&pdev->dev)) {
935 ret = sun8i_codec_runtime_resume(&pdev->dev);
940 ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
942 ARRAY_SIZE(sun8i_codec_dais));
944 dev_err(&pdev->dev, "Failed to register codec\n");
951 if (!pm_runtime_status_suspended(&pdev->dev))
952 sun8i_codec_runtime_suspend(&pdev->dev);
955 pm_runtime_disable(&pdev->dev);
960 static int sun8i_codec_remove(struct platform_device *pdev)
962 pm_runtime_disable(&pdev->dev);
963 if (!pm_runtime_status_suspended(&pdev->dev))
964 sun8i_codec_runtime_suspend(&pdev->dev);
969 static const struct sun8i_codec_quirks sun8i_a33_quirks = {
970 .legacy_widgets = true,
971 .lrck_inversion = true,
974 static const struct sun8i_codec_quirks sun50i_a64_quirks = {
977 static const struct of_device_id sun8i_codec_of_match[] = {
978 { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
979 { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
982 MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
984 static const struct dev_pm_ops sun8i_codec_pm_ops = {
985 SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
986 sun8i_codec_runtime_resume, NULL)
989 static struct platform_driver sun8i_codec_driver = {
991 .name = "sun8i-codec",
992 .of_match_table = sun8i_codec_of_match,
993 .pm = &sun8i_codec_pm_ops,
995 .probe = sun8i_codec_probe,
996 .remove = sun8i_codec_remove,
998 module_platform_driver(sun8i_codec_driver);
1000 MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
1001 MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
1002 MODULE_LICENSE("GPL");
1003 MODULE_ALIAS("platform:sun8i-codec");