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