1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
236c68493SMylène Josserand /*
336c68493SMylène Josserand * This driver supports the digital controls for the internal codec
436c68493SMylène Josserand * found in Allwinner's A33 SoCs.
536c68493SMylène Josserand *
636c68493SMylène Josserand * (C) Copyright 2010-2016
736c68493SMylène Josserand * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
836c68493SMylène Josserand * huangxin <huangxin@Reuuimllatech.com>
936c68493SMylène Josserand * Mylène Josserand <mylene.josserand@free-electrons.com>
1036c68493SMylène Josserand */
1136c68493SMylène Josserand
1236c68493SMylène Josserand #include <linux/module.h>
1336c68493SMylène Josserand #include <linux/delay.h>
1436c68493SMylène Josserand #include <linux/clk.h>
1536c68493SMylène Josserand #include <linux/io.h>
1690cac932SSamuel Holland #include <linux/of_device.h>
1736c68493SMylène Josserand #include <linux/pm_runtime.h>
1836c68493SMylène Josserand #include <linux/regmap.h>
1913c3bf17SVasily Khoruzhick #include <linux/log2.h>
2036c68493SMylène Josserand
2136c68493SMylène Josserand #include <sound/pcm_params.h>
2236c68493SMylène Josserand #include <sound/soc.h>
2336c68493SMylène Josserand #include <sound/soc-dapm.h>
24fd03cf7fSSamuel Holland #include <sound/tlv.h>
2536c68493SMylène Josserand
2636c68493SMylène Josserand #define SUN8I_SYSCLK_CTL 0x00c
2736c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
28d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL (0x2 << 8)
29d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_ENA 7
30d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL (0x2 << 4)
3136c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3
3236c68493SMylène Josserand #define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0
33d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK (0x0 << 0)
34d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF2CLK (0x1 << 0)
3536c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA 0x010
3636c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA_AIF1 15
3750ec8422SSamuel Holland #define SUN8I_MOD_CLK_ENA_AIF2 14
385a7f34abSSamuel Holland #define SUN8I_MOD_CLK_ENA_AIF3 13
39eda85d1fSMylene JOSSERAND #define SUN8I_MOD_CLK_ENA_ADC 3
4036c68493SMylène Josserand #define SUN8I_MOD_CLK_ENA_DAC 2
4136c68493SMylène Josserand #define SUN8I_MOD_RST_CTL 0x014
4236c68493SMylène Josserand #define SUN8I_MOD_RST_CTL_AIF1 15
4350ec8422SSamuel Holland #define SUN8I_MOD_RST_CTL_AIF2 14
445a7f34abSSamuel Holland #define SUN8I_MOD_RST_CTL_AIF3 13
45eda85d1fSMylene JOSSERAND #define SUN8I_MOD_RST_CTL_ADC 3
4636c68493SMylène Josserand #define SUN8I_MOD_RST_CTL_DAC 2
4736c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL 0x018
4836c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF1_FS 12
4936c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF2_FS 8
507a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL(n) (0x040 * (1 + (n)))
517a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_MSTR_MOD 15
527a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_CLK_INV 13
537a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_BCLK_DIV 9
547a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_LRCK_DIV 6
557a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_WORD_SIZ 4
567a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_DATA_FMT 2
57eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_ADCDAT_CTRL 0x044
58fa5c0ca1SSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA 15
59fa5c0ca1SSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA 14
6018ebd62cSSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC 10
6118ebd62cSSamuel Holland #define SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC 8
6236c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL 0x048
6336c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
6436c68493SMylène Josserand #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
6518ebd62cSSamuel Holland #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC 10
6618ebd62cSSamuel Holland #define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC 8
67eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC 0x04c
680ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L 15
690ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL 14
700ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL 13
710ba95493SSamuel Holland #define SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR 12
72eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R 11
73eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR 10
74eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR 9
75eda85d1fSMylene JOSSERAND #define SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL 8
76fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL1 0x050
77fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL1_AD0L_VOL 8
78fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL1_AD0R_VOL 0
79fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL3 0x058
80fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL3_DA0L_VOL 8
81fd03cf7fSSamuel Holland #define SUN8I_AIF1_VOL_CTRL3_DA0R_VOL 0
8250ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL 0x084
8350ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA 15
8450ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA 14
8550ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC 10
8650ec8422SSamuel Holland #define SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC 8
8750ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL 0x088
8850ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA 15
8950ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA 14
9050ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC 10
9150ec8422SSamuel Holland #define SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC 8
9250ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC 0x08c
9350ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L 15
9450ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L 14
9550ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR 13
9650ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL 12
9750ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R 11
9850ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R 10
9950ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL 9
10050ec8422SSamuel Holland #define SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR 8
101fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL1 0x090
102fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL1_ADCL_VOL 8
103fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL1_ADCR_VOL 0
104fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL2 0x098
105fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL2_DACL_VOL 8
106fd03cf7fSSamuel Holland #define SUN8I_AIF2_VOL_CTRL2_DACR_VOL 0
1075a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1 (0x0 << 0)
1085a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2 (0x1 << 0)
1095a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF1CLK (0x2 << 0)
11050ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL 0x0cc
11150ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC 10
11250ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC 8
11350ec8422SSamuel Holland #define SUN8I_AIF3_PATH_CTRL_AIF3_PINS_TRI 7
114eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL 0x100
11530aff91eSSamuel Holland #define SUN8I_ADC_DIG_CTRL_ENAD 15
116eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL_ADOUT_DTS 2
117eda85d1fSMylene JOSSERAND #define SUN8I_ADC_DIG_CTRL_ADOUT_DLY 1
118fd03cf7fSSamuel Holland #define SUN8I_ADC_VOL_CTRL 0x104
119fd03cf7fSSamuel Holland #define SUN8I_ADC_VOL_CTRL_ADCL_VOL 8
120fd03cf7fSSamuel Holland #define SUN8I_ADC_VOL_CTRL_ADCR_VOL 0
12136c68493SMylène Josserand #define SUN8I_DAC_DIG_CTRL 0x120
12236c68493SMylène Josserand #define SUN8I_DAC_DIG_CTRL_ENDA 15
123fd03cf7fSSamuel Holland #define SUN8I_DAC_VOL_CTRL 0x124
124fd03cf7fSSamuel Holland #define SUN8I_DAC_VOL_CTRL_DACL_VOL 8
125fd03cf7fSSamuel Holland #define SUN8I_DAC_VOL_CTRL_DACR_VOL 0
12636c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC 0x130
12736c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
12836c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
12936c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
13036c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12
13136c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
13236c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
13336c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
13436c68493SMylène Josserand #define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8
13536c68493SMylène Josserand
136d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK GENMASK(9, 8)
137d8f00682SSamuel Holland #define SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK GENMASK(5, 4)
13836c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12)
13936c68493SMylène Josserand #define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
1407a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_CLK_INV_MASK GENMASK(14, 13)
1417a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK GENMASK(12, 9)
1427a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK GENMASK(8, 6)
1437a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK GENMASK(5, 4)
1447a6b937eSSamuel Holland #define SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK GENMASK(3, 2)
1455a7f34abSSamuel Holland #define SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK GENMASK(1, 0)
14636c68493SMylène Josserand
1476c5326beSSamuel Holland #define SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE 48000
1486c5326beSSamuel Holland
149342cacb9SSamuel Holland #define SUN8I_CODEC_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 |\
150342cacb9SSamuel Holland SNDRV_PCM_FMTBIT_S16_LE |\
151342cacb9SSamuel Holland SNDRV_PCM_FMTBIT_S20_LE |\
152342cacb9SSamuel Holland SNDRV_PCM_FMTBIT_S24_LE |\
153342cacb9SSamuel Holland SNDRV_PCM_FMTBIT_S20_3LE|\
154342cacb9SSamuel Holland SNDRV_PCM_FMTBIT_S24_3LE)
155342cacb9SSamuel Holland
156c2b751d7SSamuel Holland #define SUN8I_CODEC_PCM_RATES (SNDRV_PCM_RATE_8000_48000|\
157c2b751d7SSamuel Holland SNDRV_PCM_RATE_88200 |\
158c2b751d7SSamuel Holland SNDRV_PCM_RATE_96000 |\
159c2b751d7SSamuel Holland SNDRV_PCM_RATE_176400 |\
160c2b751d7SSamuel Holland SNDRV_PCM_RATE_192000 |\
161c2b751d7SSamuel Holland SNDRV_PCM_RATE_KNOT)
162c2b751d7SSamuel Holland
1637826b8d1SSamuel Holland enum {
1647826b8d1SSamuel Holland SUN8I_CODEC_AIF1,
16550ec8422SSamuel Holland SUN8I_CODEC_AIF2,
1665a7f34abSSamuel Holland SUN8I_CODEC_AIF3,
1677826b8d1SSamuel Holland SUN8I_CODEC_NAIFS
1687826b8d1SSamuel Holland };
1697826b8d1SSamuel Holland
170afb1a600SSamuel Holland struct sun8i_codec_aif {
1715a7f34abSSamuel Holland unsigned int lrck_div_order;
1726c5326beSSamuel Holland unsigned int sample_rate;
173afb1a600SSamuel Holland unsigned int slots;
174afb1a600SSamuel Holland unsigned int slot_width;
1756c5326beSSamuel Holland unsigned int active_streams : 2;
1766c5326beSSamuel Holland unsigned int open_streams : 2;
177afb1a600SSamuel Holland };
178afb1a600SSamuel Holland
17990cac932SSamuel Holland struct sun8i_codec_quirks {
18090cac932SSamuel Holland bool legacy_widgets : 1;
1817518805fSSamuel Holland bool lrck_inversion : 1;
18290cac932SSamuel Holland };
18390cac932SSamuel Holland
18436c68493SMylène Josserand struct sun8i_codec {
18536c68493SMylène Josserand struct regmap *regmap;
18636c68493SMylène Josserand struct clk *clk_module;
18790cac932SSamuel Holland const struct sun8i_codec_quirks *quirks;
188afb1a600SSamuel Holland struct sun8i_codec_aif aifs[SUN8I_CODEC_NAIFS];
18915b45912SSamuel Holland unsigned int sysclk_rate;
19015b45912SSamuel Holland int sysclk_refcnt;
19136c68493SMylène Josserand };
19236c68493SMylène Josserand
1935a7f34abSSamuel Holland static struct snd_soc_dai_driver sun8i_codec_dais[];
1945a7f34abSSamuel Holland
sun8i_codec_runtime_resume(struct device * dev)19536c68493SMylène Josserand static int sun8i_codec_runtime_resume(struct device *dev)
19636c68493SMylène Josserand {
19736c68493SMylène Josserand struct sun8i_codec *scodec = dev_get_drvdata(dev);
19836c68493SMylène Josserand int ret;
19936c68493SMylène Josserand
20036c68493SMylène Josserand regcache_cache_only(scodec->regmap, false);
20136c68493SMylène Josserand
20236c68493SMylène Josserand ret = regcache_sync(scodec->regmap);
20336c68493SMylène Josserand if (ret) {
20436c68493SMylène Josserand dev_err(dev, "Failed to sync regmap cache\n");
2056b3bb3c8SSamuel Holland return ret;
20636c68493SMylène Josserand }
20736c68493SMylène Josserand
20836c68493SMylène Josserand return 0;
20936c68493SMylène Josserand }
21036c68493SMylène Josserand
sun8i_codec_runtime_suspend(struct device * dev)21136c68493SMylène Josserand static int sun8i_codec_runtime_suspend(struct device *dev)
21236c68493SMylène Josserand {
21336c68493SMylène Josserand struct sun8i_codec *scodec = dev_get_drvdata(dev);
21436c68493SMylène Josserand
21536c68493SMylène Josserand regcache_cache_only(scodec->regmap, true);
21636c68493SMylène Josserand regcache_mark_dirty(scodec->regmap);
21736c68493SMylène Josserand
21836c68493SMylène Josserand return 0;
21936c68493SMylène Josserand }
22036c68493SMylène Josserand
sun8i_codec_get_hw_rate(unsigned int sample_rate)2216c5326beSSamuel Holland static int sun8i_codec_get_hw_rate(unsigned int sample_rate)
22236c68493SMylène Josserand {
2236c5326beSSamuel Holland switch (sample_rate) {
22436c68493SMylène Josserand case 7350:
225c2b751d7SSamuel Holland case 8000:
22636c68493SMylène Josserand return 0x0;
22736c68493SMylène Josserand case 11025:
22836c68493SMylène Josserand return 0x1;
22936c68493SMylène Josserand case 12000:
23036c68493SMylène Josserand return 0x2;
231c2b751d7SSamuel Holland case 14700:
23236c68493SMylène Josserand case 16000:
23336c68493SMylène Josserand return 0x3;
23436c68493SMylène Josserand case 22050:
23536c68493SMylène Josserand return 0x4;
23636c68493SMylène Josserand case 24000:
23736c68493SMylène Josserand return 0x5;
238c2b751d7SSamuel Holland case 29400:
23936c68493SMylène Josserand case 32000:
24036c68493SMylène Josserand return 0x6;
24136c68493SMylène Josserand case 44100:
24236c68493SMylène Josserand return 0x7;
24336c68493SMylène Josserand case 48000:
24436c68493SMylène Josserand return 0x8;
245c2b751d7SSamuel Holland case 88200:
24636c68493SMylène Josserand case 96000:
24736c68493SMylène Josserand return 0x9;
248c2b751d7SSamuel Holland case 176400:
24936c68493SMylène Josserand case 192000:
25036c68493SMylène Josserand return 0xa;
25136c68493SMylène Josserand default:
25236c68493SMylène Josserand return -EINVAL;
25336c68493SMylène Josserand }
25436c68493SMylène Josserand }
25536c68493SMylène Josserand
sun8i_codec_update_sample_rate(struct sun8i_codec * scodec)2566c5326beSSamuel Holland static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
2576c5326beSSamuel Holland {
2586c5326beSSamuel Holland unsigned int max_rate = 0;
2596c5326beSSamuel Holland int hw_rate, i;
2606c5326beSSamuel Holland
2616c5326beSSamuel Holland for (i = SUN8I_CODEC_AIF1; i < SUN8I_CODEC_NAIFS; ++i) {
2626c5326beSSamuel Holland struct sun8i_codec_aif *aif = &scodec->aifs[i];
2636c5326beSSamuel Holland
2646c5326beSSamuel Holland if (aif->active_streams)
2656c5326beSSamuel Holland max_rate = max(max_rate, aif->sample_rate);
2666c5326beSSamuel Holland }
2676c5326beSSamuel Holland
2686c5326beSSamuel Holland /* Set the sample rate for ADC->DAC passthrough when no AIF is active. */
2696c5326beSSamuel Holland if (!max_rate)
2706c5326beSSamuel Holland max_rate = SUN8I_CODEC_PASSTHROUGH_SAMPLE_RATE;
2716c5326beSSamuel Holland
2726c5326beSSamuel Holland hw_rate = sun8i_codec_get_hw_rate(max_rate);
2736c5326beSSamuel Holland if (hw_rate < 0)
2746c5326beSSamuel Holland return hw_rate;
2756c5326beSSamuel Holland
2766c5326beSSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
2776c5326beSSamuel Holland SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
2786c5326beSSamuel Holland hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
2796c5326beSSamuel Holland
2806c5326beSSamuel Holland return 0;
2816c5326beSSamuel Holland }
2826c5326beSSamuel Holland
sun8i_codec_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)2837826b8d1SSamuel Holland static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
28436c68493SMylène Josserand {
285a886990cSSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
286c56f5f1cSSamuel Holland u32 dsp_format, format, invert, value;
28736c68493SMylène Josserand
28836c68493SMylène Josserand /* clock masters */
2897cc3965fSCharles Keepax switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
290beb89d1dSCharles Keepax case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */
291560bfe77SMaxime Ripard value = 0x1;
29236c68493SMylène Josserand break;
293beb89d1dSCharles Keepax case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */
294560bfe77SMaxime Ripard value = 0x0;
29536c68493SMylène Josserand break;
29636c68493SMylène Josserand default:
29736c68493SMylène Josserand return -EINVAL;
29836c68493SMylène Josserand }
2997a6b937eSSamuel Holland
3005a7f34abSSamuel Holland if (dai->id == SUN8I_CODEC_AIF3) {
3015a7f34abSSamuel Holland /* AIF3 only supports master mode. */
3025a7f34abSSamuel Holland if (value)
3035a7f34abSSamuel Holland return -EINVAL;
3045a7f34abSSamuel Holland
3055a7f34abSSamuel Holland /* Use the AIF2 BCLK and LRCK for AIF3. */
3065a7f34abSSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3075a7f34abSSamuel Holland SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
3085a7f34abSSamuel Holland SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
3095a7f34abSSamuel Holland } else {
3107a6b937eSSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3117a6b937eSSamuel Holland BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
3127a6b937eSSamuel Holland value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
3135a7f34abSSamuel Holland }
31436c68493SMylène Josserand
315fd57ed2dSSamuel Holland /* DAI format */
316fd57ed2dSSamuel Holland switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
317fd57ed2dSSamuel Holland case SND_SOC_DAIFMT_I2S:
318fd57ed2dSSamuel Holland format = 0x0;
319fd57ed2dSSamuel Holland break;
320fd57ed2dSSamuel Holland case SND_SOC_DAIFMT_LEFT_J:
321fd57ed2dSSamuel Holland format = 0x1;
322fd57ed2dSSamuel Holland break;
323fd57ed2dSSamuel Holland case SND_SOC_DAIFMT_RIGHT_J:
324fd57ed2dSSamuel Holland format = 0x2;
325fd57ed2dSSamuel Holland break;
326fd57ed2dSSamuel Holland case SND_SOC_DAIFMT_DSP_A:
327c56f5f1cSSamuel Holland format = 0x3;
328c56f5f1cSSamuel Holland dsp_format = 0x0; /* Set LRCK_INV to 0 */
329c56f5f1cSSamuel Holland break;
330fd57ed2dSSamuel Holland case SND_SOC_DAIFMT_DSP_B:
331fd57ed2dSSamuel Holland format = 0x3;
332c56f5f1cSSamuel Holland dsp_format = 0x1; /* Set LRCK_INV to 1 */
333fd57ed2dSSamuel Holland break;
334fd57ed2dSSamuel Holland default:
335fd57ed2dSSamuel Holland return -EINVAL;
336fd57ed2dSSamuel Holland }
3377a6b937eSSamuel Holland
3385a7f34abSSamuel Holland if (dai->id == SUN8I_CODEC_AIF3) {
3395a7f34abSSamuel Holland /* AIF3 only supports DSP mode. */
3405a7f34abSSamuel Holland if (format != 3)
3415a7f34abSSamuel Holland return -EINVAL;
3425a7f34abSSamuel Holland } else {
3437a6b937eSSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3447a6b937eSSamuel Holland SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
3457a6b937eSSamuel Holland format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
3465a7f34abSSamuel Holland }
347fd57ed2dSSamuel Holland
34836c68493SMylène Josserand /* clock inversion */
34936c68493SMylène Josserand switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
35036c68493SMylène Josserand case SND_SOC_DAIFMT_NB_NF: /* Normal */
351c56f5f1cSSamuel Holland invert = 0x0;
35236c68493SMylène Josserand break;
353c56f5f1cSSamuel Holland case SND_SOC_DAIFMT_NB_IF: /* Inverted LRCK */
354c56f5f1cSSamuel Holland invert = 0x1;
355c56f5f1cSSamuel Holland break;
356c56f5f1cSSamuel Holland case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */
357c56f5f1cSSamuel Holland invert = 0x2;
358c56f5f1cSSamuel Holland break;
359c56f5f1cSSamuel Holland case SND_SOC_DAIFMT_IB_IF: /* Both inverted */
360c56f5f1cSSamuel Holland invert = 0x3;
36136c68493SMylène Josserand break;
36236c68493SMylène Josserand default:
36336c68493SMylène Josserand return -EINVAL;
36436c68493SMylène Josserand }
365e7b8a6d3SMaxime Ripard
366c56f5f1cSSamuel Holland if (format == 0x3) {
367c56f5f1cSSamuel Holland /* Inverted LRCK is not available in DSP mode. */
368c56f5f1cSSamuel Holland if (invert & BIT(0))
369c56f5f1cSSamuel Holland return -EINVAL;
370c56f5f1cSSamuel Holland
371c56f5f1cSSamuel Holland /* Instead, the bit selects between DSP A/B formats. */
372c56f5f1cSSamuel Holland invert |= dsp_format;
373c56f5f1cSSamuel Holland } else {
374e7b8a6d3SMaxime Ripard /*
3757518805fSSamuel Holland * It appears that the DAI and the codec in the A33 SoC don't
3767518805fSSamuel Holland * share the same polarity for the LRCK signal when they mean
3777518805fSSamuel Holland * 'normal' and 'inverted' in the datasheet.
378e7b8a6d3SMaxime Ripard *
379e7b8a6d3SMaxime Ripard * Since the DAI here is our regular i2s driver that have been
380e7b8a6d3SMaxime Ripard * tested with way more codecs than just this one, it means
381e7b8a6d3SMaxime Ripard * that the codec probably gets it backward, and we have to
382e7b8a6d3SMaxime Ripard * invert the value here.
383e7b8a6d3SMaxime Ripard */
384c56f5f1cSSamuel Holland invert ^= scodec->quirks->lrck_inversion;
385c56f5f1cSSamuel Holland }
386c56f5f1cSSamuel Holland
3877a6b937eSSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
3887a6b937eSSamuel Holland SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
3897a6b937eSSamuel Holland invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
39036c68493SMylène Josserand
39136c68493SMylène Josserand return 0;
39236c68493SMylène Josserand }
39336c68493SMylène Josserand
sun8i_codec_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)394afb1a600SSamuel Holland static int sun8i_codec_set_tdm_slot(struct snd_soc_dai *dai,
395afb1a600SSamuel Holland unsigned int tx_mask, unsigned int rx_mask,
396afb1a600SSamuel Holland int slots, int slot_width)
397afb1a600SSamuel Holland {
398afb1a600SSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
399afb1a600SSamuel Holland struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
400afb1a600SSamuel Holland
401afb1a600SSamuel Holland if (slot_width && !is_power_of_2(slot_width))
402afb1a600SSamuel Holland return -EINVAL;
403afb1a600SSamuel Holland
404afb1a600SSamuel Holland aif->slots = slots;
405afb1a600SSamuel Holland aif->slot_width = slot_width;
406afb1a600SSamuel Holland
407afb1a600SSamuel Holland return 0;
408afb1a600SSamuel Holland }
409afb1a600SSamuel Holland
41015b45912SSamuel Holland static const unsigned int sun8i_codec_rates[] = {
41115b45912SSamuel Holland 7350, 8000, 11025, 12000, 14700, 16000, 22050, 24000,
41215b45912SSamuel Holland 29400, 32000, 44100, 48000, 88200, 96000, 176400, 192000,
41315b45912SSamuel Holland };
41415b45912SSamuel Holland
41515b45912SSamuel Holland static const struct snd_pcm_hw_constraint_list sun8i_codec_all_rates = {
41615b45912SSamuel Holland .list = sun8i_codec_rates,
41715b45912SSamuel Holland .count = ARRAY_SIZE(sun8i_codec_rates),
41815b45912SSamuel Holland };
41915b45912SSamuel Holland
42015b45912SSamuel Holland static const struct snd_pcm_hw_constraint_list sun8i_codec_22M_rates = {
42115b45912SSamuel Holland .list = sun8i_codec_rates,
42215b45912SSamuel Holland .count = ARRAY_SIZE(sun8i_codec_rates),
42315b45912SSamuel Holland .mask = 0x5555,
42415b45912SSamuel Holland };
42515b45912SSamuel Holland
42615b45912SSamuel Holland static const struct snd_pcm_hw_constraint_list sun8i_codec_24M_rates = {
42715b45912SSamuel Holland .list = sun8i_codec_rates,
42815b45912SSamuel Holland .count = ARRAY_SIZE(sun8i_codec_rates),
42915b45912SSamuel Holland .mask = 0xaaaa,
43015b45912SSamuel Holland };
43115b45912SSamuel Holland
sun8i_codec_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)43215b45912SSamuel Holland static int sun8i_codec_startup(struct snd_pcm_substream *substream,
43315b45912SSamuel Holland struct snd_soc_dai *dai)
43415b45912SSamuel Holland {
43515b45912SSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
43615b45912SSamuel Holland const struct snd_pcm_hw_constraint_list *list;
43715b45912SSamuel Holland
43850ec8422SSamuel Holland /* hw_constraints is not relevant for codec2codec DAIs. */
43950ec8422SSamuel Holland if (dai->id != SUN8I_CODEC_AIF1)
44050ec8422SSamuel Holland return 0;
44150ec8422SSamuel Holland
44215b45912SSamuel Holland if (!scodec->sysclk_refcnt)
44315b45912SSamuel Holland list = &sun8i_codec_all_rates;
44415b45912SSamuel Holland else if (scodec->sysclk_rate == 22579200)
44515b45912SSamuel Holland list = &sun8i_codec_22M_rates;
44615b45912SSamuel Holland else if (scodec->sysclk_rate == 24576000)
44715b45912SSamuel Holland list = &sun8i_codec_24M_rates;
44815b45912SSamuel Holland else
44915b45912SSamuel Holland return -EINVAL;
45015b45912SSamuel Holland
45115b45912SSamuel Holland return snd_pcm_hw_constraint_list(substream->runtime, 0,
45215b45912SSamuel Holland SNDRV_PCM_HW_PARAM_RATE, list);
45315b45912SSamuel Holland }
45415b45912SSamuel Holland
455316b7758SMaxime Ripard struct sun8i_codec_clk_div {
456316b7758SMaxime Ripard u8 div;
457316b7758SMaxime Ripard u8 val;
458316b7758SMaxime Ripard };
459316b7758SMaxime Ripard
460316b7758SMaxime Ripard static const struct sun8i_codec_clk_div sun8i_codec_bclk_div[] = {
461316b7758SMaxime Ripard { .div = 1, .val = 0 },
462316b7758SMaxime Ripard { .div = 2, .val = 1 },
463316b7758SMaxime Ripard { .div = 4, .val = 2 },
464316b7758SMaxime Ripard { .div = 6, .val = 3 },
465316b7758SMaxime Ripard { .div = 8, .val = 4 },
466316b7758SMaxime Ripard { .div = 12, .val = 5 },
467316b7758SMaxime Ripard { .div = 16, .val = 6 },
468316b7758SMaxime Ripard { .div = 24, .val = 7 },
469316b7758SMaxime Ripard { .div = 32, .val = 8 },
470316b7758SMaxime Ripard { .div = 48, .val = 9 },
471316b7758SMaxime Ripard { .div = 64, .val = 10 },
472316b7758SMaxime Ripard { .div = 96, .val = 11 },
473316b7758SMaxime Ripard { .div = 128, .val = 12 },
474316b7758SMaxime Ripard { .div = 192, .val = 13 },
475316b7758SMaxime Ripard };
476316b7758SMaxime Ripard
sun8i_codec_get_bclk_div(unsigned int sysclk_rate,unsigned int lrck_div_order,unsigned int sample_rate)4772464dccaSSamuel Holland static int sun8i_codec_get_bclk_div(unsigned int sysclk_rate,
47868a4f2caSSamuel Holland unsigned int lrck_div_order,
47968a4f2caSSamuel Holland unsigned int sample_rate)
480316b7758SMaxime Ripard {
48115b45912SSamuel Holland unsigned int div = sysclk_rate / sample_rate >> lrck_div_order;
482316b7758SMaxime Ripard int i;
483316b7758SMaxime Ripard
484316b7758SMaxime Ripard for (i = 0; i < ARRAY_SIZE(sun8i_codec_bclk_div); i++) {
485316b7758SMaxime Ripard const struct sun8i_codec_clk_div *bdiv = &sun8i_codec_bclk_div[i];
486316b7758SMaxime Ripard
4872464dccaSSamuel Holland if (bdiv->div == div)
4882464dccaSSamuel Holland return bdiv->val;
489316b7758SMaxime Ripard }
490316b7758SMaxime Ripard
4912464dccaSSamuel Holland return -EINVAL;
492316b7758SMaxime Ripard }
493316b7758SMaxime Ripard
sun8i_codec_get_lrck_div_order(unsigned int slots,unsigned int slot_width)494e511aed7SSamuel Holland static int sun8i_codec_get_lrck_div_order(unsigned int slots,
495e511aed7SSamuel Holland unsigned int slot_width)
49613c3bf17SVasily Khoruzhick {
497e511aed7SSamuel Holland unsigned int div = slots * slot_width;
49813c3bf17SVasily Khoruzhick
49913c3bf17SVasily Khoruzhick if (div < 16 || div > 256)
50013c3bf17SVasily Khoruzhick return -EINVAL;
50113c3bf17SVasily Khoruzhick
502e511aed7SSamuel Holland return order_base_2(div);
50313c3bf17SVasily Khoruzhick }
50413c3bf17SVasily Khoruzhick
sun8i_codec_get_sysclk_rate(unsigned int sample_rate)5053952ec2aSSamuel Holland static unsigned int sun8i_codec_get_sysclk_rate(unsigned int sample_rate)
5063952ec2aSSamuel Holland {
50754f78aebSPierre-Louis Bossart return (sample_rate % 4000) ? 22579200 : 24576000;
5083952ec2aSSamuel Holland }
5093952ec2aSSamuel Holland
sun8i_codec_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)51036c68493SMylène Josserand static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
51136c68493SMylène Josserand struct snd_pcm_hw_params *params,
51236c68493SMylène Josserand struct snd_soc_dai *dai)
51336c68493SMylène Josserand {
514a886990cSSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
515afb1a600SSamuel Holland struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
5166c5326beSSamuel Holland unsigned int sample_rate = params_rate(params);
517afb1a600SSamuel Holland unsigned int slots = aif->slots ?: params_channels(params);
518afb1a600SSamuel Holland unsigned int slot_width = aif->slot_width ?: params_width(params);
5193952ec2aSSamuel Holland unsigned int sysclk_rate = sun8i_codec_get_sysclk_rate(sample_rate);
5202464dccaSSamuel Holland int bclk_div, lrck_div_order, ret, word_size;
5215a7f34abSSamuel Holland u32 clk_reg;
52236c68493SMylène Josserand
5231abb43aeSSamuel Holland /* word size */
5241abb43aeSSamuel Holland switch (params_width(params)) {
5251abb43aeSSamuel Holland case 8:
5261abb43aeSSamuel Holland word_size = 0x0;
5271abb43aeSSamuel Holland break;
5281abb43aeSSamuel Holland case 16:
5291abb43aeSSamuel Holland word_size = 0x1;
5301abb43aeSSamuel Holland break;
5311abb43aeSSamuel Holland case 20:
5321abb43aeSSamuel Holland word_size = 0x2;
5331abb43aeSSamuel Holland break;
5341abb43aeSSamuel Holland case 24:
5351abb43aeSSamuel Holland word_size = 0x3;
5361abb43aeSSamuel Holland break;
5371abb43aeSSamuel Holland default:
5381abb43aeSSamuel Holland return -EINVAL;
5391abb43aeSSamuel Holland }
5401abb43aeSSamuel Holland
5417a6b937eSSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
5427a6b937eSSamuel Holland SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
5437a6b937eSSamuel Holland word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
54436c68493SMylène Josserand
545e511aed7SSamuel Holland /* LRCK divider (BCLK/LRCK ratio) */
546e511aed7SSamuel Holland lrck_div_order = sun8i_codec_get_lrck_div_order(slots, slot_width);
547e511aed7SSamuel Holland if (lrck_div_order < 0)
548e511aed7SSamuel Holland return lrck_div_order;
54913c3bf17SVasily Khoruzhick
5505a7f34abSSamuel Holland if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) {
5515a7f34abSSamuel Holland /* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */
5525a7f34abSSamuel Holland int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id;
5535a7f34abSSamuel Holland const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner];
5545a7f34abSSamuel Holland const char *partner_name = sun8i_codec_dais[partner].name;
5555a7f34abSSamuel Holland
5565a7f34abSSamuel Holland if (partner_aif->open_streams &&
5575a7f34abSSamuel Holland (lrck_div_order != partner_aif->lrck_div_order ||
5585a7f34abSSamuel Holland sample_rate != partner_aif->sample_rate)) {
5595a7f34abSSamuel Holland dev_err(dai->dev,
5605a7f34abSSamuel Holland "%s sample and bit rates must match %s when both are used\n",
5615a7f34abSSamuel Holland dai->name, partner_name);
5625a7f34abSSamuel Holland return -EBUSY;
5635a7f34abSSamuel Holland }
5645a7f34abSSamuel Holland
5655a7f34abSSamuel Holland clk_reg = SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF2);
5665a7f34abSSamuel Holland } else {
5675a7f34abSSamuel Holland clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
5685a7f34abSSamuel Holland }
5695a7f34abSSamuel Holland
5705a7f34abSSamuel Holland regmap_update_bits(scodec->regmap, clk_reg,
5717a6b937eSSamuel Holland SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
5727a6b937eSSamuel Holland (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
57336c68493SMylène Josserand
57468a4f2caSSamuel Holland /* BCLK divider (SYSCLK/BCLK ratio) */
57515b45912SSamuel Holland bclk_div = sun8i_codec_get_bclk_div(sysclk_rate, lrck_div_order, sample_rate);
5762464dccaSSamuel Holland if (bclk_div < 0)
5772464dccaSSamuel Holland return bclk_div;
5782464dccaSSamuel Holland
5795a7f34abSSamuel Holland regmap_update_bits(scodec->regmap, clk_reg,
5807a6b937eSSamuel Holland SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
5817a6b937eSSamuel Holland bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
58268a4f2caSSamuel Holland
5833952ec2aSSamuel Holland /*
5843952ec2aSSamuel Holland * SYSCLK rate
5853952ec2aSSamuel Holland *
5863952ec2aSSamuel Holland * Clock rate protection is reference counted; but hw_params may be
5873952ec2aSSamuel Holland * called many times per substream, without matching calls to hw_free.
5883952ec2aSSamuel Holland * Protect the clock rate once per AIF, on the first hw_params call
5893952ec2aSSamuel Holland * for the first substream. clk_set_rate() will allow clock rate
5903952ec2aSSamuel Holland * changes on subsequent calls if only one AIF has open streams.
5913952ec2aSSamuel Holland */
5923952ec2aSSamuel Holland ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module,
5933952ec2aSSamuel Holland sysclk_rate);
5943952ec2aSSamuel Holland if (ret == -EBUSY)
5953952ec2aSSamuel Holland dev_err(dai->dev,
5963952ec2aSSamuel Holland "%s sample rate (%u Hz) conflicts with other audio streams\n",
5973952ec2aSSamuel Holland dai->name, sample_rate);
5983952ec2aSSamuel Holland if (ret < 0)
5993952ec2aSSamuel Holland return ret;
6003952ec2aSSamuel Holland
60115b45912SSamuel Holland if (!aif->open_streams)
60215b45912SSamuel Holland scodec->sysclk_refcnt++;
60315b45912SSamuel Holland scodec->sysclk_rate = sysclk_rate;
60415b45912SSamuel Holland
6055a7f34abSSamuel Holland aif->lrck_div_order = lrck_div_order;
6066c5326beSSamuel Holland aif->sample_rate = sample_rate;
6076c5326beSSamuel Holland aif->open_streams |= BIT(substream->stream);
60836c68493SMylène Josserand
6096c5326beSSamuel Holland return sun8i_codec_update_sample_rate(scodec);
6106c5326beSSamuel Holland }
61136c68493SMylène Josserand
sun8i_codec_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)6126c5326beSSamuel Holland static int sun8i_codec_hw_free(struct snd_pcm_substream *substream,
6136c5326beSSamuel Holland struct snd_soc_dai *dai)
6146c5326beSSamuel Holland {
6156c5326beSSamuel Holland struct sun8i_codec *scodec = snd_soc_dai_get_drvdata(dai);
6166c5326beSSamuel Holland struct sun8i_codec_aif *aif = &scodec->aifs[dai->id];
6176c5326beSSamuel Holland
6183952ec2aSSamuel Holland /* Drop references when the last substream for the AIF is freed. */
6196c5326beSSamuel Holland if (aif->open_streams != BIT(substream->stream))
6206c5326beSSamuel Holland goto done;
6216c5326beSSamuel Holland
6223952ec2aSSamuel Holland clk_rate_exclusive_put(scodec->clk_module);
62315b45912SSamuel Holland scodec->sysclk_refcnt--;
6245a7f34abSSamuel Holland aif->lrck_div_order = 0;
6256c5326beSSamuel Holland aif->sample_rate = 0;
6266c5326beSSamuel Holland
6276c5326beSSamuel Holland done:
6286c5326beSSamuel Holland aif->open_streams &= ~BIT(substream->stream);
62936c68493SMylène Josserand return 0;
63036c68493SMylène Josserand }
63136c68493SMylène Josserand
6327826b8d1SSamuel Holland static const struct snd_soc_dai_ops sun8i_codec_dai_ops = {
63315011b23SCharles Keepax .set_fmt = sun8i_codec_set_fmt,
634afb1a600SSamuel Holland .set_tdm_slot = sun8i_codec_set_tdm_slot,
63515b45912SSamuel Holland .startup = sun8i_codec_startup,
6367826b8d1SSamuel Holland .hw_params = sun8i_codec_hw_params,
6376c5326beSSamuel Holland .hw_free = sun8i_codec_hw_free,
6387826b8d1SSamuel Holland };
6397826b8d1SSamuel Holland
6407826b8d1SSamuel Holland static struct snd_soc_dai_driver sun8i_codec_dais[] = {
6417826b8d1SSamuel Holland {
6427826b8d1SSamuel Holland .name = "sun8i-codec-aif1",
6437826b8d1SSamuel Holland .id = SUN8I_CODEC_AIF1,
6447826b8d1SSamuel Holland .ops = &sun8i_codec_dai_ops,
6457826b8d1SSamuel Holland /* capture capabilities */
6467826b8d1SSamuel Holland .capture = {
6477826b8d1SSamuel Holland .stream_name = "AIF1 Capture",
6487826b8d1SSamuel Holland .channels_min = 1,
6497826b8d1SSamuel Holland .channels_max = 2,
650c2b751d7SSamuel Holland .rates = SUN8I_CODEC_PCM_RATES,
651342cacb9SSamuel Holland .formats = SUN8I_CODEC_PCM_FORMATS,
6527826b8d1SSamuel Holland .sig_bits = 24,
6537826b8d1SSamuel Holland },
6547826b8d1SSamuel Holland /* playback capabilities */
6557826b8d1SSamuel Holland .playback = {
6567826b8d1SSamuel Holland .stream_name = "AIF1 Playback",
6577826b8d1SSamuel Holland .channels_min = 1,
6587826b8d1SSamuel Holland .channels_max = 2,
659c2b751d7SSamuel Holland .rates = SUN8I_CODEC_PCM_RATES,
660342cacb9SSamuel Holland .formats = SUN8I_CODEC_PCM_FORMATS,
6617826b8d1SSamuel Holland },
66281385708SKuninori Morimoto .symmetric_rate = true,
663e557148aSSamuel Holland .symmetric_channels = true,
66481385708SKuninori Morimoto .symmetric_sample_bits = true,
6657826b8d1SSamuel Holland },
66650ec8422SSamuel Holland {
66750ec8422SSamuel Holland .name = "sun8i-codec-aif2",
66850ec8422SSamuel Holland .id = SUN8I_CODEC_AIF2,
66950ec8422SSamuel Holland .ops = &sun8i_codec_dai_ops,
67050ec8422SSamuel Holland /* capture capabilities */
67150ec8422SSamuel Holland .capture = {
67250ec8422SSamuel Holland .stream_name = "AIF2 Capture",
67350ec8422SSamuel Holland .channels_min = 1,
67450ec8422SSamuel Holland .channels_max = 2,
67550ec8422SSamuel Holland .rates = SUN8I_CODEC_PCM_RATES,
67650ec8422SSamuel Holland .formats = SUN8I_CODEC_PCM_FORMATS,
67750ec8422SSamuel Holland .sig_bits = 24,
67850ec8422SSamuel Holland },
67950ec8422SSamuel Holland /* playback capabilities */
68050ec8422SSamuel Holland .playback = {
68150ec8422SSamuel Holland .stream_name = "AIF2 Playback",
68250ec8422SSamuel Holland .channels_min = 1,
68350ec8422SSamuel Holland .channels_max = 2,
68450ec8422SSamuel Holland .rates = SUN8I_CODEC_PCM_RATES,
68550ec8422SSamuel Holland .formats = SUN8I_CODEC_PCM_FORMATS,
68650ec8422SSamuel Holland },
68781385708SKuninori Morimoto .symmetric_rate = true,
68850ec8422SSamuel Holland .symmetric_channels = true,
68981385708SKuninori Morimoto .symmetric_sample_bits = true,
69050ec8422SSamuel Holland },
6915a7f34abSSamuel Holland {
6925a7f34abSSamuel Holland .name = "sun8i-codec-aif3",
6935a7f34abSSamuel Holland .id = SUN8I_CODEC_AIF3,
6945a7f34abSSamuel Holland .ops = &sun8i_codec_dai_ops,
6955a7f34abSSamuel Holland /* capture capabilities */
6965a7f34abSSamuel Holland .capture = {
6975a7f34abSSamuel Holland .stream_name = "AIF3 Capture",
6985a7f34abSSamuel Holland .channels_min = 1,
6995a7f34abSSamuel Holland .channels_max = 1,
7005a7f34abSSamuel Holland .rates = SUN8I_CODEC_PCM_RATES,
7015a7f34abSSamuel Holland .formats = SUN8I_CODEC_PCM_FORMATS,
7025a7f34abSSamuel Holland .sig_bits = 24,
7035a7f34abSSamuel Holland },
7045a7f34abSSamuel Holland /* playback capabilities */
7055a7f34abSSamuel Holland .playback = {
7065a7f34abSSamuel Holland .stream_name = "AIF3 Playback",
7075a7f34abSSamuel Holland .channels_min = 1,
7085a7f34abSSamuel Holland .channels_max = 1,
7095a7f34abSSamuel Holland .rates = SUN8I_CODEC_PCM_RATES,
7105a7f34abSSamuel Holland .formats = SUN8I_CODEC_PCM_FORMATS,
7115a7f34abSSamuel Holland },
71281385708SKuninori Morimoto .symmetric_rate = true,
7135a7f34abSSamuel Holland .symmetric_channels = true,
71481385708SKuninori Morimoto .symmetric_sample_bits = true,
7155a7f34abSSamuel Holland },
7167826b8d1SSamuel Holland };
7177826b8d1SSamuel Holland
718fd03cf7fSSamuel Holland static const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1);
719fd03cf7fSSamuel Holland
720fd03cf7fSSamuel Holland static const struct snd_kcontrol_new sun8i_codec_controls[] = {
721fd03cf7fSSamuel Holland SOC_DOUBLE_TLV("AIF1 AD0 Capture Volume",
722fd03cf7fSSamuel Holland SUN8I_AIF1_VOL_CTRL1,
723fd03cf7fSSamuel Holland SUN8I_AIF1_VOL_CTRL1_AD0L_VOL,
724fd03cf7fSSamuel Holland SUN8I_AIF1_VOL_CTRL1_AD0R_VOL,
725fd03cf7fSSamuel Holland 0xc0, 0, sun8i_codec_vol_scale),
726fd03cf7fSSamuel Holland SOC_DOUBLE_TLV("AIF1 DA0 Playback Volume",
727fd03cf7fSSamuel Holland SUN8I_AIF1_VOL_CTRL3,
728fd03cf7fSSamuel Holland SUN8I_AIF1_VOL_CTRL3_DA0L_VOL,
729fd03cf7fSSamuel Holland SUN8I_AIF1_VOL_CTRL3_DA0R_VOL,
730fd03cf7fSSamuel Holland 0xc0, 0, sun8i_codec_vol_scale),
731fd03cf7fSSamuel Holland SOC_DOUBLE_TLV("AIF2 ADC Capture Volume",
732fd03cf7fSSamuel Holland SUN8I_AIF2_VOL_CTRL1,
733fd03cf7fSSamuel Holland SUN8I_AIF2_VOL_CTRL1_ADCL_VOL,
734fd03cf7fSSamuel Holland SUN8I_AIF2_VOL_CTRL1_ADCR_VOL,
735fd03cf7fSSamuel Holland 0xc0, 0, sun8i_codec_vol_scale),
736fd03cf7fSSamuel Holland SOC_DOUBLE_TLV("AIF2 DAC Playback Volume",
737fd03cf7fSSamuel Holland SUN8I_AIF2_VOL_CTRL2,
738fd03cf7fSSamuel Holland SUN8I_AIF2_VOL_CTRL2_DACL_VOL,
739fd03cf7fSSamuel Holland SUN8I_AIF2_VOL_CTRL2_DACR_VOL,
740fd03cf7fSSamuel Holland 0xc0, 0, sun8i_codec_vol_scale),
741fd03cf7fSSamuel Holland SOC_DOUBLE_TLV("ADC Capture Volume",
742fd03cf7fSSamuel Holland SUN8I_ADC_VOL_CTRL,
743fd03cf7fSSamuel Holland SUN8I_ADC_VOL_CTRL_ADCL_VOL,
744fd03cf7fSSamuel Holland SUN8I_ADC_VOL_CTRL_ADCR_VOL,
745fd03cf7fSSamuel Holland 0xc0, 0, sun8i_codec_vol_scale),
746fd03cf7fSSamuel Holland SOC_DOUBLE_TLV("DAC Playback Volume",
747fd03cf7fSSamuel Holland SUN8I_DAC_VOL_CTRL,
748fd03cf7fSSamuel Holland SUN8I_DAC_VOL_CTRL_DACL_VOL,
749fd03cf7fSSamuel Holland SUN8I_DAC_VOL_CTRL_DACR_VOL,
750fd03cf7fSSamuel Holland 0xc0, 0, sun8i_codec_vol_scale),
751fd03cf7fSSamuel Holland };
752fd03cf7fSSamuel Holland
sun8i_codec_aif_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)7536c5326beSSamuel Holland static int sun8i_codec_aif_event(struct snd_soc_dapm_widget *w,
7546c5326beSSamuel Holland struct snd_kcontrol *kcontrol, int event)
7556c5326beSSamuel Holland {
7566c5326beSSamuel Holland struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
7576c5326beSSamuel Holland struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
7586c5326beSSamuel Holland struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1'];
7596c5326beSSamuel Holland int stream = w->id == snd_soc_dapm_aif_out;
7606c5326beSSamuel Holland
7616c5326beSSamuel Holland if (SND_SOC_DAPM_EVENT_ON(event))
7626c5326beSSamuel Holland aif->active_streams |= BIT(stream);
7636c5326beSSamuel Holland else
7646c5326beSSamuel Holland aif->active_streams &= ~BIT(stream);
7656c5326beSSamuel Holland
7666c5326beSSamuel Holland return sun8i_codec_update_sample_rate(scodec);
7676c5326beSSamuel Holland }
7686c5326beSSamuel Holland
76918ebd62cSSamuel Holland static const char *const sun8i_aif_stereo_mux_enum_values[] = {
77018ebd62cSSamuel Holland "Stereo", "Reverse Stereo", "Sum Mono", "Mix Mono"
77118ebd62cSSamuel Holland };
77218ebd62cSSamuel Holland
77318ebd62cSSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_ad0_stereo_mux_enum,
77418ebd62cSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL,
77518ebd62cSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_SRC,
77618ebd62cSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_SRC,
77718ebd62cSSamuel Holland sun8i_aif_stereo_mux_enum_values);
77818ebd62cSSamuel Holland
77918ebd62cSSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_ad0_stereo_mux_control =
78018ebd62cSSamuel Holland SOC_DAPM_ENUM("AIF1 AD0 Stereo Capture Route",
78118ebd62cSSamuel Holland sun8i_aif1_ad0_stereo_mux_enum);
78218ebd62cSSamuel Holland
78350ec8422SSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_adc_stereo_mux_enum,
78450ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL,
78550ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_SRC,
78650ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_SRC,
78750ec8422SSamuel Holland sun8i_aif_stereo_mux_enum_values);
78850ec8422SSamuel Holland
78950ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_adc_stereo_mux_control =
79050ec8422SSamuel Holland SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
79150ec8422SSamuel Holland sun8i_aif2_adc_stereo_mux_enum);
79250ec8422SSamuel Holland
7935a7f34abSSamuel Holland static const char *const sun8i_aif3_adc_mux_enum_values[] = {
7945a7f34abSSamuel Holland "None", "AIF2 ADCL", "AIF2 ADCR"
7955a7f34abSSamuel Holland };
7965a7f34abSSamuel Holland
7975a7f34abSSamuel Holland static SOC_ENUM_SINGLE_DECL(sun8i_aif3_adc_mux_enum,
7985a7f34abSSamuel Holland SUN8I_AIF3_PATH_CTRL,
7995a7f34abSSamuel Holland SUN8I_AIF3_PATH_CTRL_AIF3_ADC_SRC,
8005a7f34abSSamuel Holland sun8i_aif3_adc_mux_enum_values);
8015a7f34abSSamuel Holland
8025a7f34abSSamuel Holland static const struct snd_kcontrol_new sun8i_aif3_adc_mux_control =
8035a7f34abSSamuel Holland SOC_DAPM_ENUM("AIF3 ADC Source Capture Route",
8045a7f34abSSamuel Holland sun8i_aif3_adc_mux_enum);
8055a7f34abSSamuel Holland
806d58b7247SSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_ad0_mixer_controls[] = {
807d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital ADC Capture Switch",
808d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC,
809d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF1DA0L,
810d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF1DA0R, 1, 0),
811d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
812d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC,
813d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACL,
814d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACR, 1, 0),
815d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF1 Data Digital ADC Capture Switch",
816d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC,
817d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_ADCL,
818d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_ADCR, 1, 0),
819d58b7247SSamuel Holland SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
820d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC,
821d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0L_MXR_SRC_AIF2DACR,
822d58b7247SSamuel Holland SUN8I_AIF1_MXR_SRC_AD0R_MXR_SRC_AIF2DACL, 1, 0),
823d58b7247SSamuel Holland };
824d58b7247SSamuel Holland
82550ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_adc_mixer_controls[] = {
82650ec8422SSamuel Holland SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
82750ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC,
82850ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA0L,
82950ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA0R, 1, 0),
83050ec8422SSamuel Holland SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
83150ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC,
83250ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF1DA1L,
83350ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF1DA1R, 1, 0),
83450ec8422SSamuel Holland SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
83550ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC,
83650ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_AIF2DACR,
83750ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_AIF2DACL, 1, 0),
83850ec8422SSamuel Holland SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
83950ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC,
84050ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCL_MXR_SRC_ADCL,
84150ec8422SSamuel Holland SUN8I_AIF2_MXR_SRC_ADCR_MXR_SRC_ADCR, 1, 0),
84250ec8422SSamuel Holland };
84350ec8422SSamuel Holland
84450ec8422SSamuel Holland static const char *const sun8i_aif2_dac_mux_enum_values[] = {
84550ec8422SSamuel Holland "AIF2", "AIF3+2", "AIF2+3"
84650ec8422SSamuel Holland };
84750ec8422SSamuel Holland
84850ec8422SSamuel Holland static SOC_ENUM_SINGLE_DECL(sun8i_aif2_dac_mux_enum,
84950ec8422SSamuel Holland SUN8I_AIF3_PATH_CTRL,
85050ec8422SSamuel Holland SUN8I_AIF3_PATH_CTRL_AIF2_DAC_SRC,
85150ec8422SSamuel Holland sun8i_aif2_dac_mux_enum_values);
85250ec8422SSamuel Holland
85350ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_dac_mux_control =
85450ec8422SSamuel Holland SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
85550ec8422SSamuel Holland sun8i_aif2_dac_mux_enum);
85650ec8422SSamuel Holland
85718ebd62cSSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif1_da0_stereo_mux_enum,
85818ebd62cSSamuel Holland SUN8I_AIF1_DACDAT_CTRL,
85918ebd62cSSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_SRC,
86018ebd62cSSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_SRC,
86118ebd62cSSamuel Holland sun8i_aif_stereo_mux_enum_values);
86218ebd62cSSamuel Holland
86318ebd62cSSamuel Holland static const struct snd_kcontrol_new sun8i_aif1_da0_stereo_mux_control =
86418ebd62cSSamuel Holland SOC_DAPM_ENUM("AIF1 DA0 Stereo Playback Route",
86518ebd62cSSamuel Holland sun8i_aif1_da0_stereo_mux_enum);
86618ebd62cSSamuel Holland
86750ec8422SSamuel Holland static SOC_ENUM_DOUBLE_DECL(sun8i_aif2_dac_stereo_mux_enum,
86850ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL,
86950ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_SRC,
87050ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_SRC,
87150ec8422SSamuel Holland sun8i_aif_stereo_mux_enum_values);
87250ec8422SSamuel Holland
87350ec8422SSamuel Holland static const struct snd_kcontrol_new sun8i_aif2_dac_stereo_mux_control =
87450ec8422SSamuel Holland SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
87550ec8422SSamuel Holland sun8i_aif2_dac_stereo_mux_enum);
87650ec8422SSamuel Holland
877ca14da6eSMylène Josserand static const struct snd_kcontrol_new sun8i_dac_mixer_controls[] = {
878ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("AIF1 Slot 0 Digital DAC Playback Switch",
879ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC,
880ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L,
88136c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
882ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("AIF1 Slot 1 Digital DAC Playback Switch",
883ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC,
884ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L,
88536c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
886ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
887ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL,
88836c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
889ca14da6eSMylène Josserand SOC_DAPM_DOUBLE("ADC Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
890ca14da6eSMylène Josserand SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL,
89136c68493SMylène Josserand SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
89236c68493SMylène Josserand };
89336c68493SMylène Josserand
89436c68493SMylène Josserand static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
895d8f00682SSamuel Holland /* System Clocks */
8966b3bb3c8SSamuel Holland SND_SOC_DAPM_CLOCK_SUPPLY("mod"),
8976b3bb3c8SSamuel Holland
898d8f00682SSamuel Holland SND_SOC_DAPM_SUPPLY("AIF1CLK",
899d8f00682SSamuel Holland SUN8I_SYSCLK_CTL,
900d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
90150ec8422SSamuel Holland SND_SOC_DAPM_SUPPLY("AIF2CLK",
90250ec8422SSamuel Holland SUN8I_SYSCLK_CTL,
90350ec8422SSamuel Holland SUN8I_SYSCLK_CTL_AIF2CLK_ENA, 0, NULL, 0),
904d8f00682SSamuel Holland SND_SOC_DAPM_SUPPLY("SYSCLK",
905d8f00682SSamuel Holland SUN8I_SYSCLK_CTL,
906d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
907d8f00682SSamuel Holland
908ed3caa3bSSamuel Holland /* Module Clocks */
909ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK AIF1",
910ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA,
911ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
91250ec8422SSamuel Holland SND_SOC_DAPM_SUPPLY("CLK AIF2",
91350ec8422SSamuel Holland SUN8I_MOD_CLK_ENA,
91450ec8422SSamuel Holland SUN8I_MOD_CLK_ENA_AIF2, 0, NULL, 0),
9155a7f34abSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK AIF3",
9165a7f34abSSamuel Holland SUN8I_MOD_CLK_ENA,
9175a7f34abSSamuel Holland SUN8I_MOD_CLK_ENA_AIF3, 0, NULL, 0),
918ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK ADC",
919ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA,
920ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA_ADC, 0, NULL, 0),
921ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("CLK DAC",
922ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA,
923ed3caa3bSSamuel Holland SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
924ed3caa3bSSamuel Holland
925ed3caa3bSSamuel Holland /* Module Resets */
926ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("RST AIF1",
927ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL,
928ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
92950ec8422SSamuel Holland SND_SOC_DAPM_SUPPLY("RST AIF2",
93050ec8422SSamuel Holland SUN8I_MOD_RST_CTL,
93150ec8422SSamuel Holland SUN8I_MOD_RST_CTL_AIF2, 0, NULL, 0),
9325a7f34abSSamuel Holland SND_SOC_DAPM_SUPPLY("RST AIF3",
9335a7f34abSSamuel Holland SUN8I_MOD_RST_CTL,
9345a7f34abSSamuel Holland SUN8I_MOD_RST_CTL_AIF3, 0, NULL, 0),
935ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("RST ADC",
936ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL,
937ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL_ADC, 0, NULL, 0),
938ed3caa3bSSamuel Holland SND_SOC_DAPM_SUPPLY("RST DAC",
939ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL,
940ed3caa3bSSamuel Holland SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
941ed3caa3bSSamuel Holland
942d58b7247SSamuel Holland /* Module Supplies */
943d58b7247SSamuel Holland SND_SOC_DAPM_SUPPLY("ADC",
944d58b7247SSamuel Holland SUN8I_ADC_DIG_CTRL,
945d58b7247SSamuel Holland SUN8I_ADC_DIG_CTRL_ENAD, 0, NULL, 0),
946d58b7247SSamuel Holland SND_SOC_DAPM_SUPPLY("DAC",
947d58b7247SSamuel Holland SUN8I_DAC_DIG_CTRL,
948d58b7247SSamuel Holland SUN8I_DAC_DIG_CTRL_ENDA, 0, NULL, 0),
94936c68493SMylène Josserand
95090cac932SSamuel Holland /* AIF "ADC" Outputs */
9516c5326beSSamuel Holland SND_SOC_DAPM_AIF_OUT_E("AIF1 AD0L", "AIF1 Capture", 0,
952eda85d1fSMylene JOSSERAND SUN8I_AIF1_ADCDAT_CTRL,
9536c5326beSSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0L_ENA, 0,
9546c5326beSSamuel Holland sun8i_codec_aif_event,
9556c5326beSSamuel Holland SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
9567826b8d1SSamuel Holland SND_SOC_DAPM_AIF_OUT("AIF1 AD0R", "AIF1 Capture", 1,
957eda85d1fSMylene JOSSERAND SUN8I_AIF1_ADCDAT_CTRL,
958fa5c0ca1SSamuel Holland SUN8I_AIF1_ADCDAT_CTRL_AIF1_AD0R_ENA, 0),
959eda85d1fSMylene JOSSERAND
96050ec8422SSamuel Holland SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
96150ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL,
96250ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCL_ENA, 0,
96350ec8422SSamuel Holland sun8i_codec_aif_event,
96450ec8422SSamuel Holland SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
96550ec8422SSamuel Holland SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
96650ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL,
96750ec8422SSamuel Holland SUN8I_AIF2_ADCDAT_CTRL_AIF2_ADCR_ENA, 0),
96850ec8422SSamuel Holland
9695a7f34abSSamuel Holland SND_SOC_DAPM_AIF_OUT_E("AIF3 ADC", "AIF3 Capture", 0,
9705a7f34abSSamuel Holland SND_SOC_NOPM, 0, 0,
9715a7f34abSSamuel Holland sun8i_codec_aif_event,
9725a7f34abSSamuel Holland SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
9735a7f34abSSamuel Holland
97418ebd62cSSamuel Holland /* AIF "ADC" Mono/Stereo Muxes */
97518ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 AD0L Stereo Mux", SND_SOC_NOPM, 0, 0,
97618ebd62cSSamuel Holland &sun8i_aif1_ad0_stereo_mux_control),
97718ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 AD0R Stereo Mux", SND_SOC_NOPM, 0, 0,
97818ebd62cSSamuel Holland &sun8i_aif1_ad0_stereo_mux_control),
97918ebd62cSSamuel Holland
98050ec8422SSamuel Holland SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
98150ec8422SSamuel Holland &sun8i_aif2_adc_stereo_mux_control),
98250ec8422SSamuel Holland SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
98350ec8422SSamuel Holland &sun8i_aif2_adc_stereo_mux_control),
98450ec8422SSamuel Holland
9855a7f34abSSamuel Holland /* AIF "ADC" Output Muxes */
9865a7f34abSSamuel Holland SND_SOC_DAPM_MUX("AIF3 ADC Source Capture Route", SND_SOC_NOPM, 0, 0,
9875a7f34abSSamuel Holland &sun8i_aif3_adc_mux_control),
9885a7f34abSSamuel Holland
989d58b7247SSamuel Holland /* AIF "ADC" Mixers */
9907b51f3c7SSamuel Holland SOC_MIXER_ARRAY("AIF1 AD0L Mixer", SND_SOC_NOPM, 0, 0,
991d58b7247SSamuel Holland sun8i_aif1_ad0_mixer_controls),
9927b51f3c7SSamuel Holland SOC_MIXER_ARRAY("AIF1 AD0R Mixer", SND_SOC_NOPM, 0, 0,
993d58b7247SSamuel Holland sun8i_aif1_ad0_mixer_controls),
994d58b7247SSamuel Holland
99550ec8422SSamuel Holland SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
99650ec8422SSamuel Holland sun8i_aif2_adc_mixer_controls),
99750ec8422SSamuel Holland SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
99850ec8422SSamuel Holland sun8i_aif2_adc_mixer_controls),
99950ec8422SSamuel Holland
100050ec8422SSamuel Holland /* AIF "DAC" Input Muxes */
100150ec8422SSamuel Holland SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
100250ec8422SSamuel Holland &sun8i_aif2_dac_mux_control),
100350ec8422SSamuel Holland SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
100450ec8422SSamuel Holland &sun8i_aif2_dac_mux_control),
100550ec8422SSamuel Holland
100618ebd62cSSamuel Holland /* AIF "DAC" Mono/Stereo Muxes */
100718ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 DA0L Stereo Mux", SND_SOC_NOPM, 0, 0,
100818ebd62cSSamuel Holland &sun8i_aif1_da0_stereo_mux_control),
100918ebd62cSSamuel Holland SND_SOC_DAPM_MUX("AIF1 DA0R Stereo Mux", SND_SOC_NOPM, 0, 0,
101018ebd62cSSamuel Holland &sun8i_aif1_da0_stereo_mux_control),
101118ebd62cSSamuel Holland
101250ec8422SSamuel Holland SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
101350ec8422SSamuel Holland &sun8i_aif2_dac_stereo_mux_control),
101450ec8422SSamuel Holland SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
101550ec8422SSamuel Holland &sun8i_aif2_dac_stereo_mux_control),
101650ec8422SSamuel Holland
1017d58b7247SSamuel Holland /* AIF "DAC" Inputs */
10186c5326beSSamuel Holland SND_SOC_DAPM_AIF_IN_E("AIF1 DA0L", "AIF1 Playback", 0,
1019d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL,
10206c5326beSSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0,
10216c5326beSSamuel Holland sun8i_codec_aif_event,
10226c5326beSSamuel Holland SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
10237826b8d1SSamuel Holland SND_SOC_DAPM_AIF_IN("AIF1 DA0R", "AIF1 Playback", 1,
1024d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL,
1025d58b7247SSamuel Holland SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
1026d58b7247SSamuel Holland
102750ec8422SSamuel Holland SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
102850ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL,
102950ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL_AIF2_DACL_ENA, 0,
103050ec8422SSamuel Holland sun8i_codec_aif_event,
103150ec8422SSamuel Holland SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
103250ec8422SSamuel Holland SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
103350ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL,
103450ec8422SSamuel Holland SUN8I_AIF2_DACDAT_CTRL_AIF2_DACR_ENA, 0),
103550ec8422SSamuel Holland
10365a7f34abSSamuel Holland SND_SOC_DAPM_AIF_IN_E("AIF3 DAC", "AIF3 Playback", 0,
10375a7f34abSSamuel Holland SND_SOC_NOPM, 0, 0,
10385a7f34abSSamuel Holland sun8i_codec_aif_event,
10395a7f34abSSamuel Holland SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
10405a7f34abSSamuel Holland
104190cac932SSamuel Holland /* ADC Inputs (connected to analog codec DAPM context) */
104290cac932SSamuel Holland SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 0, 0),
104390cac932SSamuel Holland SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
104490cac932SSamuel Holland
104590cac932SSamuel Holland /* DAC Outputs (connected to analog codec DAPM context) */
104690cac932SSamuel Holland SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0),
104790cac932SSamuel Holland SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0),
104890cac932SSamuel Holland
1049d58b7247SSamuel Holland /* DAC Mixers */
10507b51f3c7SSamuel Holland SOC_MIXER_ARRAY("DACL Mixer", SND_SOC_NOPM, 0, 0,
1051fa22ca4fSMylène Josserand sun8i_dac_mixer_controls),
10527b51f3c7SSamuel Holland SOC_MIXER_ARRAY("DACR Mixer", SND_SOC_NOPM, 0, 0,
1053fa22ca4fSMylène Josserand sun8i_dac_mixer_controls),
105436c68493SMylène Josserand };
105536c68493SMylène Josserand
105636c68493SMylène Josserand static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
105736c68493SMylène Josserand /* Clock Routes */
1058d8f00682SSamuel Holland { "AIF1CLK", NULL, "mod" },
10596b3bb3c8SSamuel Holland
1060d8f00682SSamuel Holland { "SYSCLK", NULL, "AIF1CLK" },
106190cac932SSamuel Holland
1062ed3caa3bSSamuel Holland { "CLK AIF1", NULL, "AIF1CLK" },
1063ed3caa3bSSamuel Holland { "CLK AIF1", NULL, "SYSCLK" },
1064ed3caa3bSSamuel Holland { "RST AIF1", NULL, "CLK AIF1" },
1065ed3caa3bSSamuel Holland { "AIF1 AD0L", NULL, "RST AIF1" },
1066ed3caa3bSSamuel Holland { "AIF1 AD0R", NULL, "RST AIF1" },
1067ed3caa3bSSamuel Holland { "AIF1 DA0L", NULL, "RST AIF1" },
1068ed3caa3bSSamuel Holland { "AIF1 DA0R", NULL, "RST AIF1" },
106936c68493SMylène Josserand
107050ec8422SSamuel Holland { "CLK AIF2", NULL, "AIF2CLK" },
107150ec8422SSamuel Holland { "CLK AIF2", NULL, "SYSCLK" },
107250ec8422SSamuel Holland { "RST AIF2", NULL, "CLK AIF2" },
107350ec8422SSamuel Holland { "AIF2 ADCL", NULL, "RST AIF2" },
107450ec8422SSamuel Holland { "AIF2 ADCR", NULL, "RST AIF2" },
107550ec8422SSamuel Holland { "AIF2 DACL", NULL, "RST AIF2" },
107650ec8422SSamuel Holland { "AIF2 DACR", NULL, "RST AIF2" },
107750ec8422SSamuel Holland
10785a7f34abSSamuel Holland { "CLK AIF3", NULL, "AIF1CLK" },
10795a7f34abSSamuel Holland { "CLK AIF3", NULL, "SYSCLK" },
10805a7f34abSSamuel Holland { "RST AIF3", NULL, "CLK AIF3" },
10815a7f34abSSamuel Holland { "AIF3 ADC", NULL, "RST AIF3" },
10825a7f34abSSamuel Holland { "AIF3 DAC", NULL, "RST AIF3" },
10835a7f34abSSamuel Holland
1084ed3caa3bSSamuel Holland { "CLK ADC", NULL, "SYSCLK" },
1085ed3caa3bSSamuel Holland { "RST ADC", NULL, "CLK ADC" },
1086ed3caa3bSSamuel Holland { "ADC", NULL, "RST ADC" },
108790cac932SSamuel Holland { "ADCL", NULL, "ADC" },
108890cac932SSamuel Holland { "ADCR", NULL, "ADC" },
1089eda85d1fSMylene JOSSERAND
1090ed3caa3bSSamuel Holland { "CLK DAC", NULL, "SYSCLK" },
1091ed3caa3bSSamuel Holland { "RST DAC", NULL, "CLK DAC" },
1092ed3caa3bSSamuel Holland { "DAC", NULL, "RST DAC" },
1093ed3caa3bSSamuel Holland { "DACL", NULL, "DAC" },
1094ed3caa3bSSamuel Holland { "DACR", NULL, "DAC" },
1095ed3caa3bSSamuel Holland
1096d58b7247SSamuel Holland /* AIF "ADC" Output Routes */
109718ebd62cSSamuel Holland { "AIF1 AD0L", NULL, "AIF1 AD0L Stereo Mux" },
109818ebd62cSSamuel Holland { "AIF1 AD0R", NULL, "AIF1 AD0R Stereo Mux" },
109918ebd62cSSamuel Holland
110050ec8422SSamuel Holland { "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
110150ec8422SSamuel Holland { "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
110250ec8422SSamuel Holland
11035a7f34abSSamuel Holland { "AIF3 ADC", NULL, "AIF3 ADC Source Capture Route" },
11045a7f34abSSamuel Holland
110518ebd62cSSamuel Holland /* AIF "ADC" Mono/Stereo Mux Routes */
110618ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Stereo", "AIF1 AD0L Mixer" },
110718ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Reverse Stereo", "AIF1 AD0R Mixer" },
110818ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
110918ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
111018ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
111118ebd62cSSamuel Holland { "AIF1 AD0L Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
111218ebd62cSSamuel Holland
111318ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Stereo", "AIF1 AD0R Mixer" },
111418ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Reverse Stereo", "AIF1 AD0L Mixer" },
111518ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0L Mixer" },
111618ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Sum Mono", "AIF1 AD0R Mixer" },
111718ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0L Mixer" },
111818ebd62cSSamuel Holland { "AIF1 AD0R Stereo Mux", "Mix Mono", "AIF1 AD0R Mixer" },
1119d58b7247SSamuel Holland
112050ec8422SSamuel Holland { "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
112150ec8422SSamuel Holland { "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
112250ec8422SSamuel Holland { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
112350ec8422SSamuel Holland { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
112450ec8422SSamuel Holland { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
112550ec8422SSamuel Holland { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
112650ec8422SSamuel Holland
112750ec8422SSamuel Holland { "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
112850ec8422SSamuel Holland { "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
112950ec8422SSamuel Holland { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
113050ec8422SSamuel Holland { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
113150ec8422SSamuel Holland { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
113250ec8422SSamuel Holland { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
113350ec8422SSamuel Holland
11345a7f34abSSamuel Holland /* AIF "ADC" Output Mux Routes */
11355a7f34abSSamuel Holland { "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
11365a7f34abSSamuel Holland { "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
11375a7f34abSSamuel Holland
1138d58b7247SSamuel Holland /* AIF "ADC" Mixer Routes */
113918ebd62cSSamuel Holland { "AIF1 AD0L Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0L Stereo Mux" },
114050ec8422SSamuel Holland { "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
11417b51f3c7SSamuel Holland { "AIF1 AD0L Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCL" },
114250ec8422SSamuel Holland { "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
1143d58b7247SSamuel Holland
114418ebd62cSSamuel Holland { "AIF1 AD0R Mixer", "AIF1 Slot 0 Digital ADC Capture Switch", "AIF1 DA0R Stereo Mux" },
114550ec8422SSamuel Holland { "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
11467b51f3c7SSamuel Holland { "AIF1 AD0R Mixer", "AIF1 Data Digital ADC Capture Switch", "ADCR" },
114750ec8422SSamuel Holland { "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
114850ec8422SSamuel Holland
114950ec8422SSamuel Holland { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
115050ec8422SSamuel Holland { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
115150ec8422SSamuel Holland { "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
115250ec8422SSamuel Holland
115350ec8422SSamuel Holland { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
115450ec8422SSamuel Holland { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
115550ec8422SSamuel Holland { "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
115650ec8422SSamuel Holland
115750ec8422SSamuel Holland /* AIF "DAC" Input Mux Routes */
115850ec8422SSamuel Holland { "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
11595a7f34abSSamuel Holland { "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
116050ec8422SSamuel Holland { "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
116150ec8422SSamuel Holland
116250ec8422SSamuel Holland { "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
116350ec8422SSamuel Holland { "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
11645a7f34abSSamuel Holland { "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
1165d58b7247SSamuel Holland
116618ebd62cSSamuel Holland /* AIF "DAC" Mono/Stereo Mux Routes */
116718ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Stereo", "AIF1 DA0L" },
116818ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Reverse Stereo", "AIF1 DA0R" },
116918ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0L" },
117018ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Sum Mono", "AIF1 DA0R" },
117118ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0L" },
117218ebd62cSSamuel Holland { "AIF1 DA0L Stereo Mux", "Mix Mono", "AIF1 DA0R" },
117318ebd62cSSamuel Holland
117418ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Stereo", "AIF1 DA0R" },
117518ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Reverse Stereo", "AIF1 DA0L" },
117618ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0L" },
117718ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Sum Mono", "AIF1 DA0R" },
117818ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0L" },
117918ebd62cSSamuel Holland { "AIF1 DA0R Stereo Mux", "Mix Mono", "AIF1 DA0R" },
118018ebd62cSSamuel Holland
118150ec8422SSamuel Holland { "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
118250ec8422SSamuel Holland { "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
118350ec8422SSamuel Holland { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
118450ec8422SSamuel Holland { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
118550ec8422SSamuel Holland { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
118650ec8422SSamuel Holland { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
118750ec8422SSamuel Holland
118850ec8422SSamuel Holland { "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
118950ec8422SSamuel Holland { "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
119050ec8422SSamuel Holland { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
119150ec8422SSamuel Holland { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
119250ec8422SSamuel Holland { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
119350ec8422SSamuel Holland { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
119450ec8422SSamuel Holland
1195d58b7247SSamuel Holland /* DAC Output Routes */
11967b51f3c7SSamuel Holland { "DACL", NULL, "DACL Mixer" },
11977b51f3c7SSamuel Holland { "DACR", NULL, "DACR Mixer" },
119836c68493SMylène Josserand
119936c68493SMylène Josserand /* DAC Mixer Routes */
120018ebd62cSSamuel Holland { "DACL Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0L Stereo Mux" },
120150ec8422SSamuel Holland { "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
12027b51f3c7SSamuel Holland { "DACL Mixer", "ADC Digital DAC Playback Switch", "ADCL" },
1203e47d2dcdSSamuel Holland
120418ebd62cSSamuel Holland { "DACR Mixer", "AIF1 Slot 0 Digital DAC Playback Switch", "AIF1 DA0R Stereo Mux" },
120550ec8422SSamuel Holland { "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
12067b51f3c7SSamuel Holland { "DACR Mixer", "ADC Digital DAC Playback Switch", "ADCR" },
120736c68493SMylène Josserand };
120836c68493SMylène Josserand
120990cac932SSamuel Holland static const struct snd_soc_dapm_widget sun8i_codec_legacy_widgets[] = {
121090cac932SSamuel Holland /* Legacy ADC Inputs (connected to analog codec DAPM context) */
121190cac932SSamuel Holland SND_SOC_DAPM_ADC("AIF1 Slot 0 Left ADC", NULL, SND_SOC_NOPM, 0, 0),
121290cac932SSamuel Holland SND_SOC_DAPM_ADC("AIF1 Slot 0 Right ADC", NULL, SND_SOC_NOPM, 0, 0),
121390cac932SSamuel Holland
121490cac932SSamuel Holland /* Legacy DAC Outputs (connected to analog codec DAPM context) */
121590cac932SSamuel Holland SND_SOC_DAPM_DAC("AIF1 Slot 0 Left", NULL, SND_SOC_NOPM, 0, 0),
121690cac932SSamuel Holland SND_SOC_DAPM_DAC("AIF1 Slot 0 Right", NULL, SND_SOC_NOPM, 0, 0),
121790cac932SSamuel Holland };
121890cac932SSamuel Holland
121990cac932SSamuel Holland static const struct snd_soc_dapm_route sun8i_codec_legacy_routes[] = {
122090cac932SSamuel Holland /* Legacy ADC Routes */
122190cac932SSamuel Holland { "ADCL", NULL, "AIF1 Slot 0 Left ADC" },
122290cac932SSamuel Holland { "ADCR", NULL, "AIF1 Slot 0 Right ADC" },
122390cac932SSamuel Holland
122490cac932SSamuel Holland /* Legacy DAC Routes */
122590cac932SSamuel Holland { "AIF1 Slot 0 Left", NULL, "DACL" },
122690cac932SSamuel Holland { "AIF1 Slot 0 Right", NULL, "DACR" },
122790cac932SSamuel Holland };
122890cac932SSamuel Holland
sun8i_codec_component_probe(struct snd_soc_component * component)122990cac932SSamuel Holland static int sun8i_codec_component_probe(struct snd_soc_component *component)
123090cac932SSamuel Holland {
123190cac932SSamuel Holland struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
123290cac932SSamuel Holland struct sun8i_codec *scodec = snd_soc_component_get_drvdata(component);
123390cac932SSamuel Holland int ret;
123490cac932SSamuel Holland
123590cac932SSamuel Holland /* Add widgets for backward compatibility with old device trees. */
123690cac932SSamuel Holland if (scodec->quirks->legacy_widgets) {
123790cac932SSamuel Holland ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_legacy_widgets,
123890cac932SSamuel Holland ARRAY_SIZE(sun8i_codec_legacy_widgets));
123990cac932SSamuel Holland if (ret)
124090cac932SSamuel Holland return ret;
124190cac932SSamuel Holland
124290cac932SSamuel Holland ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_legacy_routes,
124390cac932SSamuel Holland ARRAY_SIZE(sun8i_codec_legacy_routes));
124490cac932SSamuel Holland if (ret)
124590cac932SSamuel Holland return ret;
124690cac932SSamuel Holland }
124790cac932SSamuel Holland
1248d8f00682SSamuel Holland /*
1249d8f00682SSamuel Holland * AIF1CLK and AIF2CLK share a pair of clock parents: PLL_AUDIO ("mod")
1250d8f00682SSamuel Holland * and MCLK (from the CPU DAI connected to AIF1). MCLK's parent is also
1251d8f00682SSamuel Holland * PLL_AUDIO, so using it adds no additional flexibility. Use PLL_AUDIO
1252d8f00682SSamuel Holland * directly to simplify the clock tree.
1253d8f00682SSamuel Holland */
1254d8f00682SSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
1255d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF1CLK_SRC_MASK |
1256d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF2CLK_SRC_MASK,
1257d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL |
1258d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_AIF2CLK_SRC_PLL);
1259d8f00682SSamuel Holland
1260d8f00682SSamuel Holland /* Use AIF1CLK as the SYSCLK parent since AIF1 is used most often. */
1261d8f00682SSamuel Holland regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL,
1262d8f00682SSamuel Holland BIT(SUN8I_SYSCLK_CTL_SYSCLK_SRC),
1263d8f00682SSamuel Holland SUN8I_SYSCLK_CTL_SYSCLK_SRC_AIF1CLK);
1264d8f00682SSamuel Holland
12656c5326beSSamuel Holland /* Program the default sample rate. */
12666c5326beSSamuel Holland sun8i_codec_update_sample_rate(scodec);
12676c5326beSSamuel Holland
126890cac932SSamuel Holland return 0;
126990cac932SSamuel Holland }
127090cac932SSamuel Holland
12717ec9b872SKuninori Morimoto static const struct snd_soc_component_driver sun8i_soc_component = {
1272fd03cf7fSSamuel Holland .controls = sun8i_codec_controls,
1273fd03cf7fSSamuel Holland .num_controls = ARRAY_SIZE(sun8i_codec_controls),
127436c68493SMylène Josserand .dapm_widgets = sun8i_codec_dapm_widgets,
127536c68493SMylène Josserand .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
127636c68493SMylène Josserand .dapm_routes = sun8i_codec_dapm_routes,
127736c68493SMylène Josserand .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
1278a2f6d303SSamuel Holland .probe = sun8i_codec_component_probe,
12797ec9b872SKuninori Morimoto .idle_bias_on = 1,
12807ec9b872SKuninori Morimoto .endianness = 1,
128136c68493SMylène Josserand };
128236c68493SMylène Josserand
128336c68493SMylène Josserand static const struct regmap_config sun8i_codec_regmap_config = {
128436c68493SMylène Josserand .reg_bits = 32,
128536c68493SMylène Josserand .reg_stride = 4,
128636c68493SMylène Josserand .val_bits = 32,
128736c68493SMylène Josserand .max_register = SUN8I_DAC_MXR_SRC,
128836c68493SMylène Josserand
128936c68493SMylène Josserand .cache_type = REGCACHE_FLAT,
129036c68493SMylène Josserand };
129136c68493SMylène Josserand
sun8i_codec_probe(struct platform_device * pdev)129236c68493SMylène Josserand static int sun8i_codec_probe(struct platform_device *pdev)
129336c68493SMylène Josserand {
129436c68493SMylène Josserand struct sun8i_codec *scodec;
129536c68493SMylène Josserand void __iomem *base;
129636c68493SMylène Josserand int ret;
129736c68493SMylène Josserand
129836c68493SMylène Josserand scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
129936c68493SMylène Josserand if (!scodec)
130036c68493SMylène Josserand return -ENOMEM;
130136c68493SMylène Josserand
130236c68493SMylène Josserand scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
130336c68493SMylène Josserand if (IS_ERR(scodec->clk_module)) {
130436c68493SMylène Josserand dev_err(&pdev->dev, "Failed to get the module clock\n");
130536c68493SMylène Josserand return PTR_ERR(scodec->clk_module);
130636c68493SMylène Josserand }
130736c68493SMylène Josserand
1308790b3657SYueHaibing base = devm_platform_ioremap_resource(pdev, 0);
130936c68493SMylène Josserand if (IS_ERR(base)) {
131036c68493SMylène Josserand dev_err(&pdev->dev, "Failed to map the registers\n");
131136c68493SMylène Josserand return PTR_ERR(base);
131236c68493SMylène Josserand }
131336c68493SMylène Josserand
1314efb736fbSSamuel Holland scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base,
131536c68493SMylène Josserand &sun8i_codec_regmap_config);
131636c68493SMylène Josserand if (IS_ERR(scodec->regmap)) {
131736c68493SMylène Josserand dev_err(&pdev->dev, "Failed to create our regmap\n");
131836c68493SMylène Josserand return PTR_ERR(scodec->regmap);
131936c68493SMylène Josserand }
132036c68493SMylène Josserand
132190cac932SSamuel Holland scodec->quirks = of_device_get_match_data(&pdev->dev);
132290cac932SSamuel Holland
132336c68493SMylène Josserand platform_set_drvdata(pdev, scodec);
132436c68493SMylène Josserand
132536c68493SMylène Josserand pm_runtime_enable(&pdev->dev);
132636c68493SMylène Josserand if (!pm_runtime_enabled(&pdev->dev)) {
132736c68493SMylène Josserand ret = sun8i_codec_runtime_resume(&pdev->dev);
132836c68493SMylène Josserand if (ret)
132936c68493SMylène Josserand goto err_pm_disable;
133036c68493SMylène Josserand }
133136c68493SMylène Josserand
13327ec9b872SKuninori Morimoto ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component,
13337826b8d1SSamuel Holland sun8i_codec_dais,
13347826b8d1SSamuel Holland ARRAY_SIZE(sun8i_codec_dais));
133536c68493SMylène Josserand if (ret) {
133636c68493SMylène Josserand dev_err(&pdev->dev, "Failed to register codec\n");
133736c68493SMylène Josserand goto err_suspend;
133836c68493SMylène Josserand }
133936c68493SMylène Josserand
134036c68493SMylène Josserand return ret;
134136c68493SMylène Josserand
134236c68493SMylène Josserand err_suspend:
134336c68493SMylène Josserand if (!pm_runtime_status_suspended(&pdev->dev))
134436c68493SMylène Josserand sun8i_codec_runtime_suspend(&pdev->dev);
134536c68493SMylène Josserand
134636c68493SMylène Josserand err_pm_disable:
134736c68493SMylène Josserand pm_runtime_disable(&pdev->dev);
134836c68493SMylène Josserand
134936c68493SMylène Josserand return ret;
135036c68493SMylène Josserand }
135136c68493SMylène Josserand
sun8i_codec_remove(struct platform_device * pdev)1352*a594f423SUwe Kleine-König static void sun8i_codec_remove(struct platform_device *pdev)
135336c68493SMylène Josserand {
135436c68493SMylène Josserand pm_runtime_disable(&pdev->dev);
135536c68493SMylène Josserand if (!pm_runtime_status_suspended(&pdev->dev))
135636c68493SMylène Josserand sun8i_codec_runtime_suspend(&pdev->dev);
135736c68493SMylène Josserand }
135836c68493SMylène Josserand
135990cac932SSamuel Holland static const struct sun8i_codec_quirks sun8i_a33_quirks = {
136090cac932SSamuel Holland .legacy_widgets = true,
13617518805fSSamuel Holland .lrck_inversion = true,
136290cac932SSamuel Holland };
136390cac932SSamuel Holland
136490cac932SSamuel Holland static const struct sun8i_codec_quirks sun50i_a64_quirks = {
136590cac932SSamuel Holland };
136690cac932SSamuel Holland
136736c68493SMylène Josserand static const struct of_device_id sun8i_codec_of_match[] = {
136890cac932SSamuel Holland { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
136990cac932SSamuel Holland { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
137036c68493SMylène Josserand {}
137136c68493SMylène Josserand };
137236c68493SMylène Josserand MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
137336c68493SMylène Josserand
137436c68493SMylène Josserand static const struct dev_pm_ops sun8i_codec_pm_ops = {
137536c68493SMylène Josserand SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
137636c68493SMylène Josserand sun8i_codec_runtime_resume, NULL)
137736c68493SMylène Josserand };
137836c68493SMylène Josserand
137936c68493SMylène Josserand static struct platform_driver sun8i_codec_driver = {
138036c68493SMylène Josserand .driver = {
138136c68493SMylène Josserand .name = "sun8i-codec",
138236c68493SMylène Josserand .of_match_table = sun8i_codec_of_match,
138336c68493SMylène Josserand .pm = &sun8i_codec_pm_ops,
138436c68493SMylène Josserand },
138536c68493SMylène Josserand .probe = sun8i_codec_probe,
1386*a594f423SUwe Kleine-König .remove_new = sun8i_codec_remove,
138736c68493SMylène Josserand };
138836c68493SMylène Josserand module_platform_driver(sun8i_codec_driver);
138936c68493SMylène Josserand
139036c68493SMylène Josserand MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
139136c68493SMylène Josserand MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
139236c68493SMylène Josserand MODULE_LICENSE("GPL");
139336c68493SMylène Josserand MODULE_ALIAS("platform:sun8i-codec");
1394