1 /*
2  * This driver supports the analog controls for the internal codec
3  * found in Allwinner's A31s, A23, A33 and H3 SoCs.
4  *
5  * Copyright 2016 Chen-Yu Tsai <wens@csie.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  */
17 
18 #include <linux/io.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/of.h>
22 #include <linux/of_device.h>
23 #include <linux/platform_device.h>
24 #include <linux/regmap.h>
25 
26 #include <sound/soc.h>
27 #include <sound/soc-dapm.h>
28 #include <sound/tlv.h>
29 
30 /* Codec analog control register offsets and bit fields */
31 #define SUN8I_ADDA_HP_VOLC		0x00
32 #define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE		7
33 #define SUN8I_ADDA_HP_VOLC_HP_VOL		0
34 #define SUN8I_ADDA_LOMIXSC		0x01
35 #define SUN8I_ADDA_LOMIXSC_MIC1			6
36 #define SUN8I_ADDA_LOMIXSC_MIC2			5
37 #define SUN8I_ADDA_LOMIXSC_PHONE		4
38 #define SUN8I_ADDA_LOMIXSC_PHONEN		3
39 #define SUN8I_ADDA_LOMIXSC_LINEINL		2
40 #define SUN8I_ADDA_LOMIXSC_DACL			1
41 #define SUN8I_ADDA_LOMIXSC_DACR			0
42 #define SUN8I_ADDA_ROMIXSC		0x02
43 #define SUN8I_ADDA_ROMIXSC_MIC1			6
44 #define SUN8I_ADDA_ROMIXSC_MIC2			5
45 #define SUN8I_ADDA_ROMIXSC_PHONE		4
46 #define SUN8I_ADDA_ROMIXSC_PHONEP		3
47 #define SUN8I_ADDA_ROMIXSC_LINEINR		2
48 #define SUN8I_ADDA_ROMIXSC_DACR			1
49 #define SUN8I_ADDA_ROMIXSC_DACL			0
50 #define SUN8I_ADDA_DAC_PA_SRC		0x03
51 #define SUN8I_ADDA_DAC_PA_SRC_DACAREN		7
52 #define SUN8I_ADDA_DAC_PA_SRC_DACALEN		6
53 #define SUN8I_ADDA_DAC_PA_SRC_RMIXEN		5
54 #define SUN8I_ADDA_DAC_PA_SRC_LMIXEN		4
55 #define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE		3
56 #define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE		2
57 #define SUN8I_ADDA_DAC_PA_SRC_RHPIS		1
58 #define SUN8I_ADDA_DAC_PA_SRC_LHPIS		0
59 #define SUN8I_ADDA_PHONEIN_GCTRL	0x04
60 #define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG	4
61 #define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG	0
62 #define SUN8I_ADDA_LINEIN_GCTRL		0x05
63 #define SUN8I_ADDA_LINEIN_GCTRL_LINEING		4
64 #define SUN8I_ADDA_LINEIN_GCTRL_PHONEG		0
65 #define SUN8I_ADDA_MICIN_GCTRL		0x06
66 #define SUN8I_ADDA_MICIN_GCTRL_MIC1G		4
67 #define SUN8I_ADDA_MICIN_GCTRL_MIC2G		0
68 #define SUN8I_ADDA_PAEN_HP_CTRL		0x07
69 #define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN		7
70 #define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN	7	/* H3 specific */
71 #define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC	5
72 #define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN		4
73 #define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL	2
74 #define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE	1
75 #define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE	0
76 #define SUN8I_ADDA_PHONEOUT_CTRL	0x08
77 #define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG	5
78 #define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN	4
79 #define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1	3
80 #define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2	2
81 #define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX	1
82 #define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX	0
83 #define SUN8I_ADDA_PHONE_GAIN_CTRL	0x09
84 #define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL	3
85 #define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG	0
86 #define SUN8I_ADDA_MIC2G_CTRL		0x0a
87 #define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN		7
88 #define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST		4
89 #define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN	3
90 #define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN	2
91 #define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC	1
92 #define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC	0
93 #define SUN8I_ADDA_MIC1G_MICBIAS_CTRL	0x0b
94 #define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN	7
95 #define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN	6
96 #define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE	5
97 #define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN		3
98 #define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST		0
99 #define SUN8I_ADDA_LADCMIXSC		0x0c
100 #define SUN8I_ADDA_LADCMIXSC_MIC1		6
101 #define SUN8I_ADDA_LADCMIXSC_MIC2		5
102 #define SUN8I_ADDA_LADCMIXSC_PHONE		4
103 #define SUN8I_ADDA_LADCMIXSC_PHONEN		3
104 #define SUN8I_ADDA_LADCMIXSC_LINEINL		2
105 #define SUN8I_ADDA_LADCMIXSC_OMIXRL		1
106 #define SUN8I_ADDA_LADCMIXSC_OMIXRR		0
107 #define SUN8I_ADDA_RADCMIXSC		0x0d
108 #define SUN8I_ADDA_RADCMIXSC_MIC1		6
109 #define SUN8I_ADDA_RADCMIXSC_MIC2		5
110 #define SUN8I_ADDA_RADCMIXSC_PHONE		4
111 #define SUN8I_ADDA_RADCMIXSC_PHONEP		3
112 #define SUN8I_ADDA_RADCMIXSC_LINEINR		2
113 #define SUN8I_ADDA_RADCMIXSC_OMIXR		1
114 #define SUN8I_ADDA_RADCMIXSC_OMIXL		0
115 #define SUN8I_ADDA_RES			0x0e
116 #define SUN8I_ADDA_RES_MMICBIAS_SEL		4
117 #define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL		0
118 #define SUN8I_ADDA_ADC_AP_EN		0x0f
119 #define SUN8I_ADDA_ADC_AP_EN_ADCREN		7
120 #define SUN8I_ADDA_ADC_AP_EN_ADCLEN		6
121 #define SUN8I_ADDA_ADC_AP_EN_ADCG		0
122 
123 /* Analog control register access bits */
124 #define ADDA_PR			0x0		/* PRCM base + 0x1c0 */
125 #define ADDA_PR_RESET			BIT(28)
126 #define ADDA_PR_WRITE			BIT(24)
127 #define ADDA_PR_ADDR_SHIFT		16
128 #define ADDA_PR_ADDR_MASK		GENMASK(4, 0)
129 #define ADDA_PR_DATA_IN_SHIFT		8
130 #define ADDA_PR_DATA_IN_MASK		GENMASK(7, 0)
131 #define ADDA_PR_DATA_OUT_SHIFT		0
132 #define ADDA_PR_DATA_OUT_MASK		GENMASK(7, 0)
133 
134 /* regmap access bits */
135 static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
136 {
137 	void __iomem *base = (void __iomem *)context;
138 	u32 tmp;
139 
140 	/* De-assert reset */
141 	writel(readl(base) | ADDA_PR_RESET, base);
142 
143 	/* Clear write bit */
144 	writel(readl(base) & ~ADDA_PR_WRITE, base);
145 
146 	/* Set register address */
147 	tmp = readl(base);
148 	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
149 	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
150 	writel(tmp, base);
151 
152 	/* Read back value */
153 	*val = readl(base) & ADDA_PR_DATA_OUT_MASK;
154 
155 	return 0;
156 }
157 
158 static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
159 {
160 	void __iomem *base = (void __iomem *)context;
161 	u32 tmp;
162 
163 	/* De-assert reset */
164 	writel(readl(base) | ADDA_PR_RESET, base);
165 
166 	/* Set register address */
167 	tmp = readl(base);
168 	tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
169 	tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
170 	writel(tmp, base);
171 
172 	/* Set data to write */
173 	tmp = readl(base);
174 	tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
175 	tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
176 	writel(tmp, base);
177 
178 	/* Set write bit to signal a write */
179 	writel(readl(base) | ADDA_PR_WRITE, base);
180 
181 	/* Clear write bit */
182 	writel(readl(base) & ~ADDA_PR_WRITE, base);
183 
184 	return 0;
185 }
186 
187 static const struct regmap_config adda_pr_regmap_cfg = {
188 	.name		= "adda-pr",
189 	.reg_bits	= 5,
190 	.reg_stride	= 1,
191 	.val_bits	= 8,
192 	.reg_read	= adda_reg_read,
193 	.reg_write	= adda_reg_write,
194 	.fast_io	= true,
195 	.max_register	= 24,
196 };
197 
198 /* mixer controls */
199 static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
200 	SOC_DAPM_DOUBLE_R("DAC Playback Switch",
201 			  SUN8I_ADDA_LOMIXSC,
202 			  SUN8I_ADDA_ROMIXSC,
203 			  SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
204 	SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
205 			  SUN8I_ADDA_LOMIXSC,
206 			  SUN8I_ADDA_ROMIXSC,
207 			  SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
208 	SOC_DAPM_DOUBLE_R("Line In Playback Switch",
209 			  SUN8I_ADDA_LOMIXSC,
210 			  SUN8I_ADDA_ROMIXSC,
211 			  SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0),
212 	SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
213 			  SUN8I_ADDA_LOMIXSC,
214 			  SUN8I_ADDA_ROMIXSC,
215 			  SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
216 	SOC_DAPM_DOUBLE_R("Mic2 Playback Switch",
217 			  SUN8I_ADDA_LOMIXSC,
218 			  SUN8I_ADDA_ROMIXSC,
219 			  SUN8I_ADDA_LOMIXSC_MIC2, 1, 0),
220 };
221 
222 /* mixer controls */
223 static const struct snd_kcontrol_new sun8i_v3s_codec_mixer_controls[] = {
224 	SOC_DAPM_DOUBLE_R("DAC Playback Switch",
225 			  SUN8I_ADDA_LOMIXSC,
226 			  SUN8I_ADDA_ROMIXSC,
227 			  SUN8I_ADDA_LOMIXSC_DACL, 1, 0),
228 	SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch",
229 			  SUN8I_ADDA_LOMIXSC,
230 			  SUN8I_ADDA_ROMIXSC,
231 			  SUN8I_ADDA_LOMIXSC_DACR, 1, 0),
232 	SOC_DAPM_DOUBLE_R("Mic1 Playback Switch",
233 			  SUN8I_ADDA_LOMIXSC,
234 			  SUN8I_ADDA_ROMIXSC,
235 			  SUN8I_ADDA_LOMIXSC_MIC1, 1, 0),
236 };
237 
238 /* ADC mixer controls */
239 static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = {
240 	SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
241 			  SUN8I_ADDA_LADCMIXSC,
242 			  SUN8I_ADDA_RADCMIXSC,
243 			  SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
244 	SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
245 			  SUN8I_ADDA_LADCMIXSC,
246 			  SUN8I_ADDA_RADCMIXSC,
247 			  SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
248 	SOC_DAPM_DOUBLE_R("Line In Capture Switch",
249 			  SUN8I_ADDA_LADCMIXSC,
250 			  SUN8I_ADDA_RADCMIXSC,
251 			  SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0),
252 	SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
253 			  SUN8I_ADDA_LADCMIXSC,
254 			  SUN8I_ADDA_RADCMIXSC,
255 			  SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
256 	SOC_DAPM_DOUBLE_R("Mic2 Capture Switch",
257 			  SUN8I_ADDA_LADCMIXSC,
258 			  SUN8I_ADDA_RADCMIXSC,
259 			  SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0),
260 };
261 
262 /* ADC mixer controls */
263 static const struct snd_kcontrol_new sun8i_v3s_codec_adc_mixer_controls[] = {
264 	SOC_DAPM_DOUBLE_R("Mixer Capture Switch",
265 			  SUN8I_ADDA_LADCMIXSC,
266 			  SUN8I_ADDA_RADCMIXSC,
267 			  SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0),
268 	SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch",
269 			  SUN8I_ADDA_LADCMIXSC,
270 			  SUN8I_ADDA_RADCMIXSC,
271 			  SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0),
272 	SOC_DAPM_DOUBLE_R("Mic1 Capture Switch",
273 			  SUN8I_ADDA_LADCMIXSC,
274 			  SUN8I_ADDA_RADCMIXSC,
275 			  SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0),
276 };
277 
278 /* volume / mute controls */
279 static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale,
280 				  -450, 150, 0);
281 static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale,
282 	0, 0, TLV_DB_SCALE_ITEM(0, 0, 0),
283 	1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0),
284 );
285 
286 static const struct snd_kcontrol_new sun8i_codec_common_controls[] = {
287 	/* Mixer pre-gain */
288 	SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL,
289 		       SUN8I_ADDA_MICIN_GCTRL_MIC1G,
290 		       0x7, 0, sun8i_codec_out_mixer_pregain_scale),
291 
292 	/* Microphone Amp boost gain */
293 	SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
294 		       SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0,
295 		       sun8i_codec_mic_gain_scale),
296 
297 	/* ADC */
298 	SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN,
299 		       SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0,
300 		       sun8i_codec_out_mixer_pregain_scale),
301 };
302 
303 static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = {
304 	/* ADC */
305 	SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
306 			 SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0),
307 	SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN,
308 			 SUN8I_ADDA_ADC_AP_EN_ADCREN, 0),
309 
310 	/* DAC */
311 	SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
312 			 SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0),
313 	SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC,
314 			 SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0),
315 	/*
316 	 * Due to this component and the codec belonging to separate DAPM
317 	 * contexts, we need to manually link the above widgets to their
318 	 * stream widgets at the card level.
319 	 */
320 
321 	/* Microphone input */
322 	SND_SOC_DAPM_INPUT("MIC1"),
323 
324 	/* Mic input path */
325 	SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
326 			 SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0),
327 };
328 
329 static const struct snd_soc_dapm_widget sun8i_codec_mixer_widgets[] = {
330 	SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
331 			   SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
332 			   sun8i_codec_mixer_controls,
333 			   ARRAY_SIZE(sun8i_codec_mixer_controls)),
334 	SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
335 			   SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
336 			   sun8i_codec_mixer_controls,
337 			   ARRAY_SIZE(sun8i_codec_mixer_controls)),
338 	SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
339 			   SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
340 			   sun8i_codec_adc_mixer_controls,
341 			   ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
342 	SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
343 			   SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
344 			   sun8i_codec_adc_mixer_controls,
345 			   ARRAY_SIZE(sun8i_codec_adc_mixer_controls)),
346 };
347 
348 static const struct snd_soc_dapm_widget sun8i_v3s_codec_mixer_widgets[] = {
349 	SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC,
350 			   SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0,
351 			   sun8i_v3s_codec_mixer_controls,
352 			   ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)),
353 	SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC,
354 			   SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0,
355 			   sun8i_v3s_codec_mixer_controls,
356 			   ARRAY_SIZE(sun8i_v3s_codec_mixer_controls)),
357 	SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
358 			   SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0,
359 			   sun8i_v3s_codec_adc_mixer_controls,
360 			   ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)),
361 	SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN,
362 			   SUN8I_ADDA_ADC_AP_EN_ADCREN, 0,
363 			   sun8i_v3s_codec_adc_mixer_controls,
364 			   ARRAY_SIZE(sun8i_v3s_codec_adc_mixer_controls)),
365 };
366 
367 static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = {
368 	/* Microphone Routes */
369 	{ "Mic1 Amplifier", NULL, "MIC1"},
370 };
371 
372 static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = {
373 	/* Left Mixer Routes */
374 	{ "Left Mixer", "DAC Playback Switch", "Left DAC" },
375 	{ "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" },
376 	{ "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
377 
378 	/* Right Mixer Routes */
379 	{ "Right Mixer", "DAC Playback Switch", "Right DAC" },
380 	{ "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" },
381 	{ "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" },
382 
383 	/* Left ADC Mixer Routes */
384 	{ "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" },
385 	{ "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" },
386 	{ "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
387 
388 	/* Right ADC Mixer Routes */
389 	{ "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" },
390 	{ "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" },
391 	{ "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" },
392 
393 	/* ADC Routes */
394 	{ "Left ADC", NULL, "Left ADC Mixer" },
395 	{ "Right ADC", NULL, "Right ADC Mixer" },
396 };
397 
398 /* headphone specific controls, widgets, and routes */
399 static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
400 static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
401 	SOC_SINGLE_TLV("Headphone Playback Volume",
402 		       SUN8I_ADDA_HP_VOLC,
403 		       SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
404 		       sun8i_codec_hp_vol_scale),
405 	SOC_DOUBLE("Headphone Playback Switch",
406 		   SUN8I_ADDA_DAC_PA_SRC,
407 		   SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE,
408 		   SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0),
409 };
410 
411 static const char * const sun8i_codec_hp_src_enum_text[] = {
412 	"DAC", "Mixer",
413 };
414 
415 static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum,
416 			    SUN8I_ADDA_DAC_PA_SRC,
417 			    SUN8I_ADDA_DAC_PA_SRC_LHPIS,
418 			    SUN8I_ADDA_DAC_PA_SRC_RHPIS,
419 			    sun8i_codec_hp_src_enum_text);
420 
421 static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
422 	SOC_DAPM_ENUM("Headphone Source Playback Route",
423 		      sun8i_codec_hp_src_enum),
424 };
425 
426 static int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w,
427 				     struct snd_kcontrol *k, int event)
428 {
429 	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
430 
431 	if (SND_SOC_DAPM_EVENT_ON(event)) {
432 		snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL,
433 					      BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN),
434 					      BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN));
435 		/*
436 		 * Need a delay to have the amplifier up. 700ms seems the best
437 		 * compromise between the time to let the amplifier up and the
438 		 * time not to feel this delay while playing a sound.
439 		 */
440 		msleep(700);
441 	} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
442 		snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL,
443 					      BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN),
444 					      0x0);
445 	}
446 
447 	return 0;
448 }
449 
450 static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
451 	SND_SOC_DAPM_MUX("Headphone Source Playback Route",
452 			 SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
453 	SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
454 			       SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0,
455 			       sun8i_headphone_amp_event,
456 			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
457 	SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
458 			    SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
459 	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
460 			 SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0),
461 	SND_SOC_DAPM_OUTPUT("HP"),
462 };
463 
464 static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = {
465 	{ "Headphone Source Playback Route", "DAC", "Left DAC" },
466 	{ "Headphone Source Playback Route", "DAC", "Right DAC" },
467 	{ "Headphone Source Playback Route", "Mixer", "Left Mixer" },
468 	{ "Headphone Source Playback Route", "Mixer", "Right Mixer" },
469 	{ "Headphone Amp", NULL, "Headphone Source Playback Route" },
470 	{ "HPCOM", NULL, "HPCOM Protection" },
471 	{ "HP", NULL, "Headphone Amp" },
472 };
473 
474 static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt)
475 {
476 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
477 	struct device *dev = cmpnt->dev;
478 	int ret;
479 
480 	ret = snd_soc_add_component_controls(cmpnt,
481 					     sun8i_codec_headphone_controls,
482 					     ARRAY_SIZE(sun8i_codec_headphone_controls));
483 	if (ret) {
484 		dev_err(dev, "Failed to add Headphone controls: %d\n", ret);
485 		return ret;
486 	}
487 
488 	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets,
489 					ARRAY_SIZE(sun8i_codec_headphone_widgets));
490 	if (ret) {
491 		dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret);
492 		return ret;
493 	}
494 
495 	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes,
496 				      ARRAY_SIZE(sun8i_codec_headphone_routes));
497 	if (ret) {
498 		dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret);
499 		return ret;
500 	}
501 
502 	return 0;
503 }
504 
505 /* mbias specific widget */
506 static const struct snd_soc_dapm_widget sun8i_codec_mbias_widgets[] = {
507 	SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
508 			    SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN,
509 			    0, NULL, 0),
510 };
511 
512 static int sun8i_codec_add_mbias(struct snd_soc_component *cmpnt)
513 {
514 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
515 	struct device *dev = cmpnt->dev;
516 	int ret;
517 
518 	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mbias_widgets,
519 					ARRAY_SIZE(sun8i_codec_mbias_widgets));
520 	if (ret)
521 		dev_err(dev, "Failed to add MBIAS DAPM widgets: %d\n", ret);
522 
523 	return ret;
524 }
525 
526 /* hmic specific widget */
527 static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = {
528 	SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL,
529 			    SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN,
530 			    0, NULL, 0),
531 };
532 
533 static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt)
534 {
535 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
536 	struct device *dev = cmpnt->dev;
537 	int ret;
538 
539 	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets,
540 					ARRAY_SIZE(sun8i_codec_hmic_widgets));
541 	if (ret)
542 		dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret);
543 
544 	return ret;
545 }
546 
547 /* line in specific controls, widgets and rines */
548 static const struct snd_kcontrol_new sun8i_codec_linein_controls[] = {
549 	/* Mixer pre-gain */
550 	SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL,
551 		       SUN8I_ADDA_LINEIN_GCTRL_LINEING,
552 		       0x7, 0, sun8i_codec_out_mixer_pregain_scale),
553 };
554 
555 static const struct snd_soc_dapm_widget sun8i_codec_linein_widgets[] = {
556 	/* Line input */
557 	SND_SOC_DAPM_INPUT("LINEIN"),
558 };
559 
560 static const struct snd_soc_dapm_route sun8i_codec_linein_routes[] = {
561 	{ "Left Mixer", "Line In Playback Switch", "LINEIN" },
562 
563 	{ "Right Mixer", "Line In Playback Switch", "LINEIN" },
564 
565 	{ "Left ADC Mixer", "Line In Capture Switch", "LINEIN" },
566 
567 	{ "Right ADC Mixer", "Line In Capture Switch", "LINEIN" },
568 };
569 
570 static int sun8i_codec_add_linein(struct snd_soc_component *cmpnt)
571 {
572 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
573 	struct device *dev = cmpnt->dev;
574 	int ret;
575 
576 	ret = snd_soc_add_component_controls(cmpnt,
577 					     sun8i_codec_linein_controls,
578 					     ARRAY_SIZE(sun8i_codec_linein_controls));
579 	if (ret) {
580 		dev_err(dev, "Failed to add Line In controls: %d\n", ret);
581 		return ret;
582 	}
583 
584 	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_linein_widgets,
585 					ARRAY_SIZE(sun8i_codec_linein_widgets));
586 	if (ret) {
587 		dev_err(dev, "Failed to add Line In DAPM widgets: %d\n", ret);
588 		return ret;
589 	}
590 
591 	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_linein_routes,
592 				      ARRAY_SIZE(sun8i_codec_linein_routes));
593 	if (ret) {
594 		dev_err(dev, "Failed to add Line In DAPM routes: %d\n", ret);
595 		return ret;
596 	}
597 
598 	return 0;
599 }
600 
601 
602 /* line out specific controls, widgets and routes */
603 static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale,
604 	0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
605 	2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0),
606 );
607 static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = {
608 	SOC_SINGLE_TLV("Line Out Playback Volume",
609 		       SUN8I_ADDA_PHONE_GAIN_CTRL,
610 		       SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0,
611 		       sun8i_codec_lineout_vol_scale),
612 	SOC_DOUBLE("Line Out Playback Switch",
613 		   SUN8I_ADDA_MIC2G_CTRL,
614 		   SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN,
615 		   SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0),
616 };
617 
618 static const char * const sun8i_codec_lineout_src_enum_text[] = {
619 	"Stereo", "Mono Differential",
620 };
621 
622 static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum,
623 			    SUN8I_ADDA_MIC2G_CTRL,
624 			    SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC,
625 			    SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC,
626 			    sun8i_codec_lineout_src_enum_text);
627 
628 static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = {
629 	SOC_DAPM_ENUM("Line Out Source Playback Route",
630 		      sun8i_codec_lineout_src_enum),
631 };
632 
633 static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = {
634 	SND_SOC_DAPM_MUX("Line Out Source Playback Route",
635 			 SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src),
636 	/* It is unclear if this is a buffer or gate, model it as a supply */
637 	SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL,
638 			    SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0),
639 	SND_SOC_DAPM_OUTPUT("LINEOUT"),
640 };
641 
642 static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = {
643 	{ "Line Out Source Playback Route", "Stereo", "Left Mixer" },
644 	{ "Line Out Source Playback Route", "Stereo", "Right Mixer" },
645 	{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
646 	{ "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
647 	{ "LINEOUT", NULL, "Line Out Source Playback Route" },
648 	{ "LINEOUT", NULL, "Line Out Enable", },
649 };
650 
651 static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt)
652 {
653 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
654 	struct device *dev = cmpnt->dev;
655 	int ret;
656 
657 	ret = snd_soc_add_component_controls(cmpnt,
658 					     sun8i_codec_lineout_controls,
659 					     ARRAY_SIZE(sun8i_codec_lineout_controls));
660 	if (ret) {
661 		dev_err(dev, "Failed to add Line Out controls: %d\n", ret);
662 		return ret;
663 	}
664 
665 	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets,
666 					ARRAY_SIZE(sun8i_codec_lineout_widgets));
667 	if (ret) {
668 		dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret);
669 		return ret;
670 	}
671 
672 	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes,
673 				      ARRAY_SIZE(sun8i_codec_lineout_routes));
674 	if (ret) {
675 		dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret);
676 		return ret;
677 	}
678 
679 	return 0;
680 }
681 
682 /* mic2 specific controls, widgets and routes */
683 static const struct snd_kcontrol_new sun8i_codec_mic2_controls[] = {
684 	/* Mixer pre-gain */
685 	SOC_SINGLE_TLV("Mic2 Playback Volume",
686 		       SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G,
687 		       0x7, 0, sun8i_codec_out_mixer_pregain_scale),
688 
689 	/* Microphone Amp boost gain */
690 	SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL,
691 		       SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0,
692 		       sun8i_codec_mic_gain_scale),
693 };
694 
695 static const struct snd_soc_dapm_widget sun8i_codec_mic2_widgets[] = {
696 	/* Microphone input */
697 	SND_SOC_DAPM_INPUT("MIC2"),
698 
699 	/* Mic input path */
700 	SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL,
701 			 SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0),
702 };
703 
704 static const struct snd_soc_dapm_route sun8i_codec_mic2_routes[] = {
705 	{ "Mic2 Amplifier", NULL, "MIC2"},
706 
707 	{ "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
708 
709 	{ "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" },
710 
711 	{ "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
712 
713 	{ "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" },
714 };
715 
716 static int sun8i_codec_add_mic2(struct snd_soc_component *cmpnt)
717 {
718 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
719 	struct device *dev = cmpnt->dev;
720 	int ret;
721 
722 	ret = snd_soc_add_component_controls(cmpnt,
723 					     sun8i_codec_mic2_controls,
724 					     ARRAY_SIZE(sun8i_codec_mic2_controls));
725 	if (ret) {
726 		dev_err(dev, "Failed to add MIC2 controls: %d\n", ret);
727 		return ret;
728 	}
729 
730 	ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_mic2_widgets,
731 					ARRAY_SIZE(sun8i_codec_mic2_widgets));
732 	if (ret) {
733 		dev_err(dev, "Failed to add MIC2 DAPM widgets: %d\n", ret);
734 		return ret;
735 	}
736 
737 	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mic2_routes,
738 				      ARRAY_SIZE(sun8i_codec_mic2_routes));
739 	if (ret) {
740 		dev_err(dev, "Failed to add MIC2 DAPM routes: %d\n", ret);
741 		return ret;
742 	}
743 
744 	return 0;
745 }
746 
747 struct sun8i_codec_analog_quirks {
748 	bool has_headphone;
749 	bool has_hmic;
750 	bool has_linein;
751 	bool has_lineout;
752 	bool has_mbias;
753 	bool has_mic2;
754 };
755 
756 static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
757 	.has_headphone	= true,
758 	.has_hmic	= true,
759 	.has_linein	= true,
760 	.has_mbias	= true,
761 	.has_mic2	= true,
762 };
763 
764 static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = {
765 	.has_linein	= true,
766 	.has_lineout	= true,
767 	.has_mbias	= true,
768 	.has_mic2	= true,
769 };
770 
771 static int sun8i_codec_analog_add_mixer(struct snd_soc_component *cmpnt,
772 					const struct sun8i_codec_analog_quirks *quirks)
773 {
774 	struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt);
775 	struct device *dev = cmpnt->dev;
776 	int ret;
777 
778 	if (!quirks->has_mic2 && !quirks->has_linein) {
779 		/*
780 		 * Apply the special widget set which has uses a control
781 		 * without MIC2 and Line In, for SoCs without these.
782 		 * TODO: not all special cases are supported now, this case
783 		 * is present because it's the case of V3s.
784 		 */
785 		ret = snd_soc_dapm_new_controls(dapm,
786 						sun8i_v3s_codec_mixer_widgets,
787 						ARRAY_SIZE(sun8i_v3s_codec_mixer_widgets));
788 		if (ret) {
789 			dev_err(dev, "Failed to add V3s Mixer DAPM widgets: %d\n", ret);
790 			return ret;
791 		}
792 	} else {
793 		/* Apply the generic mixer widget set. */
794 		ret = snd_soc_dapm_new_controls(dapm,
795 						sun8i_codec_mixer_widgets,
796 						ARRAY_SIZE(sun8i_codec_mixer_widgets));
797 		if (ret) {
798 			dev_err(dev, "Failed to add Mixer DAPM widgets: %d\n", ret);
799 			return ret;
800 		}
801 	}
802 
803 	ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_mixer_routes,
804 				      ARRAY_SIZE(sun8i_codec_mixer_routes));
805 	if (ret) {
806 		dev_err(dev, "Failed to add Mixer DAPM routes: %d\n", ret);
807 		return ret;
808 	}
809 
810 	return 0;
811 }
812 
813 static const struct sun8i_codec_analog_quirks sun8i_v3s_quirks = {
814 	.has_headphone	= true,
815 	.has_hmic	= true,
816 };
817 
818 static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt)
819 {
820 	struct device *dev = cmpnt->dev;
821 	const struct sun8i_codec_analog_quirks *quirks;
822 	int ret;
823 
824 	/*
825 	 * This would never return NULL unless someone directly registers a
826 	 * platform device matching this driver's name, without specifying a
827 	 * device tree node.
828 	 */
829 	quirks = of_device_get_match_data(dev);
830 
831 	/* Add controls, widgets, and routes for individual features */
832 	ret = sun8i_codec_analog_add_mixer(cmpnt, quirks);
833 	if (ret)
834 		return ret;
835 
836 	if (quirks->has_headphone) {
837 		ret = sun8i_codec_add_headphone(cmpnt);
838 		if (ret)
839 			return ret;
840 	}
841 
842 	if (quirks->has_hmic) {
843 		ret = sun8i_codec_add_hmic(cmpnt);
844 		if (ret)
845 			return ret;
846 	}
847 
848 	if (quirks->has_linein) {
849 		ret = sun8i_codec_add_linein(cmpnt);
850 		if (ret)
851 			return ret;
852 	}
853 
854 	if (quirks->has_lineout) {
855 		ret = sun8i_codec_add_lineout(cmpnt);
856 		if (ret)
857 			return ret;
858 	}
859 
860 	if (quirks->has_mbias) {
861 		ret = sun8i_codec_add_mbias(cmpnt);
862 		if (ret)
863 			return ret;
864 	}
865 
866 	if (quirks->has_mic2) {
867 		ret = sun8i_codec_add_mic2(cmpnt);
868 		if (ret)
869 			return ret;
870 	}
871 
872 	return 0;
873 }
874 
875 static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = {
876 	.controls		= sun8i_codec_common_controls,
877 	.num_controls		= ARRAY_SIZE(sun8i_codec_common_controls),
878 	.dapm_widgets		= sun8i_codec_common_widgets,
879 	.num_dapm_widgets	= ARRAY_SIZE(sun8i_codec_common_widgets),
880 	.dapm_routes		= sun8i_codec_common_routes,
881 	.num_dapm_routes	= ARRAY_SIZE(sun8i_codec_common_routes),
882 	.probe			= sun8i_codec_analog_cmpnt_probe,
883 };
884 
885 static const struct of_device_id sun8i_codec_analog_of_match[] = {
886 	{
887 		.compatible = "allwinner,sun8i-a23-codec-analog",
888 		.data = &sun8i_a23_quirks,
889 	},
890 	{
891 		.compatible = "allwinner,sun8i-h3-codec-analog",
892 		.data = &sun8i_h3_quirks,
893 	},
894 	{
895 		.compatible = "allwinner,sun8i-v3s-codec-analog",
896 		.data = &sun8i_v3s_quirks,
897 	},
898 	{}
899 };
900 MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
901 
902 static int sun8i_codec_analog_probe(struct platform_device *pdev)
903 {
904 	struct resource *res;
905 	struct regmap *regmap;
906 	void __iomem *base;
907 
908 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
909 	base = devm_ioremap_resource(&pdev->dev, res);
910 	if (IS_ERR(base)) {
911 		dev_err(&pdev->dev, "Failed to map the registers\n");
912 		return PTR_ERR(base);
913 	}
914 
915 	regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg);
916 	if (IS_ERR(regmap)) {
917 		dev_err(&pdev->dev, "Failed to create regmap\n");
918 		return PTR_ERR(regmap);
919 	}
920 
921 	return devm_snd_soc_register_component(&pdev->dev,
922 					       &sun8i_codec_analog_cmpnt_drv,
923 					       NULL, 0);
924 }
925 
926 static struct platform_driver sun8i_codec_analog_driver = {
927 	.driver = {
928 		.name = "sun8i-codec-analog",
929 		.of_match_table = sun8i_codec_analog_of_match,
930 	},
931 	.probe = sun8i_codec_analog_probe,
932 };
933 module_platform_driver(sun8i_codec_analog_driver);
934 
935 MODULE_DESCRIPTION("Allwinner internal codec analog controls driver");
936 MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
937 MODULE_LICENSE("GPL");
938 MODULE_ALIAS("platform:sun8i-codec-analog");
939