2 * Copyright (c) 2014-2016 Jared D. McNeill <jmcneill@invisible.ca>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
30 * Allwinner A10/A20 Audio Codec
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
40 #include <sys/condvar.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
45 #include <machine/bus.h>
47 #include <dev/sound/pcm/sound.h>
48 #include <dev/sound/chip.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
53 #include <dev/extres/clk/clk.h>
55 #include "sunxi_dma_if.h"
59 #define TX_TRIG_LEVEL 0xf
60 #define RX_TRIG_LEVEL 0x7
61 #define DRQ_CLR_CNT 0x3
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
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
139 static uint32_t a10codec_fmt[] = {
140 SND_FORMAT(AFMT_S16_LE, 1, 0),
141 SND_FORMAT(AFMT_S16_LE, 2, 0),
145 static struct pcmchan_caps a10codec_pcaps = { 8000, 192000, a10codec_fmt, 0 };
146 static struct pcmchan_caps a10codec_rcaps = { 8000, 48000, a10codec_fmt, 0 };
148 struct a10codec_info;
150 struct a10codec_chinfo {
151 struct snd_dbuf *buffer;
152 struct pcm_channel *channel;
153 struct a10codec_info *parent;
169 struct a10codec_info {
171 struct resource *res[2];
177 unsigned drqtype_codec;
178 unsigned drqtype_sdram;
180 struct a10codec_chinfo play;
181 struct a10codec_chinfo rec;
184 static struct resource_spec a10codec_spec[] = {
185 { SYS_RES_MEMORY, 0, RF_ACTIVE },
186 { SYS_RES_IRQ, 0, RF_ACTIVE },
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))
198 a10codec_mixer_init(struct snd_mixer *m)
200 struct a10codec_info *sc = mix_getdevinfo(m);
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);
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);
217 val = CODEC_READ(sc, AC_ADC_ACTL);
218 val |= ADC_ACTL_PA_EN;
219 CODEC_WRITE(sc, AC_ADC_ACTL, val);
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]);
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);
236 static const struct a10codec_mixer {
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 },
250 a10codec_mixer_set(struct snd_mixer *m, unsigned dev, unsigned left,
253 struct a10codec_info *sc = mix_getdevinfo(m);
257 max = a10codec_mixers[dev].mask >> a10codec_mixers[dev].shift;
258 nvol = (left * max) / 100;
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);
265 left = right = (left * 100) / max;
266 return (left | (right << 8));
270 a10codec_mixer_setrecsrc(struct snd_mixer *m, uint32_t src)
272 struct a10codec_info *sc = mix_getdevinfo(m);
275 val = CODEC_READ(sc, AC_ADC_ACTL);
278 case SOUND_MASK_LINE: /* line-in */
279 val &= ~ADC_ACTL_ADCIS_MASK;
280 val |= (ADC_IS_LINEIN << ADC_ACTL_ADCIS_SHIFT);
282 case SOUND_MASK_MIC: /* MIC1 */
283 val &= ~ADC_ACTL_ADCIS_MASK;
284 val |= (ADC_IS_MIC1 << ADC_ACTL_ADCIS_SHIFT);
286 case SOUND_MASK_LINE1: /* MIC2 */
287 val &= ~ADC_ACTL_ADCIS_MASK;
288 val |= (ADC_IS_MIC2 << ADC_ACTL_ADCIS_SHIFT);
294 CODEC_WRITE(sc, AC_ADC_ACTL, val);
296 switch ((val & ADC_ACTL_ADCIS_MASK) >> ADC_ACTL_ADCIS_SHIFT) {
298 return (SOUND_MASK_LINE);
300 return (SOUND_MASK_MIC);
302 return (SOUND_MASK_LINE1);
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),
314 MIXER_DECLARE(a10codec_mixer);
322 a10codec_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
324 struct a10codec_chinfo *ch = arg;
329 ch->physaddr = segs[0].ds_addr;
333 a10codec_transfer(struct a10codec_chinfo *ch)
338 if (ch->dir == PCMDIR_PLAY) {
339 src = ch->physaddr + ch->pos;
343 dst = ch->physaddr + ch->pos;
346 error = SUNXI_DMA_TRANSFER(ch->dmac, ch->dmachan, src, dst,
350 device_printf(ch->parent->dev, "DMA transfer failed: %d\n",
356 a10codec_dmaconfig(struct a10codec_chinfo *ch)
358 struct a10codec_info *sc = ch->parent;
359 struct sunxi_dma_config conf;
361 memset(&conf, 0, sizeof(conf));
362 conf.src_width = conf.dst_width = 16;
363 conf.src_burst_len = conf.dst_burst_len = 4;
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;
370 conf.src_noincr = true;
371 conf.src_drqtype = sc->drqtype_codec;
372 conf.dst_drqtype = sc->drqtype_sdram;
375 SUNXI_DMA_SET_CONFIG(ch->dmac, ch->dmachan, &conf);
379 a10codec_dmaintr(void *priv)
381 struct a10codec_chinfo *ch = priv;
384 bufsize = sndbuf_getsize(ch->buffer);
386 ch->pos += ch->blocksize;
387 if (ch->pos >= bufsize)
391 chn_intr(ch->channel);
392 a10codec_transfer(ch);
397 a10codec_fs(struct a10codec_chinfo *ch)
401 return (DAC_FS_48KHZ);
403 return (DAC_FS_24KHZ);
405 return (DAC_FS_12KHZ);
407 return (DAC_FS_192KHZ);
409 return (DAC_FS_32KHZ);
411 return (DAC_FS_16KHZ);
413 return (DAC_FS_8KHZ);
415 return (DAC_FS_96KHZ);
417 return (DAC_FS_48KHZ);
422 a10codec_start(struct a10codec_chinfo *ch)
424 struct a10codec_info *sc = ch->parent;
429 if (ch->dir == PCMDIR_PLAY) {
431 CODEC_WRITE(sc, AC_DAC_FIFOC, DAC_FIFOC_FIFO_FLUSH);
433 /* Clear DAC FIFO status */
434 CODEC_WRITE(sc, AC_DAC_FIFOS, CODEC_READ(sc, AC_DAC_FIFOS));
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);
443 /* Configure DAC DMA channel */
444 a10codec_dmaconfig(ch);
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));
455 val = CODEC_READ(sc, AC_DAC_FIFOC);
456 val |= DAC_FIFOC_DRQ_EN;
457 CODEC_WRITE(sc, AC_DAC_FIFOC, val);
460 CODEC_WRITE(sc, AC_ADC_FIFOC, ADC_FIFOC_FIFO_FLUSH);
462 /* Clear ADC FIFO status */
463 CODEC_WRITE(sc, AC_ADC_FIFOS, CODEC_READ(sc, AC_ADC_FIFOS));
465 /* Enable ADC analog left/right channels, MIC1 preamp,
466 * and VMIC pin voltage
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);
475 /* Configure ADC DMA channel */
476 a10codec_dmaconfig(ch);
478 /* Configure ADC FIFO */
479 CODEC_WRITE(sc, AC_ADC_FIFOC,
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));
487 val = CODEC_READ(sc, AC_ADC_FIFOC);
488 val |= ADC_FIFOC_DRQ_EN;
489 CODEC_WRITE(sc, AC_ADC_FIFOC, val);
492 /* Start DMA transfer */
493 a10codec_transfer(ch);
497 a10codec_stop(struct a10codec_chinfo *ch)
499 struct a10codec_info *sc = ch->parent;
502 /* Disable DMA channel */
503 SUNXI_DMA_HALT(ch->dmac, ch->dmachan);
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);
513 /* Disable DAC DRQ */
514 CODEC_WRITE(sc, AC_DAC_FIFOC, 0);
516 /* Disable ADC analog left/right channels, MIC1 preamp,
517 * and VMIC pin voltage
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);
526 /* Disable ADC DRQ */
527 CODEC_WRITE(sc, AC_ADC_FIFOC, 0);
532 a10codec_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
533 struct pcm_channel *c, int dir)
535 struct a10codec_info *sc = devinfo;
536 struct a10codec_chinfo *ch = dir == PCMDIR_PLAY ? &sc->play : &sc->rec;
543 ch->fifo = rman_get_start(sc->res[0]) +
544 (dir == PCMDIR_REC ? AC_ADC_RXDATA : AC_DAC_TXDATA);
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");
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");
557 error = bus_dmamem_alloc(sc->dmat, &ch->dmaaddr,
558 BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &ch->dmamap);
560 device_printf(sc->dev, "cannot allocate channel buffer\n");
563 error = bus_dmamap_load(sc->dmat, ch->dmamap, ch->dmaaddr,
564 sc->dmasize, a10codec_dmamap_cb, ch, BUS_DMA_NOWAIT);
566 device_printf(sc->dev, "cannot load DMA map\n");
569 memset(ch->dmaaddr, 0, sc->dmasize);
571 if (sndbuf_setup(ch->buffer, ch->dmaaddr, sc->dmasize) != 0) {
572 device_printf(sc->dev, "cannot setup sndbuf\n");
580 a10codec_chan_free(kobj_t obj, void *data)
582 struct a10codec_chinfo *ch = data;
583 struct a10codec_info *sc = ch->parent;
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);
593 a10codec_chan_setformat(kobj_t obj, void *data, uint32_t format)
595 struct a10codec_chinfo *ch = data;
603 a10codec_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
605 struct a10codec_chinfo *ch = data;
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.
623 /* 96 KHz / 192 KHz mode only supported for playback */
624 if (ch->dir == PCMDIR_PLAY) {
648 a10codec_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
650 struct a10codec_chinfo *ch = data;
652 ch->blocksize = blocksize & ~3;
654 return (ch->blocksize);
658 a10codec_chan_trigger(kobj_t obj, void *data, int go)
660 struct a10codec_chinfo *ch = data;
661 struct a10codec_info *sc = ch->parent;
663 if (!PCMTRIG_COMMON(go))
666 snd_mtxlock(sc->lock);
680 snd_mtxunlock(sc->lock);
686 a10codec_chan_getptr(kobj_t obj, void *data)
688 struct a10codec_chinfo *ch = data;
693 static struct pcmchan_caps *
694 a10codec_chan_getcaps(kobj_t obj, void *data)
696 struct a10codec_chinfo *ch = data;
698 if (ch->dir == PCMDIR_PLAY) {
699 return (&a10codec_pcaps);
701 return (&a10codec_rcaps);
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),
716 CHANNEL_DECLARE(a10codec_chan);
723 static struct ofw_compat_data compat_data[] = {
724 {"allwinner,sun4i-a10-codec", 1},
725 {"allwinner,sun7i-a20-codec", 1},
730 a10codec_probe(device_t dev)
732 if (!ofw_bus_status_okay(dev))
735 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
738 device_set_desc(dev, "Allwinner Audio Codec");
739 return (BUS_PROBE_DEFAULT);
743 a10codec_attach(device_t dev)
745 struct a10codec_info *sc;
746 char status[SND_STATUSLEN];
747 clk_t clk_apb, clk_codec;
751 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
753 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "a10codec softc");
755 if (bus_alloc_resources(dev, a10codec_spec, sc->res)) {
756 device_printf(dev, "cannot allocate resources for device\n");
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;
767 device_printf(dev, "DRQ types not known for this SoC\n");
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 */
784 device_printf(dev, "cannot create DMA tag\n");
789 error = clk_get_by_ofw_name(dev, 0, "apb", &clk_apb);
791 device_printf(dev, "cannot find apb clock\n");
794 error = clk_get_by_ofw_name(dev, 0, "codec", &clk_codec);
796 device_printf(dev, "cannot find codec clock\n");
800 /* Gating APB clock for codec */
801 error = clk_enable(clk_apb);
803 device_printf(dev, "cannot enable apb clock\n");
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.
815 error = clk_set_freq(clk_codec, 24576000, CLK_SET_ROUND_DOWN);
817 device_printf(dev, "cannot set codec clock frequency\n");
820 /* Enable audio codec clock */
821 error = clk_enable(clk_codec);
823 device_printf(dev, "cannot enable codec clock\n");
828 val = CODEC_READ(sc, AC_DAC_DPC);
829 val |= DAC_DPC_EN_DA;
830 CODEC_WRITE(sc, AC_DAC_DPC, val);
833 error = snd_setup_intr(dev, sc->irq, INTR_MPSAFE, a10codec_intr, sc,
836 device_printf(dev, "could not setup interrupt handler\n");
841 if (mixer_init(dev, &a10codec_mixer_class, sc)) {
842 device_printf(dev, "mixer_init failed\n");
846 pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
848 if (pcm_register(dev, sc, 1, 1)) {
849 device_printf(dev, "pcm_register failed\n");
853 pcm_addchan(dev, PCMDIR_PLAY, &a10codec_chan_class, sc);
854 pcm_addchan(dev, PCMDIR_REC, &a10codec_chan_class, sc);
856 snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
857 pcm_setstatus(dev, status);
862 bus_release_resources(dev, a10codec_spec, sc->res);
863 snd_mtxfree(sc->lock);
869 static device_method_t a10codec_pcm_methods[] = {
870 /* Device interface */
871 DEVMETHOD(device_probe, a10codec_probe),
872 DEVMETHOD(device_attach, a10codec_attach),
877 static driver_t a10codec_pcm_driver = {
879 a10codec_pcm_methods,
883 DRIVER_MODULE(a10codec, simplebus, a10codec_pcm_driver, pcm_devclass, 0, 0);
884 MODULE_DEPEND(a10codec, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
885 MODULE_VERSION(a10codec, 1);