Merge tag 'riscv-for-linus-5.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.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("Mic1 Playback Switch",
125                           SUN50I_ADDA_OL_MIX_CTRL,
126                           SUN50I_ADDA_OR_MIX_CTRL,
127                           SUN50I_ADDA_OL_MIX_CTRL_MIC1, 1, 0),
128         SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
129                           SUN50I_ADDA_OL_MIX_CTRL,
130                           SUN50I_ADDA_OR_MIX_CTRL,
131                           SUN50I_ADDA_OL_MIX_CTRL_MIC2, 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("DAC Playback Switch",
137                           SUN50I_ADDA_OL_MIX_CTRL,
138                           SUN50I_ADDA_OR_MIX_CTRL,
139                           SUN50I_ADDA_OL_MIX_CTRL_DACL, 1, 0),
140         SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
141                           SUN50I_ADDA_OL_MIX_CTRL,
142                           SUN50I_ADDA_OR_MIX_CTRL,
143                           SUN50I_ADDA_OL_MIX_CTRL_DACR, 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("Mic1 Capture Switch",
149                           SUN50I_ADDA_L_ADCMIX_SRC,
150                           SUN50I_ADDA_R_ADCMIX_SRC,
151                           SUN50I_ADDA_L_ADCMIX_SRC_MIC1, 1, 0),
152         SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
153                           SUN50I_ADDA_L_ADCMIX_SRC,
154                           SUN50I_ADDA_R_ADCMIX_SRC,
155                           SUN50I_ADDA_L_ADCMIX_SRC_MIC2, 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("Mixer Capture Switch",
161                           SUN50I_ADDA_L_ADCMIX_SRC,
162                           SUN50I_ADDA_R_ADCMIX_SRC,
163                           SUN50I_ADDA_L_ADCMIX_SRC_OMIXRL, 1, 0),
164         SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
165                           SUN50I_ADDA_L_ADCMIX_SRC,
166                           SUN50I_ADDA_R_ADCMIX_SRC,
167                           SUN50I_ADDA_L_ADCMIX_SRC_OMIXRR, 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         /* Mixer pre-gain */
197         SOC_SINGLE_TLV("Mic1 Playback Volume", SUN50I_ADDA_MIC1_CTRL,
198                        SUN50I_ADDA_MIC1_CTRL_MIC1G,
199                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
200
201         /* Microphone Amp boost gain */
202         SOC_SINGLE_TLV("Mic1 Boost Volume", SUN50I_ADDA_MIC1_CTRL,
203                        SUN50I_ADDA_MIC1_CTRL_MIC1BOOST, 0x7, 0,
204                        sun50i_codec_mic_gain_scale),
205
206         /* Mixer pre-gain */
207         SOC_SINGLE_TLV("Mic2 Playback Volume",
208                        SUN50I_ADDA_MIC2_CTRL, SUN50I_ADDA_MIC2_CTRL_MIC2G,
209                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
210
211         /* Microphone Amp boost gain */
212         SOC_SINGLE_TLV("Mic2 Boost Volume", SUN50I_ADDA_MIC2_CTRL,
213                        SUN50I_ADDA_MIC2_CTRL_MIC2BOOST, 0x7, 0,
214                        sun50i_codec_mic_gain_scale),
215
216         /* ADC */
217         SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN50I_ADDA_ADC_CTRL,
218                        SUN50I_ADDA_ADC_CTRL_ADCG, 0x7, 0,
219                        sun50i_codec_out_mixer_pregain_scale),
220
221         /* Mixer pre-gain */
222         SOC_SINGLE_TLV("Line In Playback Volume", SUN50I_ADDA_LINEIN_CTRL,
223                        SUN50I_ADDA_LINEIN_CTRL_LINEING,
224                        0x7, 0, sun50i_codec_out_mixer_pregain_scale),
225
226         SOC_SINGLE_TLV("Line Out Playback Volume",
227                        SUN50I_ADDA_LINEOUT_CTRL1,
228                        SUN50I_ADDA_LINEOUT_CTRL1_VOL, 0x1f, 0,
229                        sun50i_codec_lineout_vol_scale),
230
231         SOC_SINGLE_TLV("Earpiece Playback Volume",
232                        SUN50I_ADDA_EARPIECE_CTRL1,
233                        SUN50I_ADDA_EARPIECE_CTRL1_ESP_VOL, 0x1f, 0,
234                        sun50i_codec_earpiece_vol_scale),
235 };
236
237 static const char * const sun50i_codec_hp_src_enum_text[] = {
238         "DAC", "Mixer",
239 };
240
241 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_hp_src_enum,
242                             SUN50I_ADDA_MIX_DAC_CTRL,
243                             SUN50I_ADDA_MIX_DAC_CTRL_LHPIS,
244                             SUN50I_ADDA_MIX_DAC_CTRL_RHPIS,
245                             sun50i_codec_hp_src_enum_text);
246
247 static const struct snd_kcontrol_new sun50i_codec_hp_src[] = {
248         SOC_DAPM_ENUM("Headphone Source Playback Route",
249                       sun50i_codec_hp_src_enum),
250 };
251
252 static const struct snd_kcontrol_new sun50i_codec_hp_switch =
253         SOC_DAPM_DOUBLE("Headphone Playback Switch",
254                         SUN50I_ADDA_MIX_DAC_CTRL,
255                         SUN50I_ADDA_MIX_DAC_CTRL_LHPPAMUTE,
256                         SUN50I_ADDA_MIX_DAC_CTRL_RHPPAMUTE, 1, 0);
257
258 static const char * const sun50i_codec_lineout_src_enum_text[] = {
259         "Stereo", "Mono Differential",
260 };
261
262 static SOC_ENUM_DOUBLE_DECL(sun50i_codec_lineout_src_enum,
263                             SUN50I_ADDA_LINEOUT_CTRL0,
264                             SUN50I_ADDA_LINEOUT_CTRL0_LSRC_SEL,
265                             SUN50I_ADDA_LINEOUT_CTRL0_RSRC_SEL,
266                             sun50i_codec_lineout_src_enum_text);
267
268 static const struct snd_kcontrol_new sun50i_codec_lineout_src[] = {
269         SOC_DAPM_ENUM("Line Out Source Playback Route",
270                       sun50i_codec_lineout_src_enum),
271 };
272
273 static const struct snd_kcontrol_new sun50i_codec_lineout_switch =
274         SOC_DAPM_DOUBLE("Line Out Playback Switch",
275                         SUN50I_ADDA_LINEOUT_CTRL0,
276                         SUN50I_ADDA_LINEOUT_CTRL0_LEN,
277                         SUN50I_ADDA_LINEOUT_CTRL0_REN, 1, 0);
278
279 static const char * const sun50i_codec_earpiece_src_enum_text[] = {
280         "DACR", "DACL", "Right Mixer", "Left Mixer",
281 };
282
283 static SOC_ENUM_SINGLE_DECL(sun50i_codec_earpiece_src_enum,
284                             SUN50I_ADDA_EARPIECE_CTRL0,
285                             SUN50I_ADDA_EARPIECE_CTRL0_ESPSR,
286                             sun50i_codec_earpiece_src_enum_text);
287
288 static const struct snd_kcontrol_new sun50i_codec_earpiece_src[] = {
289         SOC_DAPM_ENUM("Earpiece Source Playback Route",
290                       sun50i_codec_earpiece_src_enum),
291 };
292
293 static const struct snd_kcontrol_new sun50i_codec_earpiece_switch[] = {
294         SOC_DAPM_SINGLE("Earpiece Playback Switch",
295                         SUN50I_ADDA_EARPIECE_CTRL1,
296                         SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_MUTE, 1, 0),
297 };
298
299 static const struct snd_soc_dapm_widget sun50i_a64_codec_widgets[] = {
300         /* DAC */
301         SND_SOC_DAPM_DAC("Left DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
302                          SUN50I_ADDA_MIX_DAC_CTRL_DACALEN, 0),
303         SND_SOC_DAPM_DAC("Right DAC", NULL, SUN50I_ADDA_MIX_DAC_CTRL,
304                          SUN50I_ADDA_MIX_DAC_CTRL_DACAREN, 0),
305         /* ADC */
306         SND_SOC_DAPM_ADC("Left ADC", NULL, SUN50I_ADDA_ADC_CTRL,
307                          SUN50I_ADDA_ADC_CTRL_ADCLEN, 0),
308         SND_SOC_DAPM_ADC("Right ADC", NULL, SUN50I_ADDA_ADC_CTRL,
309                          SUN50I_ADDA_ADC_CTRL_ADCREN, 0),
310         /*
311          * Due to this component and the codec belonging to separate DAPM
312          * contexts, we need to manually link the above widgets to their
313          * stream widgets at the card level.
314          */
315
316         SND_SOC_DAPM_REGULATOR_SUPPLY("cpvdd", 0, 0),
317         SND_SOC_DAPM_MUX("Left Headphone Source",
318                          SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
319         SND_SOC_DAPM_MUX("Right Headphone Source",
320                          SND_SOC_NOPM, 0, 0, sun50i_codec_hp_src),
321         SND_SOC_DAPM_SWITCH("Left Headphone Switch",
322                             SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
323         SND_SOC_DAPM_SWITCH("Right Headphone Switch",
324                             SND_SOC_NOPM, 0, 0, &sun50i_codec_hp_switch),
325         SND_SOC_DAPM_OUT_DRV("Left Headphone Amp",
326                              SND_SOC_NOPM, 0, 0, NULL, 0),
327         SND_SOC_DAPM_OUT_DRV("Right Headphone Amp",
328                              SND_SOC_NOPM, 0, 0, NULL, 0),
329         SND_SOC_DAPM_SUPPLY("Headphone Amp", SUN50I_ADDA_HP_CTRL,
330                              SUN50I_ADDA_HP_CTRL_HPPA_EN, 0, NULL, 0),
331         SND_SOC_DAPM_OUTPUT("HP"),
332
333         SND_SOC_DAPM_MUX("Left Line Out Source",
334                          SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
335         SND_SOC_DAPM_MUX("Right Line Out Source",
336                          SND_SOC_NOPM, 0, 0, sun50i_codec_lineout_src),
337         SND_SOC_DAPM_SWITCH("Left Line Out Switch",
338                             SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
339         SND_SOC_DAPM_SWITCH("Right Line Out Switch",
340                             SND_SOC_NOPM, 0, 0, &sun50i_codec_lineout_switch),
341         SND_SOC_DAPM_OUTPUT("LINEOUT"),
342
343         SND_SOC_DAPM_MUX("Earpiece Source Playback Route",
344                          SND_SOC_NOPM, 0, 0, sun50i_codec_earpiece_src),
345         SOC_MIXER_NAMED_CTL_ARRAY("Earpiece Switch",
346                                   SND_SOC_NOPM, 0, 0,
347                                   sun50i_codec_earpiece_switch),
348         SND_SOC_DAPM_OUT_DRV("Earpiece Amp", SUN50I_ADDA_EARPIECE_CTRL1,
349                              SUN50I_ADDA_EARPIECE_CTRL1_ESPPA_EN, 0, NULL, 0),
350         SND_SOC_DAPM_OUTPUT("EARPIECE"),
351
352         /* Microphone inputs */
353         SND_SOC_DAPM_INPUT("MIC1"),
354
355         /* Microphone Bias */
356         SND_SOC_DAPM_SUPPLY("MBIAS", SUN50I_ADDA_HS_MBIAS_CTRL,
357                             SUN50I_ADDA_HS_MBIAS_CTRL_MMICBIASEN,
358                             0, NULL, 0),
359
360         /* Mic input path */
361         SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN50I_ADDA_MIC1_CTRL,
362                          SUN50I_ADDA_MIC1_CTRL_MIC1AMPEN, 0, NULL, 0),
363
364         /* Microphone input */
365         SND_SOC_DAPM_INPUT("MIC2"),
366
367         /* Microphone Bias */
368         SND_SOC_DAPM_SUPPLY("HBIAS", SUN50I_ADDA_JACK_MIC_CTRL,
369                             SUN50I_ADDA_JACK_MIC_CTRL_HMICBIASEN,
370                             0, NULL, 0),
371
372         /* Mic input path */
373         SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN50I_ADDA_MIC2_CTRL,
374                          SUN50I_ADDA_MIC2_CTRL_MIC2AMPEN, 0, NULL, 0),
375
376         /* Line input */
377         SND_SOC_DAPM_INPUT("LINEIN"),
378
379         /* Mixers */
380         SND_SOC_DAPM_MIXER("Left Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
381                            SUN50I_ADDA_MIX_DAC_CTRL_LMIXEN, 0,
382                            sun50i_a64_codec_mixer_controls,
383                            ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
384         SND_SOC_DAPM_MIXER("Right Mixer", SUN50I_ADDA_MIX_DAC_CTRL,
385                            SUN50I_ADDA_MIX_DAC_CTRL_RMIXEN, 0,
386                            sun50i_a64_codec_mixer_controls,
387                            ARRAY_SIZE(sun50i_a64_codec_mixer_controls)),
388         SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
389                            sun50i_codec_adc_mixer_controls,
390                            ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
391         SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
392                            sun50i_codec_adc_mixer_controls,
393                            ARRAY_SIZE(sun50i_codec_adc_mixer_controls)),
394 };
395
396 static const struct snd_soc_dapm_route sun50i_a64_codec_routes[] = {
397         /* Left Mixer Routes */
398         { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
399         { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
400         { "Left Mixer", "Line In Playback Switch", "LINEIN" },
401         { "Left Mixer", "DAC Playback Switch", "Left DAC" },
402         { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
403
404         /* Right Mixer Routes */
405         { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
406         { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
407         { "Right Mixer", "Line In Playback Switch", "LINEIN" },
408         { "Right Mixer", "DAC Playback Switch", "Right DAC" },
409         { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
410
411         /* Left ADC Mixer Routes */
412         { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
413         { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
414         { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
415         { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
416         { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
417
418         /* Right ADC Mixer Routes */
419         { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
420         { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
421         { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
422         { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
423         { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
424
425         /* ADC Routes */
426         { "Left ADC", NULL, "Left ADC Mixer" },
427         { "Right ADC", NULL, "Right ADC Mixer" },
428
429         /* Headphone Routes */
430         { "Left Headphone Source", "DAC", "Left DAC" },
431         { "Left Headphone Source", "Mixer", "Left Mixer" },
432         { "Left Headphone Switch", "Headphone Playback Switch", "Left Headphone Source" },
433         { "Left Headphone Amp", NULL, "Left Headphone Switch" },
434         { "Left Headphone Amp", NULL, "Headphone Amp" },
435         { "HP", NULL, "Left Headphone Amp" },
436
437         { "Right Headphone Source", "DAC", "Right DAC" },
438         { "Right Headphone Source", "Mixer", "Right Mixer" },
439         { "Right Headphone Switch", "Headphone Playback Switch", "Right Headphone Source" },
440         { "Right Headphone Amp", NULL, "Right Headphone Switch" },
441         { "Right Headphone Amp", NULL, "Headphone Amp" },
442         { "HP", NULL, "Right Headphone Amp" },
443
444         { "Headphone Amp", NULL, "cpvdd" },
445
446         /* Microphone Routes */
447         { "Mic1 Amplifier", NULL, "MIC1"},
448
449         /* Microphone Routes */
450         { "Mic2 Amplifier", NULL, "MIC2"},
451
452         /* Line-out Routes */
453         { "Left Line Out Source", "Stereo", "Left Mixer" },
454         { "Left Line Out Source", "Mono Differential", "Left Mixer" },
455         { "Left Line Out Source", "Mono Differential", "Right Mixer" },
456         { "Left Line Out Switch", "Line Out Playback Switch", "Left Line Out Source" },
457         { "LINEOUT", NULL, "Left Line Out Switch" },
458
459         { "Right Line Out Switch", "Line Out Playback Switch", "Right Mixer" },
460         { "Right Line Out Source", "Stereo", "Right Line Out Switch" },
461         { "Right Line Out Source", "Mono Differential", "Left Line Out Switch" },
462         { "LINEOUT", NULL, "Right Line Out Source" },
463
464         /* Earpiece Routes */
465         { "Earpiece Source Playback Route", "DACL", "Left DAC" },
466         { "Earpiece Source Playback Route", "DACR", "Right DAC" },
467         { "Earpiece Source Playback Route", "Left Mixer", "Left Mixer" },
468         { "Earpiece Source Playback Route", "Right Mixer", "Right Mixer" },
469         { "Earpiece Switch", "Earpiece Playback Switch", "Earpiece Source Playback Route" },
470         { "Earpiece Amp", NULL, "Earpiece Switch" },
471         { "EARPIECE", NULL, "Earpiece Amp" },
472 };
473
474 static int sun50i_a64_codec_suspend(struct snd_soc_component *component)
475 {
476         return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
477                                   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE),
478                                   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE));
479 }
480
481 static int sun50i_a64_codec_resume(struct snd_soc_component *component)
482 {
483         return regmap_update_bits(component->regmap, SUN50I_ADDA_HP_CTRL,
484                                   BIT(SUN50I_ADDA_HP_CTRL_PA_CLK_GATE), 0);
485 }
486
487 static const struct snd_soc_component_driver sun50i_codec_analog_cmpnt_drv = {
488         .controls               = sun50i_a64_codec_controls,
489         .num_controls           = ARRAY_SIZE(sun50i_a64_codec_controls),
490         .dapm_widgets           = sun50i_a64_codec_widgets,
491         .num_dapm_widgets       = ARRAY_SIZE(sun50i_a64_codec_widgets),
492         .dapm_routes            = sun50i_a64_codec_routes,
493         .num_dapm_routes        = ARRAY_SIZE(sun50i_a64_codec_routes),
494         .suspend                = sun50i_a64_codec_suspend,
495         .resume                 = sun50i_a64_codec_resume,
496 };
497
498 static const struct of_device_id sun50i_codec_analog_of_match[] = {
499         {
500                 .compatible = "allwinner,sun50i-a64-codec-analog",
501         },
502         {}
503 };
504 MODULE_DEVICE_TABLE(of, sun50i_codec_analog_of_match);
505
506 static int sun50i_codec_analog_probe(struct platform_device *pdev)
507 {
508         struct regmap *regmap;
509         void __iomem *base;
510
511         base = devm_platform_ioremap_resource(pdev, 0);
512         if (IS_ERR(base)) {
513                 dev_err(&pdev->dev, "Failed to map the registers\n");
514                 return PTR_ERR(base);
515         }
516
517         regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
518         if (IS_ERR(regmap)) {
519                 dev_err(&pdev->dev, "Failed to create regmap\n");
520                 return PTR_ERR(regmap);
521         }
522
523         return devm_snd_soc_register_component(&pdev->dev,
524                                                &sun50i_codec_analog_cmpnt_drv,
525                                                NULL, 0);
526 }
527
528 static struct platform_driver sun50i_codec_analog_driver = {
529         .driver = {
530                 .name = "sun50i-codec-analog",
531                 .of_match_table = sun50i_codec_analog_of_match,
532         },
533         .probe = sun50i_codec_analog_probe,
534 };
535 module_platform_driver(sun50i_codec_analog_driver);
536
537 MODULE_DESCRIPTION("Allwinner internal codec analog controls driver for A64");
538 MODULE_AUTHOR("Vasily Khoruzhick <anarsoul@gmail.com>");
539 MODULE_LICENSE("GPL");
540 MODULE_ALIAS("platform:sun50i-codec-analog");