GNU Linux-libre 5.4.200-gnu1
[releases.git] / sound / soc / sunxi / sun50i-codec-analog.c
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_EARPIECE_CTRL0      0x03
53 #define SUN50I_ADDA_EARPIECE_CTRL0_EAR_RAMP_TIME        4
54 #define SUN50I_ADDA_EARPIECE_CTRL0_ESPSR                0
55
56 #define SUN50I_ADDA_EARPIECE_CTRL1      0x04
57 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN     7
58 #define SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE   6
59 #define SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL      0
60
61 #define SUN50I_ADDA_LINEOUT_CTRL0       0x05
62 #define SUN50I_ADDA_LINEOUT_CTRL0_LEN           7
63 #define SUN50I_ADDA_LINEOUT_CTRL0_REN           6
64 #define SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL      5
65 #define SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL      4
66
67 #define SUN50I_ADDA_LINEOUT_CTRL1       0x06
68 #define SUN50I_ADDA_LINEOUT_CTRL1_VOL           0
69
70 #define SUN50I_ADDA_MIC1_CTRL           0x07
71 #define SUN50I_ADDA_MIC1_CTRL_MIC1G             4
72 #define SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN         3
73 #define SUN50I_ADDA_MIC1_CTRL_MIC1BOOST         0
74
75 #define SUN50I_ADDA_MIC2_CTRL           0x08
76 #define SUN50I_ADDA_MIC2_CTRL_MIC2G             4
77 #define SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN         3
78 #define SUN50I_ADDA_MIC2_CTRL_MIC2BOOST         0
79
80 #define SUN50I_ADDA_LINEIN_CTRL         0x09
81 #define SUN50I_ADDA_LINEIN_CTRL_LINEING         0
82
83 #define SUN50I_ADDA_MIX_DAC_CTRL        0x0a
84 #define SUN50I_ADDA_MIX_DAC_CTRL_DACAREN        7
85 #define SUN50I_ADDA_MIX_DAC_CTRL_DACALEN        6
86 #define SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN         5
87 #define SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN         4
88 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE      3
89 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE      2
90 #define SUN50I_ADDA_MIX_DAC_CTRL_RHPIS          1
91 #define SUN50I_ADDA_MIX_DAC_CTRL_LHPIS          0
92
93 #define SUN50I_ADDA_L_ADCMIX_SRC        0x0b
94 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC1           6
95 #define SUN50I_ADDA_L_ADCMIX_SRC_MIC2           5
96 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONE          4
97 #define SUN50I_ADDA_L_ADCMIX_SRC_PHONEN         3
98 #define SUN50I_ADDA_L_ADCMIX_SRC_LINEINL        2
99 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL         1
100 #define SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR         0
101
102 #define SUN50I_ADDA_R_ADCMIX_SRC        0x0c
103 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC1           6
104 #define SUN50I_ADDA_R_ADCMIX_SRC_MIC2           5
105 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONE          4
106 #define SUN50I_ADDA_R_ADCMIX_SRC_PHONEP         3
107 #define SUN50I_ADDA_R_ADCMIX_SRC_LINEINR        2
108 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXR          1
109 #define SUN50I_ADDA_R_ADCMIX_SRC_OMIXL          0
110
111 #define SUN50I_ADDA_ADC_CTRL            0x0d
112 #define SUN50I_ADDA_ADC_CTRL_ADCREN             7
113 #define SUN50I_ADDA_ADC_CTRL_ADCLEN             6
114 #define SUN50I_ADDA_ADC_CTRL_ADCG               0
115
116 #define SUN50I_ADDA_HS_MBIAS_CTRL       0x0e
117 #define SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN    7
118
119 #define SUN50I_ADDA_JACK_MIC_CTRL       0x1d
120 #define SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN    5
121
122 /* mixer controls */
123 static const struct snd_kcontrol_new sun50i_a64_codec_mixer_controls[] = {
124         SOC_DAPM_DOUBLE_R("DAC Playback Switch",
125                           SUN50I_ADDA_OL_MIX_CTRL,
126                           SUN50I_ADDA_OR_MIX_CTRL,
127                           SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
128         SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
129                           SUN50I_ADDA_OL_MIX_CTRL,
130                           SUN50I_ADDA_OR_MIX_CTRL,
131                           SUN50I_ADDA_OL_MIX_CTRL_DACR, 1, 0),
132         SOC_DAPM_DOUBLE_R("Line In Playback Switch",
133                           SUN50I_ADDA_OL_MIX_CTRL,
134                           SUN50I_ADDA_OR_MIX_CTRL,
135                           SUN50I_ADDA_OL_MIX_CTRL_LINEINL, 1, 0),
136         SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
137                           SUN50I_ADDA_OL_MIX_CTRL,
138                           SUN50I_ADDA_OR_MIX_CTRL,
139                           SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
140         SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
141                           SUN50I_ADDA_OL_MIX_CTRL,
142                           SUN50I_ADDA_OR_MIX_CTRL,
143                           SUN50I_ADDA_OL_MIX_CTRL_MIC2, 1, 0),
144 };
145
146 /* ADC mixer controls */
147 static const struct snd_kcontrol_new sun50i_codec_adc_mixer_controls[] = {
148         SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
149                           SUN50I_ADDA_L_ADCMIX_SRC,
150                           SUN50I_ADDA_R_ADCMIX_SRC,
151                           SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
152         SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
153                           SUN50I_ADDA_L_ADCMIX_SRC,
154                           SUN50I_ADDA_R_ADCMIX_SRC,
155                           SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 1, 0),
156         SOC_DAPM_DOUBLE_R("Line In Capture Switch",
157                           SUN50I_ADDA_L_ADCMIX_SRC,
158                           SUN50I_ADDA_R_ADCMIX_SRC,
159                           SUN50I_ADDA_L_ADCMIX_SRC_LINEINL, 1, 0),
160         SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
161                           SUN50I_ADDA_L_ADCMIX_SRC,
162                           SUN50I_ADDA_R_ADCMIX_SRC,
163                           SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
164         SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
165                           SUN50I_ADDA_L_ADCMIX_SRC,
166                           SUN50I_ADDA_R_ADCMIX_SRC,
167                           SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 1, 0),
168 };
169
170 static const DECLARE_TLV_DB_SCALE(sun50i_codec_out_mixer_pregain_scale,
171                                   -450, 150, 0);
172 static const DECLARE_TLV_DB_RANGE(sun50i_codec_mic_gain_scale,
173         0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
174         1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
175 );
176
177 static const DECLARE_TLV_DB_SCALE(sun50i_codec_hp_vol_scale, -6300, 100, 1);
178
179 static const DECLARE_TLV_DB_RANGE(sun50i_codec_lineout_vol_scale,
180         0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
181         2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
182 );
183
184 static const DECLARE_TLV_DB_RANGE(sun50i_codec_earpiece_vol_scale,
185         0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
186         2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
187 );
188
189 /* volume / mute controls */
190 static const struct snd_kcontrol_new sun50i_a64_codec_controls[] = {
191         SOC_SINGLE_TLV("Headphone Playback Volume",
192                        SUN50I_ADDA_HP_CTRL,
193                        SUN50I_ADDA_HP_CTRL_HPVOL, 0x3f, 0,
194                        sun50i_codec_hp_vol_scale),
195
196         SOC_DOUBLE("Headphone Playback Switch",
197                    SUN50I_ADDA_MIX_DAC_CTRL,
198                    SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
199                    SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0),
200
201         /* Mixer pre-gain */
202         SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,
203                        SUN50I_ADDA_MIC1_CTRL_MIC1G,
204                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
205
206         /* Microphone Amp boost gain */
207         SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL,
208                        SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0,
209                        sun50i_codec_mic_gain_scale),
210
211         /* Mixer pre-gain */
212         SOC_SINGLE_TLV("Mic2 Playback Volume",
213                        SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G,
214                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
215
216         /* Microphone Amp boost gain */
217         SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL,
218                        SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0,
219                        sun50i_codec_mic_gain_scale),
220
221         /* ADC */
222         SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL,
223                        SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0,
224                        sun50i_codec_out_mixer_pregain_scale),
225
226         /* Mixer pre-gain */
227         SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL,
228                        SUN50I_ADDA_LINEIN_CTRL_LINEING,
229                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
230
231         SOC_SINGLE_TLV("Line Out Playback Volume",
232                        SUN50I_ADDA_LINEOUT_CTRL1,
233                        SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
234                        sun50i_codec_lineout_vol_scale),
235
236         SOC_DOUBLE("Line Out Playback Switch",
237                    SUN50I_ADDA_LINEOUT_CTRL0,
238                    SUN50I_ADDA_LINEOUT_CTRL0_LEN,
239                    SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0),
240
241         SOC_SINGLE_TLV("Earpiece Playback Volume",
242                        SUN50I_ADDA_EARPIECE_CTRL1,
243                        SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0,
244                        sun50i_codec_earpiece_vol_scale),
245
246         SOC_SINGLE("Earpiece Playback Switch",
247                    SUN50I_ADDA_EARPIECE_CTRL1,
248                    SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
249
250 };
251
252 static const char * const sun50i_codec_hp_src_enum_text[] = {
253         "DAC", "Mixer",
254 };
255
256 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum,
257                             SUN50I_ADDA_MIX_DAC_CTRL,
258                             SUN50I_ADDA_MIX_DAC_CTRL_LHPIS,
259                             SUN50I_ADDA_MIX_DAC_CTRL_RHPIS,
260                             sun50i_codec_hp_src_enum_text);
261
262 static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {
263         SOC_DAPM_ENUM("Headphone Source Playback Route",
264                       sun50i_codec_hp_src_enum),
265 };
266
267 static const char * const sun50i_codec_lineout_src_enum_text[] = {
268         "Stereo", "Mono Differential",
269 };
270
271 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,
272                             SUN50I_ADDA_LINEOUT_CTRL0,
273                             SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,
274                             SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,
275                             sun50i_codec_lineout_src_enum_text);
276
277 static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
278         SOC_DAPM_ENUM("Line Out Source Playback Route",
279                       sun50i_codec_lineout_src_enum),
280 };
281
282 static const char * const sun50i_codec_earpiece_src_enum_text[] = {
283         "DACR", "DACL", "Right Mixer", "Left Mixer",
284 };
285
286 static SOC_ENUM_SINGLE_DECL(sun50i_codec_earpiece_src_enum,
287                             SUN50I_ADDA_EARPIECE_CTRL0,
288                             SUN50I_ADDA_EARPIECE_CTRL0_ESPSR,
289                             sun50i_codec_earpiece_src_enum_text);
290
291 static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = {
292         SOC_DAPM_ENUM("Earpiece Source Playback Route",
293                       sun50i_codec_earpiece_src_enum),
294 };
295
296 static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
297         /* DAC */
298         SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
299                          SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0),
300         SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
301                          SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0),
302         /* ADC */
303         SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL,
304                          SUN50I_ADDA_ADC_CTRL_ADCLEN, 0),
305         SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL,
306                          SUN50I_ADDA_ADC_CTRL_ADCREN, 0),
307         /*
308          * Due to this component and the codec belonging to separate DAPM
309          * contexts, we need to manually link the above widgets to their
310          * stream widgets at the card level.
311          */
312
313         SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0),
314         SND_SOC_DAPM_MUX("Headphone Source Playback Route",
315                          SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
316         SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN50I_ADDA_HP_CTRL,
317                              SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),
318         SND_SOC_DAPM_OUTPUT("HP"),
319
320         SND_SOC_DAPM_MUX("Line Out Source Playback Route",
321                          SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
322         SND_SOC_DAPM_OUTPUT("LINEOUT"),
323
324         SND_SOC_DAPM_MUX("Earpiece Source Playback Route",
325                          SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src),
326         SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1,
327                              SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0),
328         SND_SOC_DAPM_OUTPUT("EARPIECE"),
329
330         /* Microphone inputs */
331         SND_SOC_DAPM_INPUT("MIC1"),
332
333         /* Microphone Bias */
334         SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL,
335                             SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN,
336                             0, NULL, 0),
337
338         /* Mic input path */
339         SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL,
340                          SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0),
341
342         /* Microphone input */
343         SND_SOC_DAPM_INPUT("MIC2"),
344
345         /* Microphone Bias */
346         SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,
347                             SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,
348                             0, NULL, 0),
349
350         /* Mic input path */
351         SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,
352                          SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0),
353
354         /* Line input */
355         SND_SOC_DAPM_INPUT("LINEIN"),
356
357         /* Mixers */
358         SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
359                            SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0,
360                            sun50i_a64_codec_mixer_controls,
361                            ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
362         SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
363                            SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,
364                            sun50i_a64_codec_mixer_controls,
365                            ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
366         SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN50I_ADDA_ADC_CTRL,
367                            SUN50I_ADDA_ADC_CTRL_ADCLEN, 0,
368                            sun50i_codec_adc_mixer_controls,
369                            ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
370         SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN50I_ADDA_ADC_CTRL,
371                            SUN50I_ADDA_ADC_CTRL_ADCREN, 0,
372                            sun50i_codec_adc_mixer_controls,
373                            ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
374 };
375
376 static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
377         /* Left Mixer Routes */
378         { "Left Mixer", "DAC Playback Switch", "Left DAC" },
379         { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
380         { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
381
382         /* Right Mixer Routes */
383         { "Right Mixer", "DAC Playback Switch", "Right DAC" },
384         { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
385         { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
386
387         /* Left ADC Mixer Routes */
388         { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
389         { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
390         { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
391
392         /* Right ADC Mixer Routes */
393         { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
394         { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
395         { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
396
397         /* ADC Routes */
398         { "Left ADC", NULL, "Left ADC Mixer" },
399         { "Right ADC", NULL, "Right ADC Mixer" },
400
401         /* Headphone Routes */
402         { "Headphone Source Playback Route", "DAC", "Left DAC" },
403         { "Headphone Source Playback Route", "DAC", "Right DAC" },
404         { "Headphone Source Playback Route", "Mixer", "Left Mixer" },
405         { "Headphone Source Playback Route", "Mixer", "Right Mixer" },
406         { "Headphone Amp", NULL, "Headphone Source Playback Route" },
407         { "Headphone Amp", NULL, "cpvdd" },
408         { "HP", NULL, "Headphone Amp" },
409
410         /* Microphone Routes */
411         { "Mic1 Amplifier", NULL, "MIC1"},
412
413         /* Microphone Routes */
414         { "Mic2 Amplifier", NULL, "MIC2"},
415         { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
416         { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
417         { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
418         { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
419
420         /* Line-in Routes */
421         { "Left Mixer", "Line In Playback Switch", "LINEIN" },
422         { "Right Mixer", "Line In Playback Switch", "LINEIN" },
423         { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
424         { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
425
426         /* Line-out Routes */
427         { "Line Out Source Playback Route", "Stereo", "Left Mixer" },
428         { "Line Out Source Playback Route", "Stereo", "Right Mixer" },
429         { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
430         { "Line Out Source Playback Route", "Mono Differential",
431                 "Right Mixer" },
432         { "LINEOUT", NULL, "Line Out Source Playback Route" },
433
434         /* Earpiece Routes */
435         { "Earpiece Source Playback Route", "DACL", "Left DAC" },
436         { "Earpiece Source Playback Route", "DACR", "Right DAC" },
437         { "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" },
438         { "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" },
439         { "Earpiece Amp", NULL, "Earpiece Source Playback Route" },
440         { "EARPIECE", NULL, "Earpiece Amp" },
441 };
442
443 static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
444         .controls               = sun50i_a64_codec_controls,
445         .num_controls           = ARRAY_SIZE(sun50i_a64_codec_controls),
446         .dapm_widgets           = sun50i_a64_codec_widgets,
447         .num_dapm_widgets       = ARRAY_SIZE(sun50i_a64_codec_widgets),
448         .dapm_routes            = sun50i_a64_codec_routes,
449         .num_dapm_routes        = ARRAY_SIZE(sun50i_a64_codec_routes),
450 };
451
452 static const struct of_device_id sun50i_codec_analog_of_match[] = {
453         {
454                 .compatible = "allwinner,sun50i-a64-codec-analog",
455         },
456         {}
457 };
458 MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match);
459
460 static int sun50i_codec_analog_probe(struct platform_device *pdev)
461 {
462         struct regmap *regmap;
463         void __iomem *base;
464
465         base = devm_platform_ioremap_resource(pdev, 0);
466         if (IS_ERR(base)) {
467                 dev_err(&pdev->dev, "Failed to map the registers\n");
468                 return PTR_ERR(base);
469         }
470
471         regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
472         if (IS_ERR(regmap)) {
473                 dev_err(&pdev->dev, "Failed to create regmap\n");
474                 return PTR_ERR(regmap);
475         }
476
477         return devm_snd_soc_register_component(&pdev->dev,
478                                                &sun50i_codec_analog_cmpnt_drv,
479                                                NULL, 0);
480 }
481
482 static struct platform_driver sun50i_codec_analog_driver = {
483         .driver = {
484                 .name = "sun50i-codec-analog",
485                 .of_match_table = sun50i_codec_analog_of_match,
486         },
487         .probe = sun50i_codec_analog_probe,
488 };
489 module_platform_driver(sun50i_codec_analog_driver);
490
491 MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64");
492 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
493 MODULE_LICENSE("GPL");
494 MODULE_ALIAS("platform:sun50i-codec-analog");