a10_codec.c revision 305436
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: stable/11/sys/arm/allwinner/a10_codec.c 305436 2016-09-05 20:17:18Z manu $
27 */
28
29/*
30 * Allwinner A10/A20 Audio Codec
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/a10_codec.c 305436 2016-09-05 20:17:18Z manu $");
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 <dev/extres/clk/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
139static uint32_t a10codec_fmt[] = {
140	SND_FORMAT(AFMT_S16_LE, 1, 0),
141	SND_FORMAT(AFMT_S16_LE, 2, 0),
142	0
143};
144
145static struct pcmchan_caps a10codec_pcaps = { 8000, 192000, a10codec_fmt, 0 };
146static struct pcmchan_caps a10codec_rcaps = { 8000, 48000, a10codec_fmt, 0 };
147
148struct a10codec_info;
149
150struct 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
169struct 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
184static 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
197static int
198a10codec_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
236static 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
249static int
250a10codec_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
269static uint32_t
270a10codec_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
308static 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};
314MIXER_DECLARE(a10codec_mixer);
315
316
317/*
318 * Channel interface
319 */
320
321static void
322a10codec_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
332static void
333a10codec_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
355static void
356a10codec_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
378static void
379a10codec_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
396static unsigned
397a10codec_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
421static void
422a10codec_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
496static void
497a10codec_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
531static void *
532a10codec_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
579static int
580a10codec_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
592static int
593a10codec_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
602static uint32_t
603a10codec_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
647static uint32_t
648a10codec_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
657static int
658a10codec_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
685static uint32_t
686a10codec_chan_getptr(kobj_t obj, void *data)
687{
688	struct a10codec_chinfo *ch = data;
689
690	return (ch->pos);
691}
692
693static struct pcmchan_caps *
694a10codec_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
705static 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};
716CHANNEL_DECLARE(a10codec_chan);
717
718
719/*
720 * Device interface
721 */
722
723static struct ofw_compat_data compat_data[] = {
724	{"allwinner,sun4i-a10-codec", 1},
725	{"allwinner,sun7i-a20-codec", 1},
726	{NULL, 0},
727};
728
729static int
730a10codec_probe(device_t dev)
731{
732	if (!ofw_bus_status_okay(dev))
733		return (ENXIO);
734
735	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
736		return (ENXIO);
737
738	device_set_desc(dev, "Allwinner Audio Codec");
739	return (BUS_PROBE_DEFAULT);
740}
741
742static int
743a10codec_attach(device_t dev)
744{
745	struct a10codec_info *sc;
746	char status[SND_STATUSLEN];
747	clk_t clk_apb, clk_codec;
748	uint32_t val;
749	int error;
750
751	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
752	sc->dev = dev;
753	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "a10codec softc");
754
755	if (bus_alloc_resources(dev, a10codec_spec, sc->res)) {
756		device_printf(dev, "cannot allocate resources for device\n");
757		error = ENXIO;
758		goto fail;
759	}
760
761	/* XXX DRQ types should come from FDT, but how? */
762	if (ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-codec") ||
763	    ofw_bus_is_compatible(dev, "allwinner,sun7i-a20-codec")) {
764		sc->drqtype_codec = 19;
765		sc->drqtype_sdram = 22;
766	} else {
767		device_printf(dev, "DRQ types not known for this SoC\n");
768		error = ENXIO;
769		goto fail;
770	}
771
772	sc->dmasize = 131072;
773	error = bus_dma_tag_create(
774	    bus_get_dma_tag(dev),
775	    4, sc->dmasize,		/* alignment, boundary */
776	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
777	    BUS_SPACE_MAXADDR,		/* highaddr */
778	    NULL, NULL,			/* filter, filterarg */
779	    sc->dmasize, 1,		/* maxsize, nsegs */
780	    sc->dmasize, 0,		/* maxsegsize, flags */
781	    NULL, NULL,			/* lockfunc, lockarg */
782	    &sc->dmat);
783	if (error != 0) {
784		device_printf(dev, "cannot create DMA tag\n");
785		goto fail;
786	}
787
788	/* Get clocks */
789	error = clk_get_by_ofw_name(dev, "apb", &clk_apb);
790	if (error != 0) {
791		device_printf(dev, "cannot find apb clock\n");
792		goto fail;
793	}
794	error = clk_get_by_ofw_name(dev, "codec", &clk_codec);
795	if (error != 0) {
796		device_printf(dev, "cannot find codec clock\n");
797		goto fail;
798	}
799
800	/* Gating APB clock for codec */
801	error = clk_enable(clk_apb);
802	if (error != 0) {
803		device_printf(dev, "cannot enable apb clock\n");
804		goto fail;
805	}
806	/* Activate audio codec clock. According to the A10 and A20 user
807	 * manuals, Audio_pll can be either 24.576MHz or 22.5792MHz. Most
808	 * audio sampling rates require an 24.576MHz input clock with the
809	 * exception of 44.1kHz, 22.05kHz, and 11.025kHz. Unfortunately,
810	 * both capture and playback use the same clock source so to
811	 * safely support independent full duplex operation, we use a fixed
812	 * 24.576MHz clock source and don't advertise native support for
813	 * the three sampling rates that require a 22.5792MHz input.
814	 */
815	error = clk_set_freq(clk_codec, 24576000, CLK_SET_ROUND_DOWN);
816	if (error != 0) {
817		device_printf(dev, "cannot set codec clock frequency\n");
818		goto fail;
819	}
820	/* Enable audio codec clock */
821	error = clk_enable(clk_codec);
822	if (error != 0) {
823		device_printf(dev, "cannot enable codec clock\n");
824		goto fail;
825	}
826
827	/* Enable DAC */
828	val = CODEC_READ(sc, AC_DAC_DPC);
829	val |= DAC_DPC_EN_DA;
830	CODEC_WRITE(sc, AC_DAC_DPC, val);
831
832#ifdef notdef
833	error = snd_setup_intr(dev, sc->irq, INTR_MPSAFE, a10codec_intr, sc,
834	    &sc->ih);
835	if (error != 0) {
836		device_printf(dev, "could not setup interrupt handler\n");
837		goto fail;
838	}
839#endif
840
841	if (mixer_init(dev, &a10codec_mixer_class, sc)) {
842		device_printf(dev, "mixer_init failed\n");
843		goto fail;
844	}
845
846	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
847
848	if (pcm_register(dev, sc, 1, 1)) {
849		device_printf(dev, "pcm_register failed\n");
850		goto fail;
851	}
852
853	pcm_addchan(dev, PCMDIR_PLAY, &a10codec_chan_class, sc);
854	pcm_addchan(dev, PCMDIR_REC, &a10codec_chan_class, sc);
855
856	snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
857	pcm_setstatus(dev, status);
858
859	return (0);
860
861fail:
862	bus_release_resources(dev, a10codec_spec, sc->res);
863	snd_mtxfree(sc->lock);
864	free(sc, M_DEVBUF);
865
866	return (error);
867}
868
869static device_method_t a10codec_pcm_methods[] = {
870	/* Device interface */
871	DEVMETHOD(device_probe,		a10codec_probe),
872	DEVMETHOD(device_attach,	a10codec_attach),
873
874	DEVMETHOD_END
875};
876
877static driver_t a10codec_pcm_driver = {
878	"pcm",
879	a10codec_pcm_methods,
880	PCM_SOFTC_SIZE,
881};
882
883DRIVER_MODULE(a10codec, simplebus, a10codec_pcm_driver, pcm_devclass, 0, 0);
884MODULE_DEPEND(a10codec, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
885MODULE_VERSION(a10codec, 1);
886