1 /* $NetBSD: pxa2x0_i2s.c,v 1.8 2009/03/13 13:55:18 nonaka Exp $ */ 2 /* $OpenBSD: pxa2x0_i2s.c,v 1.7 2006/04/04 11:45:40 pascoe Exp $ */ 3 4 /* 5 * Copyright (c) 2005 Christopher Pascoe <pascoe@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/cdefs.h> 21 __KERNEL_RCSID(0, "$NetBSD: pxa2x0_i2s.c,v 1.8 2009/03/13 13:55:18 nonaka Exp $"); 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 #include <sys/malloc.h> 27 28 #include <machine/bus.h> 29 30 #include <arm/xscale/pxa2x0reg.h> 31 #include <arm/xscale/pxa2x0var.h> 32 #include <arm/xscale/pxa2x0_gpio.h> 33 #include <arm/xscale/pxa2x0_i2s.h> 34 #include <arm/xscale/pxa2x0_dmac.h> 35 36 struct pxa2x0_i2s_dma { 37 struct pxa2x0_i2s_dma *next; 38 void *addr; 39 size_t size; 40 bus_dmamap_t map; 41 #define I2S_N_SEGS 1 42 bus_dma_segment_t segs[I2S_N_SEGS]; 43 int nsegs; 44 struct dmac_xfer *dx; 45 }; 46 47 static void pxa2x0_i2s_dmac_ointr(struct dmac_xfer *, int); 48 static void pxa2x0_i2s_dmac_iintr(struct dmac_xfer *, int); 49 50 void 51 pxa2x0_i2s_init(struct pxa2x0_i2s_softc *sc) 52 { 53 54 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0, SACR0_RST); 55 delay(100); 56 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0, 57 SACR0_BCKD | SACR0_SET_TFTH(7) | SACR0_SET_RFTH(7)); 58 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR1, 0); 59 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADR, 0); 60 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv); 61 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SACR0, 62 SACR0_BCKD | SACR0_SET_TFTH(7) | SACR0_SET_RFTH(7) | SACR0_ENB); 63 } 64 65 int 66 pxa2x0_i2s_attach_sub(struct pxa2x0_i2s_softc *sc) 67 { 68 int rv; 69 70 rv = bus_space_map(sc->sc_iot, PXA2X0_I2S_BASE, PXA2X0_I2S_SIZE, 0, 71 &sc->sc_ioh); 72 if (rv) { 73 sc->sc_size = 0; 74 return 1; 75 } 76 77 sc->sc_dr.ds_addr = PXA2X0_I2S_BASE + I2S_SADR; 78 sc->sc_dr.ds_len = 4; 79 80 sc->sc_sadiv = SADIV_3_058MHz; 81 82 bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_size, 83 BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 84 85 pxa2x0_i2s_init(sc); 86 87 return 0; 88 } 89 90 void 91 pxa2x0_i2s_open(struct pxa2x0_i2s_softc *sc) 92 { 93 94 if (sc->sc_open++ == 0) { 95 pxa2x0_clkman_config(CKEN_I2S, 1); 96 } 97 } 98 99 void 100 pxa2x0_i2s_close(struct pxa2x0_i2s_softc *sc) 101 { 102 103 if (--sc->sc_open == 0) { 104 pxa2x0_clkman_config(CKEN_I2S, 0); 105 } 106 } 107 108 int 109 pxa2x0_i2s_detach_sub(struct pxa2x0_i2s_softc *sc) 110 { 111 112 if (sc->sc_size > 0) { 113 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); 114 sc->sc_size = 0; 115 } 116 pxa2x0_clkman_config(CKEN_I2S, 0); 117 118 return 0; 119 } 120 121 void 122 pxa2x0_i2s_write(struct pxa2x0_i2s_softc *sc, uint32_t data) 123 { 124 125 if (sc->sc_open == 0) 126 return; 127 128 /* Clear intr and underrun bit if set. */ 129 if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, I2S_SASR0) & SASR0_TUR) 130 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SAICR, SAICR_TUR); 131 132 /* Wait for transmit fifo to have space. */ 133 while ((bus_space_read_4(sc->sc_iot, sc->sc_ioh, I2S_SASR0) & SASR0_TNF) 134 == 0) 135 continue; /* nothing */ 136 137 /* Queue data */ 138 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADR, data); 139 } 140 141 void 142 pxa2x0_i2s_setspeed(struct pxa2x0_i2s_softc *sc, u_int *argp) 143 { 144 /* 145 * The available speeds are in the following table. 146 * Keep the speeds in increasing order. 147 */ 148 static const struct speed_struct { 149 int speed; 150 int div; 151 } speed_table[] = { 152 {8000, SADIV_513_25kHz}, 153 {11025, SADIV_702_75kHz}, 154 {16000, SADIV_1_026MHz}, 155 {22050, SADIV_1_405MHz}, 156 {44100, SADIV_2_836MHz}, 157 {48000, SADIV_3_058MHz}, 158 }; 159 const int n = (int)__arraycount(speed_table); 160 u_int arg = (u_int)*argp; 161 int selected = -1; 162 int i; 163 164 if (arg < speed_table[0].speed) 165 selected = 0; 166 if (arg > speed_table[n - 1].speed) 167 selected = n - 1; 168 169 for (i = 1; selected == -1 && i < n; i++) { 170 if (speed_table[i].speed == arg) 171 selected = i; 172 else if (speed_table[i].speed > arg) { 173 int diff1, diff2; 174 175 diff1 = arg - speed_table[i - 1].speed; 176 diff2 = speed_table[i].speed - arg; 177 if (diff1 < diff2) 178 selected = i - 1; 179 else 180 selected = i; 181 } 182 } 183 184 if (selected == -1) 185 selected = 0; 186 187 *argp = speed_table[selected].speed; 188 189 sc->sc_sadiv = speed_table[selected].div; 190 bus_space_write_4(sc->sc_iot, sc->sc_ioh, I2S_SADIV, sc->sc_sadiv); 191 } 192 193 void * 194 pxa2x0_i2s_allocm(void *hdl, int direction, size_t size, 195 struct malloc_type *type, int flags) 196 { 197 struct pxa2x0_i2s_softc *sc = hdl; 198 struct pxa2x0_i2s_dma *p; 199 struct dmac_xfer *dx; 200 int error; 201 202 p = malloc(sizeof(*p), type, flags); 203 if (p == NULL) 204 return NULL; 205 206 dx = pxa2x0_dmac_allocate_xfer(M_NOWAIT); 207 if (dx == NULL) { 208 goto fail_alloc; 209 } 210 p->dx = dx; 211 212 p->size = size; 213 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, p->segs, 214 I2S_N_SEGS, &p->nsegs, BUS_DMA_NOWAIT)) != 0) { 215 goto fail_xfer; 216 } 217 218 if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, size, 219 &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { 220 goto fail_map; 221 } 222 223 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 224 BUS_DMA_NOWAIT, &p->map)) != 0) { 225 goto fail_create; 226 } 227 228 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL, 229 BUS_DMA_NOWAIT)) != 0) { 230 goto fail_load; 231 } 232 233 dx->dx_cookie = sc; 234 dx->dx_priority = DMAC_PRIORITY_NORMAL; 235 dx->dx_dev_width = DMAC_DEV_WIDTH_4; 236 dx->dx_burst_size = DMAC_BURST_SIZE_32; 237 238 p->next = sc->sc_dmas; 239 sc->sc_dmas = p; 240 241 return p->addr; 242 243 fail_load: 244 bus_dmamap_destroy(sc->sc_dmat, p->map); 245 fail_create: 246 bus_dmamem_unmap(sc->sc_dmat, p->addr, size); 247 fail_map: 248 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 249 fail_xfer: 250 pxa2x0_dmac_free_xfer(dx); 251 fail_alloc: 252 free(p, type); 253 return NULL; 254 } 255 256 void 257 pxa2x0_i2s_freem(void *hdl, void *ptr, struct malloc_type *type) 258 { 259 struct pxa2x0_i2s_softc *sc = hdl; 260 struct pxa2x0_i2s_dma **pp, *p; 261 262 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) { 263 if (p->addr == ptr) { 264 pxa2x0_dmac_abort_xfer(p->dx); 265 pxa2x0_dmac_free_xfer(p->dx); 266 p->segs[0].ds_len = p->size; /* XXX */ 267 bus_dmamap_unload(sc->sc_dmat, p->map); 268 bus_dmamap_destroy(sc->sc_dmat, p->map); 269 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size); 270 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs); 271 272 *pp = p->next; 273 free(p, type); 274 return; 275 } 276 } 277 panic("pxa2x0_i2s_freem: trying to free unallocated memory"); 278 } 279 280 paddr_t 281 pxa2x0_i2s_mappage(void *hdl, void *mem, off_t off, int prot) 282 { 283 struct pxa2x0_i2s_softc *sc = hdl; 284 struct pxa2x0_i2s_dma *p; 285 286 if (off < 0) 287 return -1; 288 289 for (p = sc->sc_dmas; p && p->addr != mem; p = p->next) 290 continue; 291 if (p == NULL) 292 return -1; 293 294 if (off > p->size) 295 return -1; 296 297 return bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs, off, prot, 298 BUS_DMA_WAITOK); 299 } 300 301 int 302 pxa2x0_i2s_round_blocksize(void *hdl, int bs, int mode, 303 const struct audio_params *param) 304 { 305 306 /* Enforce individual DMA block size limit */ 307 if (bs > DCMD_LENGTH_MASK) 308 return (DCMD_LENGTH_MASK & ~0x07); 309 310 return (bs + 0x07) & ~0x07; /* XXX: 64-bit multiples */ 311 } 312 313 size_t 314 pxa2x0_i2s_round_buffersize(void *hdl, int direction, size_t bufsize) 315 { 316 317 return bufsize; 318 } 319 320 int 321 pxa2x0_i2s_halt_output(void *hdl) 322 { 323 struct pxa2x0_i2s_softc *sc = hdl; 324 int s; 325 326 s = splaudio(); 327 if (sc->sc_txdma) { 328 pxa2x0_dmac_abort_xfer(sc->sc_txdma->dx); 329 sc->sc_txdma = NULL; 330 } 331 splx(s); 332 333 return 0; 334 } 335 336 int 337 pxa2x0_i2s_halt_input(void *hdl) 338 { 339 struct pxa2x0_i2s_softc *sc = hdl; 340 int s; 341 342 s = splaudio(); 343 if (sc->sc_rxdma) { 344 pxa2x0_dmac_abort_xfer(sc->sc_rxdma->dx); 345 sc->sc_rxdma = NULL; 346 } 347 splx(s); 348 349 return 0; 350 } 351 352 int 353 pxa2x0_i2s_start_output(void *hdl, void *block, int bsize, 354 void (*tx_func)(void *), void *tx_arg) 355 { 356 struct pxa2x0_i2s_softc *sc = hdl; 357 struct pxa2x0_i2s_dma *p; 358 struct dmac_xfer *dx; 359 360 if (sc->sc_txdma) 361 return EBUSY; 362 363 /* Find mapping which contains block completely */ 364 for (p = sc->sc_dmas; 365 p != NULL && 366 (((char*)block < (char *)p->addr) || 367 ((char *)block + bsize > (char *)p->addr + p->size)); 368 p = p->next) { 369 continue; /* Nothing */ 370 } 371 if (p == NULL) { 372 aprint_error("pxa2x0_i2s_start_output: " 373 "request with bad start address: %p, size: %d)\n", 374 block, bsize); 375 return ENXIO; 376 } 377 sc->sc_txdma = p; 378 379 p->segs[0].ds_addr = p->map->dm_segs[0].ds_addr + 380 ((char *)block - (char *)p->addr); 381 p->segs[0].ds_len = bsize; 382 383 dx = p->dx; 384 dx->dx_done = pxa2x0_i2s_dmac_ointr; 385 dx->dx_peripheral = DMAC_PERIPH_I2STX; 386 dx->dx_flow = DMAC_FLOW_CTRL_DEST; 387 dx->dx_loop_notify = DMAC_DONT_LOOP; 388 dx->dx_desc[DMAC_DESC_SRC].xd_addr_hold = false; 389 dx->dx_desc[DMAC_DESC_SRC].xd_nsegs = p->nsegs; 390 dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs = p->segs; 391 dx->dx_desc[DMAC_DESC_DST].xd_addr_hold = true; 392 dx->dx_desc[DMAC_DESC_DST].xd_nsegs = 1; 393 dx->dx_desc[DMAC_DESC_DST].xd_dma_segs = &sc->sc_dr; 394 395 sc->sc_txfunc = tx_func; 396 sc->sc_txarg = tx_arg; 397 398 /* Start DMA */ 399 return pxa2x0_dmac_start_xfer(dx); 400 } 401 402 int 403 pxa2x0_i2s_start_input(void *hdl, void *block, int bsize, 404 void (*rx_func)(void *), void *rx_arg) 405 { 406 struct pxa2x0_i2s_softc *sc = hdl; 407 struct pxa2x0_i2s_dma *p; 408 struct dmac_xfer *dx; 409 410 if (sc->sc_rxdma) 411 return EBUSY; 412 413 /* Find mapping which contains block completely */ 414 for (p = sc->sc_dmas; 415 p != NULL && 416 (((char*)block < (char *)p->addr) || 417 ((char *)block + bsize > (char *)p->addr + p->size)); 418 p = p->next) { 419 continue; /* Nothing */ 420 } 421 if (p == NULL) { 422 aprint_error("pxa2x0_i2s_start_input: " 423 "request with bad start address: %p, size: %d)\n", 424 block, bsize); 425 return ENXIO; 426 } 427 sc->sc_rxdma = p; 428 429 p->segs[0].ds_addr = p->map->dm_segs[0].ds_addr + 430 ((char *)block - (char *)p->addr); 431 p->segs[0].ds_len = bsize; 432 433 dx = p->dx; 434 dx->dx_done = pxa2x0_i2s_dmac_iintr; 435 dx->dx_peripheral = DMAC_PERIPH_I2SRX; 436 dx->dx_flow = DMAC_FLOW_CTRL_SRC; 437 dx->dx_loop_notify = DMAC_DONT_LOOP; 438 dx->dx_desc[DMAC_DESC_SRC].xd_addr_hold = true; 439 dx->dx_desc[DMAC_DESC_SRC].xd_nsegs = 1; 440 dx->dx_desc[DMAC_DESC_SRC].xd_dma_segs = &sc->sc_dr; 441 dx->dx_desc[DMAC_DESC_DST].xd_addr_hold = false; 442 dx->dx_desc[DMAC_DESC_DST].xd_nsegs = p->nsegs; 443 dx->dx_desc[DMAC_DESC_DST].xd_dma_segs = p->segs; 444 445 sc->sc_rxfunc = rx_func; 446 sc->sc_rxarg = rx_arg; 447 448 /* Start DMA */ 449 return pxa2x0_dmac_start_xfer(dx); 450 } 451 452 static void 453 pxa2x0_i2s_dmac_ointr(struct dmac_xfer *dx, int status) 454 { 455 struct pxa2x0_i2s_softc *sc = dx->dx_cookie; 456 int s; 457 458 if (sc->sc_txdma == NULL) { 459 panic("pxa2x_i2s_dmac_ointr: bad TX DMA descriptor!"); 460 } 461 if (sc->sc_txdma->dx != dx) { 462 panic("pxa2x_i2s_dmac_ointr: xfer mismatch!"); 463 } 464 sc->sc_txdma = NULL; 465 466 if (status) { 467 aprint_error("pxa2x0_i2s_dmac_ointr: " 468 "non-zero completion status %d\n", status); 469 } 470 471 s = splaudio(); 472 (sc->sc_txfunc)(sc->sc_txarg); 473 splx(s); 474 } 475 476 static void 477 pxa2x0_i2s_dmac_iintr(struct dmac_xfer *dx, int status) 478 { 479 struct pxa2x0_i2s_softc *sc = dx->dx_cookie; 480 int s; 481 482 if (sc->sc_rxdma == NULL) { 483 panic("pxa2x_i2s_dmac_iintr: bad RX DMA descriptor!"); 484 } 485 if (sc->sc_rxdma->dx != dx) { 486 panic("pxa2x_i2s_dmac_iintr: xfer mismatch!"); 487 } 488 sc->sc_rxdma = NULL; 489 490 if (status) { 491 aprint_error("pxa2x0_i2s_dmac_iintr: " 492 "non-zero completion status %d\n", status); 493 } 494 495 496 s = splaudio(); 497 (sc->sc_rxfunc)(sc->sc_rxarg); 498 splx(s); 499 } 500