1 /* $OpenBSD: simpleaudio.c,v 1.2 2021/04/05 14:36:18 kn Exp $ */ 2 /* 3 * Copyright (c) 2020 Patrick Wildt <patrick@blueri.se> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <machine/fdt.h> 24 25 #include <dev/ofw/openfirm.h> 26 #include <dev/ofw/ofw_misc.h> 27 #include <dev/ofw/ofw_pinctrl.h> 28 29 #include <sys/audioio.h> 30 #include <dev/audio_if.h> 31 #include <dev/midi_if.h> 32 33 struct simpleaudio_softc { 34 struct device sc_dev; 35 int sc_node; 36 37 uint32_t sc_mclk_fs; 38 39 struct dai_device *sc_dai_cpu; 40 struct dai_device *sc_dai_codec; 41 struct dai_device **sc_dai_aux; 42 int sc_dai_naux; 43 }; 44 45 int simpleaudio_match(struct device *, void *, void *); 46 void simpleaudio_attach(struct device *, struct device *, void *); 47 void simpleaudio_attach_deferred(struct device *); 48 void simpleaudio_set_format(struct simpleaudio_softc *, uint32_t, 49 uint32_t, uint32_t); 50 51 int simpleaudio_open(void *, int); 52 void simpleaudio_close(void *); 53 int simpleaudio_set_params(void *, int, int, 54 struct audio_params *, struct audio_params *); 55 void *simpleaudio_allocm(void *, int, size_t, int, int); 56 void simpleaudio_freem(void *, void *, int); 57 int simpleaudio_set_port(void *, mixer_ctrl_t *); 58 int simpleaudio_get_port(void *, mixer_ctrl_t *); 59 int simpleaudio_query_devinfo(void *, mixer_devinfo_t *); 60 int simpleaudio_get_props(void *); 61 int simpleaudio_round_blocksize(void *, int); 62 size_t simpleaudio_round_buffersize(void *, int, size_t); 63 int simpleaudio_trigger_output(void *, void *, void *, int, 64 void (*)(void *), void *, struct audio_params *); 65 int simpleaudio_trigger_input(void *, void *, void *, int, 66 void (*)(void *), void *, struct audio_params *); 67 int simpleaudio_halt_output(void *); 68 int simpleaudio_halt_input(void *); 69 70 struct audio_hw_if simpleaudio_hw_if = { 71 .open = simpleaudio_open, 72 .close = simpleaudio_close, 73 .set_params = simpleaudio_set_params, 74 .allocm = simpleaudio_allocm, 75 .freem = simpleaudio_freem, 76 .set_port = simpleaudio_set_port, 77 .get_port = simpleaudio_get_port, 78 .query_devinfo = simpleaudio_query_devinfo, 79 .get_props = simpleaudio_get_props, 80 .round_blocksize = simpleaudio_round_blocksize, 81 .round_buffersize = simpleaudio_round_buffersize, 82 .trigger_output = simpleaudio_trigger_output, 83 .trigger_input = simpleaudio_trigger_input, 84 .halt_output = simpleaudio_halt_output, 85 .halt_input = simpleaudio_halt_input, 86 }; 87 88 struct cfattach simpleaudio_ca = { 89 sizeof(struct simpleaudio_softc), simpleaudio_match, simpleaudio_attach 90 }; 91 92 struct cfdriver simpleaudio_cd = { 93 NULL, "simpleaudio", DV_DULL 94 }; 95 96 int 97 simpleaudio_match(struct device *parent, void *match, void *aux) 98 { 99 struct fdt_attach_args *faa = aux; 100 101 return OF_is_compatible(faa->fa_node, "simple-audio-card"); 102 } 103 104 void 105 simpleaudio_attach(struct device *parent, struct device *self, void *aux) 106 { 107 struct simpleaudio_softc *sc = (struct simpleaudio_softc *)self; 108 struct fdt_attach_args *faa = aux; 109 110 printf("\n"); 111 112 pinctrl_byname(faa->fa_node, "default"); 113 114 sc->sc_node = faa->fa_node; 115 config_defer(self, simpleaudio_attach_deferred); 116 } 117 118 void 119 simpleaudio_attach_deferred(struct device *self) 120 { 121 struct simpleaudio_softc *sc = (struct simpleaudio_softc *)self; 122 char format[16] = { 0 }; 123 uint32_t fmt, pol, clk; 124 uint32_t *auxdevs; 125 ssize_t len; 126 int i, node; 127 128 /* TODO: implement simple-audio-card,dai-link */ 129 if (OF_getnodebyname(sc->sc_node, "simple-audio-card,cpu") == 0 || 130 OF_getnodebyname(sc->sc_node, "simple-audio-card,codec") == 0) 131 return; 132 133 sc->sc_mclk_fs = OF_getpropint(sc->sc_node, 134 "simple-audio-card,mclk-fs", 0); 135 136 node = OF_getnodebyname(sc->sc_node, "simple-audio-card,cpu"); 137 sc->sc_dai_cpu = dai_byphandle(OF_getpropint(node, "sound-dai", 0)); 138 139 node = OF_getnodebyname(sc->sc_node, "simple-audio-card,codec"); 140 sc->sc_dai_codec = dai_byphandle(OF_getpropint(node, "sound-dai", 0)); 141 142 if (sc->sc_dai_cpu == NULL || sc->sc_dai_codec == NULL) 143 return; 144 145 OF_getprop(sc->sc_node, "simple-audio-card,format", 146 format, sizeof(format)); 147 if (!strcmp(format, "i2s")) 148 fmt = DAI_FORMAT_I2S; 149 else if (!strcmp(format, "right_j")) 150 fmt = DAI_FORMAT_RJ; 151 else if (!strcmp(format, "left_j")) 152 fmt = DAI_FORMAT_LJ; 153 else if (!strcmp(format, "dsp_a")) 154 fmt = DAI_FORMAT_DSPA; 155 else if (!strcmp(format, "dsp_b")) 156 fmt = DAI_FORMAT_DSPB; 157 else if (!strcmp(format, "ac97")) 158 fmt = DAI_FORMAT_AC97; 159 else if (!strcmp(format, "pdm")) 160 fmt = DAI_FORMAT_PDM; 161 else if (!strcmp(format, "msb")) 162 fmt = DAI_FORMAT_MSB; 163 else if (!strcmp(format, "lsb")) 164 fmt = DAI_FORMAT_LSB; 165 else 166 return; 167 168 pol = 0; 169 if (OF_getproplen(sc->sc_node, "simple-audio-card,frame-inversion") == 0) 170 pol |= DAI_POLARITY_IF; 171 else 172 pol |= DAI_POLARITY_NF; 173 if (OF_getproplen(sc->sc_node, "simple-audio-card,bitclock-inversion") == 0) 174 pol |= DAI_POLARITY_IB; 175 else 176 pol |= DAI_POLARITY_NB; 177 178 clk = 0; 179 if (OF_getproplen(sc->sc_node, "simple-audio-card,frame-master") == 0) 180 clk |= DAI_CLOCK_CFM; 181 else 182 clk |= DAI_CLOCK_CFS; 183 if (OF_getproplen(sc->sc_node, "simple-audio-card,bitclock-master") == 0) 184 clk |= DAI_CLOCK_CBM; 185 else 186 clk |= DAI_CLOCK_CBS; 187 188 len = OF_getproplen(sc->sc_node, "simple-audio-card,aux-devs"); 189 if (len > 0) { 190 if (len % sizeof(uint32_t) != 0) 191 return; 192 193 auxdevs = malloc(len, M_TEMP, M_WAITOK); 194 OF_getpropintarray(sc->sc_node, "simple-audio-card,aux-devs", 195 auxdevs, len); 196 197 sc->sc_dai_naux = len / sizeof(uint32_t); 198 sc->sc_dai_aux = mallocarray(sc->sc_dai_naux, 199 sizeof(struct dai_device *), M_DEVBUF, M_WAITOK | M_ZERO); 200 201 for (i = 0; i < sc->sc_dai_naux; i++) 202 sc->sc_dai_aux[i] = dai_byphandle(auxdevs[i]); 203 204 free(auxdevs, M_TEMP, len); 205 } 206 207 simpleaudio_set_format(sc, fmt, pol, clk); 208 209 audio_attach_mi(&simpleaudio_hw_if, sc, &sc->sc_dev); 210 } 211 212 void 213 simpleaudio_set_format(struct simpleaudio_softc *sc, uint32_t fmt, uint32_t pol, 214 uint32_t clk) 215 { 216 if (sc->sc_dai_cpu->dd_set_format) 217 sc->sc_dai_cpu->dd_set_format(sc->sc_dai_cpu->dd_cookie, 218 fmt, pol, clk); 219 if (sc->sc_dai_codec->dd_set_format) 220 sc->sc_dai_codec->dd_set_format(sc->sc_dai_codec->dd_cookie, 221 fmt, pol, clk); 222 } 223 224 int 225 simpleaudio_open(void *cookie, int flags) 226 { 227 struct simpleaudio_softc *sc = cookie; 228 struct dai_device *dai; 229 struct audio_hw_if *hwif; 230 int error, i; 231 232 dai = sc->sc_dai_cpu; 233 hwif = dai->dd_hw_if; 234 if (hwif->open) { 235 error = hwif->open(dai->dd_cookie, flags); 236 if (error) { 237 simpleaudio_close(cookie); 238 return error; 239 } 240 } 241 242 dai = sc->sc_dai_codec; 243 hwif = dai->dd_hw_if; 244 if (hwif->open) { 245 error = hwif->open(dai->dd_cookie, flags); 246 if (error) { 247 simpleaudio_close(cookie); 248 return error; 249 } 250 } 251 252 for (i = 0; i < sc->sc_dai_naux; i++) { 253 dai = sc->sc_dai_aux[i]; 254 hwif = dai->dd_hw_if; 255 if (hwif->open) { 256 error = hwif->open(dai->dd_cookie, flags); 257 if (error) { 258 simpleaudio_close(cookie); 259 return error; 260 } 261 } 262 } 263 264 return 0; 265 } 266 267 void 268 simpleaudio_close(void *cookie) 269 { 270 struct simpleaudio_softc *sc = cookie; 271 struct dai_device *dai; 272 struct audio_hw_if *hwif; 273 int i; 274 275 for (i = 0; i < sc->sc_dai_naux; i++) { 276 dai = sc->sc_dai_aux[i]; 277 hwif = dai->dd_hw_if; 278 if (hwif->close) 279 hwif->close(dai->dd_cookie); 280 } 281 282 dai = sc->sc_dai_codec; 283 hwif = dai->dd_hw_if; 284 if (hwif->close) 285 hwif->close(dai->dd_cookie); 286 287 dai = sc->sc_dai_cpu; 288 hwif = dai->dd_hw_if; 289 if (hwif->close) 290 hwif->close(dai->dd_cookie); 291 } 292 293 int 294 simpleaudio_set_params(void *cookie, int setmode, int usemode, 295 struct audio_params *play, struct audio_params *rec) 296 { 297 struct simpleaudio_softc *sc = cookie; 298 struct dai_device *dai; 299 struct audio_hw_if *hwif; 300 uint32_t rate; 301 int error; 302 303 if (sc->sc_mclk_fs) { 304 if (setmode & AUMODE_PLAY) 305 rate = play->sample_rate * sc->sc_mclk_fs; 306 else 307 rate = rec->sample_rate * sc->sc_mclk_fs; 308 309 dai = sc->sc_dai_codec; 310 if (dai->dd_set_sysclk) { 311 error = dai->dd_set_sysclk(dai->dd_cookie, rate); 312 if (error) 313 return error; 314 } 315 316 dai = sc->sc_dai_cpu; 317 if (dai->dd_set_sysclk) { 318 error = dai->dd_set_sysclk(dai->dd_cookie, rate); 319 if (error) 320 return error; 321 } 322 } 323 324 dai = sc->sc_dai_cpu; 325 hwif = dai->dd_hw_if; 326 if (hwif->set_params) { 327 error = hwif->set_params(dai->dd_cookie, 328 setmode, usemode, play, rec); 329 if (error) 330 return error; 331 } 332 333 dai = sc->sc_dai_codec; 334 hwif = dai->dd_hw_if; 335 if (hwif->set_params) { 336 error = hwif->set_params(dai->dd_cookie, 337 setmode, usemode, play, rec); 338 if (error) 339 return error; 340 } 341 342 return 0; 343 } 344 345 void * 346 simpleaudio_allocm(void *cookie, int direction, size_t size, int type, 347 int flags) 348 { 349 struct simpleaudio_softc *sc = cookie; 350 struct dai_device *dai = sc->sc_dai_cpu; 351 struct audio_hw_if *hwif = dai->dd_hw_if; 352 353 if (hwif->allocm) 354 return hwif->allocm(dai->dd_cookie, 355 direction, size, type, flags); 356 357 return NULL; 358 } 359 360 void 361 simpleaudio_freem(void *cookie, void *addr, int type) 362 { 363 struct simpleaudio_softc *sc = cookie; 364 struct dai_device *dai = sc->sc_dai_cpu; 365 struct audio_hw_if *hwif = dai->dd_hw_if; 366 367 if (hwif->freem) 368 hwif->freem(dai->dd_cookie, addr, type); 369 } 370 371 int 372 simpleaudio_set_port(void *cookie, mixer_ctrl_t *cp) 373 { 374 struct simpleaudio_softc *sc = cookie; 375 struct dai_device *dai = sc->sc_dai_codec; 376 struct audio_hw_if *hwif = dai->dd_hw_if; 377 378 if (hwif->set_port) 379 return hwif->set_port(dai->dd_cookie, cp); 380 381 return ENXIO; 382 } 383 384 int 385 simpleaudio_get_port(void *cookie, mixer_ctrl_t *cp) 386 { 387 struct simpleaudio_softc *sc = cookie; 388 struct dai_device *dai = sc->sc_dai_codec; 389 struct audio_hw_if *hwif = dai->dd_hw_if; 390 391 if (hwif->get_port) 392 return hwif->get_port(dai->dd_cookie, cp); 393 394 return ENXIO; 395 } 396 397 int 398 simpleaudio_query_devinfo(void *cookie, mixer_devinfo_t *dip) 399 { 400 struct simpleaudio_softc *sc = cookie; 401 struct dai_device *dai = sc->sc_dai_codec; 402 struct audio_hw_if *hwif = dai->dd_hw_if; 403 404 if (hwif->query_devinfo) 405 return hwif->query_devinfo(dai->dd_cookie, dip); 406 407 return ENXIO; 408 } 409 410 int 411 simpleaudio_get_props(void *cookie) 412 { 413 struct simpleaudio_softc *sc = cookie; 414 struct dai_device *dai = sc->sc_dai_cpu; 415 struct audio_hw_if *hwif = dai->dd_hw_if; 416 417 if (hwif->get_props) 418 return hwif->get_props(dai->dd_cookie); 419 420 return 0; 421 } 422 423 int 424 simpleaudio_round_blocksize(void *cookie, int block) 425 { 426 struct simpleaudio_softc *sc = cookie; 427 struct dai_device *dai = sc->sc_dai_cpu; 428 struct audio_hw_if *hwif = dai->dd_hw_if; 429 430 if (hwif->round_blocksize) 431 return hwif->round_blocksize(dai->dd_cookie, block); 432 433 return block; 434 } 435 436 size_t 437 simpleaudio_round_buffersize(void *cookie, int direction, size_t bufsize) 438 { 439 struct simpleaudio_softc *sc = cookie; 440 struct dai_device *dai = sc->sc_dai_cpu; 441 struct audio_hw_if *hwif = dai->dd_hw_if; 442 443 if (hwif->round_buffersize) 444 return hwif->round_buffersize(dai->dd_cookie, 445 direction, bufsize); 446 447 return bufsize; 448 } 449 450 int 451 simpleaudio_trigger_output(void *cookie, void *start, void *end, int blksize, 452 void (*intr)(void *), void *arg, struct audio_params *param) 453 { 454 struct simpleaudio_softc *sc = cookie; 455 struct dai_device *dai; 456 struct audio_hw_if *hwif; 457 int error, i; 458 459 for (i = 0; i < sc->sc_dai_naux; i++) { 460 dai = sc->sc_dai_aux[i]; 461 hwif = dai->dd_hw_if; 462 if (hwif->trigger_output) { 463 error = hwif->trigger_output(dai->dd_cookie, 464 start, end, blksize, intr, arg, param); 465 if (error) { 466 simpleaudio_halt_output(cookie); 467 return error; 468 } 469 } 470 } 471 472 dai = sc->sc_dai_codec; 473 hwif = dai->dd_hw_if; 474 if (hwif->trigger_output) { 475 error = hwif->trigger_output(dai->dd_cookie, 476 start, end, blksize, intr, arg, param); 477 if (error) { 478 simpleaudio_halt_output(cookie); 479 return error; 480 } 481 } 482 483 dai = sc->sc_dai_cpu; 484 hwif = dai->dd_hw_if; 485 if (hwif->trigger_output) { 486 error = hwif->trigger_output(dai->dd_cookie, 487 start, end, blksize, intr, arg, param); 488 if (error) { 489 simpleaudio_halt_output(cookie); 490 return error; 491 } 492 } 493 494 return 0; 495 } 496 497 int 498 simpleaudio_trigger_input(void *cookie, void *start, void *end, int blksize, 499 void (*intr)(void *), void *arg, struct audio_params *param) 500 { 501 struct simpleaudio_softc *sc = cookie; 502 struct dai_device *dai; 503 struct audio_hw_if *hwif; 504 int error, i; 505 506 for (i = 0; i < sc->sc_dai_naux; i++) { 507 dai = sc->sc_dai_aux[i]; 508 hwif = dai->dd_hw_if; 509 if (hwif->trigger_input) { 510 error = hwif->trigger_input(dai->dd_cookie, 511 start, end, blksize, intr, arg, param); 512 if (error) { 513 simpleaudio_halt_input(cookie); 514 return error; 515 } 516 } 517 } 518 519 dai = sc->sc_dai_codec; 520 hwif = dai->dd_hw_if; 521 if (hwif->trigger_input) { 522 error = hwif->trigger_input(dai->dd_cookie, 523 start, end, blksize, intr, arg, param); 524 if (error) { 525 simpleaudio_halt_input(cookie); 526 return error; 527 } 528 } 529 530 dai = sc->sc_dai_cpu; 531 hwif = dai->dd_hw_if; 532 if (hwif->trigger_input) { 533 error = hwif->trigger_input(dai->dd_cookie, 534 start, end, blksize, intr, arg, param); 535 if (error) { 536 simpleaudio_halt_input(cookie); 537 return error; 538 } 539 } 540 541 return 0; 542 } 543 544 int simpleaudio_halt_output(void *cookie) 545 { 546 struct simpleaudio_softc *sc = cookie; 547 struct dai_device *dai; 548 struct audio_hw_if *hwif; 549 int i; 550 551 for (i = 0; i < sc->sc_dai_naux; i++) { 552 dai = sc->sc_dai_aux[i]; 553 hwif = dai->dd_hw_if; 554 if (hwif->halt_output) 555 hwif->halt_output(dai->dd_cookie); 556 } 557 558 dai = sc->sc_dai_codec; 559 hwif = dai->dd_hw_if; 560 if (hwif->halt_output) 561 hwif->halt_output(dai->dd_cookie); 562 563 dai = sc->sc_dai_cpu; 564 hwif = dai->dd_hw_if; 565 if (hwif->halt_output) 566 hwif->halt_output(dai->dd_cookie); 567 568 return 0; 569 } 570 571 int simpleaudio_halt_input(void *cookie) 572 { 573 struct simpleaudio_softc *sc = cookie; 574 struct dai_device *dai; 575 struct audio_hw_if *hwif; 576 int i; 577 578 for (i = 0; i < sc->sc_dai_naux; i++) { 579 dai = sc->sc_dai_aux[i]; 580 hwif = dai->dd_hw_if; 581 if (hwif->halt_input) 582 hwif->halt_input(dai->dd_cookie); 583 } 584 585 dai = sc->sc_dai_codec; 586 hwif = dai->dd_hw_if; 587 if (hwif->halt_input) 588 hwif->halt_input(dai->dd_cookie); 589 590 dai = sc->sc_dai_cpu; 591 hwif = dai->dd_hw_if; 592 if (hwif->halt_input) 593 hwif->halt_input(dai->dd_cookie); 594 595 return 0; 596 } 597