xref: /openbmc/linux/sound/soc/sunxi/sun4i-codec.c (revision a8da474e)
1 /*
2  * Copyright 2014 Emilio López <emilio@elopez.com.ar>
3  * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
4  * Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
5  *
6  * Based on the Allwinner SDK driver, released under the GPL.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18 
19 #include <linux/init.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/delay.h>
24 #include <linux/slab.h>
25 #include <linux/of.h>
26 #include <linux/of_platform.h>
27 #include <linux/of_address.h>
28 #include <linux/clk.h>
29 #include <linux/regmap.h>
30 
31 #include <sound/core.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/soc.h>
35 #include <sound/tlv.h>
36 #include <sound/initval.h>
37 #include <sound/dmaengine_pcm.h>
38 
39 /* Codec DAC register offsets and bit fields */
40 #define SUN4I_CODEC_DAC_DPC			(0x00)
41 #define SUN4I_CODEC_DAC_DPC_EN_DA			(31)
42 #define SUN4I_CODEC_DAC_DPC_DVOL			(12)
43 #define SUN4I_CODEC_DAC_FIFOC			(0x04)
44 #define SUN4I_CODEC_DAC_FIFOC_DAC_FS			(29)
45 #define SUN4I_CODEC_DAC_FIFOC_FIR_VERSION		(28)
46 #define SUN4I_CODEC_DAC_FIFOC_SEND_LASAT		(26)
47 #define SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE		(24)
48 #define SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT		(21)
49 #define SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL		(8)
50 #define SUN4I_CODEC_DAC_FIFOC_MONO_EN			(6)
51 #define SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS		(5)
52 #define SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN		(4)
53 #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH		(0)
54 #define SUN4I_CODEC_DAC_FIFOS			(0x08)
55 #define SUN4I_CODEC_DAC_TXDATA			(0x0c)
56 #define SUN4I_CODEC_DAC_ACTL			(0x10)
57 #define SUN4I_CODEC_DAC_ACTL_DACAENR			(31)
58 #define SUN4I_CODEC_DAC_ACTL_DACAENL			(30)
59 #define SUN4I_CODEC_DAC_ACTL_MIXEN			(29)
60 #define SUN4I_CODEC_DAC_ACTL_LDACLMIXS			(15)
61 #define SUN4I_CODEC_DAC_ACTL_RDACRMIXS			(14)
62 #define SUN4I_CODEC_DAC_ACTL_LDACRMIXS			(13)
63 #define SUN4I_CODEC_DAC_ACTL_DACPAS			(8)
64 #define SUN4I_CODEC_DAC_ACTL_MIXPAS			(7)
65 #define SUN4I_CODEC_DAC_ACTL_PA_MUTE			(6)
66 #define SUN4I_CODEC_DAC_ACTL_PA_VOL			(0)
67 #define SUN4I_CODEC_DAC_TUNE			(0x14)
68 #define SUN4I_CODEC_DAC_DEBUG			(0x18)
69 
70 /* Codec ADC register offsets and bit fields */
71 #define SUN4I_CODEC_ADC_FIFOC			(0x1c)
72 #define SUN4I_CODEC_ADC_FIFOC_EN_AD			(28)
73 #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE		(24)
74 #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL		(8)
75 #define SUN4I_CODEC_ADC_FIFOC_MONO_EN			(7)
76 #define SUN4I_CODEC_ADC_FIFOC_RX_SAMPLE_BITS		(6)
77 #define SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN		(4)
78 #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH		(0)
79 #define SUN4I_CODEC_ADC_FIFOS			(0x20)
80 #define SUN4I_CODEC_ADC_RXDATA			(0x24)
81 #define SUN4I_CODEC_ADC_ACTL			(0x28)
82 #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN			(31)
83 #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN			(30)
84 #define SUN4I_CODEC_ADC_ACTL_PREG1EN			(29)
85 #define SUN4I_CODEC_ADC_ACTL_PREG2EN			(28)
86 #define SUN4I_CODEC_ADC_ACTL_VMICEN			(27)
87 #define SUN4I_CODEC_ADC_ACTL_VADCG			(20)
88 #define SUN4I_CODEC_ADC_ACTL_ADCIS			(17)
89 #define SUN4I_CODEC_ADC_ACTL_PA_EN			(4)
90 #define SUN4I_CODEC_ADC_ACTL_DDE			(3)
91 #define SUN4I_CODEC_ADC_DEBUG			(0x2c)
92 
93 /* Other various ADC registers */
94 #define SUN4I_CODEC_DAC_TXCNT			(0x30)
95 #define SUN4I_CODEC_ADC_RXCNT			(0x34)
96 #define SUN4I_CODEC_AC_SYS_VERI			(0x38)
97 #define SUN4I_CODEC_AC_MIC_PHONE_CAL		(0x3c)
98 
99 struct sun4i_codec {
100 	struct device	*dev;
101 	struct regmap	*regmap;
102 	struct clk	*clk_apb;
103 	struct clk	*clk_module;
104 
105 	struct snd_dmaengine_dai_dma_data	playback_dma_data;
106 };
107 
108 static void sun4i_codec_start_playback(struct sun4i_codec *scodec)
109 {
110 	/*
111 	 * FIXME: according to the BSP, we might need to drive a PA
112 	 *        GPIO high here on some boards
113 	 */
114 
115 	/* Flush TX FIFO */
116 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
117 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
118 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
119 
120 	/* Enable DAC DRQ */
121 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
122 			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
123 			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN));
124 }
125 
126 static void sun4i_codec_stop_playback(struct sun4i_codec *scodec)
127 {
128 	/*
129 	 * FIXME: according to the BSP, we might need to drive a PA
130 	 *        GPIO low here on some boards
131 	 */
132 
133 	/* Disable DAC DRQ */
134 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
135 			   BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN),
136 			   0);
137 }
138 
139 static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd,
140 			       struct snd_soc_dai *dai)
141 {
142 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
143 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
144 
145 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
146 		return -ENOTSUPP;
147 
148 	switch (cmd) {
149 	case SNDRV_PCM_TRIGGER_START:
150 	case SNDRV_PCM_TRIGGER_RESUME:
151 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
152 		sun4i_codec_start_playback(scodec);
153 		break;
154 
155 	case SNDRV_PCM_TRIGGER_STOP:
156 	case SNDRV_PCM_TRIGGER_SUSPEND:
157 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
158 		sun4i_codec_stop_playback(scodec);
159 		break;
160 
161 	default:
162 		return -EINVAL;
163 	}
164 
165 	return 0;
166 }
167 
168 static int sun4i_codec_prepare(struct snd_pcm_substream *substream,
169 			       struct snd_soc_dai *dai)
170 {
171 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
172 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
173 	u32 val;
174 
175 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
176 		return -ENOTSUPP;
177 
178 	/* Flush the TX FIFO */
179 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
180 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH),
181 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH));
182 
183 	/* Set TX FIFO Empty Trigger Level */
184 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
185 			   0x3f << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL,
186 			   0xf << SUN4I_CODEC_DAC_FIFOC_TX_TRIG_LEVEL);
187 
188 	if (substream->runtime->rate > 32000)
189 		/* Use 64 bits FIR filter */
190 		val = 0;
191 	else
192 		/* Use 32 bits FIR filter */
193 		val = BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION);
194 
195 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
196 			   BIT(SUN4I_CODEC_DAC_FIFOC_FIR_VERSION),
197 			   val);
198 
199 	/* Send zeros when we have an underrun */
200 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
201 			   BIT(SUN4I_CODEC_DAC_FIFOC_SEND_LASAT),
202 			   0);
203 
204 	return 0;
205 }
206 
207 static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
208 {
209 	unsigned int rate = params_rate(params);
210 
211 	switch (rate) {
212 	case 176400:
213 	case 88200:
214 	case 44100:
215 	case 33075:
216 	case 22050:
217 	case 14700:
218 	case 11025:
219 	case 7350:
220 		return 22579200;
221 
222 	case 192000:
223 	case 96000:
224 	case 48000:
225 	case 32000:
226 	case 24000:
227 	case 16000:
228 	case 12000:
229 	case 8000:
230 		return 24576000;
231 
232 	default:
233 		return 0;
234 	}
235 }
236 
237 static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
238 {
239 	unsigned int rate = params_rate(params);
240 
241 	switch (rate) {
242 	case 192000:
243 	case 176400:
244 		return 6;
245 
246 	case 96000:
247 	case 88200:
248 		return 7;
249 
250 	case 48000:
251 	case 44100:
252 		return 0;
253 
254 	case 32000:
255 	case 33075:
256 		return 1;
257 
258 	case 24000:
259 	case 22050:
260 		return 2;
261 
262 	case 16000:
263 	case 14700:
264 		return 3;
265 
266 	case 12000:
267 	case 11025:
268 		return 4;
269 
270 	case 8000:
271 	case 7350:
272 		return 5;
273 
274 	default:
275 		return -EINVAL;
276 	}
277 }
278 
279 static int sun4i_codec_hw_params(struct snd_pcm_substream *substream,
280 				 struct snd_pcm_hw_params *params,
281 				 struct snd_soc_dai *dai)
282 {
283 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
284 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
285 	unsigned long clk_freq;
286 	int ret, hwrate;
287 	u32 val;
288 
289 	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
290 		return -ENOTSUPP;
291 
292 	clk_freq = sun4i_codec_get_mod_freq(params);
293 	if (!clk_freq)
294 		return -EINVAL;
295 
296 	ret = clk_set_rate(scodec->clk_module, clk_freq);
297 	if (ret)
298 		return ret;
299 
300 	hwrate = sun4i_codec_get_hw_rate(params);
301 	if (hwrate < 0)
302 		return hwrate;
303 
304 	/* Set DAC sample rate */
305 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
306 			   7 << SUN4I_CODEC_DAC_FIFOC_DAC_FS,
307 			   hwrate << SUN4I_CODEC_DAC_FIFOC_DAC_FS);
308 
309 	/* Set the number of channels we want to use */
310 	if (params_channels(params) == 1)
311 		val = BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN);
312 	else
313 		val = 0;
314 
315 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
316 			   BIT(SUN4I_CODEC_DAC_FIFOC_MONO_EN),
317 			   val);
318 
319 	/* Set the number of sample bits to either 16 or 24 bits */
320 	if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32) {
321 		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
322 				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
323 				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS));
324 
325 		/* Set TX FIFO mode to padding the LSBs with 0 */
326 		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
327 				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
328 				   0);
329 
330 		scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
331 	} else {
332 		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
333 				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_SAMPLE_BITS),
334 				   0);
335 
336 		/* Set TX FIFO mode to repeat the MSB */
337 		regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
338 				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE),
339 				   BIT(SUN4I_CODEC_DAC_FIFOC_TX_FIFO_MODE));
340 
341 		scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
342 	}
343 
344 	return 0;
345 }
346 
347 static int sun4i_codec_startup(struct snd_pcm_substream *substream,
348 			       struct snd_soc_dai *dai)
349 {
350 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
351 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
352 
353 	/*
354 	 * Stop issuing DRQ when we have room for less than 16 samples
355 	 * in our TX FIFO
356 	 */
357 	regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC,
358 			   3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT,
359 			   3 << SUN4I_CODEC_DAC_FIFOC_DRQ_CLR_CNT);
360 
361 	return clk_prepare_enable(scodec->clk_module);
362 }
363 
364 static void sun4i_codec_shutdown(struct snd_pcm_substream *substream,
365 				 struct snd_soc_dai *dai)
366 {
367 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
368 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card);
369 
370 	clk_disable_unprepare(scodec->clk_module);
371 }
372 
373 static const struct snd_soc_dai_ops sun4i_codec_dai_ops = {
374 	.startup	= sun4i_codec_startup,
375 	.shutdown	= sun4i_codec_shutdown,
376 	.trigger	= sun4i_codec_trigger,
377 	.hw_params	= sun4i_codec_hw_params,
378 	.prepare	= sun4i_codec_prepare,
379 };
380 
381 static struct snd_soc_dai_driver sun4i_codec_dai = {
382 	.name	= "Codec",
383 	.ops	= &sun4i_codec_dai_ops,
384 	.playback = {
385 		.stream_name	= "Codec Playback",
386 		.channels_min	= 1,
387 		.channels_max	= 2,
388 		.rate_min	= 8000,
389 		.rate_max	= 192000,
390 		.rates		= SNDRV_PCM_RATE_8000_48000 |
391 				  SNDRV_PCM_RATE_96000 |
392 				  SNDRV_PCM_RATE_192000,
393 		.formats	= SNDRV_PCM_FMTBIT_S16_LE |
394 				  SNDRV_PCM_FMTBIT_S32_LE,
395 		.sig_bits	= 24,
396 	},
397 };
398 
399 /*** Codec ***/
400 static const struct snd_kcontrol_new sun4i_codec_pa_mute =
401 	SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL,
402 			SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0);
403 
404 static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
405 
406 static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
407 	SOC_SINGLE_TLV("PA Volume", SUN4I_CODEC_DAC_ACTL,
408 		       SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
409 		       sun4i_codec_pa_volume_scale),
410 };
411 
412 static const struct snd_kcontrol_new sun4i_codec_left_mixer_controls[] = {
413 	SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
414 			SUN4I_CODEC_DAC_ACTL_LDACLMIXS, 1, 0),
415 };
416 
417 static const struct snd_kcontrol_new sun4i_codec_right_mixer_controls[] = {
418 	SOC_DAPM_SINGLE("Right DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
419 			SUN4I_CODEC_DAC_ACTL_RDACRMIXS, 1, 0),
420 	SOC_DAPM_SINGLE("Left DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
421 			SUN4I_CODEC_DAC_ACTL_LDACRMIXS, 1, 0),
422 };
423 
424 static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = {
425 	SOC_DAPM_SINGLE("DAC Playback Switch", SUN4I_CODEC_DAC_ACTL,
426 			SUN4I_CODEC_DAC_ACTL_DACPAS, 1, 0),
427 	SOC_DAPM_SINGLE("Mixer Playback Switch", SUN4I_CODEC_DAC_ACTL,
428 			SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0),
429 };
430 
431 static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
432 	/* Digital parts of the DACs */
433 	SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC,
434 			    SUN4I_CODEC_DAC_DPC_EN_DA, 0,
435 			    NULL, 0),
436 
437 	/* Analog parts of the DACs */
438 	SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
439 			 SUN4I_CODEC_DAC_ACTL_DACAENL, 0),
440 	SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL,
441 			 SUN4I_CODEC_DAC_ACTL_DACAENR, 0),
442 
443 	/* Mixers */
444 	SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
445 			   sun4i_codec_left_mixer_controls,
446 			   ARRAY_SIZE(sun4i_codec_left_mixer_controls)),
447 	SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
448 			   sun4i_codec_right_mixer_controls,
449 			   ARRAY_SIZE(sun4i_codec_right_mixer_controls)),
450 
451 	/* Global Mixer Enable */
452 	SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
453 			    SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
454 
455 	/* Pre-Amplifier */
456 	SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
457 			   SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
458 			   sun4i_codec_pa_mixer_controls,
459 			   ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
460 	SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0,
461 			    &sun4i_codec_pa_mute),
462 
463 	SND_SOC_DAPM_OUTPUT("HP Right"),
464 	SND_SOC_DAPM_OUTPUT("HP Left"),
465 };
466 
467 static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
468 	/* Left DAC Routes */
469 	{ "Left DAC", NULL, "DAC" },
470 
471 	/* Right DAC Routes */
472 	{ "Right DAC", NULL, "DAC" },
473 
474 	/* Right Mixer Routes */
475 	{ "Right Mixer", NULL, "Mixer Enable" },
476 	{ "Right Mixer", "Left DAC Playback Switch", "Left DAC" },
477 	{ "Right Mixer", "Right DAC Playback Switch", "Right DAC" },
478 
479 	/* Left Mixer Routes */
480 	{ "Left Mixer", NULL, "Mixer Enable" },
481 	{ "Left Mixer", "Left DAC Playback Switch", "Left DAC" },
482 
483 	/* Pre-Amplifier Mixer Routes */
484 	{ "Pre-Amplifier", "Mixer Playback Switch", "Left Mixer" },
485 	{ "Pre-Amplifier", "Mixer Playback Switch", "Right Mixer" },
486 	{ "Pre-Amplifier", "DAC Playback Switch", "Left DAC" },
487 	{ "Pre-Amplifier", "DAC Playback Switch", "Right DAC" },
488 
489 	/* PA -> HP path */
490 	{ "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" },
491 	{ "HP Right", NULL, "Pre-Amplifier Mute" },
492 	{ "HP Left", NULL, "Pre-Amplifier Mute" },
493 };
494 
495 static struct snd_soc_codec_driver sun4i_codec_codec = {
496 	.controls		= sun4i_codec_widgets,
497 	.num_controls		= ARRAY_SIZE(sun4i_codec_widgets),
498 	.dapm_widgets		= sun4i_codec_dapm_widgets,
499 	.num_dapm_widgets	= ARRAY_SIZE(sun4i_codec_dapm_widgets),
500 	.dapm_routes		= sun4i_codec_dapm_routes,
501 	.num_dapm_routes	= ARRAY_SIZE(sun4i_codec_dapm_routes),
502 };
503 
504 static const struct snd_soc_component_driver sun4i_codec_component = {
505 	.name = "sun4i-codec",
506 };
507 
508 #define SUN4I_CODEC_RATES	SNDRV_PCM_RATE_8000_192000
509 #define SUN4I_CODEC_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
510 				 SNDRV_PCM_FMTBIT_S32_LE)
511 
512 static int sun4i_codec_dai_probe(struct snd_soc_dai *dai)
513 {
514 	struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
515 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
516 
517 	snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data,
518 				  NULL);
519 
520 	return 0;
521 }
522 
523 static struct snd_soc_dai_driver dummy_cpu_dai = {
524 	.name	= "sun4i-codec-cpu-dai",
525 	.probe	= sun4i_codec_dai_probe,
526 	.playback = {
527 		.stream_name	= "Playback",
528 		.channels_min	= 1,
529 		.channels_max	= 2,
530 		.rates		= SUN4I_CODEC_RATES,
531 		.formats	= SUN4I_CODEC_FORMATS,
532 		.sig_bits	= 24,
533 	},
534 };
535 
536 static const struct regmap_config sun4i_codec_regmap_config = {
537 	.reg_bits	= 32,
538 	.reg_stride	= 4,
539 	.val_bits	= 32,
540 	.max_register	= SUN4I_CODEC_AC_MIC_PHONE_CAL,
541 };
542 
543 static const struct of_device_id sun4i_codec_of_match[] = {
544 	{ .compatible = "allwinner,sun4i-a10-codec" },
545 	{ .compatible = "allwinner,sun7i-a20-codec" },
546 	{}
547 };
548 MODULE_DEVICE_TABLE(of, sun4i_codec_of_match);
549 
550 static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
551 							int *num_links)
552 {
553 	struct snd_soc_dai_link *link = devm_kzalloc(dev, sizeof(*link),
554 						     GFP_KERNEL);
555 	if (!link)
556 		return NULL;
557 
558 	link->name		= "cdc";
559 	link->stream_name	= "CDC PCM";
560 	link->codec_dai_name	= "Codec";
561 	link->cpu_dai_name	= dev_name(dev);
562 	link->codec_name	= dev_name(dev);
563 	link->platform_name	= dev_name(dev);
564 	link->dai_fmt		= SND_SOC_DAIFMT_I2S;
565 
566 	*num_links = 1;
567 
568 	return link;
569 };
570 
571 static struct snd_soc_card *sun4i_codec_create_card(struct device *dev)
572 {
573 	struct snd_soc_card *card;
574 
575 	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
576 	if (!card)
577 		return NULL;
578 
579 	card->dai_link = sun4i_codec_create_link(dev, &card->num_links);
580 	if (!card->dai_link)
581 		return NULL;
582 
583 	card->dev		= dev;
584 	card->name		= "sun4i-codec";
585 
586 	return card;
587 };
588 
589 static int sun4i_codec_probe(struct platform_device *pdev)
590 {
591 	struct snd_soc_card *card;
592 	struct sun4i_codec *scodec;
593 	struct resource *res;
594 	void __iomem *base;
595 	int ret;
596 
597 	scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
598 	if (!scodec)
599 		return -ENOMEM;
600 
601 	scodec->dev = &pdev->dev;
602 
603 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
604 	base = devm_ioremap_resource(&pdev->dev, res);
605 	if (IS_ERR(base)) {
606 		dev_err(&pdev->dev, "Failed to map the registers\n");
607 		return PTR_ERR(base);
608 	}
609 
610 	scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
611 					     &sun4i_codec_regmap_config);
612 	if (IS_ERR(scodec->regmap)) {
613 		dev_err(&pdev->dev, "Failed to create our regmap\n");
614 		return PTR_ERR(scodec->regmap);
615 	}
616 
617 	/* Get the clocks from the DT */
618 	scodec->clk_apb = devm_clk_get(&pdev->dev, "apb");
619 	if (IS_ERR(scodec->clk_apb)) {
620 		dev_err(&pdev->dev, "Failed to get the APB clock\n");
621 		return PTR_ERR(scodec->clk_apb);
622 	}
623 
624 	scodec->clk_module = devm_clk_get(&pdev->dev, "codec");
625 	if (IS_ERR(scodec->clk_module)) {
626 		dev_err(&pdev->dev, "Failed to get the module clock\n");
627 		return PTR_ERR(scodec->clk_module);
628 	}
629 
630 	/* Enable the bus clock */
631 	if (clk_prepare_enable(scodec->clk_apb)) {
632 		dev_err(&pdev->dev, "Failed to enable the APB clock\n");
633 		return -EINVAL;
634 	}
635 
636 	/* DMA configuration for TX FIFO */
637 	scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA;
638 	scodec->playback_dma_data.maxburst = 4;
639 	scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
640 
641 	ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec,
642 				     &sun4i_codec_dai, 1);
643 	if (ret) {
644 		dev_err(&pdev->dev, "Failed to register our codec\n");
645 		goto err_clk_disable;
646 	}
647 
648 	ret = devm_snd_soc_register_component(&pdev->dev,
649 					      &sun4i_codec_component,
650 					      &dummy_cpu_dai, 1);
651 	if (ret) {
652 		dev_err(&pdev->dev, "Failed to register our DAI\n");
653 		goto err_unregister_codec;
654 	}
655 
656 	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
657 	if (ret) {
658 		dev_err(&pdev->dev, "Failed to register against DMAEngine\n");
659 		goto err_unregister_codec;
660 	}
661 
662 	card = sun4i_codec_create_card(&pdev->dev);
663 	if (!card) {
664 		dev_err(&pdev->dev, "Failed to create our card\n");
665 		goto err_unregister_codec;
666 	}
667 
668 	platform_set_drvdata(pdev, card);
669 	snd_soc_card_set_drvdata(card, scodec);
670 
671 	ret = snd_soc_register_card(card);
672 	if (ret) {
673 		dev_err(&pdev->dev, "Failed to register our card\n");
674 		goto err_unregister_codec;
675 	}
676 
677 	return 0;
678 
679 err_unregister_codec:
680 	snd_soc_unregister_codec(&pdev->dev);
681 err_clk_disable:
682 	clk_disable_unprepare(scodec->clk_apb);
683 	return ret;
684 }
685 
686 static int sun4i_codec_remove(struct platform_device *pdev)
687 {
688 	struct snd_soc_card *card = platform_get_drvdata(pdev);
689 	struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
690 
691 	snd_soc_unregister_card(card);
692 	snd_soc_unregister_codec(&pdev->dev);
693 	clk_disable_unprepare(scodec->clk_apb);
694 
695 	return 0;
696 }
697 
698 static struct platform_driver sun4i_codec_driver = {
699 	.driver = {
700 		.name = "sun4i-codec",
701 		.of_match_table = sun4i_codec_of_match,
702 	},
703 	.probe = sun4i_codec_probe,
704 	.remove = sun4i_codec_remove,
705 };
706 module_platform_driver(sun4i_codec_driver);
707 
708 MODULE_DESCRIPTION("Allwinner A10 codec driver");
709 MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
710 MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
711 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
712 MODULE_LICENSE("GPL");
713