summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorVasily Khoruzhick <anarsoul@gmail.com>2018-10-17 03:38:09 -0400
committerMark Brown <broonie@kernel.org>2018-10-17 06:11:01 -0400
commit42371f327df0b8e9d479b929c5cd301846dd0f70 (patch)
treeb0c84ef61a77a7beffeca63edaf06eb5cd9be3c4 /sound
parentaf2c06c41970eb0110a03696fd7f8f07854719db (diff)
ASoC: sunxi: Add new driver for Allwinner A64 codec's analog path controls
The internal codec on A64 is split into 2 parts. The analog path controls are routed through an embedded custom register bus accessed through the PRCM block. Add an ASoC component driver for it. This should be tied to the codec audio card as an auxiliary device. Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com> Acked-by: Maxime Ripard <maxime.ripard@bootlin.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/sunxi/Kconfig8
-rw-r--r--sound/soc/sunxi/Makefile1
-rw-r--r--sound/soc/sunxi/sun50i-codec-analog.c444
3 files changed, 453 insertions, 0 deletions
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 83b770cdfdaa..8a055ca1819a 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -28,6 +28,14 @@ config SND_SUN8I_CODEC_ANALOG
28 Say Y or M if you want to add support for the analog controls for 28 Say Y or M if you want to add support for the analog controls for
29 the codec embedded in newer Allwinner SoCs. 29 the codec embedded in newer Allwinner SoCs.
30 30
31config SND_SUN50I_CODEC_ANALOG
32 tristate "Allwinner sun50i Codec Analog Controls Support"
33 depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
34 select SND_SUNXI_ADDA_PR_REGMAP
35 help
36 Say Y or M if you want to add support for the analog controls for
37 the codec embedded in Allwinner A64 SoC.
38
31config SND_SUN4I_I2S 39config SND_SUN4I_I2S
32 tristate "Allwinner A10 I2S Support" 40 tristate "Allwinner A10 I2S Support"
33 select SND_SOC_GENERIC_DMAENGINE_PCM 41 select SND_SOC_GENERIC_DMAENGINE_PCM
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index 74b99d55cfca..a86be340a076 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -3,5 +3,6 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
3obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o 3obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
4obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o 4obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
5obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o 5obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
6obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o
6obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o 7obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
7obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o 8obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o
diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c
new file mode 100644
index 000000000000..8f5f999df631
--- /dev/null
+++ b/sound/soc/sunxi/sun50i-codec-analog.c
@@ -0,0 +1,444 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * This driver supports the analog controls for the internal codec
4 * found in Allwinner's A64 SoC.
5 *
6 * Copyright (C) 2016 Chen-Yu Tsai <wens@csie.org>
7 * Copyright (C) 2017 Marcus Cooper <codekipper@gmail.com>
8 * Copyright (C) 2018 Vasily Khoruzhick <anarsoul@gmail.com>
9 *
10 * Based on sun8i-codec-analog.c
11 *
12 */
13
14#include <linux/io.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/of.h>
18#include <linux/of_device.h>
19#include <linux/platform_device.h>
20#include <linux/regmap.h>
21
22#include <sound/soc.h>
23#include <sound/soc-dapm.h>
24#include <sound/tlv.h>
25
26#include "sun8i-adda-pr-regmap.h"
27
28/* Codec analog control register offsets and bit fields */
29#define SUN50I_ADDA_HP_CTRL 0x00
30#define SUN50I_ADDA_HP_CTRL_PA_CLK_GATE 7
31#define SUN50I_ADDA_HP_CTRL_HPPA_EN 6
32#define SUN50I_ADDA_HP_CTRL_HPVOL 0
33
34#define SUN50I_ADDA_OL_MIX_CTRL 0x01
35#define SUN50I_ADDA_OL_MIX_CTRL_MIC1 6
36#define SUN50I_ADDA_OL_MIX_CTRL_MIC2 5
37#define SUN50I_ADDA_OL_MIX_CTRL_PHONE 4
38#define SUN50I_ADDA_OL_MIX_CTRL_PHONEN 3
39#define SUN50I_ADDA_OL_MIX_CTRL_LINEINL 2
40#define SUN50I_ADDA_OL_MIX_CTRL_DACL 1
41#define SUN50I_ADDA_OL_MIX_CTRL_DACR 0
42
43#define SUN50I_ADDA_OR_MIX_CTRL 0x02
44#define SUN50I_ADDA_OR_MIX_CTRL_MIC1 6
45#define SUN50I_ADDA_OR_MIX_CTRL_MIC2 5
46#define SUN50I_ADDA_OR_MIX_CTRL_PHONE 4
47#define SUN50I_ADDA_OR_MIX_CTRL_PHONEP 3
48#define SUN50I_ADDA_OR_MIX_CTRL_LINEINR 2
49#define SUN50I_ADDA_OR_MIX_CTRL_DACR 1
50#define SUN50I_ADDA_OR_MIX_CTRL_DACL 0
51
52#define SUN50I_ADDA_LINEOUT_CTRL0 0x05
53#define SUN50I_ADDA_LINEOUT_CTRL0_LEN 7
54#define SUN50I_ADDA_LINEOUT_CTRL0_REN 6
55#define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL 5
56#define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL 4
57
58#define SUN50I_ADDA_LINEOUT_CTRL1 0x06
59#define SUN50I_ADDA_LINEOUT_CTRL1_VOL 0
60
61#define SUN50I_ADDA_MIC1_CTRL 0x07
62#define SUN50I_ADDA_MIC1_CTRL_MIC1G 4
63#define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN 3
64#define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST 0
65
66#define SUN50I_ADDA_MIC2_CTRL 0x08
67#define SUN50I_ADDA_MIC2_CTRL_MIC2G 4
68#define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN 3
69#define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST 0
70
71#define SUN50I_ADDA_LINEIN_CTRL 0x09
72#define SUN50I_ADDA_LINEIN_CTRL_LINEING 0
73
74#define SUN50I_ADDA_MIX_DAC_CTRL 0x0a
75#define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN 7
76#define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN 6
77#define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN 5
78#define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN 4
79#define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE 3
80#define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE 2
81#define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS 1
82#define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS 0
83
84#define SUN50I_ADDA_L_ADCMIX_SRC 0x0b
85#define SUN50I_ADDA_L_ADCMIX_SRC_MIC1 6
86#define SUN50I_ADDA_L_ADCMIX_SRC_MIC2 5
87#define SUN50I_ADDA_L_ADCMIX_SRC_PHONE 4
88#define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN 3
89#define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL 2
90#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL 1
91#define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR 0
92
93#define SUN50I_ADDA_R_ADCMIX_SRC 0x0c
94#define SUN50I_ADDA_R_ADCMIX_SRC_MIC1 6
95#define SUN50I_ADDA_R_ADCMIX_SRC_MIC2 5
96#define SUN50I_ADDA_R_ADCMIX_SRC_PHONE 4
97#define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP 3
98#define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR 2
99#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR 1
100#define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL 0
101
102#define SUN50I_ADDA_ADC_CTRL 0x0d
103#define SUN50I_ADDA_ADC_CTRL_ADCREN 7
104#define SUN50I_ADDA_ADC_CTRL_ADCLEN 6
105#define SUN50I_ADDA_ADC_CTRL_ADCG 0
106
107#define SUN50I_ADDA_HS_MBIAS_CTRL 0x0e
108#define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN 7
109
110#define SUN50I_ADDA_JACK_MIC_CTRL 0x1d
111#define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN 5
112
113/* mixer controls */
114static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {
115 SOC_DAPM_DOUBLE_R("DAC Playback Switch",
116 SUN50I_ADDA_OL_MIX_CTRL,
117 SUN50I_ADDA_OR_MIX_CTRL,
118 SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
119 SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
120 SUN50I_ADDA_OL_MIX_CTRL,
121 SUN50I_ADDA_OR_MIX_CTRL,
122 SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),
123 SOC_DAPM_DOUBLE_R("Line In Playback Switch",
124 SUN50I_ADDA_OL_MIX_CTRL,
125 SUN50I_ADDA_OR_MIX_CTRL,
126 SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0),
127 SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
128 SUN50I_ADDA_OL_MIX_CTRL,
129 SUN50I_ADDA_OR_MIX_CTRL,
130 SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
131 SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
132 SUN50I_ADDA_OL_MIX_CTRL,
133 SUN50I_ADDA_OR_MIX_CTRL,
134 SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),
135};
136
137/* ADC mixer controls */
138static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = {
139 SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
140 SUN50I_ADDA_L_ADCMIX_SRC,
141 SUN50I_ADDA_R_ADCMIX_SRC,
142 SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
143 SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
144 SUN50I_ADDA_L_ADCMIX_SRC,
145 SUN50I_ADDA_R_ADCMIX_SRC,
146 SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),
147 SOC_DAPM_DOUBLE_R("Line In Capture Switch",
148 SUN50I_ADDA_L_ADCMIX_SRC,
149 SUN50I_ADDA_R_ADCMIX_SRC,
150 SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0),
151 SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
152 SUN50I_ADDA_L_ADCMIX_SRC,
153 SUN50I_ADDA_R_ADCMIX_SRC,
154 SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
155 SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
156 SUN50I_ADDA_L_ADCMIX_SRC,
157 SUN50I_ADDA_R_ADCMIX_SRC,
158 SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),
159};
160
161static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale,
162 -450, 150, 0);
163static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale,
164 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
165 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
166);
167
168static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1);
169
170static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale,
171 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
172 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
173);
174
175
176/* volume / mute controls */
177static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {
178 SOC_SINGLE_TLV("Headphone Playback Volume",
179 SUN50I_ADDA_HP_CTRL,
180 SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0,
181 sun50i_codec_hp_vol_scale),
182
183 SOC_DOUBLE("Headphone Playback Switch",
184 SUN50I_ADDA_MIX_DAC_CTRL,
185 SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
186 SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0),
187
188 /* Mixer pre-gain */
189 SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,
190 SUN50I_ADDA_MIC1_CTRL_MIC1G,
191 0x7, 0, sun50i_codec_out_mixer_pregain_scale),
192
193 /* Microphone Amp boost gain */
194 SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL,
195 SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0,
196 sun50i_codec_mic_gain_scale),
197
198 /* Mixer pre-gain */
199 SOC_SINGLE_TLV("Mic2 Playback Volume",
200 SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G,
201 0x7, 0, sun50i_codec_out_mixer_pregain_scale),
202
203 /* Microphone Amp boost gain */
204 SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL,
205 SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0,
206 sun50i_codec_mic_gain_scale),
207
208 /* ADC */
209 SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL,
210 SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0,
211 sun50i_codec_out_mixer_pregain_scale),
212
213 /* Mixer pre-gain */
214 SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL,
215 SUN50I_ADDA_LINEIN_CTRL_LINEING,
216 0x7, 0, sun50i_codec_out_mixer_pregain_scale),
217
218 SOC_SINGLE_TLV("Line Out Playback Volume",
219 SUN50I_ADDA_LINEOUT_CTRL1,
220 SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
221 sun50i_codec_lineout_vol_scale),
222
223 SOC_DOUBLE("Line Out Playback Switch",
224 SUN50I_ADDA_LINEOUT_CTRL0,
225 SUN50I_ADDA_LINEOUT_CTRL0_LEN,
226 SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0),
227
228};
229
230static const char * const sun50i_codec_hp_src_enum_text[] = {
231 "DAC", "Mixer",
232};
233
234static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum,
235 SUN50I_ADDA_MIX_DAC_CTRL,
236 SUN50I_ADDA_MIX_DAC_CTRL_LHPIS,
237 SUN50I_ADDA_MIX_DAC_CTRL_RHPIS,
238 sun50i_codec_hp_src_enum_text);
239
240static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {
241 SOC_DAPM_ENUM("Headphone Source Playback Route",
242 sun50i_codec_hp_src_enum),
243};
244
245static const char * const sun50i_codec_lineout_src_enum_text[] = {
246 "Stereo", "Mono Differential",
247};
248
249static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,
250 SUN50I_ADDA_LINEOUT_CTRL0,
251 SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,
252 SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,
253 sun50i_codec_lineout_src_enum_text);
254
255static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
256 SOC_DAPM_ENUM("Line Out Source Playback Route",
257 sun50i_codec_lineout_src_enum),
258};
259
260static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
261 /* DAC */
262 SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
263 SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0),
264 SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
265 SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0),
266 /* ADC */
267 SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL,
268 SUN50I_ADDA_ADC_CTRL_ADCLEN, 0),
269 SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL,
270 SUN50I_ADDA_ADC_CTRL_ADCREN, 0),
271 /*
272 * Due to this component and the codec belonging to separate DAPM
273 * contexts, we need to manually link the above widgets to their
274 * stream widgets at the card level.
275 */
276
277 SND_SOC_DAPM_MUX("Headphone Source Playback Route",
278 SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
279 SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL,
280 SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),
281 SND_SOC_DAPM_OUTPUT("HP"),
282
283 SND_SOC_DAPM_MUX("Line Out Source Playback Route",
284 SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
285 SND_SOC_DAPM_OUTPUT("LINEOUT"),
286
287 /* Microphone inputs */
288 SND_SOC_DAPM_INPUT("MIC1"),
289
290 /* Microphone Bias */
291 SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL,
292 SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN,
293 0, NULL, 0),
294
295 /* Mic input path */
296 SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL,
297 SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0),
298
299 /* Microphone input */
300 SND_SOC_DAPM_INPUT("MIC2"),
301
302 /* Microphone Bias */
303 SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,
304 SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,
305 0, NULL, 0),
306
307 /* Mic input path */
308 SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,
309 SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0),
310
311 /* Line input */
312 SND_SOC_DAPM_INPUT("LINEIN"),
313
314 /* Mixers */
315 SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
316 SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0,
317 sun50i_a64_codec_mixer_controls,
318 ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
319 SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
320 SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,
321 sun50i_a64_codec_mixer_controls,
322 ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
323 SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL,
324 SUN50I_ADDA_ADC_CTRL_ADCLEN, 0,
325 sun50i_codec_adc_mixer_controls,
326 ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
327 SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL,
328 SUN50I_ADDA_ADC_CTRL_ADCREN, 0,
329 sun50i_codec_adc_mixer_controls,
330 ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
331};
332
333static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
334 /* Left Mixer Routes */
335 { "Left Mixer", "DAC Playback Switch", "Left DAC" },
336 { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
337 { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
338
339 /* Right Mixer Routes */
340 { "Right Mixer", "DAC Playback Switch", "Right DAC" },
341 { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
342 { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
343
344 /* Left ADC Mixer Routes */
345 { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
346 { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
347 { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
348
349 /* Right ADC Mixer Routes */
350 { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
351 { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
352 { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
353
354 /* ADC Routes */
355 { "Left ADC", NULL, "Left ADC Mixer" },
356 { "Right ADC", NULL, "Right ADC Mixer" },
357
358 /* Headphone Routes */
359 { "Headphone Source Playback Route", "DAC", "Left DAC" },
360 { "Headphone Source Playback Route", "DAC", "Right DAC" },
361 { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
362 { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
363 { "Headphone Amp", NULL, "Headphone Source Playback Route" },
364 { "HP", NULL, "Headphone Amp" },
365
366 /* Microphone Routes */
367 { "Mic1 Amplifier", NULL, "MIC1"},
368
369 /* Microphone Routes */
370 { "Mic2 Amplifier", NULL, "MIC2"},
371 { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
372 { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
373 { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
374 { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
375
376 /* Line-in Routes */
377 { "Left Mixer", "Line In Playback Switch", "LINEIN" },
378 { "Right Mixer", "Line In Playback Switch", "LINEIN" },
379 { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
380 { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
381
382 /* Line-out Routes */
383 { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
384 { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
385 { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
386 { "Line Out Source Playback Route", "Mono Differential",
387 "Right Mixer" },
388 { "LINEOUT", NULL, "Line Out Source Playback Route" },
389};
390
391static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
392 .controls = sun50i_a64_codec_controls,
393 .num_controls = ARRAY_SIZE(sun50i_a64_codec_controls),
394 .dapm_widgets = sun50i_a64_codec_widgets,
395 .num_dapm_widgets = ARRAY_SIZE(sun50i_a64_codec_widgets),
396 .dapm_routes = sun50i_a64_codec_routes,
397 .num_dapm_routes = ARRAY_SIZE(sun50i_a64_codec_routes),
398};
399
400static const struct of_device_id sun50i_codec_analog_of_match[] = {
401 {
402 .compatible = "allwinner,sun50i-a64-codec-analog",
403 },
404 {}
405};
406MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match);
407
408static int sun50i_codec_analog_probe(struct platform_device *pdev)
409{
410 struct resource *res;
411 struct regmap *regmap;
412 void __iomem *base;
413
414 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
415 base = devm_ioremap_resource(&pdev->dev, res);
416 if (IS_ERR(base)) {
417 dev_err(&pdev->dev, "Failed to map the registers\n");
418 return PTR_ERR(base);
419 }
420
421 regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
422 if (IS_ERR(regmap)) {
423 dev_err(&pdev->dev, "Failed to create regmap\n");
424 return PTR_ERR(regmap);
425 }
426
427 return devm_snd_soc_register_component(&pdev->dev,
428 &sun50i_codec_analog_cmpnt_drv,
429 NULL, 0);
430}
431
432static struct platform_driver sun50i_codec_analog_driver = {
433 .driver = {
434 .name = "sun50i-codec-analog",
435 .of_match_table = sun50i_codec_analog_of_match,
436 },
437 .probe = sun50i_codec_analog_probe,
438};
439module_platform_driver(sun50i_codec_analog_driver);
440
441MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64");
442MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
443MODULE_LICENSE("GPL");
444MODULE_ALIAS("platform:sun50i-codec-analog");