1 /* $OpenBSD: simpleaudio.c,v 1.7 2022/10/28 15:09:45 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_round_blocksize(void *, int); 61 size_t simpleaudio_round_buffersize(void *, int, size_t); 62 int simpleaudio_trigger_output(void *, void *, void *, int, 63 void (*)(void *), void *, struct audio_params *); 64 int simpleaudio_trigger_input(void *, void *, void *, int, 65 void (*)(void *), void *, struct audio_params *); 66 int simpleaudio_halt_output(void *); 67 int simpleaudio_halt_input(void *); 68 69 const struct audio_hw_if simpleaudio_hw_if = { 70 .open = simpleaudio_open, 71 .close = simpleaudio_close, 72 .set_params = simpleaudio_set_params, 73 .allocm = simpleaudio_allocm, 74 .freem = simpleaudio_freem, 75 .set_port = simpleaudio_set_port, 76 .get_port = simpleaudio_get_port, 77 .query_devinfo = simpleaudio_query_devinfo, 78 .round_blocksize = simpleaudio_round_blocksize, 79 .round_buffersize = simpleaudio_round_buffersize, 80 .trigger_output = simpleaudio_trigger_output, 81 .trigger_input = simpleaudio_trigger_input, 82 .halt_output = simpleaudio_halt_output, 83 .halt_input = simpleaudio_halt_input, 84 }; 85 86 const struct cfattach simpleaudio_ca = { 87 sizeof(struct simpleaudio_softc), simpleaudio_match, simpleaudio_attach 88 }; 89 90 struct cfdriver simpleaudio_cd = { 91 NULL, "simpleaudio", DV_DULL 92 }; 93 94 int 95 simpleaudio_match(struct device *parent, void *match, void *aux) 96 { 97 struct fdt_attach_args *faa = aux; 98 99 return OF_is_compatible(faa->fa_node, "simple-audio-card"); 100 } 101 102 void 103 simpleaudio_attach(struct device *parent, struct device *self, void *aux) 104 { 105 struct simpleaudio_softc *sc = (struct simpleaudio_softc *)self; 106 struct fdt_attach_args *faa = aux; 107 108 printf("\n"); 109 110 pinctrl_byname(faa->fa_node, "default"); 111 112 sc->sc_node = faa->fa_node; 113 config_defer(self, simpleaudio_attach_deferred); 114 } 115 116 void 117 simpleaudio_attach_deferred(struct device *self) 118 { 119 struct simpleaudio_softc *sc = (struct simpleaudio_softc *)self; 120 char format[16] = { 0 }; 121 uint32_t fmt, pol, clk; 122 uint32_t *auxdevs; 123 ssize_t len; 124 int i, node; 125 126 /* TODO: implement simple-audio-card,dai-link */ 127 if (OF_getnodebyname(sc->sc_node, "simple-audio-card,cpu") == 0 || 128 OF_getnodebyname(sc->sc_node, "simple-audio-card,codec") == 0) 129 return; 130 131 sc->sc_mclk_fs = OF_getpropint(sc->sc_node, 132 "simple-audio-card,mclk-fs", 0); 133 134 node = OF_getnodebyname(sc->sc_node, "simple-audio-card,cpu"); 135 sc->sc_dai_cpu = dai_byphandle(OF_getpropint(node, "sound-dai", 0)); 136 137 node = OF_getnodebyname(sc->sc_node, "simple-audio-card,codec"); 138 sc->sc_dai_codec = dai_byphandle(OF_getpropint(node, "sound-dai", 0)); 139 140 if (sc->sc_dai_cpu == NULL || sc->sc_dai_codec == NULL) 141 return; 142 143 OF_getprop(sc->sc_node, "simple-audio-card,format", 144 format, sizeof(format)); 145 if (!strcmp(format, "i2s")) 146 fmt = DAI_FORMAT_I2S; 147 else if (!strcmp(format, "right_j")) 148 fmt = DAI_FORMAT_RJ; 149 else if (!strcmp(format, "left_j")) 150 fmt = DAI_FORMAT_LJ; 151 else if (!strcmp(format, "dsp_a")) 152 fmt = DAI_FORMAT_DSPA; 153 else if (!strcmp(format, "dsp_b")) 154 fmt = DAI_FORMAT_DSPB; 155 else if (!strcmp(format, "ac97")) 156 fmt = DAI_FORMAT_AC97; 157 else if (!strcmp(format, "pdm")) 158 fmt = DAI_FORMAT_PDM; 159 else if (!strcmp(format, "msb")) 160 fmt = DAI_FORMAT_MSB; 161 else if (!strcmp(format, "lsb")) 162 fmt = DAI_FORMAT_LSB; 163 else 164 return; 165 166 pol = 0; 167 if (OF_getproplen(sc->sc_node, "simple-audio-card,frame-inversion") == 0) 168 pol |= DAI_POLARITY_IF; 169 else 170 pol |= DAI_POLARITY_NF; 171 if (OF_getproplen(sc->sc_node, "simple-audio-card,bitclock-inversion") == 0) 172 pol |= DAI_POLARITY_IB; 173 else 174 pol |= DAI_POLARITY_NB; 175 176 clk = 0; 177 if (OF_getproplen(sc->sc_node, "simple-audio-card,frame-master") == 0) 178 clk |= DAI_CLOCK_CFM; 179 else 180 clk |= DAI_CLOCK_CFS; 181 if (OF_getproplen(sc->sc_node, "simple-audio-card,bitclock-master") == 0) 182 clk |= DAI_CLOCK_CBM; 183 else 184 clk |= DAI_CLOCK_CBS; 185 186 len = OF_getproplen(sc->sc_node, "simple-audio-card,aux-devs"); 187 if (len > 0) { 188 if (len % sizeof(uint32_t) != 0) 189 return; 190 191 auxdevs = malloc(len, M_TEMP, M_WAITOK); 192 OF_getpropintarray(sc->sc_node, "simple-audio-card,aux-devs", 193 auxdevs, len); 194 195 sc->sc_dai_naux = len / sizeof(uint32_t); 196 sc->sc_dai_aux = mallocarray(sc->sc_dai_naux, 197 sizeof(struct dai_device *), M_DEVBUF, M_WAITOK | M_ZERO); 198 199 for (i = 0; i < sc->sc_dai_naux; i++) 200 sc->sc_dai_aux[i] = dai_byphandle(auxdevs[i]); 201 202 free(auxdevs, M_TEMP, len); 203 } 204 205 simpleaudio_set_format(sc, fmt, pol, clk); 206 207 audio_attach_mi(&simpleaudio_hw_if, sc, NULL, &sc->sc_dev); 208 } 209 210 void 211 simpleaudio_set_format(struct simpleaudio_softc *sc, uint32_t fmt, uint32_t pol, 212 uint32_t clk) 213 { 214 if (sc->sc_dai_cpu->dd_set_format) 215 sc->sc_dai_cpu->dd_set_format(sc->sc_dai_cpu->dd_cookie, 216 fmt, pol, clk); 217 if (sc->sc_dai_codec->dd_set_format) 218 sc->sc_dai_codec->dd_set_format(sc->sc_dai_codec->dd_cookie, 219 fmt, pol, clk); 220 } 221 222 int 223 simpleaudio_open(void *cookie, int flags) 224 { 225 struct simpleaudio_softc *sc = cookie; 226 struct dai_device *dai; 227 const struct audio_hw_if *hwif; 228 int error, i; 229 230 dai = sc->sc_dai_cpu; 231 hwif = dai->dd_hw_if; 232 if (hwif->open) { 233 error = hwif->open(dai->dd_cookie, flags); 234 if (error) { 235 simpleaudio_close(cookie); 236 return error; 237 } 238 } 239 240 dai = sc->sc_dai_codec; 241 hwif = dai->dd_hw_if; 242 if (hwif->open) { 243 error = hwif->open(dai->dd_cookie, flags); 244 if (error) { 245 simpleaudio_close(cookie); 246 return error; 247 } 248 } 249 250 for (i = 0; i < sc->sc_dai_naux; i++) { 251 dai = sc->sc_dai_aux[i]; 252 hwif = dai->dd_hw_if; 253 if (hwif->open) { 254 error = hwif->open(dai->dd_cookie, flags); 255 if (error) { 256 simpleaudio_close(cookie); 257 return error; 258 } 259 } 260 } 261 262 return 0; 263 } 264 265 void 266 simpleaudio_close(void *cookie) 267 { 268 struct simpleaudio_softc *sc = cookie; 269 struct dai_device *dai; 270 const struct audio_hw_if *hwif; 271 int i; 272 273 for (i = 0; i < sc->sc_dai_naux; i++) { 274 dai = sc->sc_dai_aux[i]; 275 hwif = dai->dd_hw_if; 276 if (hwif->close) 277 hwif->close(dai->dd_cookie); 278 } 279 280 dai = sc->sc_dai_codec; 281 hwif = dai->dd_hw_if; 282 if (hwif->close) 283 hwif->close(dai->dd_cookie); 284 285 dai = sc->sc_dai_cpu; 286 hwif = dai->dd_hw_if; 287 if (hwif->close) 288 hwif->close(dai->dd_cookie); 289 } 290 291 int 292 simpleaudio_set_params(void *cookie, int setmode, int usemode, 293 struct audio_params *play, struct audio_params *rec) 294 { 295 struct simpleaudio_softc *sc = cookie; 296 struct dai_device *dai; 297 const struct audio_hw_if *hwif; 298 uint32_t rate; 299 int error; 300 301 if (sc->sc_mclk_fs) { 302 if (setmode & AUMODE_PLAY) 303 rate = play->sample_rate * sc->sc_mclk_fs; 304 else 305 rate = rec->sample_rate * sc->sc_mclk_fs; 306 307 dai = sc->sc_dai_codec; 308 if (dai->dd_set_sysclk) { 309 error = dai->dd_set_sysclk(dai->dd_cookie, rate); 310 if (error) 311 return error; 312 } 313 314 dai = sc->sc_dai_cpu; 315 if (dai->dd_set_sysclk) { 316 error = dai->dd_set_sysclk(dai->dd_cookie, rate); 317 if (error) 318 return error; 319 } 320 } 321 322 dai = sc->sc_dai_cpu; 323 hwif = dai->dd_hw_if; 324 if (hwif->set_params) { 325 error = hwif->set_params(dai->dd_cookie, 326 setmode, usemode, play, rec); 327 if (error) 328 return error; 329 } 330 331 dai = sc->sc_dai_codec; 332 hwif = dai->dd_hw_if; 333 if (hwif->set_params) { 334 error = hwif->set_params(dai->dd_cookie, 335 setmode, usemode, play, rec); 336 if (error) 337 return error; 338 } 339 340 return 0; 341 } 342 343 void * 344 simpleaudio_allocm(void *cookie, int direction, size_t size, int type, 345 int flags) 346 { 347 struct simpleaudio_softc *sc = cookie; 348 struct dai_device *dai = sc->sc_dai_cpu; 349 const struct audio_hw_if *hwif = dai->dd_hw_if; 350 351 if (hwif->allocm) 352 return hwif->allocm(dai->dd_cookie, 353 direction, size, type, flags); 354 355 return NULL; 356 } 357 358 void 359 simpleaudio_freem(void *cookie, void *addr, int type) 360 { 361 struct simpleaudio_softc *sc = cookie; 362 struct dai_device *dai = sc->sc_dai_cpu; 363 const struct audio_hw_if *hwif = dai->dd_hw_if; 364 365 if (hwif->freem) 366 hwif->freem(dai->dd_cookie, addr, type); 367 } 368 369 int 370 simpleaudio_set_port(void *cookie, mixer_ctrl_t *cp) 371 { 372 struct simpleaudio_softc *sc = cookie; 373 struct dai_device *dai = sc->sc_dai_codec; 374 const struct audio_hw_if *hwif = dai->dd_hw_if; 375 376 if (hwif->set_port) 377 return hwif->set_port(dai->dd_cookie, cp); 378 379 return ENXIO; 380 } 381 382 int 383 simpleaudio_get_port(void *cookie, mixer_ctrl_t *cp) 384 { 385 struct simpleaudio_softc *sc = cookie; 386 struct dai_device *dai = sc->sc_dai_codec; 387 const struct audio_hw_if *hwif = dai->dd_hw_if; 388 389 if (hwif->get_port) 390 return hwif->get_port(dai->dd_cookie, cp); 391 392 return ENXIO; 393 } 394 395 int 396 simpleaudio_query_devinfo(void *cookie, mixer_devinfo_t *dip) 397 { 398 struct simpleaudio_softc *sc = cookie; 399 struct dai_device *dai = sc->sc_dai_codec; 400 const struct audio_hw_if *hwif = dai->dd_hw_if; 401 402 if (hwif->query_devinfo) 403 return hwif->query_devinfo(dai->dd_cookie, dip); 404 405 return ENXIO; 406 } 407 408 int 409 simpleaudio_round_blocksize(void *cookie, int block) 410 { 411 struct simpleaudio_softc *sc = cookie; 412 struct dai_device *dai = sc->sc_dai_cpu; 413 const struct audio_hw_if *hwif = dai->dd_hw_if; 414 415 if (hwif->round_blocksize) 416 return hwif->round_blocksize(dai->dd_cookie, block); 417 418 return block; 419 } 420 421 size_t 422 simpleaudio_round_buffersize(void *cookie, int direction, size_t bufsize) 423 { 424 struct simpleaudio_softc *sc = cookie; 425 struct dai_device *dai = sc->sc_dai_cpu; 426 const struct audio_hw_if *hwif = dai->dd_hw_if; 427 428 if (hwif->round_buffersize) 429 return hwif->round_buffersize(dai->dd_cookie, 430 direction, bufsize); 431 432 return bufsize; 433 } 434 435 int 436 simpleaudio_trigger_output(void *cookie, void *start, void *end, int blksize, 437 void (*intr)(void *), void *arg, struct audio_params *param) 438 { 439 struct simpleaudio_softc *sc = cookie; 440 struct dai_device *dai; 441 const struct audio_hw_if *hwif; 442 int error, i; 443 444 for (i = 0; i < sc->sc_dai_naux; i++) { 445 dai = sc->sc_dai_aux[i]; 446 hwif = dai->dd_hw_if; 447 if (hwif->trigger_output) { 448 error = hwif->trigger_output(dai->dd_cookie, 449 start, end, blksize, intr, arg, param); 450 if (error) { 451 simpleaudio_halt_output(cookie); 452 return error; 453 } 454 } 455 } 456 457 dai = sc->sc_dai_codec; 458 hwif = dai->dd_hw_if; 459 if (hwif->trigger_output) { 460 error = hwif->trigger_output(dai->dd_cookie, 461 start, end, blksize, intr, arg, param); 462 if (error) { 463 simpleaudio_halt_output(cookie); 464 return error; 465 } 466 } 467 468 dai = sc->sc_dai_cpu; 469 hwif = dai->dd_hw_if; 470 if (hwif->trigger_output) { 471 error = hwif->trigger_output(dai->dd_cookie, 472 start, end, blksize, intr, arg, param); 473 if (error) { 474 simpleaudio_halt_output(cookie); 475 return error; 476 } 477 } 478 479 return 0; 480 } 481 482 int 483 simpleaudio_trigger_input(void *cookie, void *start, void *end, int blksize, 484 void (*intr)(void *), void *arg, struct audio_params *param) 485 { 486 struct simpleaudio_softc *sc = cookie; 487 struct dai_device *dai; 488 const struct audio_hw_if *hwif; 489 int error, i; 490 491 for (i = 0; i < sc->sc_dai_naux; i++) { 492 dai = sc->sc_dai_aux[i]; 493 hwif = dai->dd_hw_if; 494 if (hwif->trigger_input) { 495 error = hwif->trigger_input(dai->dd_cookie, 496 start, end, blksize, intr, arg, param); 497 if (error) { 498 simpleaudio_halt_input(cookie); 499 return error; 500 } 501 } 502 } 503 504 dai = sc->sc_dai_codec; 505 hwif = dai->dd_hw_if; 506 if (hwif->trigger_input) { 507 error = hwif->trigger_input(dai->dd_cookie, 508 start, end, blksize, intr, arg, param); 509 if (error) { 510 simpleaudio_halt_input(cookie); 511 return error; 512 } 513 } 514 515 dai = sc->sc_dai_cpu; 516 hwif = dai->dd_hw_if; 517 if (hwif->trigger_input) { 518 error = hwif->trigger_input(dai->dd_cookie, 519 start, end, blksize, intr, arg, param); 520 if (error) { 521 simpleaudio_halt_input(cookie); 522 return error; 523 } 524 } 525 526 return 0; 527 } 528 529 int 530 simpleaudio_halt_output(void *cookie) 531 { 532 struct simpleaudio_softc *sc = cookie; 533 struct dai_device *dai; 534 const struct audio_hw_if *hwif; 535 int i; 536 537 for (i = 0; i < sc->sc_dai_naux; i++) { 538 dai = sc->sc_dai_aux[i]; 539 hwif = dai->dd_hw_if; 540 if (hwif->halt_output) 541 hwif->halt_output(dai->dd_cookie); 542 } 543 544 dai = sc->sc_dai_codec; 545 hwif = dai->dd_hw_if; 546 if (hwif->halt_output) 547 hwif->halt_output(dai->dd_cookie); 548 549 dai = sc->sc_dai_cpu; 550 hwif = dai->dd_hw_if; 551 if (hwif->halt_output) 552 hwif->halt_output(dai->dd_cookie); 553 554 return 0; 555 } 556 557 int 558 simpleaudio_halt_input(void *cookie) 559 { 560 struct simpleaudio_softc *sc = cookie; 561 struct dai_device *dai; 562 const struct audio_hw_if *hwif; 563 int i; 564 565 for (i = 0; i < sc->sc_dai_naux; i++) { 566 dai = sc->sc_dai_aux[i]; 567 hwif = dai->dd_hw_if; 568 if (hwif->halt_input) 569 hwif->halt_input(dai->dd_cookie); 570 } 571 572 dai = sc->sc_dai_codec; 573 hwif = dai->dd_hw_if; 574 if (hwif->halt_input) 575 hwif->halt_input(dai->dd_cookie); 576 577 dai = sc->sc_dai_cpu; 578 hwif = dai->dd_hw_if; 579 if (hwif->halt_input) 580 hwif->halt_input(dai->dd_cookie); 581 582 return 0; 583 } 584