1 /* $NetBSD: sunxi_i2s.c,v 1.2 2018/05/16 10:15:20 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 Jared McNeill <jmcneill@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 2018/05/16 10:15:20 jmcneill 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