sunxi_i2s.c revision 1.2.2.2 1 /* $NetBSD: sunxi_i2s.c,v 1.2.2.2 2018/05/21 04:35:59 pgoyette Exp $ */
2
3 /*-
4 * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: sunxi_i2s.c,v 1.2.2.2 2018/05/21 04:35:59 pgoyette Exp $");
31
32 #include <sys/param.h>
33 #include <sys/bus.h>
34 #include <sys/cpu.h>
35 #include <sys/device.h>
36 #include <sys/kmem.h>
37 #include <sys/gpio.h>
38
39 #include <sys/audioio.h>
40 #include <dev/audio_if.h>
41 #include <dev/auconv.h>
42
43 #include <dev/fdt/fdtvar.h>
44
45 #define SUNXI_I2S_CLK_RATE 24576000
46
47 #define DA_CTL 0x00
48 #define DA_CTL_SDO_EN __BIT(8)
49 #define DA_CTL_MS __BIT(5)
50 #define DA_CTL_PCM __BIT(4)
51 #define DA_CTL_TXEN __BIT(2)
52 #define DA_CTL_RXEN __BIT(1)
53 #define DA_CTL_GEN __BIT(0)
54 #define DA_FAT0 0x04
55 #define DA_FAT0_LRCP __BIT(7)
56 #define DA_LRCP_NORMAL 0
57 #define DA_LRCP_INVERTED 1
58 #define DA_FAT0_BCP __BIT(6)
59 #define DA_BCP_NORMAL 0
60 #define DA_BCP_INVERTED 1
61 #define DA_FAT0_SR __BITS(5,4)
62 #define DA_FAT0_WSS __BITS(3,2)
63 #define DA_FAT0_FMT __BITS(1,0)
64 #define DA_FMT_I2S 0
65 #define DA_FMT_LJ 1
66 #define DA_FMT_RJ 2
67 #define DA_FAT1 0x08
68 #define DA_ISTA 0x0c
69 #define DA_RXFIFO 0x10
70 #define DA_FCTL 0x14
71 #define DA_FCTL_HUB_EN __BIT(31)
72 #define DA_FCTL_FTX __BIT(25)
73 #define DA_FCTL_FRX __BIT(24)
74 #define DA_FSTA 0x18
75 #define DA_INT 0x1c
76 #define DA_INT_TX_DRQ __BIT(7)
77 #define DA_INT_RX_DRQ __BIT(3)
78 #define DA_TXFIFO 0x20
79 #define DA_CLKD 0x24
80 #define DA_CLKD_MCLKO_EN __BIT(7)
81 #define DA_CLKD_BCLKDIV __BITS(6,4)
82 #define DA_CLKD_BCLKDIV_16 5
83 #define DA_CLKD_MCLKDIV __BITS(3,0)
84 #define DA_CLKD_MCLKDIV_1 0
85 #define DA_TXCNT 0x28
86 #define DA_RXCNT 0x2c
87
88 #define DA_CHSEL_EN __BITS(11,4)
89 #define DA_CHSEL_SEL __BITS(2,0)
90
91 struct sunxi_i2s_config {
92 const char *name;
93 bus_size_t txchsel;
94 bus_size_t txchmap;
95 bus_size_t rxchsel;
96 bus_size_t rxchmap;
97 };
98
99 static const struct sunxi_i2s_config sun50i_a64_codec_config = {
100 .name = "Audio Codec (digital part)",
101 .txchsel = 0x30,
102 .txchmap = 0x34,
103 .rxchsel = 0x38,
104 .rxchmap = 0x3c,
105 };
106
107 static const struct of_compat_data compat_data[] = {
108 { "allwinner,sun50i-a64-acodec-i2s",
109 (uintptr_t)&sun50i_a64_codec_config },
110
111 { NULL }
112 };
113
114 struct sunxi_i2s_softc;
115
116 struct sunxi_i2s_chan {
117 struct sunxi_i2s_softc *ch_sc;
118 u_int ch_mode;
119
120 struct fdtbus_dma *ch_dma;
121 struct fdtbus_dma_req ch_req;
122
123 audio_params_t ch_params;
124
125 bus_addr_t ch_start_phys;
126 bus_addr_t ch_end_phys;
127 bus_addr_t ch_cur_phys;
128 int ch_blksize;
129
130 void (*ch_intr)(void *);
131 void *ch_intrarg;
132 };
133
134 struct sunxi_i2s_dma {
135 LIST_ENTRY(sunxi_i2s_dma) dma_list;
136 bus_dmamap_t dma_map;
137 void *dma_addr;
138 size_t dma_size;
139 bus_dma_segment_t dma_segs[1];
140 int dma_nsegs;
141 };
142
143 struct sunxi_i2s_softc {
144 device_t sc_dev;
145 bus_space_tag_t sc_bst;
146 bus_space_handle_t sc_bsh;
147 bus_dma_tag_t sc_dmat;
148 int sc_phandle;
149 bus_addr_t sc_baseaddr;
150
151 struct sunxi_i2s_config *sc_cfg;
152
153 LIST_HEAD(, sunxi_i2s_dma) sc_dmalist;
154
155 kmutex_t sc_lock;
156 kmutex_t sc_intr_lock;
157
158 struct audio_format sc_format;
159 struct audio_encoding_set *sc_encodings;
160
161 struct sunxi_i2s_chan sc_pchan;
162 struct sunxi_i2s_chan sc_rchan;
163
164 struct audio_dai_device sc_dai;
165 };
166
167 #define I2S_READ(sc, reg) \
168 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
169 #define I2S_WRITE(sc, reg, val) \
170 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
171
172 static int
173 sunxi_i2s_allocdma(struct sunxi_i2s_softc *sc, size_t size,
174 size_t align, struct sunxi_i2s_dma *dma)
175 {
176 int error;
177
178 dma->dma_size = size;
179 error = bus_dmamem_alloc(sc->sc_dmat, dma->dma_size, align, 0,
180 dma->dma_segs, 1, &dma->dma_nsegs, BUS_DMA_WAITOK);
181 if (error)
182 return error;
183
184 error = bus_dmamem_map(sc->sc_dmat, dma->dma_segs, dma->dma_nsegs,
185 dma->dma_size, &dma->dma_addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
186 if (error)
187 goto free;
188
189 error = bus_dmamap_create(sc->sc_dmat, dma->dma_size, dma->dma_nsegs,
190 dma->dma_size, 0, BUS_DMA_WAITOK, &dma->dma_map);
191 if (error)
192 goto unmap;
193
194 error = bus_dmamap_load(sc->sc_dmat, dma->dma_map, dma->dma_addr,
195 dma->dma_size, NULL, BUS_DMA_WAITOK);
196 if (error)
197 goto destroy;
198
199 return 0;
200
201 destroy:
202 bus_dmamap_destroy(sc->sc_dmat, dma->dma_map);
203 unmap:
204 bus_dmamem_unmap(sc->sc_dmat, dma->dma_addr, dma->dma_size);
205 free:
206 bus_dmamem_free(sc->sc_dmat, dma->dma_segs, dma->dma_nsegs);
207
208 return error;
209 }
210
211 static void
212 sunxi_i2s_freedma(struct sunxi_i2s_softc *sc, struct sunxi_i2s_dma *dma)
213 {
214 bus_dmamap_unload(sc->sc_dmat, dma->dma_map);
215 bus_dmamap_destroy(sc->sc_dmat, dma->dma_map);
216 bus_dmamem_unmap(sc->sc_dmat, dma->dma_addr, dma->dma_size);
217 bus_dmamem_free(sc->sc_dmat, dma->dma_segs, dma->dma_nsegs);
218 }
219
220 static int
221 sunxi_i2s_transfer(struct sunxi_i2s_chan *ch)
222 {
223 bus_dma_segment_t seg;
224
225 seg.ds_addr = ch->ch_cur_phys;
226 seg.ds_len = ch->ch_blksize;
227 ch->ch_req.dreq_segs = &seg;
228 ch->ch_req.dreq_nsegs = 1;
229
230 return fdtbus_dma_transfer(ch->ch_dma, &ch->ch_req);
231 }
232
233 static int
234 sunxi_i2s_open(void *priv, int flags)
235 {
236 return 0;
237 }
238
239 static void
240 sunxi_i2s_close(void *priv)
241 {
242 }
243
244 static int
245 sunxi_i2s_query_encoding(void *priv, struct audio_encoding *ae)
246 {
247 struct sunxi_i2s_softc * const sc = priv;
248
249 return auconv_query_encoding(sc->sc_encodings, ae);
250 }
251
252 static int
253 sunxi_i2s_set_params(void *priv, int setmode, int usemode,
254 audio_params_t *play, audio_params_t *rec,
255 stream_filter_list_t *pfil, stream_filter_list_t *rfil)
256 {
257 struct sunxi_i2s_softc * const sc = priv;
258 int index;
259
260 if (play && (setmode & AUMODE_PLAY)) {
261 index = auconv_set_converter(&sc->sc_format, 1,
262 AUMODE_PLAY, play, true, pfil);
263 if (index < 0)
264 return EINVAL;
265 sc->sc_pchan.ch_params = pfil->req_size > 0 ?
266 pfil->filters[0].param : *play;
267 }
268 if (rec && (setmode & AUMODE_RECORD)) {
269 index = auconv_set_converter(&sc->sc_format, 1,
270 AUMODE_RECORD, rec, true, rfil);
271 if (index < 0)
272 return EINVAL;
273 sc->sc_rchan.ch_params = rfil->req_size > 0 ?
274 rfil->filters[0].param : *rec;
275 }
276
277 return 0;
278 }
279
280 static void *
281 sunxi_i2s_allocm(void *priv, int dir, size_t size)
282 {
283 struct sunxi_i2s_softc * const sc = priv;
284 struct sunxi_i2s_dma *dma;
285 int error;
286
287 dma = kmem_alloc(sizeof(*dma), KM_SLEEP);
288
289 error = sunxi_i2s_allocdma(sc, size, 16, dma);
290 if (error) {
291 kmem_free(dma, sizeof(*dma));
292 device_printf(sc->sc_dev, "couldn't allocate DMA memory (%d)\n",
293 error);
294 return NULL;
295 }
296
297 LIST_INSERT_HEAD(&sc->sc_dmalist, dma, dma_list);
298
299 return dma->dma_addr;
300 }
301
302 static void
303 sunxi_i2s_freem(void *priv, void *addr, size_t size)
304 {
305 struct sunxi_i2s_softc * const sc = priv;
306 struct sunxi_i2s_dma *dma;
307
308 LIST_FOREACH(dma, &sc->sc_dmalist, dma_list)
309 if (dma->dma_addr == addr) {
310 sunxi_i2s_freedma(sc, dma);
311 LIST_REMOVE(dma, dma_list);
312 kmem_free(dma, sizeof(*dma));
313 break;
314 }
315 }
316
317 static paddr_t
318 sunxi_i2s_mappage(void *priv, void *addr, off_t off, int prot)
319 {
320 struct sunxi_i2s_softc * const sc = priv;
321 struct sunxi_i2s_dma *dma;
322
323 if (off < 0)
324 return -1;
325
326 LIST_FOREACH(dma, &sc->sc_dmalist, dma_list)
327 if (dma->dma_addr == addr) {
328 return bus_dmamem_mmap(sc->sc_dmat, dma->dma_segs,
329 dma->dma_nsegs, off, prot, BUS_DMA_WAITOK);
330 }
331
332 return -1;
333 }
334
335 static int
336 sunxi_i2s_get_props(void *priv)
337 {
338 return AUDIO_PROP_PLAYBACK|AUDIO_PROP_CAPTURE|
339 AUDIO_PROP_MMAP|AUDIO_PROP_FULLDUPLEX|AUDIO_PROP_INDEPENDENT;
340 }
341
342 static int
343 sunxi_i2s_round_blocksize(void *priv, int bs, int mode,
344 const audio_params_t *params)
345 {
346 bs &= ~3;
347 if (bs == 0)
348 bs = 4;
349 return bs;
350 }
351
352 static size_t
353 sunxi_i2s_round_buffersize(void *priv, int dir, size_t bufsize)
354 {
355 return bufsize;
356 }
357
358 static int
359 sunxi_i2s_trigger_output(void *priv, void *start, void *end, int blksize,
360 void (*intr)(void *), void *intrarg, const audio_params_t *params)
361 {
362 struct sunxi_i2s_softc * const sc = priv;
363 struct sunxi_i2s_chan *ch = &sc->sc_pchan;
364 struct sunxi_i2s_dma *dma;
365 bus_addr_t pstart;
366 bus_size_t psize;
367 uint32_t val;
368 int error;
369
370 pstart = 0;
371 psize = (uintptr_t)end - (uintptr_t)start;
372
373 LIST_FOREACH(dma, &sc->sc_dmalist, dma_list)
374 if (dma->dma_addr == start) {
375 pstart = dma->dma_map->dm_segs[0].ds_addr;
376 break;
377 }
378 if (pstart == 0) {
379 device_printf(sc->sc_dev, "bad addr %p\n", start);
380 return EINVAL;
381 }
382
383 ch->ch_intr = intr;
384 ch->ch_intrarg = intrarg;
385 ch->ch_start_phys = ch->ch_cur_phys = pstart;
386 ch->ch_end_phys = pstart + psize;
387 ch->ch_blksize = blksize;
388
389 /* Flush FIFO */
390 val = I2S_READ(sc, DA_FCTL);
391 I2S_WRITE(sc, DA_FCTL, val | DA_FCTL_FTX);
392 I2S_WRITE(sc, DA_FCTL, val & ~DA_FCTL_FTX);
393
394 /* Reset TX sample counter */
395 I2S_WRITE(sc, DA_TXCNT, 0);
396
397 /* Enable transmitter block */
398 val = I2S_READ(sc, DA_CTL);
399 I2S_WRITE(sc, DA_CTL, val | DA_CTL_TXEN);
400
401 /* Enable TX DRQ */
402 val = I2S_READ(sc, DA_INT);
403 I2S_WRITE(sc, DA_INT, val | DA_INT_TX_DRQ);
404
405 /* Start DMA transfer */
406 error = sunxi_i2s_transfer(ch);
407 if (error != 0) {
408 aprint_error_dev(sc->sc_dev,
409 "failed to start DMA transfer: %d\n", error);
410 return error;
411 }
412
413 return 0;
414 }
415
416 static int
417 sunxi_i2s_trigger_input(void *priv, void *start, void *end, int blksize,
418 void (*intr)(void *), void *intrarg, const audio_params_t *params)
419 {
420 struct sunxi_i2s_softc * const sc = priv;
421 struct sunxi_i2s_chan *ch = &sc->sc_rchan;
422 struct sunxi_i2s_dma *dma;
423 bus_addr_t pstart;
424 bus_size_t psize;
425 uint32_t val;
426 int error;
427
428 pstart = 0;
429 psize = (uintptr_t)end - (uintptr_t)start;
430
431 LIST_FOREACH(dma, &sc->sc_dmalist, dma_list)
432 if (dma->dma_addr == start) {
433 pstart = dma->dma_map->dm_segs[0].ds_addr;
434 break;
435 }
436 if (pstart == 0) {
437 device_printf(sc->sc_dev, "bad addr %p\n", start);
438 return EINVAL;
439 }
440
441 ch->ch_intr = intr;
442 ch->ch_intrarg = intrarg;
443 ch->ch_start_phys = ch->ch_cur_phys = pstart;
444 ch->ch_end_phys = pstart + psize;
445 ch->ch_blksize = blksize;
446
447 /* Flush FIFO */
448 val = I2S_READ(sc, DA_FCTL);
449 I2S_WRITE(sc, DA_FCTL, val | DA_FCTL_FRX);
450 I2S_WRITE(sc, DA_FCTL, val & ~DA_FCTL_FRX);
451
452 /* Reset RX sample counter */
453 I2S_WRITE(sc, DA_RXCNT, 0);
454
455 /* Enable receiver block */
456 val = I2S_READ(sc, DA_CTL);
457 I2S_WRITE(sc, DA_CTL, val | DA_CTL_RXEN);
458
459 /* Enable RX DRQ */
460 val = I2S_READ(sc, DA_INT);
461 I2S_WRITE(sc, DA_INT, val | DA_INT_RX_DRQ);
462
463 /* Start DMA transfer */
464 error = sunxi_i2s_transfer(ch);
465 if (error != 0) {
466 aprint_error_dev(sc->sc_dev,
467 "failed to start DMA transfer: %d\n", error);
468 return error;
469 }
470
471 return 0;
472 }
473
474 static int
475 sunxi_i2s_halt_output(void *priv)
476 {
477 struct sunxi_i2s_softc * const sc = priv;
478 struct sunxi_i2s_chan *ch = &sc->sc_pchan;
479 uint32_t val;
480
481 /* Disable DMA channel */
482 fdtbus_dma_halt(ch->ch_dma);
483
484 /* Disable transmitter block */
485 val = I2S_READ(sc, DA_CTL);
486 I2S_WRITE(sc, DA_CTL, val & ~DA_CTL_TXEN);
487
488 /* Disable TX DRQ */
489 val = I2S_READ(sc, DA_INT);
490 I2S_WRITE(sc, DA_INT, val & ~DA_INT_TX_DRQ);
491
492 ch->ch_intr = NULL;
493 ch->ch_intrarg = NULL;
494
495 return 0;
496 }
497
498 static int
499 sunxi_i2s_halt_input(void *priv)
500 {
501 struct sunxi_i2s_softc * const sc = priv;
502 struct sunxi_i2s_chan *ch = &sc->sc_rchan;
503 uint32_t val;
504
505 /* Disable DMA channel */
506 fdtbus_dma_halt(ch->ch_dma);
507
508 /* Disable receiver block */
509 val = I2S_READ(sc, DA_CTL);
510 I2S_WRITE(sc, DA_CTL, val & ~DA_CTL_RXEN);
511
512 /* Disable RX DRQ */
513 val = I2S_READ(sc, DA_INT);
514 I2S_WRITE(sc, DA_INT, val & ~DA_INT_RX_DRQ);
515
516 return 0;
517 }
518
519 static void
520 sunxi_i2s_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread)
521 {
522 struct sunxi_i2s_softc * const sc = priv;
523
524 *intr = &sc->sc_intr_lock;
525 *thread = &sc->sc_lock;
526 }
527
528 static const struct audio_hw_if sunxi_i2s_hw_if = {
529 .open = sunxi_i2s_open,
530 .close = sunxi_i2s_close,
531 .drain = NULL,
532 .query_encoding = sunxi_i2s_query_encoding,
533 .set_params = sunxi_i2s_set_params,
534 .allocm = sunxi_i2s_allocm,
535 .freem = sunxi_i2s_freem,
536 .mappage = sunxi_i2s_mappage,
537 .get_props = sunxi_i2s_get_props,
538 .round_blocksize = sunxi_i2s_round_blocksize,
539 .round_buffersize = sunxi_i2s_round_buffersize,
540 .trigger_output = sunxi_i2s_trigger_output,
541 .trigger_input = sunxi_i2s_trigger_input,
542 .halt_output = sunxi_i2s_halt_output,
543 .halt_input = sunxi_i2s_halt_input,
544 .get_locks = sunxi_i2s_get_locks,
545 };
546
547 static void
548 sunxi_i2s_dmaintr(void *priv)
549 {
550 struct sunxi_i2s_chan * const ch = priv;
551 struct sunxi_i2s_softc * const sc = ch->ch_sc;
552
553 mutex_enter(&sc->sc_intr_lock);
554 ch->ch_cur_phys += ch->ch_blksize;
555 if (ch->ch_cur_phys >= ch->ch_end_phys)
556 ch->ch_cur_phys = ch->ch_start_phys;
557
558 if (ch->ch_intr) {
559 ch->ch_intr(ch->ch_intrarg);
560 sunxi_i2s_transfer(ch);
561 }
562 mutex_exit(&sc->sc_intr_lock);
563 }
564
565 static int
566 sunxi_i2s_chan_init(struct sunxi_i2s_softc *sc,
567 struct sunxi_i2s_chan *ch, u_int mode, const char *dmaname)
568 {
569 ch->ch_sc = sc;
570 ch->ch_mode = mode;
571 ch->ch_dma = fdtbus_dma_get(sc->sc_phandle, dmaname, sunxi_i2s_dmaintr, ch);
572 if (ch->ch_dma == NULL) {
573 aprint_error(": couldn't get dma channel \"%s\"\n", dmaname);
574 return ENXIO;
575 }
576
577 if (mode == AUMODE_PLAY) {
578 ch->ch_req.dreq_dir = FDT_DMA_WRITE;
579 ch->ch_req.dreq_dev_phys =
580 sc->sc_baseaddr + DA_TXFIFO;
581 } else {
582 ch->ch_req.dreq_dir = FDT_DMA_READ;
583 ch->ch_req.dreq_dev_phys =
584 sc->sc_baseaddr + DA_RXFIFO;
585 }
586 ch->ch_req.dreq_mem_opt.opt_bus_width = 32;
587 ch->ch_req.dreq_mem_opt.opt_burst_len = 8;
588 ch->ch_req.dreq_dev_opt.opt_bus_width = 32;
589 ch->ch_req.dreq_dev_opt.opt_burst_len = 8;
590
591 return 0;
592 }
593
594 static int
595 sunxi_i2s_dai_set_sysclk(audio_dai_tag_t dai, u_int rate, int dir)
596 {
597 struct sunxi_i2s_softc * const sc = audio_dai_private(dai);
598 uint32_t val;
599
600 /* XXX */
601
602 val = DA_CLKD_MCLKO_EN;
603 val |= __SHIFTIN(DA_CLKD_BCLKDIV_16, DA_CLKD_BCLKDIV);
604 val |= __SHIFTIN(DA_CLKD_MCLKDIV_1, DA_CLKD_MCLKDIV);
605
606 I2S_WRITE(sc, DA_CLKD, val);
607
608 return 0;
609 }
610
611 static int
612 sunxi_i2s_dai_set_format(audio_dai_tag_t dai, u_int format)
613 {
614 struct sunxi_i2s_softc * const sc = audio_dai_private(dai);
615 uint32_t ctl, fat0;
616
617 const u_int fmt = __SHIFTOUT(format, AUDIO_DAI_FORMAT_MASK);
618 const u_int pol = __SHIFTOUT(format, AUDIO_DAI_POLARITY_MASK);
619 const u_int clk = __SHIFTOUT(format, AUDIO_DAI_CLOCK_MASK);
620
621 ctl = I2S_READ(sc, DA_CTL);
622 fat0 = I2S_READ(sc, DA_FAT0);
623
624 fat0 &= ~DA_FAT0_FMT;
625 switch (fmt) {
626 case AUDIO_DAI_FORMAT_I2S:
627 fat0 |= __SHIFTIN(DA_FMT_I2S, DA_FAT0_FMT);
628 break;
629 case AUDIO_DAI_FORMAT_RJ:
630 fat0 |= __SHIFTIN(DA_FMT_RJ, DA_FAT0_FMT);
631 break;
632 case AUDIO_DAI_FORMAT_LJ:
633 fat0 |= __SHIFTIN(DA_FMT_LJ, DA_FAT0_FMT);
634 break;
635 default:
636 return EINVAL;
637 }
638
639 fat0 &= ~(DA_FAT0_LRCP|DA_FAT0_BCP);
640 if (AUDIO_DAI_POLARITY_B(pol))
641 fat0 |= __SHIFTIN(DA_BCP_INVERTED, DA_FAT0_BCP);
642 if (AUDIO_DAI_POLARITY_F(pol))
643 fat0 |= __SHIFTIN(DA_LRCP_INVERTED, DA_FAT0_LRCP);
644
645 switch (clk) {
646 case AUDIO_DAI_CLOCK_CBM_CFM:
647 ctl |= DA_CTL_MS; /* codec is master */
648 break;
649 case AUDIO_DAI_CLOCK_CBS_CFS:
650 ctl &= ~DA_CTL_MS; /* codec is slave */
651 break;
652 default:
653 return EINVAL;
654 }
655
656 ctl &= ~DA_CTL_PCM;
657
658 I2S_WRITE(sc, DA_CTL, ctl);
659 I2S_WRITE(sc, DA_FAT0, fat0);
660
661 return 0;
662 }
663
664 static audio_dai_tag_t
665 sunxi_i2s_dai_get_tag(device_t dev, const void *data, size_t len)
666 {
667 struct sunxi_i2s_softc * const sc = device_private(dev);
668
669 if (len != 4)
670 return NULL;
671
672 return &sc->sc_dai;
673 }
674
675 static struct fdtbus_dai_controller_func sunxi_i2s_dai_funcs = {
676 .get_tag = sunxi_i2s_dai_get_tag
677 };
678
679 static int
680 sunxi_i2s_clock_init(int phandle)
681 {
682 struct fdtbus_reset *rst;
683 struct clk *clk;
684 int error;
685
686 /* Set module clock to 24.576MHz, suitable for 48 kHz sampling rates */
687 clk = fdtbus_clock_get(phandle, "mod");
688 if (clk == NULL) {
689 aprint_error(": couldn't find mod clock\n");
690 return ENXIO;
691 }
692 error = clk_set_rate(clk, SUNXI_I2S_CLK_RATE);
693 if (error != 0) {
694 aprint_error(": couldn't set mod clock rate: %d\n", error);
695 return error;
696 }
697 error = clk_enable(clk);
698 if (error != 0) {
699 aprint_error(": couldn't enable mod clock: %d\n", error);
700 return error;
701 }
702
703 /* Enable APB clock */
704 clk = fdtbus_clock_get(phandle, "apb");
705 if (clk == NULL) {
706 aprint_error(": couldn't find apb clock\n");
707 return ENXIO;
708 }
709 error = clk_enable(clk);
710 if (error != 0) {
711 aprint_error(": couldn't enable apb clock: %d\n", error);
712 return error;
713 }
714
715 /* De-assert reset */
716 rst = fdtbus_reset_get(phandle, "rst");
717 if (rst == NULL) {
718 aprint_error(": couldn't find reset\n");
719 return ENXIO;
720 }
721 error = fdtbus_reset_deassert(rst);
722 if (error != 0) {
723 aprint_error(": couldn't de-assert reset: %d\n", error);
724 return error;
725 }
726
727 return 0;
728 }
729
730 static int
731 sunxi_i2s_match(device_t parent, cfdata_t cf, void *aux)
732 {
733 struct fdt_attach_args * const faa = aux;
734
735 return of_match_compat_data(faa->faa_phandle, compat_data);
736 }
737
738 static void
739 sunxi_i2s_attach(device_t parent, device_t self, void *aux)
740 {
741 struct sunxi_i2s_softc * const sc = device_private(self);
742 struct fdt_attach_args * const faa = aux;
743 const int phandle = faa->faa_phandle;
744 bus_addr_t addr;
745 bus_size_t size;
746 uint32_t val;
747 int error;
748
749 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
750 aprint_error(": couldn't get registers\n");
751 return;
752 }
753
754 if (sunxi_i2s_clock_init(phandle) != 0)
755 return;
756
757 sc->sc_dev = self;
758 sc->sc_phandle = phandle;
759 sc->sc_baseaddr = addr;
760 sc->sc_bst = faa->faa_bst;
761 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
762 aprint_error(": couldn't map registers\n");
763 return;
764 }
765 sc->sc_dmat = faa->faa_dmat;
766 LIST_INIT(&sc->sc_dmalist);
767 sc->sc_cfg = (void *)of_search_compatible(phandle, compat_data)->data;
768 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
769 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
770
771 if (sunxi_i2s_chan_init(sc, &sc->sc_pchan, AUMODE_PLAY, "tx") != 0 ||
772 sunxi_i2s_chan_init(sc, &sc->sc_rchan, AUMODE_RECORD, "rx") != 0) {
773 aprint_error(": couldn't setup channels\n");
774 return;
775 }
776
777 aprint_naive("\n");
778 aprint_normal(": %s\n", sc->sc_cfg->name);
779
780 /* Reset */
781 val = I2S_READ(sc, DA_CTL);
782 val &= ~(DA_CTL_TXEN|DA_CTL_RXEN|DA_CTL_GEN);
783 I2S_WRITE(sc, DA_CTL, val);
784
785 val = I2S_READ(sc, DA_FCTL);
786 val &= ~(DA_FCTL_FTX|DA_FCTL_FRX);
787 I2S_WRITE(sc, DA_FCTL, val);
788
789 I2S_WRITE(sc, DA_TXCNT, 0);
790 I2S_WRITE(sc, DA_RXCNT, 0);
791
792 /* Enable */
793 I2S_WRITE(sc, DA_CTL, DA_CTL_GEN | DA_CTL_SDO_EN);
794
795 /* Setup channels */
796 I2S_WRITE(sc, sc->sc_cfg->txchmap, 0x76543210);
797 I2S_WRITE(sc, sc->sc_cfg->txchsel, __SHIFTIN(1, DA_CHSEL_SEL) |
798 __SHIFTIN(3, DA_CHSEL_EN));
799 I2S_WRITE(sc, sc->sc_cfg->rxchmap, 0x76543210);
800 I2S_WRITE(sc, sc->sc_cfg->rxchsel, __SHIFTIN(1, DA_CHSEL_SEL) |
801 __SHIFTIN(3, DA_CHSEL_EN));
802
803 sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD;
804 sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE;
805 sc->sc_format.validbits = 16;
806 sc->sc_format.precision = 16;
807 sc->sc_format.channels = 2;
808 sc->sc_format.channel_mask = AUFMT_STEREO;
809 sc->sc_format.frequency_type = 0;
810 sc->sc_format.frequency[0] = sc->sc_format.frequency[1] = 48000;
811
812 error = auconv_create_encodings(&sc->sc_format, 1, &sc->sc_encodings);
813 if (error) {
814 aprint_error_dev(self, "couldn't create encodings\n");
815 return;
816 }
817
818 sc->sc_dai.dai_set_sysclk = sunxi_i2s_dai_set_sysclk;
819 sc->sc_dai.dai_set_format = sunxi_i2s_dai_set_format;
820 sc->sc_dai.dai_hw_if = &sunxi_i2s_hw_if;
821 sc->sc_dai.dai_dev = self;
822 sc->sc_dai.dai_priv = sc;
823 fdtbus_register_dai_controller(self, phandle, &sunxi_i2s_dai_funcs);
824 }
825
826 CFATTACH_DECL_NEW(sunxi_i2s, sizeof(struct sunxi_i2s_softc),
827 sunxi_i2s_match, sunxi_i2s_attach, NULL, NULL);
828