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