1 /* $NetBSD: imx23_digfilt.c,v 1.12 2026/07/07 04:54:34 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Petri Laakso. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/cdefs.h> 34 #include <sys/types.h> 35 #include <sys/device.h> 36 #include <sys/errno.h> 37 #include <sys/systm.h> 38 #include <sys/bus.h> 39 #include <sys/mutex.h> 40 #include <sys/audioio.h> 41 #include <sys/mallocvar.h> 42 43 #include <dev/audio/audio_if.h> 44 #include <dev/fdt/fdtvar.h> 45 46 #include <arm/imx/imx23_digfiltreg.h> 47 #include <arm/imx/imx23var.h> 48 49 #define DIGFILT_DMA_NSEGS 1 50 51 struct imx23_digfilt_softc { 52 device_t sc_dev; 53 device_t sc_audiodev; 54 struct audio_format sc_format; 55 bus_space_handle_t sc_aohdl; 56 struct fdtbus_dma *dma_channel; 57 bus_dma_tag_t sc_dmat; 58 bus_dmamap_t sc_dmamp; 59 bus_dma_segment_t sc_ds[DIGFILT_DMA_NSEGS]; 60 bus_space_handle_t sc_hdl; 61 bus_space_tag_t sc_iot; 62 kmutex_t sc_intr_lock; 63 kmutex_t sc_lock; 64 audio_params_t sc_pparam; 65 void *sc_buffer; 66 void *sc_intarg; 67 void (*sc_intr)(void*); 68 uint8_t sc_mute; 69 }; 70 71 /* Autoconf. */ 72 static int imx23_digfilt_match(device_t, cfdata_t, void *); 73 static void imx23_digfilt_attach(device_t, device_t, void *); 74 75 /* Audio driver interface. */ 76 static int imx23_digfilt_query_format(void *, audio_format_query_t *); 77 static int imx23_digfilt_set_format(void *, int, const audio_params_t *, 78 const audio_params_t *, audio_filter_reg_t *, 79 audio_filter_reg_t *); 80 static int imx23_digfilt_round_blocksize(void *, int, int, 81 const audio_params_t *); 82 static int imx23_digfilt_init_output(void *, void *, int ); 83 static int imx23_digfilt_start_output(void *, void *, int, void (*)(void *), 84 void *); 85 static int imx23_digfilt_halt_output(void *); 86 static int imx23_digfilt_getdev(void *, struct audio_device *); 87 static int imx23_digfilt_set_port(void *, mixer_ctrl_t *); 88 static int imx23_digfilt_get_port(void *, mixer_ctrl_t *); 89 static int imx23_digfilt_query_devinfo(void *, mixer_devinfo_t *); 90 static void *imx23_digfilt_allocm(void *, int, size_t); 91 static void imx23_digfilt_freem(void *, void *, size_t); 92 static size_t imx23_digfilt_round_buffersize(void *, int, size_t); 93 static int imx23_digfilt_get_props(void *); 94 static void imx23_digfilt_get_locks(void *, kmutex_t **, kmutex_t **); 95 96 /* IRQs */ 97 static int imx23_dac_error_intr(void *); 98 static void imx23_dac_dma_intr(void *); 99 100 /* Audio out. */ 101 static void imx23_digfilt_ao_apply_mutes(struct imx23_digfilt_softc *); 102 static void imx23_digfilt_ao_init(struct imx23_digfilt_softc *); 103 static void imx23_digfilt_ao_reset(struct imx23_digfilt_softc *); 104 static void imx23_digfilt_ao_set_rate(struct imx23_digfilt_softc *, int); 105 106 #define DIGFILT_BLOCKSIZE_MAX 8192 107 #define DIGFILT_BLOCKSIZE_ROUND 2048 108 #define DIGFILT_DMA_CHAIN_LENGTH 3 109 #define DIGFILT_DMA_CHANNEL 1 110 #define DIGFILT_MUTE_DAC 1 111 #define DIGFILT_MUTE_HP 2 112 #define DIGFILT_MUTE_LINE 4 113 #define DIGFILT_SOFT_RST_LOOP 455 /* At least 1 us. */ 114 115 #define AO_RD(sc, reg) \ 116 bus_space_read_4(sc->sc_iot, sc->sc_aohdl, (reg)) 117 #define AO_WR(sc, reg, val) \ 118 bus_space_write_4(sc->sc_iot, sc->sc_aohdl, (reg), (val)) 119 120 CFATTACH_DECL_NEW(imx23digfilt, sizeof(struct imx23_digfilt_softc), 121 imx23_digfilt_match, imx23_digfilt_attach, NULL, NULL); 122 123 static const struct audio_hw_if imx23_digfilt_hw_if = { 124 .open = NULL, 125 .close = NULL, 126 .query_format = imx23_digfilt_query_format, 127 .set_format = imx23_digfilt_set_format, 128 .round_blocksize = imx23_digfilt_round_blocksize, 129 .commit_settings = NULL, 130 .init_output = imx23_digfilt_init_output, 131 .init_input = NULL, 132 .start_output = imx23_digfilt_start_output, 133 .start_input = NULL, 134 .halt_output = imx23_digfilt_halt_output, 135 .speaker_ctl = NULL, 136 .getdev = imx23_digfilt_getdev, 137 .set_port = imx23_digfilt_set_port, 138 .get_port = imx23_digfilt_get_port, 139 .query_devinfo = imx23_digfilt_query_devinfo, 140 .allocm = imx23_digfilt_allocm, 141 .freem = imx23_digfilt_freem, 142 .round_buffersize = imx23_digfilt_round_buffersize, 143 .get_props = imx23_digfilt_get_props, 144 .trigger_output = NULL, 145 .trigger_input = NULL, 146 .dev_ioctl = NULL, 147 .get_locks = imx23_digfilt_get_locks 148 }; 149 150 enum { 151 DIGFILT_OUTPUT_CLASS, 152 DIGFILT_OUTPUT_DAC_VOLUME, 153 DIGFILT_OUTPUT_DAC_MUTE, 154 DIGFILT_OUTPUT_HP_VOLUME, 155 DIGFILT_OUTPUT_HP_MUTE, 156 DIGFILT_OUTPUT_LINE_VOLUME, 157 DIGFILT_OUTPUT_LINE_MUTE, 158 DIGFILT_ENUM_LAST 159 }; 160 161 static const struct device_compatible_entry compat_data[] = { 162 { .compat = "fsl,imx23-audioout" }, 163 DEVICE_COMPAT_EOL 164 }; 165 166 static int 167 imx23_digfilt_match(device_t parent, cfdata_t match, void *aux) 168 { 169 struct fdt_attach_args * const faa = aux; 170 171 return of_compatible_match(faa->faa_phandle, compat_data); 172 } 173 174 static void 175 imx23_digfilt_attach(device_t parent, device_t self, void *aux) 176 { 177 struct imx23_digfilt_softc * const sc = device_private(self); 178 struct fdt_attach_args * const faa = aux; 179 const int phandle = faa->faa_phandle; 180 int error; 181 char intrstr[128]; 182 183 sc->sc_dev = self; 184 sc->sc_iot = faa->faa_bst; 185 sc->sc_dmat = faa->faa_dmat; 186 187 bus_addr_t addr; 188 bus_size_t size; 189 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 190 aprint_error(": couldn't get register address\n"); 191 return; 192 } 193 /* Map DIGFILT bus space. */ 194 if (bus_space_map(faa->faa_bst, addr, size, 0, &sc->sc_hdl)) { 195 aprint_error(": couldn't map registers\n"); 196 return; 197 } 198 /* Map AUDIOOUT subregion from parent bus space. */ 199 if (bus_space_subregion(sc->sc_iot, sc->sc_hdl, 0, size, 200 &sc->sc_aohdl)) { 201 aprint_error_dev(sc->sc_dev, 202 "Unable to submap AUDIOOUT bus space\n"); 203 return; 204 } 205 206 /* acquire DMA channel */ 207 sc->dma_channel = fdtbus_dma_get(phandle,"tx", imx23_dac_dma_intr, sc); 208 if (sc->dma_channel == NULL) { 209 aprint_error(": couldn't get dma access\n"); 210 return; 211 } 212 213 /* Allocate DMA for audio buffer. */ 214 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DIGFILT_DMA_NSEGS, 215 MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 216 &sc->sc_dmamp); 217 if (error) { 218 aprint_error_dev(sc->sc_dev, "Unable to allocate DMA handle\n"); 219 return; 220 } 221 222 imx23_digfilt_ao_reset(sc); /* Reset AUDIOOUT. */ 223 224 uint32_t v = AO_RD(sc, HW_AUDIOOUT_VERSION); 225 aprint_normal(": DIGFILT Block v%" __PRIuBIT ".%" __PRIuBIT 226 ".%" __PRIuBIT, 227 __SHIFTOUT(v, HW_AUDIOOUT_VERSION_MAJOR), 228 __SHIFTOUT(v, HW_AUDIOOUT_VERSION_MINOR), 229 __SHIFTOUT(v, HW_AUDIOOUT_VERSION_STEP)); 230 231 imx23_digfilt_ao_init(sc); 232 /* Default sample rate 44.1 kHz. */ 233 imx23_digfilt_ao_set_rate(sc, 44100); 234 235 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 236 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 237 238 /* HW supported formats. */ 239 sc->sc_format.mode = AUMODE_PLAY; 240 sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE; 241 sc->sc_format.validbits = 16; 242 sc->sc_format.precision = 16; 243 sc->sc_format.channels = 2; 244 sc->sc_format.channel_mask = AUFMT_STEREO; 245 sc->sc_format.frequency_type = 8; 246 sc->sc_format.frequency[0] = 8000; 247 sc->sc_format.frequency[1] = 11025; 248 sc->sc_format.frequency[2] = 12000; 249 sc->sc_format.frequency[3] = 16000; 250 sc->sc_format.frequency[4] = 22050; 251 sc->sc_format.frequency[5] = 24000; 252 sc->sc_format.frequency[6] = 32000; 253 sc->sc_format.frequency[7] = 44100; 254 255 sc->sc_audiodev = audio_attach_mi(&imx23_digfilt_hw_if, sc, sc->sc_dev); 256 257 /* Default mutes. */ 258 sc->sc_mute = DIGFILT_MUTE_LINE; 259 imx23_digfilt_ao_apply_mutes(sc); 260 261 /* establish error interrupt */ 262 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 263 aprint_error(": failed to decode interrupt\n"); 264 return; 265 } 266 void *ih = fdtbus_intr_establish_xname(phandle, 0, IPL_SCHED, IST_LEVEL, 267 imx23_dac_error_intr, sc, 268 device_xname(self)); 269 if (ih == NULL) { 270 aprint_error_dev(self, "couldn't establish error interrupt\n"); 271 return; 272 } 273 274 aprint_normal("\n"); 275 } 276 277 static int 278 imx23_digfilt_query_format(void *priv, audio_format_query_t *afp) 279 { 280 struct imx23_digfilt_softc *sc = priv; 281 282 return audio_query_format(&sc->sc_format, 1, afp); 283 } 284 285 static int 286 imx23_digfilt_set_format(void *priv, int setmode, const audio_params_t *play, 287 const audio_params_t *rec, audio_filter_reg_t *pfil, 288 audio_filter_reg_t *rfil) 289 { 290 struct imx23_digfilt_softc *sc = priv; 291 292 if ((setmode & AUMODE_PLAY)) { 293 sc->sc_pparam = *play; 294 295 /* At this point bitrate should be figured out. */ 296 imx23_digfilt_ao_set_rate(sc, sc->sc_pparam.sample_rate); 297 } 298 299 return 0; 300 } 301 302 static int 303 imx23_digfilt_round_blocksize(void *priv, int bs, int mode, 304 const audio_params_t *param) 305 { 306 int blocksize; 307 308 if (bs > DIGFILT_BLOCKSIZE_MAX) 309 blocksize = DIGFILT_BLOCKSIZE_MAX; 310 else 311 blocksize = bs & ~(DIGFILT_BLOCKSIZE_ROUND-1); 312 if (blocksize < DIGFILT_BLOCKSIZE_ROUND) 313 blocksize = DIGFILT_BLOCKSIZE_ROUND; 314 315 return blocksize; 316 } 317 318 static int 319 imx23_digfilt_init_output(void *priv, void *buffer, int size) 320 { 321 return 0; 322 } 323 324 static int 325 imx23_digfilt_start_output(void *priv, void *start, int bs, 326 void (*intr)(void *), void *intarg) 327 { 328 struct imx23_digfilt_softc *sc = priv; 329 struct fdtbus_dma_req req; 330 331 sc->sc_intr = intr; 332 sc->sc_intarg = intarg; 333 334 /* synthesize a dma segment with the correct offset+size */ 335 bus_addr_t offset = (bus_addr_t)start - (bus_addr_t)sc->sc_buffer; 336 bus_dma_segment_t dma_seg; 337 dma_seg.ds_addr = sc->sc_dmamp->dm_segs[0].ds_addr + offset; 338 dma_seg.ds_len = bs; 339 340 /* configure DMA request */ 341 req.dreq_dir = FDT_DMA_WRITE; 342 req.dreq_segs = &dma_seg; 343 req.dreq_nsegs = 1; 344 req.dreq_block_irq = 0; 345 346 /* configure DMA PIO words */ 347 uint32_t pio_words[1]; 348 pio_words[0] = HW_AUDIOOUT_CTRL_WORD_LENGTH | 349 HW_AUDIOOUT_CTRL_RUN; 350 req.dreq_datalen = 1; 351 req.dreq_data = &pio_words; 352 353 /* send it off*/ 354 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamp, offset, bs, 355 BUS_DMASYNC_PREWRITE); 356 fdtbus_dma_transfer(sc->dma_channel, &req); 357 358 return 0; 359 } 360 361 static int 362 imx23_digfilt_halt_output(void *priv) 363 { 364 struct imx23_digfilt_softc *sc = priv; 365 366 /* We have intr lock when this is called */ 367 sc->sc_intr = NULL; 368 369 return 0; 370 } 371 372 static int 373 imx23_digfilt_getdev(void *priv, struct audio_device *ad) 374 { 375 struct imx23_digfilt_softc *sc = priv; 376 377 strncpy(ad->name, device_xname(sc->sc_dev), MAX_AUDIO_DEV_LEN); 378 strncpy(ad->version, "", MAX_AUDIO_DEV_LEN); 379 strncpy(ad->config, "", MAX_AUDIO_DEV_LEN); 380 381 return 0; 382 } 383 384 static int 385 imx23_digfilt_set_port(void *priv, mixer_ctrl_t *mc) 386 { 387 struct imx23_digfilt_softc *sc = priv; 388 uint32_t val; 389 uint8_t nvol; 390 391 switch (mc->dev) { 392 case DIGFILT_OUTPUT_DAC_VOLUME: 393 val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME); 394 val &= ~(HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT | 395 HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT); 396 397 /* DAC volume field is 8 bits. */ 398 nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 399 if (nvol > 0xff) 400 nvol = 0xff; 401 402 val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT); 403 404 nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 405 if (nvol > 0xff) 406 nvol = 0xff; 407 408 val |= __SHIFTIN(nvol, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT); 409 410 AO_WR(sc, HW_AUDIOOUT_DACVOLUME, val); 411 412 return 0; 413 414 case DIGFILT_OUTPUT_HP_VOLUME: 415 val = AO_RD(sc, HW_AUDIOOUT_HPVOL); 416 val &= ~(HW_AUDIOOUT_HPVOL_VOL_LEFT | 417 HW_AUDIOOUT_HPVOL_VOL_RIGHT); 418 419 /* HP volume field is 7 bits. */ 420 nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 421 if (nvol > 0x7f) 422 nvol = 0x7f; 423 424 nvol = ~nvol; 425 val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_LEFT); 426 427 nvol = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 428 if (nvol > 0x7f) 429 nvol = 0x7f; 430 431 nvol = ~nvol; 432 val |= __SHIFTIN(nvol, HW_AUDIOOUT_HPVOL_VOL_RIGHT); 433 434 AO_WR(sc, HW_AUDIOOUT_HPVOL, val); 435 436 return 0; 437 438 case DIGFILT_OUTPUT_LINE_VOLUME: 439 return 1; 440 441 case DIGFILT_OUTPUT_DAC_MUTE: 442 if (mc->un.ord) 443 sc->sc_mute |= DIGFILT_MUTE_DAC; 444 else 445 sc->sc_mute &= ~DIGFILT_MUTE_DAC; 446 447 imx23_digfilt_ao_apply_mutes(sc); 448 449 return 0; 450 451 case DIGFILT_OUTPUT_HP_MUTE: 452 if (mc->un.ord) 453 sc->sc_mute |= DIGFILT_MUTE_HP; 454 else 455 sc->sc_mute &= ~DIGFILT_MUTE_HP; 456 457 imx23_digfilt_ao_apply_mutes(sc); 458 459 return 0; 460 461 case DIGFILT_OUTPUT_LINE_MUTE: 462 if (mc->un.ord) 463 sc->sc_mute |= DIGFILT_MUTE_LINE; 464 else 465 sc->sc_mute &= ~DIGFILT_MUTE_LINE; 466 467 imx23_digfilt_ao_apply_mutes(sc); 468 469 return 0; 470 } 471 472 return ENXIO; 473 } 474 475 static int 476 imx23_digfilt_get_port(void *priv, mixer_ctrl_t *mc) 477 { 478 struct imx23_digfilt_softc *sc = priv; 479 uint32_t val; 480 uint8_t nvol; 481 482 switch (mc->dev) { 483 case DIGFILT_OUTPUT_DAC_VOLUME: 484 val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME); 485 486 nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_LEFT); 487 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = nvol; 488 489 nvol = __SHIFTOUT(val, HW_AUDIOOUT_DACVOLUME_VOLUME_RIGHT); 490 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = nvol; 491 492 return 0; 493 494 case DIGFILT_OUTPUT_HP_VOLUME: 495 val = AO_RD(sc, HW_AUDIOOUT_HPVOL); 496 497 nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_LEFT); 498 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = ~nvol & 0x7f; 499 500 nvol = __SHIFTOUT(val, HW_AUDIOOUT_HPVOL_VOL_RIGHT); 501 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = ~nvol & 0x7f; 502 503 return 0; 504 505 case DIGFILT_OUTPUT_LINE_VOLUME: 506 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 255; 507 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 255; 508 509 return 0; 510 511 case DIGFILT_OUTPUT_DAC_MUTE: 512 val = AO_RD(sc, HW_AUDIOOUT_DACVOLUME); 513 514 mc->un.ord = (val & (HW_AUDIOOUT_DACVOLUME_MUTE_LEFT | 515 HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT)) ? 1 : 0; 516 517 return 0; 518 519 case DIGFILT_OUTPUT_HP_MUTE: 520 val = AO_RD(sc, HW_AUDIOOUT_HPVOL); 521 522 mc->un.ord = (val & HW_AUDIOOUT_HPVOL_MUTE) ? 1 : 0; 523 524 return 0; 525 526 case DIGFILT_OUTPUT_LINE_MUTE: 527 val = AO_RD(sc, HW_AUDIOOUT_SPEAKERCTRL); 528 529 mc->un.ord = (val & HW_AUDIOOUT_SPEAKERCTRL_MUTE) ? 1 : 0; 530 531 return 0; 532 } 533 534 return ENXIO; 535 } 536 537 static int 538 imx23_digfilt_query_devinfo(void *priv, mixer_devinfo_t *di) 539 { 540 541 switch (di->index) { 542 case DIGFILT_OUTPUT_CLASS: 543 di->mixer_class = DIGFILT_OUTPUT_CLASS; 544 strcpy(di->label.name, AudioCoutputs); 545 di->type = AUDIO_MIXER_CLASS; 546 di->next = di->prev = AUDIO_MIXER_LAST; 547 return 0; 548 549 case DIGFILT_OUTPUT_DAC_VOLUME: 550 di->mixer_class = DIGFILT_OUTPUT_CLASS; 551 strcpy(di->label.name, AudioNdac); 552 di->type = AUDIO_MIXER_VALUE; 553 di->prev = AUDIO_MIXER_LAST; 554 di->next = DIGFILT_OUTPUT_DAC_MUTE; 555 di->un.v.num_channels = 2; 556 strcpy(di->un.v.units.name, AudioNvolume); 557 return 0; 558 559 case DIGFILT_OUTPUT_DAC_MUTE: 560 di->mixer_class = DIGFILT_OUTPUT_CLASS; 561 di->type = AUDIO_MIXER_ENUM; 562 di->prev = DIGFILT_OUTPUT_DAC_VOLUME; 563 di->next = AUDIO_MIXER_LAST; 564 mute: 565 strlcpy(di->label.name, AudioNmute, sizeof(di->label.name)); 566 di->un.e.num_mem = 2; 567 strlcpy(di->un.e.member[0].label.name, AudioNon, 568 sizeof(di->un.e.member[0].label.name)); 569 di->un.e.member[0].ord = 1; 570 strlcpy(di->un.e.member[1].label.name, AudioNoff, 571 sizeof(di->un.e.member[1].label.name)); 572 di->un.e.member[1].ord = 0; 573 return 0; 574 575 case DIGFILT_OUTPUT_HP_VOLUME: 576 di->mixer_class = DIGFILT_OUTPUT_CLASS; 577 strcpy(di->label.name, AudioNheadphone); 578 di->type = AUDIO_MIXER_VALUE; 579 di->prev = AUDIO_MIXER_LAST; 580 di->next = DIGFILT_OUTPUT_HP_MUTE; 581 di->un.v.num_channels = 2; 582 strcpy(di->un.v.units.name, AudioNvolume); 583 return 0; 584 585 case DIGFILT_OUTPUT_HP_MUTE: 586 di->mixer_class = DIGFILT_OUTPUT_CLASS; 587 di->type = AUDIO_MIXER_ENUM; 588 di->prev = DIGFILT_OUTPUT_HP_VOLUME; 589 di->next = AUDIO_MIXER_LAST; 590 goto mute; 591 592 case DIGFILT_OUTPUT_LINE_VOLUME: 593 di->mixer_class = DIGFILT_OUTPUT_CLASS; 594 strcpy(di->label.name, AudioNline); 595 di->type = AUDIO_MIXER_VALUE; 596 di->prev = AUDIO_MIXER_LAST; 597 di->next = DIGFILT_OUTPUT_LINE_MUTE; 598 di->un.v.num_channels = 2; 599 strcpy(di->un.v.units.name, AudioNvolume); 600 return 0; 601 602 case DIGFILT_OUTPUT_LINE_MUTE: 603 di->mixer_class = DIGFILT_OUTPUT_CLASS; 604 di->type = AUDIO_MIXER_ENUM; 605 di->prev = DIGFILT_OUTPUT_LINE_VOLUME; 606 di->next = AUDIO_MIXER_LAST; 607 goto mute; 608 } 609 610 return ENXIO; 611 } 612 613 static void * 614 imx23_digfilt_allocm(void *priv, int direction, size_t size) 615 { 616 struct imx23_digfilt_softc *sc = priv; 617 int rsegs; 618 int error; 619 620 sc->sc_buffer = NULL; 621 622 /* 623 * AUMODE_PLAY is DMA from memory to device. 624 */ 625 if (direction != AUMODE_PLAY) 626 return NULL; 627 628 error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &sc->sc_ds[0], DIGFILT_DMA_NSEGS, &rsegs, BUS_DMA_NOWAIT); 629 if (error) { 630 aprint_error_dev(sc->sc_dev, 631 "bus_dmamem_alloc: %d\n", error); 632 goto out; 633 } 634 635 error = bus_dmamem_map(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS, size, &sc->sc_buffer, BUS_DMA_NOWAIT); 636 if (error) { 637 aprint_error_dev(sc->sc_dev, "bus_dmamem_map: %d\n", error); 638 goto dmamem_free; 639 } 640 641 /* After load sc_dmamp is valid. */ 642 error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamp, sc->sc_buffer, size, NULL, BUS_DMA_NOWAIT|BUS_DMA_WRITE); 643 if (error) { 644 aprint_error_dev(sc->sc_dev, "bus_dmamap_load: %d\n", error); 645 goto dmamem_unmap; 646 } 647 648 memset(sc->sc_buffer, 0x00, size); 649 650 return sc->sc_buffer; 651 652 dmamem_unmap: 653 bus_dmamem_unmap(sc->sc_dmat, sc->sc_buffer, size); 654 dmamem_free: 655 bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS); 656 out: 657 return NULL; 658 } 659 660 static void 661 imx23_digfilt_freem(void *priv, void *kvap, size_t size) 662 { 663 struct imx23_digfilt_softc *sc = priv; 664 665 bus_dmamem_unmap(sc->sc_dmat, kvap, size); 666 bus_dmamem_free(sc->sc_dmat, sc->sc_ds, DIGFILT_DMA_NSEGS); 667 } 668 669 static size_t 670 imx23_digfilt_round_buffersize(void *hdl, int direction, size_t bs) 671 { 672 return bs; 673 } 674 675 static int 676 imx23_digfilt_get_props(void *sc) 677 { 678 return AUDIO_PROP_PLAYBACK; 679 } 680 681 static void 682 imx23_digfilt_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread) 683 { 684 struct imx23_digfilt_softc *sc = priv; 685 686 *intr = &sc->sc_intr_lock; 687 *thread = &sc->sc_lock; 688 } 689 690 /* 691 * IRQ for DAC error. 692 */ 693 static int 694 imx23_dac_error_intr(void *arg) 695 { 696 struct imx23_digfilt_softc *sc = arg; 697 AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ); 698 return 1; 699 } 700 701 /* 702 * IRQ from DMA. 703 */ 704 static void 705 imx23_dac_dma_intr(void *arg) 706 { 707 struct imx23_digfilt_softc *sc = arg; 708 709 mutex_enter(&sc->sc_intr_lock); 710 711 /* 712 * When halting, the driver finishes playing the current block, but 713 * the audio subsystem no longer expects us to call back 714 */ 715 if (sc->sc_intr != NULL) { 716 sc->sc_intr(sc->sc_intarg); 717 } 718 719 mutex_exit(&sc->sc_intr_lock); 720 } 721 722 static void 723 imx23_digfilt_ao_apply_mutes(struct imx23_digfilt_softc *sc) 724 { 725 726 /* DAC. */ 727 if (sc->sc_mute & DIGFILT_MUTE_DAC) { 728 AO_WR(sc, HW_AUDIOOUT_DACVOLUME_SET, 729 HW_AUDIOOUT_DACVOLUME_MUTE_LEFT | 730 HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT 731 ); 732 733 } else { 734 AO_WR(sc, HW_AUDIOOUT_DACVOLUME_CLR, 735 HW_AUDIOOUT_DACVOLUME_MUTE_LEFT | 736 HW_AUDIOOUT_DACVOLUME_MUTE_RIGHT 737 ); 738 } 739 740 /* HP. */ 741 if (sc->sc_mute & DIGFILT_MUTE_HP) 742 AO_WR(sc, HW_AUDIOOUT_HPVOL_SET, HW_AUDIOOUT_HPVOL_MUTE); 743 else 744 AO_WR(sc, HW_AUDIOOUT_HPVOL_CLR, HW_AUDIOOUT_HPVOL_MUTE); 745 746 /* Line. */ 747 if (sc->sc_mute & DIGFILT_MUTE_LINE) 748 AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_SET, 749 HW_AUDIOOUT_SPEAKERCTRL_MUTE); 750 else 751 AO_WR(sc, HW_AUDIOOUT_SPEAKERCTRL_CLR, 752 HW_AUDIOOUT_SPEAKERCTRL_MUTE); 753 } 754 755 /* 756 * Initialize audio system. 757 */ 758 static void 759 imx23_digfilt_ao_init(struct imx23_digfilt_softc *sc) 760 { 761 762 AO_WR(sc, HW_AUDIOOUT_ANACLKCTRL_CLR, HW_AUDIOOUT_ANACLKCTRL_CLKGATE); 763 while ((AO_RD(sc, HW_AUDIOOUT_ANACLKCTRL) & HW_AUDIOOUT_ANACLKCTRL_CLKGATE)) 764 continue; 765 766 /* Hold headphones outputs at ground. */ 767 AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND); 768 769 /* Release pull down */ 770 AO_WR(sc, HW_AUDIOOUT_ANACTRL_CLR, HW_AUDIOOUT_ANACTRL_HP_HOLD_GND); 771 772 AO_WR(sc, HW_AUDIOOUT_ANACTRL_SET, HW_AUDIOOUT_ANACTRL_HP_CLASSAB); 773 774 /* Enable Modules. */ 775 AO_WR(sc, HW_AUDIOOUT_PWRDN_CLR, 776 HW_AUDIOOUT_PWRDN_RIGHT_ADC | 777 HW_AUDIOOUT_PWRDN_DAC | 778 HW_AUDIOOUT_PWRDN_CAPLESS | 779 HW_AUDIOOUT_PWRDN_HEADPHONE 780 ); 781 } 782 783 /* 784 * Reset the AUDIOOUT block. 785 * 786 * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block" 787 */ 788 static void 789 imx23_digfilt_ao_reset(struct imx23_digfilt_softc *sc) 790 { 791 unsigned int loop; 792 793 /* 794 * Prepare for soft-reset by making sure that SFTRST is not currently 795 * asserted. Also clear CLKGATE so we can wait for its assertion below. 796 */ 797 AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST); 798 799 /* Wait at least a microsecond for SFTRST to deassert. */ 800 loop = 0; 801 while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) || 802 (loop < DIGFILT_SOFT_RST_LOOP)) 803 loop++; 804 805 /* Clear CLKGATE so we can wait for its assertion below. */ 806 AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE); 807 808 /* Soft-reset the block. */ 809 AO_WR(sc, HW_AUDIOOUT_CTRL_SET, HW_AUDIOOUT_CTRL_SFTRST); 810 811 /* Wait until clock is in the gated state. */ 812 while (!(AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE)) 813 continue; 814 815 /* Bring block out of reset. */ 816 AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_SFTRST); 817 818 loop = 0; 819 while ((AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_SFTRST) || 820 (loop < DIGFILT_SOFT_RST_LOOP)) 821 loop++; 822 823 AO_WR(sc, HW_AUDIOOUT_CTRL_CLR, HW_AUDIOOUT_CTRL_CLKGATE); 824 825 /* Wait until clock is in the NON-gated state. */ 826 while (AO_RD(sc, HW_AUDIOOUT_CTRL) & HW_AUDIOOUT_CTRL_CLKGATE) 827 continue; 828 } 829 830 static void 831 imx23_digfilt_ao_set_rate(struct imx23_digfilt_softc *sc, int sr) 832 { 833 uint32_t val; 834 835 836 val = AO_RD(sc, HW_AUDIOOUT_DACSRR); 837 838 839 val &= ~(HW_AUDIOOUT_DACSRR_BASEMULT | HW_AUDIOOUT_DACSRR_SRC_HOLD | 840 HW_AUDIOOUT_DACSRR_SRC_INT | HW_AUDIOOUT_DACSRR_SRC_FRAC); 841 842 switch(sr) { 843 case 8000: 844 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 845 __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 846 __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) | 847 __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 848 break; 849 case 11025: 850 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 851 __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 852 __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) | 853 __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 854 break; 855 case 12000: 856 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 857 __SHIFTIN(0x3, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 858 __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) | 859 __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 860 break; 861 case 16000: 862 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 863 __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 864 __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) | 865 __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 866 break; 867 case 22050: 868 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 869 __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 870 __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) | 871 __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 872 break; 873 case 24000: 874 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 875 __SHIFTIN(0x1, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 876 __SHIFTIN(0x0F, HW_AUDIOOUT_DACSRR_SRC_INT) | 877 __SHIFTIN(0x13FF, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 878 break; 879 case 32000: 880 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 881 __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 882 __SHIFTIN(0x17, HW_AUDIOOUT_DACSRR_SRC_INT) | 883 __SHIFTIN(0x0E00, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 884 break; 885 default: 886 aprint_error_dev(sc->sc_dev, "unknown sample rate: %d\n", sr); 887 case 44100: 888 val |= (__SHIFTIN(0x1 ,HW_AUDIOOUT_DACSRR_BASEMULT) | 889 __SHIFTIN(0x0, HW_AUDIOOUT_DACSRR_SRC_HOLD) | 890 __SHIFTIN(0x11, HW_AUDIOOUT_DACSRR_SRC_INT) | 891 __SHIFTIN(0x0037, HW_AUDIOOUT_DACSRR_SRC_FRAC)); 892 break; 893 } 894 895 AO_WR(sc, HW_AUDIOOUT_DACSRR, val); 896 897 val = AO_RD(sc, HW_AUDIOOUT_DACSRR); 898 } 899