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