Linux Audio

Check our new training course

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