xref: /freebsd/sys/arm/allwinner/a10_codec.c (revision 3884d6f8bd7e13a2b152fedc2d0d4f6de5ad17b8)
1 /*-
2  * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill@invisible.ca>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 /*
30  * Allwinner A10/A20 Audio Codec
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/condvar.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/gpio.h>
44 
45 #include <machine/bus.h>
46 
47 #include <dev/sound/pcm/sound.h>
48 #include <dev/sound/chip.h>
49 
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 
53 #include <arm/allwinner/a10_clk.h>
54 
55 #include "sunxi_dma_if.h"
56 #include "mixer_if.h"
57 #include "gpio_if.h"
58 
59 #define	TX_TRIG_LEVEL	0xf
60 #define	RX_TRIG_LEVEL	0x7
61 #define	DRQ_CLR_CNT	0x3
62 
63 #define	AC_DAC_DPC	0x00
64 #define	 DAC_DPC_EN_DA			0x80000000
65 #define	AC_DAC_FIFOC	0x04
66 #define	 DAC_FIFOC_FS_SHIFT		29
67 #define	 DAC_FIFOC_FS_MASK		(7U << DAC_FIFOC_FS_SHIFT)
68 #define	  DAC_FS_48KHZ			0
69 #define	  DAC_FS_32KHZ			1
70 #define	  DAC_FS_24KHZ			2
71 #define	  DAC_FS_16KHZ			3
72 #define	  DAC_FS_12KHZ			4
73 #define	  DAC_FS_8KHZ			5
74 #define	  DAC_FS_192KHZ			6
75 #define	  DAC_FS_96KHZ			7
76 #define	 DAC_FIFOC_FIFO_MODE_SHIFT	24
77 #define	 DAC_FIFOC_FIFO_MODE_MASK	(3U << DAC_FIFOC_FIFO_MODE_SHIFT)
78 #define	  FIFO_MODE_24_31_8		0
79 #define	  FIFO_MODE_16_31_16		0
80 #define	  FIFO_MODE_16_15_0		1
81 #define	 DAC_FIFOC_DRQ_CLR_CNT_SHIFT	21
82 #define	 DAC_FIFOC_DRQ_CLR_CNT_MASK	(3U << DAC_FIFOC_DRQ_CLR_CNT_SHIFT)
83 #define	 DAC_FIFOC_TX_TRIG_LEVEL_SHIFT	8
84 #define	 DAC_FIFOC_TX_TRIG_LEVEL_MASK	(0x7f << DAC_FIFOC_TX_TRIG_LEVEL_SHIFT)
85 #define	 DAC_FIFOC_MONO_EN		(1U << 6)
86 #define	 DAC_FIFOC_TX_BITS		(1U << 5)
87 #define	 DAC_FIFOC_DRQ_EN		(1U << 4)
88 #define	 DAC_FIFOC_FIFO_FLUSH		(1U << 0)
89 #define	AC_DAC_FIFOS	0x08
90 #define	AC_DAC_TXDATA	0x0c
91 #define	AC_DAC_ACTL	0x10
92 #define	 DAC_ACTL_DACAREN		(1U << 31)
93 #define	 DAC_ACTL_DACALEN		(1U << 30)
94 #define	 DAC_ACTL_MIXEN			(1U << 29)
95 #define	 DAC_ACTL_DACPAS		(1U << 8)
96 #define	 DAC_ACTL_PAMUTE		(1U << 6)
97 #define	 DAC_ACTL_PAVOL_SHIFT		0
98 #define	 DAC_ACTL_PAVOL_MASK		(0x3f << DAC_ACTL_PAVOL_SHIFT)
99 #define	AC_ADC_FIFOC	0x1c
100 #define	 ADC_FIFOC_FS_SHIFT		29
101 #define	 ADC_FIFOC_FS_MASK		(7U << ADC_FIFOC_FS_SHIFT)
102 #define	  ADC_FS_48KHZ		0
103 #define	 ADC_FIFOC_EN_AD		(1U << 28)
104 #define	 ADC_FIFOC_RX_FIFO_MODE		(1U << 24)
105 #define	 ADC_FIFOC_RX_TRIG_LEVEL_SHIFT	8
106 #define	 ADC_FIFOC_RX_TRIG_LEVEL_MASK	(0x1f << ADC_FIFOC_RX_TRIG_LEVEL_SHIFT)
107 #define	 ADC_FIFOC_MONO_EN		(1U << 7)
108 #define	 ADC_FIFOC_RX_BITS		(1U << 6)
109 #define	 ADC_FIFOC_DRQ_EN		(1U << 4)
110 #define	 ADC_FIFOC_FIFO_FLUSH		(1U << 1)
111 #define	AC_ADC_FIFOS	0x20
112 #define	AC_ADC_RXDATA	0x24
113 #define	AC_ADC_ACTL	0x28
114 #define	 ADC_ACTL_ADCREN		(1U << 31)
115 #define	 ADC_ACTL_ADCLEN		(1U << 30)
116 #define	 ADC_ACTL_PREG1EN		(1U << 29)
117 #define	 ADC_ACTL_PREG2EN		(1U << 28)
118 #define	 ADC_ACTL_VMICEN		(1U << 27)
119 #define	 ADC_ACTL_ADCG_SHIFT		20
120 #define	 ADC_ACTL_ADCG_MASK		(7U << ADC_ACTL_ADCG_SHIFT)
121 #define	 ADC_ACTL_ADCIS_SHIFT		17
122 #define	 ADC_ACTL_ADCIS_MASK		(7U << ADC_ACTL_ADCIS_SHIFT)
123 #define	  ADC_IS_LINEIN			0
124 #define	  ADC_IS_FMIN			1
125 #define	  ADC_IS_MIC1			2
126 #define	  ADC_IS_MIC2			3
127 #define	  ADC_IS_MIC1_L_MIC2_R		4
128 #define	  ADC_IS_MIC1_LR_MIC2_LR	5
129 #define	  ADC_IS_OMIX			6
130 #define	  ADC_IS_LINEIN_L_MIC1_R	7
131 #define	 ADC_ACTL_LNRDF			(1U << 16)
132 #define	 ADC_ACTL_LNPREG_SHIFT		13
133 #define	 ADC_ACTL_LNPREG_MASK		(7U << ADC_ACTL_LNPREG_SHIFT)
134 #define	 ADC_ACTL_PA_EN			(1U << 4)
135 #define	 ADC_ACTL_DDE			(1U << 3)
136 #define	AC_DAC_CNT	0x30
137 #define	AC_ADC_CNT	0x34
138 
139 static uint32_t a10codec_fmt[] = {
140 	SND_FORMAT(AFMT_S16_LE, 1, 0),
141 	SND_FORMAT(AFMT_S16_LE, 2, 0),
142 	0
143 };
144 
145 static struct pcmchan_caps a10codec_pcaps = { 8000, 192000, a10codec_fmt, 0 };
146 static struct pcmchan_caps a10codec_rcaps = { 8000, 48000, a10codec_fmt, 0 };
147 
148 struct a10codec_info;
149 
150 struct a10codec_chinfo {
151 	struct snd_dbuf		*buffer;
152 	struct pcm_channel	*channel;
153 	struct a10codec_info	*parent;
154 	bus_dmamap_t		dmamap;
155 	void			*dmaaddr;
156 	bus_addr_t		physaddr;
157 	bus_size_t		fifo;
158 	device_t		dmac;
159 	void			*dmachan;
160 
161 	int			dir;
162 	int			run;
163 	uint32_t		pos;
164 	uint32_t		format;
165 	uint32_t		blocksize;
166 	uint32_t		speed;
167 };
168 
169 struct a10codec_info {
170 	device_t		dev;
171 	struct resource		*res[2];
172 	struct mtx		*lock;
173 	bus_dma_tag_t		dmat;
174 	unsigned		dmasize;
175 	void			*ih;
176 
177 	unsigned		drqtype_codec;
178 	unsigned		drqtype_sdram;
179 
180 	struct a10codec_chinfo	play;
181 	struct a10codec_chinfo	rec;
182 };
183 
184 static struct resource_spec a10codec_spec[] = {
185 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
186 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
187 	{ -1, 0 }
188 };
189 
190 #define	CODEC_READ(sc, reg)		bus_read_4((sc)->res[0], (reg))
191 #define	CODEC_WRITE(sc, reg, val)	bus_write_4((sc)->res[0], (reg), (val))
192 
193 /*
194  * Mixer interface
195  */
196 
197 static int
198 a10codec_mixer_init(struct snd_mixer *m)
199 {
200 	struct a10codec_info *sc = mix_getdevinfo(m);
201 	pcell_t prop[4];
202 	phandle_t node;
203 	device_t gpio;
204 	uint32_t val;
205 	ssize_t len;
206 	int pin;
207 
208 	mix_setdevs(m, SOUND_MASK_VOLUME | SOUND_MASK_LINE | SOUND_MASK_RECLEV);
209 	mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC);
210 
211 	/* Unmute input source to PA */
212 	val = CODEC_READ(sc, AC_DAC_ACTL);
213 	val |= DAC_ACTL_PAMUTE;
214 	CODEC_WRITE(sc, AC_DAC_ACTL, val);
215 
216 	/* Enable PA */
217 	val = CODEC_READ(sc, AC_ADC_ACTL);
218 	val |= ADC_ACTL_PA_EN;
219 	CODEC_WRITE(sc, AC_ADC_ACTL, val);
220 
221 	/* Unmute PA */
222 	node = ofw_bus_get_node(sc->dev);
223 	len = OF_getencprop(node, "allwinner,pa-gpios", prop, sizeof(prop));
224 	if (len > 0 && (len / sizeof(prop[0])) == 4) {
225 		gpio = OF_device_from_xref(prop[0]);
226 		if (gpio != NULL) {
227 			pin = prop[1] * 32 + prop[2];
228 			GPIO_PIN_SETFLAGS(gpio, pin, GPIO_PIN_OUTPUT);
229 			GPIO_PIN_SET(gpio, pin, GPIO_PIN_LOW);
230 		}
231 	}
232 
233 	return (0);
234 }
235 
236 static const struct a10codec_mixer {
237 	unsigned reg;
238 	unsigned mask;
239 	unsigned shift;
240 } a10codec_mixers[SOUND_MIXER_NRDEVICES] = {
241 	[SOUND_MIXER_VOLUME]	= { AC_DAC_ACTL, DAC_ACTL_PAVOL_MASK,
242 				    DAC_ACTL_PAVOL_SHIFT },
243 	[SOUND_MIXER_LINE]	= { AC_ADC_ACTL, ADC_ACTL_LNPREG_MASK,
244 				    ADC_ACTL_LNPREG_SHIFT },
245 	[SOUND_MIXER_RECLEV]	= { AC_ADC_ACTL, ADC_ACTL_ADCG_MASK,
246 				    ADC_ACTL_ADCG_SHIFT },
247 };
248 
249 static int
250 a10codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left,
251     unsigned right)
252 {
253 	struct a10codec_info *sc = mix_getdevinfo(m);
254 	uint32_t val;
255 	unsigned nvol, max;
256 
257 	max = a10codec_mixers[dev].mask >> a10codec_mixers[dev].shift;
258 	nvol = (left * max) / 100;
259 
260 	val = CODEC_READ(sc, a10codec_mixers[dev].reg);
261 	val &= ~a10codec_mixers[dev].mask;
262 	val |= (nvol << a10codec_mixers[dev].shift);
263 	CODEC_WRITE(sc, a10codec_mixers[dev].reg, val);
264 
265 	left = right = (left * 100) / max;
266 	return (left | (right << 8));
267 }
268 
269 static uint32_t
270 a10codec_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
271 {
272 	struct a10codec_info *sc = mix_getdevinfo(m);
273 	uint32_t val;
274 
275 	val = CODEC_READ(sc, AC_ADC_ACTL);
276 
277 	switch (src) {
278 	case SOUND_MASK_LINE:	/* line-in */
279 		val &= ~ADC_ACTL_ADCIS_MASK;
280 		val |= (ADC_IS_LINEIN << ADC_ACTL_ADCIS_SHIFT);
281 		break;
282 	case SOUND_MASK_MIC:	/* MIC1 */
283 		val &= ~ADC_ACTL_ADCIS_MASK;
284 		val |= (ADC_IS_MIC1 << ADC_ACTL_ADCIS_SHIFT);
285 		break;
286 	case SOUND_MASK_LINE1:	/* MIC2 */
287 		val &= ~ADC_ACTL_ADCIS_MASK;
288 		val |= (ADC_IS_MIC2 << ADC_ACTL_ADCIS_SHIFT);
289 		break;
290 	default:
291 		break;
292 	}
293 
294 	CODEC_WRITE(sc, AC_ADC_ACTL, val);
295 
296 	switch ((val & ADC_ACTL_ADCIS_MASK) >> ADC_ACTL_ADCIS_SHIFT) {
297 	case ADC_IS_LINEIN:
298 		return (SOUND_MASK_LINE);
299 	case ADC_IS_MIC1:
300 		return (SOUND_MASK_MIC);
301 	case ADC_IS_MIC2:
302 		return (SOUND_MASK_LINE1);
303 	default:
304 		return (0);
305 	}
306 }
307 
308 static kobj_method_t a10codec_mixer_methods[] = {
309 	KOBJMETHOD(mixer_init,		a10codec_mixer_init),
310 	KOBJMETHOD(mixer_set,		a10codec_mixer_set),
311 	KOBJMETHOD(mixer_setrecsrc,	a10codec_mixer_setrecsrc),
312 	KOBJMETHOD_END
313 };
314 MIXER_DECLARE(a10codec_mixer);
315 
316 
317 /*
318  * Channel interface
319  */
320 
321 static void
322 a10codec_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
323 {
324 	struct a10codec_chinfo *ch = arg;
325 
326 	if (error != 0)
327 		return;
328 
329 	ch->physaddr = segs[0].ds_addr;
330 }
331 
332 static void
333 a10codec_transfer(struct a10codec_chinfo *ch)
334 {
335 	bus_addr_t src, dst;
336 	int error;
337 
338 	if (ch->dir == PCMDIR_PLAY) {
339 		src = ch->physaddr + ch->pos;
340 		dst = ch->fifo;
341 	} else {
342 		src = ch->fifo;
343 		dst = ch->physaddr + ch->pos;
344 	}
345 
346 	error = SUNXI_DMA_TRANSFER(ch->dmac, ch->dmachan, src, dst,
347 	    ch->blocksize);
348 	if (error) {
349 		ch->run = 0;
350 		device_printf(ch->parent->dev, "DMA transfer failed: %d\n",
351 		    error);
352 	}
353 }
354 
355 static void
356 a10codec_dmaconfig(struct a10codec_chinfo *ch)
357 {
358 	struct a10codec_info *sc = ch->parent;
359 	struct sunxi_dma_config conf;
360 
361 	memset(&conf, 0, sizeof(conf));
362 	conf.src_width = conf.dst_width = 16;
363 	conf.src_burst_len = conf.dst_burst_len = 4;
364 
365 	if (ch->dir == PCMDIR_PLAY) {
366 		conf.dst_noincr = true;
367 		conf.src_drqtype = sc->drqtype_sdram;
368 		conf.dst_drqtype = sc->drqtype_codec;
369 	} else {
370 		conf.src_noincr = true;
371 		conf.src_drqtype = sc->drqtype_codec;
372 		conf.dst_drqtype = sc->drqtype_sdram;
373 	}
374 
375 	SUNXI_DMA_SET_CONFIG(ch->dmac, ch->dmachan, &conf);
376 }
377 
378 static void
379 a10codec_dmaintr(void *priv)
380 {
381 	struct a10codec_chinfo *ch = priv;
382 	unsigned bufsize;
383 
384 	bufsize = sndbuf_getsize(ch->buffer);
385 
386 	ch->pos += ch->blocksize;
387 	if (ch->pos >= bufsize)
388 		ch->pos -= bufsize;
389 
390 	if (ch->run) {
391 		chn_intr(ch->channel);
392 		a10codec_transfer(ch);
393 	}
394 }
395 
396 static unsigned
397 a10codec_fs(struct a10codec_chinfo *ch)
398 {
399 	switch (ch->speed) {
400 	case 48000:
401 		return (DAC_FS_48KHZ);
402 	case 24000:
403 		return (DAC_FS_24KHZ);
404 	case 12000:
405 		return (DAC_FS_12KHZ);
406 	case 192000:
407 		return (DAC_FS_192KHZ);
408 	case 32000:
409 		return (DAC_FS_32KHZ);
410 	case 16000:
411 		return (DAC_FS_16KHZ);
412 	case 8000:
413 		return (DAC_FS_8KHZ);
414 	case 96000:
415 		return (DAC_FS_96KHZ);
416 	default:
417 		return (DAC_FS_48KHZ);
418 	}
419 }
420 
421 static void
422 a10codec_start(struct a10codec_chinfo *ch)
423 {
424 	struct a10codec_info *sc = ch->parent;
425 	uint32_t val;
426 
427 	ch->pos = 0;
428 
429 	if (ch->dir == PCMDIR_PLAY) {
430 		/* Flush DAC FIFO */
431 		CODEC_WRITE(sc, AC_DAC_FIFOC, DAC_FIFOC_FIFO_FLUSH);
432 
433 		/* Clear DAC FIFO status */
434 		CODEC_WRITE(sc, AC_DAC_FIFOS, CODEC_READ(sc, AC_DAC_FIFOS));
435 
436 		/* Enable DAC analog left/right channels and output mixer */
437 		val = CODEC_READ(sc, AC_DAC_ACTL);
438 		val |= DAC_ACTL_DACAREN;
439 		val |= DAC_ACTL_DACALEN;
440 		val |= DAC_ACTL_DACPAS;
441 		CODEC_WRITE(sc, AC_DAC_ACTL, val);
442 
443 		/* Configure DAC DMA channel */
444 		a10codec_dmaconfig(ch);
445 
446 		/* Configure DAC FIFO */
447 		CODEC_WRITE(sc, AC_DAC_FIFOC,
448 		    (AFMT_CHANNEL(ch->format) == 1 ? DAC_FIFOC_MONO_EN : 0) |
449 		    (a10codec_fs(ch) << DAC_FIFOC_FS_SHIFT) |
450 		    (FIFO_MODE_16_15_0 << DAC_FIFOC_FIFO_MODE_SHIFT) |
451 		    (DRQ_CLR_CNT << DAC_FIFOC_DRQ_CLR_CNT_SHIFT) |
452 		    (TX_TRIG_LEVEL << DAC_FIFOC_TX_TRIG_LEVEL_SHIFT));
453 
454 		/* Enable DAC DRQ */
455 		val = CODEC_READ(sc, AC_DAC_FIFOC);
456 		val |= DAC_FIFOC_DRQ_EN;
457 		CODEC_WRITE(sc, AC_DAC_FIFOC, val);
458 	} else {
459 		/* Flush ADC FIFO */
460 		CODEC_WRITE(sc, AC_ADC_FIFOC, ADC_FIFOC_FIFO_FLUSH);
461 
462 		/* Clear ADC FIFO status */
463 		CODEC_WRITE(sc, AC_ADC_FIFOS, CODEC_READ(sc, AC_ADC_FIFOS));
464 
465 		/* Enable ADC analog left/right channels, MIC1 preamp,
466 		 * and VMIC pin voltage
467 		 */
468 		val = CODEC_READ(sc, AC_ADC_ACTL);
469 		val |= ADC_ACTL_ADCREN;
470 		val |= ADC_ACTL_ADCLEN;
471 		val |= ADC_ACTL_PREG1EN;
472 		val |= ADC_ACTL_VMICEN;
473 		CODEC_WRITE(sc, AC_ADC_ACTL, val);
474 
475 		/* Configure ADC DMA channel */
476 		a10codec_dmaconfig(ch);
477 
478 		/* Configure ADC FIFO */
479 		CODEC_WRITE(sc, AC_ADC_FIFOC,
480 		    ADC_FIFOC_EN_AD |
481 		    ADC_FIFOC_RX_FIFO_MODE |
482 		    (AFMT_CHANNEL(ch->format) == 1 ? ADC_FIFOC_MONO_EN : 0) |
483 		    (a10codec_fs(ch) << ADC_FIFOC_FS_SHIFT) |
484 		    (RX_TRIG_LEVEL << ADC_FIFOC_RX_TRIG_LEVEL_SHIFT));
485 
486 		/* Enable ADC DRQ */
487 		val = CODEC_READ(sc, AC_ADC_FIFOC);
488 		val |= ADC_FIFOC_DRQ_EN;
489 		CODEC_WRITE(sc, AC_ADC_FIFOC, val);
490 	}
491 
492 	/* Start DMA transfer */
493 	a10codec_transfer(ch);
494 }
495 
496 static void
497 a10codec_stop(struct a10codec_chinfo *ch)
498 {
499 	struct a10codec_info *sc = ch->parent;
500 	uint32_t val;
501 
502 	/* Disable DMA channel */
503 	SUNXI_DMA_HALT(ch->dmac, ch->dmachan);
504 
505 	if (ch->dir == PCMDIR_PLAY) {
506 		/* Disable DAC analog left/right channels and output mixer */
507 		val = CODEC_READ(sc, AC_DAC_ACTL);
508 		val &= ~DAC_ACTL_DACAREN;
509 		val &= ~DAC_ACTL_DACALEN;
510 		val &= ~DAC_ACTL_DACPAS;
511 		CODEC_WRITE(sc, AC_DAC_ACTL, val);
512 
513 		/* Disable DAC DRQ */
514 		CODEC_WRITE(sc, AC_DAC_FIFOC, 0);
515 	} else {
516 		/* Disable ADC analog left/right channels, MIC1 preamp,
517 		 * and VMIC pin voltage
518 		 */
519 		val = CODEC_READ(sc, AC_ADC_ACTL);
520 		val &= ~ADC_ACTL_ADCREN;
521 		val &= ~ADC_ACTL_ADCLEN;
522 		val &= ~ADC_ACTL_PREG1EN;
523 		val &= ~ADC_ACTL_VMICEN;
524 		CODEC_WRITE(sc, AC_ADC_ACTL, val);
525 
526 		/* Disable ADC DRQ */
527 		CODEC_WRITE(sc, AC_ADC_FIFOC, 0);
528 	}
529 }
530 
531 static void *
532 a10codec_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
533     struct pcm_channel *c, int dir)
534 {
535 	struct a10codec_info *sc = devinfo;
536 	struct a10codec_chinfo *ch = dir == PCMDIR_PLAY ? &sc->play : &sc->rec;
537 	int error;
538 
539 	ch->parent = sc;
540 	ch->channel = c;
541 	ch->buffer = b;
542 	ch->dir = dir;
543 	ch->fifo = rman_get_start(sc->res[0]) +
544 	    (dir == PCMDIR_REC ? AC_ADC_RXDATA : AC_DAC_TXDATA);
545 
546 	ch->dmac = devclass_get_device(devclass_find("a10dmac"), 0);
547 	if (ch->dmac == NULL) {
548 		device_printf(sc->dev, "cannot find DMA controller\n");
549 		return (NULL);
550 	}
551 	ch->dmachan = SUNXI_DMA_ALLOC(ch->dmac, false, a10codec_dmaintr, ch);
552 	if (ch->dmachan == NULL) {
553 		device_printf(sc->dev, "cannot allocate DMA channel\n");
554 		return (NULL);
555 	}
556 
557 	error = bus_dmamem_alloc(sc->dmat, &ch->dmaaddr,
558 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &ch->dmamap);
559 	if (error != 0) {
560 		device_printf(sc->dev, "cannot allocate channel buffer\n");
561 		return (NULL);
562 	}
563 	error = bus_dmamap_load(sc->dmat, ch->dmamap, ch->dmaaddr,
564 	    sc->dmasize, a10codec_dmamap_cb, ch, BUS_DMA_NOWAIT);
565 	if (error != 0) {
566 		device_printf(sc->dev, "cannot load DMA map\n");
567 		return (NULL);
568 	}
569 	memset(ch->dmaaddr, 0, sc->dmasize);
570 
571 	if (sndbuf_setup(ch->buffer, ch->dmaaddr, sc->dmasize) != 0) {
572 		device_printf(sc->dev, "cannot setup sndbuf\n");
573 		return (NULL);
574 	}
575 
576 	return (ch);
577 }
578 
579 static int
580 a10codec_chan_free(kobj_t obj, void *data)
581 {
582 	struct a10codec_chinfo *ch = data;
583 	struct a10codec_info *sc = ch->parent;
584 
585 	SUNXI_DMA_FREE(ch->dmac, ch->dmachan);
586 	bus_dmamap_unload(sc->dmat, ch->dmamap);
587 	bus_dmamem_free(sc->dmat, ch->dmaaddr, ch->dmamap);
588 
589 	return (0);
590 }
591 
592 static int
593 a10codec_chan_setformat(kobj_t obj, void *data, uint32_t format)
594 {
595 	struct a10codec_chinfo *ch = data;
596 
597 	ch->format = format;
598 
599 	return (0);
600 }
601 
602 static uint32_t
603 a10codec_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
604 {
605 	struct a10codec_chinfo *ch = data;
606 
607 	/*
608 	 * The codec supports full duplex operation but both DAC and ADC
609 	 * use the same source clock (PLL2). Limit the available speeds to
610 	 * those supported by a 24576000 Hz input.
611 	 */
612 	switch (speed) {
613 	case 8000:
614 	case 12000:
615 	case 16000:
616 	case 24000:
617 	case 32000:
618 	case 48000:
619 		ch->speed = speed;
620 		break;
621 	case 96000:
622 	case 192000:
623 		/* 96 KHz / 192 KHz mode only supported for playback */
624 		if (ch->dir == PCMDIR_PLAY) {
625 			ch->speed = speed;
626 		} else {
627 			ch->speed = 48000;
628 		}
629 		break;
630 	case 44100:
631 		ch->speed = 48000;
632 		break;
633 	case 22050:
634 		ch->speed = 24000;
635 		break;
636 	case 11025:
637 		ch->speed = 12000;
638 		break;
639 	default:
640 		ch->speed = 48000;
641 		break;
642 	}
643 
644 	return (ch->speed);
645 }
646 
647 static uint32_t
648 a10codec_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
649 {
650 	struct a10codec_chinfo *ch = data;
651 
652 	ch->blocksize = blocksize & ~3;
653 
654 	return (ch->blocksize);
655 }
656 
657 static int
658 a10codec_chan_trigger(kobj_t obj, void *data, int go)
659 {
660 	struct a10codec_chinfo *ch = data;
661 	struct a10codec_info *sc = ch->parent;
662 
663 	if (!PCMTRIG_COMMON(go))
664 		return (0);
665 
666 	snd_mtxlock(sc->lock);
667 	switch (go) {
668 	case PCMTRIG_START:
669 		ch->run = 1;
670 		a10codec_start(ch);
671 		break;
672 	case PCMTRIG_STOP:
673 	case PCMTRIG_ABORT:
674 		ch->run = 0;
675 		a10codec_stop(ch);
676 		break;
677 	default:
678 		break;
679 	}
680 	snd_mtxunlock(sc->lock);
681 
682 	return (0);
683 }
684 
685 static uint32_t
686 a10codec_chan_getptr(kobj_t obj, void *data)
687 {
688 	struct a10codec_chinfo *ch = data;
689 
690 	return (ch->pos);
691 }
692 
693 static struct pcmchan_caps *
694 a10codec_chan_getcaps(kobj_t obj, void *data)
695 {
696 	struct a10codec_chinfo *ch = data;
697 
698 	if (ch->dir == PCMDIR_PLAY) {
699 		return (&a10codec_pcaps);
700 	} else {
701 		return (&a10codec_rcaps);
702 	}
703 }
704 
705 static kobj_method_t a10codec_chan_methods[] = {
706 	KOBJMETHOD(channel_init,		a10codec_chan_init),
707 	KOBJMETHOD(channel_free,		a10codec_chan_free),
708 	KOBJMETHOD(channel_setformat,		a10codec_chan_setformat),
709 	KOBJMETHOD(channel_setspeed,		a10codec_chan_setspeed),
710 	KOBJMETHOD(channel_setblocksize,	a10codec_chan_setblocksize),
711 	KOBJMETHOD(channel_trigger,		a10codec_chan_trigger),
712 	KOBJMETHOD(channel_getptr,		a10codec_chan_getptr),
713 	KOBJMETHOD(channel_getcaps,		a10codec_chan_getcaps),
714 	KOBJMETHOD_END
715 };
716 CHANNEL_DECLARE(a10codec_chan);
717 
718 
719 /*
720  * Device interface
721  */
722 
723 static int
724 a10codec_probe(device_t dev)
725 {
726 	if (!ofw_bus_status_okay(dev))
727 		return (ENXIO);
728 
729 	if (!ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-codec"))
730 		return (ENXIO);
731 
732 	device_set_desc(dev, "Allwinner Audio Codec");
733 	return (BUS_PROBE_DEFAULT);
734 }
735 
736 static int
737 a10codec_attach(device_t dev)
738 {
739 	struct a10codec_info *sc;
740 	char status[SND_STATUSLEN];
741 	uint32_t val;
742 	int error;
743 
744 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
745 	sc->dev = dev;
746 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "a10codec softc");
747 
748 	if (bus_alloc_resources(dev, a10codec_spec, sc->res)) {
749 		device_printf(dev, "cannot allocate resources for device\n");
750 		error = ENXIO;
751 		goto fail;
752 	}
753 
754 	/* XXX DRQ types should come from FDT, but how? */
755 	if (ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-codec") ||
756 	    ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-codec")) {
757 		sc->drqtype_codec = 19;
758 		sc->drqtype_sdram = 22;
759 	} else {
760 		device_printf(dev, "DRQ types not known for this SoC\n");
761 		error = ENXIO;
762 		goto fail;
763 	}
764 
765 	sc->dmasize = 131072;
766 	error = bus_dma_tag_create(
767 	    bus_get_dma_tag(dev),
768 	    4, sc->dmasize,		/* alignment, boundary */
769 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
770 	    BUS_SPACE_MAXADDR,		/* highaddr */
771 	    NULL, NULL,			/* filter, filterarg */
772 	    sc->dmasize, 1,		/* maxsize, nsegs */
773 	    sc->dmasize, 0,		/* maxsegsize, flags */
774 	    NULL, NULL,			/* lockfunc, lockarg */
775 	    &sc->dmat);
776 	if (error != 0) {
777 		device_printf(dev, "cannot create DMA tag\n");
778 		goto fail;
779 	}
780 
781 	/* Activate audio codec clock. According to the A10 and A20 user
782 	 * manuals, Audio_pll can be either 24.576MHz or 22.5792MHz. Most
783 	 * audio sampling rates require an 24.576MHz input clock with the
784 	 * exception of 44.1kHz, 22.05kHz, and 11.025kHz. Unfortunately,
785 	 * both capture and playback use the same clock source so to
786 	 * safely support independent full duplex operation, we use a fixed
787 	 * 24.576MHz clock source and don't advertise native support for
788 	 * the three sampling rates that require a 22.5792MHz input.
789 	 */
790 	a10_clk_codec_activate(24576000);
791 
792 	/* Enable DAC */
793 	val = CODEC_READ(sc, AC_DAC_DPC);
794 	val |= DAC_DPC_EN_DA;
795 	CODEC_WRITE(sc, AC_DAC_DPC, val);
796 
797 #ifdef notdef
798 	error = snd_setup_intr(dev, sc->irq, INTR_MPSAFE, a10codec_intr, sc,
799 	    &sc->ih);
800 	if (error != 0) {
801 		device_printf(dev, "could not setup interrupt handler\n");
802 		goto fail;
803 	}
804 #endif
805 
806 	if (mixer_init(dev, &a10codec_mixer_class, sc)) {
807 		device_printf(dev, "mixer_init failed\n");
808 		goto fail;
809 	}
810 
811 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
812 
813 	if (pcm_register(dev, sc, 1, 1)) {
814 		device_printf(dev, "pcm_register failed\n");
815 		goto fail;
816 	}
817 
818 	pcm_addchan(dev, PCMDIR_PLAY, &a10codec_chan_class, sc);
819 	pcm_addchan(dev, PCMDIR_REC, &a10codec_chan_class, sc);
820 
821 	snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
822 	pcm_setstatus(dev, status);
823 
824 	return (0);
825 
826 fail:
827 	bus_release_resources(dev, a10codec_spec, sc->res);
828 	snd_mtxfree(sc->lock);
829 	free(sc, M_DEVBUF);
830 
831 	return (error);
832 }
833 
834 static device_method_t a10codec_pcm_methods[] = {
835 	/* Device interface */
836 	DEVMETHOD(device_probe,		a10codec_probe),
837 	DEVMETHOD(device_attach,	a10codec_attach),
838 
839 	DEVMETHOD_END
840 };
841 
842 static driver_t a10codec_pcm_driver = {
843 	"pcm",
844 	a10codec_pcm_methods,
845 	PCM_SOFTC_SIZE,
846 };
847 
848 DRIVER_MODULE(a10codec, simplebus, a10codec_pcm_driver, pcm_devclass, 0, 0);
849 MODULE_DEPEND(a10codec, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
850 MODULE_VERSION(a10codec, 1);
851