Lines Matching +full:pcm +full:- +full:clock +full:- +full:mode

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2012-2016 Ruslan Bukin <br@bsdpad.com>
5 * Copyright (c) 2023-2024 Florian Walpen <dev@submerge.ch>
38 #include <dev/sound/pcm/sound.h>
52 &hdspe_unified_pcm, 0, "Combine physical ports in one unified pcm device");
122 snd_mtxlock(sc->lock); in hdspe_intr()
126 if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0) in hdspe_intr()
131 if (scp->ih != NULL) in hdspe_intr()
132 scp->ih(scp); in hdspe_intr()
139 snd_mtxunlock(sc->lock); in hdspe_intr()
146 device_printf(sc->dev, "hdspe_dmapsetmap()\n"); in hdspe_dmapsetmap()
155 sc->csid = PCIR_BAR(0); in hdspe_alloc_resources()
156 sc->cs = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, in hdspe_alloc_resources()
157 &sc->csid, RF_ACTIVE); in hdspe_alloc_resources()
159 if (!sc->cs) { in hdspe_alloc_resources()
160 device_printf(sc->dev, "Unable to map SYS_RES_MEMORY.\n"); in hdspe_alloc_resources()
164 sc->cst = rman_get_bustag(sc->cs); in hdspe_alloc_resources()
165 sc->csh = rman_get_bushandle(sc->cs); in hdspe_alloc_resources()
168 sc->irqid = 0; in hdspe_alloc_resources()
169 sc->irq = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irqid, in hdspe_alloc_resources()
172 if (!sc->irq || in hdspe_alloc_resources()
173 bus_setup_intr(sc->dev, sc->irq, INTR_MPSAFE | INTR_TYPE_AV, in hdspe_alloc_resources()
174 NULL, hdspe_intr, sc, &sc->ih)) { in hdspe_alloc_resources()
175 device_printf(sc->dev, "Unable to alloc interrupt resource.\n"); in hdspe_alloc_resources()
180 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), in hdspe_alloc_resources()
193 /*dmatag*/&sc->dmat) != 0) { in hdspe_alloc_resources()
194 device_printf(sc->dev, "Unable to create dma tag.\n"); in hdspe_alloc_resources()
198 sc->bufsize = HDSPE_DMASEGSIZE; in hdspe_alloc_resources()
201 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_WAITOK, in hdspe_alloc_resources()
202 &sc->pmap)) { in hdspe_alloc_resources()
203 device_printf(sc->dev, "Can't alloc pbuf.\n"); in hdspe_alloc_resources()
207 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->bufsize, in hdspe_alloc_resources()
209 device_printf(sc->dev, "Can't load pbuf.\n"); in hdspe_alloc_resources()
214 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_WAITOK, in hdspe_alloc_resources()
215 &sc->rmap)) { in hdspe_alloc_resources()
216 device_printf(sc->dev, "Can't alloc rbuf.\n"); in hdspe_alloc_resources()
220 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->bufsize, in hdspe_alloc_resources()
222 device_printf(sc->dev, "Can't load rbuf.\n"); in hdspe_alloc_resources()
226 bzero(sc->pbuf, sc->bufsize); in hdspe_alloc_resources()
227 bzero(sc->rbuf, sc->bufsize); in hdspe_alloc_resources()
238 paddr = vtophys(sc->pbuf); in hdspe_map_dmabuf()
239 raddr = vtophys(sc->rbuf); in hdspe_map_dmabuf()
258 return ("-10dBV"); in hdspe_settings_input_level()
273 sc = oidp->oid_arg1; in hdspe_sysctl_input_level()
276 if (sc->type != HDSPE_AIO) in hdspe_sysctl_input_level()
280 settings = sc->settings_register & HDSPE_INPUT_LEVEL_MASK; in hdspe_sysctl_input_level()
287 if (error != 0 || req->newptr == NULL) in hdspe_sysctl_input_level()
303 if (settings != (sc->settings_register & HDSPE_INPUT_LEVEL_MASK)) { in hdspe_sysctl_input_level()
304 snd_mtxlock(sc->lock); in hdspe_sysctl_input_level()
305 sc->settings_register &= ~HDSPE_INPUT_LEVEL_MASK; in hdspe_sysctl_input_level()
306 sc->settings_register |= settings; in hdspe_sysctl_input_level()
307 hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); in hdspe_sysctl_input_level()
308 snd_mtxunlock(sc->lock); in hdspe_sysctl_input_level()
322 return ("-10dBV"); in hdspe_settings_output_level()
337 sc = oidp->oid_arg1; in hdspe_sysctl_output_level()
340 if (sc->type != HDSPE_AIO) in hdspe_sysctl_output_level()
344 settings = sc->settings_register & HDSPE_OUTPUT_LEVEL_MASK; in hdspe_sysctl_output_level()
351 if (error != 0 || req->newptr == NULL) in hdspe_sysctl_output_level()
367 if (settings != (sc->settings_register & HDSPE_OUTPUT_LEVEL_MASK)) { in hdspe_sysctl_output_level()
368 snd_mtxlock(sc->lock); in hdspe_sysctl_output_level()
369 sc->settings_register &= ~HDSPE_OUTPUT_LEVEL_MASK; in hdspe_sysctl_output_level()
370 sc->settings_register |= settings; in hdspe_sysctl_output_level()
371 hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); in hdspe_sysctl_output_level()
372 snd_mtxunlock(sc->lock); in hdspe_sysctl_output_level()
386 return ("-10dBV"); in hdspe_settings_phones_level()
401 sc = oidp->oid_arg1; in hdspe_sysctl_phones_level()
404 if (sc->type != HDSPE_AIO) in hdspe_sysctl_phones_level()
408 settings = sc->settings_register & HDSPE_PHONES_LEVEL_MASK; in hdspe_sysctl_phones_level()
415 if (error != 0 || req->newptr == NULL) in hdspe_sysctl_phones_level()
431 if (settings != (sc->settings_register & HDSPE_PHONES_LEVEL_MASK)) { in hdspe_sysctl_phones_level()
432 snd_mtxlock(sc->lock); in hdspe_sysctl_phones_level()
433 sc->settings_register &= ~HDSPE_PHONES_LEVEL_MASK; in hdspe_sysctl_phones_level()
434 sc->settings_register |= settings; in hdspe_sysctl_phones_level()
435 hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); in hdspe_sysctl_phones_level()
436 snd_mtxunlock(sc->lock); in hdspe_sysctl_phones_level()
444 struct sc_info *sc = oidp->oid_arg1; in hdspe_sysctl_sample_rate()
448 speed = sc->force_speed; in hdspe_sysctl_sample_rate()
452 if (error != 0 || req->newptr == NULL) in hdspe_sysctl_sample_rate()
455 /* Speed from 32000 to 192000, 0 falls back to pcm speed setting. */ in hdspe_sysctl_sample_rate()
456 sc->force_speed = 0; in hdspe_sysctl_sample_rate()
465 sc->force_speed = 32000 * multiplier; in hdspe_sysctl_sample_rate()
467 sc->force_speed = 44100 * multiplier; in hdspe_sysctl_sample_rate()
469 sc->force_speed = 48000 * multiplier; in hdspe_sysctl_sample_rate()
479 struct sc_info *sc = oidp->oid_arg1; in hdspe_sysctl_period()
483 period = sc->force_period; in hdspe_sysctl_period()
487 if (error != 0 || req->newptr == NULL) in hdspe_sysctl_period()
490 /* Period is from 2^5 to 2^14, 0 falls back to pcm latency settings. */ in hdspe_sysctl_period()
491 sc->force_period = 0; in hdspe_sysctl_period()
493 sc->force_period = 32; in hdspe_sysctl_period()
494 while (sc->force_period < period && sc->force_period < 4096) in hdspe_sysctl_period()
495 sc->force_period <<= 1; in hdspe_sysctl_period()
505 struct hdspe_clock_source *clock_table, *clock; in hdspe_sysctl_clock_preference() local
510 sc = oidp->oid_arg1; in hdspe_sysctl_clock_preference()
513 if (sc->type == HDSPE_AIO) in hdspe_sysctl_clock_preference()
515 else if (sc->type == HDSPE_RAYDAT) in hdspe_sysctl_clock_preference()
520 /* Extract preferred clock source from settings register. */ in hdspe_sysctl_clock_preference()
521 setting = sc->settings_register & HDSPE_SETTING_CLOCK_MASK; in hdspe_sysctl_clock_preference()
522 for (clock = clock_table; clock->name != NULL; ++clock) { in hdspe_sysctl_clock_preference()
523 if (clock->setting == setting) in hdspe_sysctl_clock_preference()
526 if (clock->name != NULL) in hdspe_sysctl_clock_preference()
527 strlcpy(buf, clock->name, sizeof(buf)); in hdspe_sysctl_clock_preference()
531 if (error != 0 || req->newptr == NULL) in hdspe_sysctl_clock_preference()
534 /* Find clock source matching the sysctl string. */ in hdspe_sysctl_clock_preference()
535 for (clock = clock_table; clock->name != NULL; ++clock) { in hdspe_sysctl_clock_preference()
536 if (strncasecmp(buf, clock->name, sizeof(buf)) == 0) in hdspe_sysctl_clock_preference()
540 /* Set preferred clock source in settings register. */ in hdspe_sysctl_clock_preference()
541 if (clock->name != NULL) { in hdspe_sysctl_clock_preference()
542 setting = clock->setting & HDSPE_SETTING_CLOCK_MASK; in hdspe_sysctl_clock_preference()
543 snd_mtxlock(sc->lock); in hdspe_sysctl_clock_preference()
544 sc->settings_register &= ~HDSPE_SETTING_CLOCK_MASK; in hdspe_sysctl_clock_preference()
545 sc->settings_register |= setting; in hdspe_sysctl_clock_preference()
546 hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); in hdspe_sysctl_clock_preference()
547 snd_mtxunlock(sc->lock); in hdspe_sysctl_clock_preference()
556 struct hdspe_clock_source *clock_table, *clock; in hdspe_sysctl_clock_source() local
560 sc = oidp->oid_arg1; in hdspe_sysctl_clock_source()
563 if (sc->type == HDSPE_AIO) in hdspe_sysctl_clock_source()
565 else if (sc->type == HDSPE_RAYDAT) in hdspe_sysctl_clock_source()
570 /* Read current (autosync) clock source from status register. */ in hdspe_sysctl_clock_source()
571 snd_mtxlock(sc->lock); in hdspe_sysctl_clock_source()
574 snd_mtxunlock(sc->lock); in hdspe_sysctl_clock_source()
576 /* Translate status register value to clock source. */ in hdspe_sysctl_clock_source()
577 for (clock = clock_table; clock->name != NULL; ++clock) { in hdspe_sysctl_clock_source()
578 /* In clock master mode, override with internal clock source. */ in hdspe_sysctl_clock_source()
579 if (sc->settings_register & HDSPE_SETTING_MASTER) { in hdspe_sysctl_clock_source()
580 if (clock->setting & HDSPE_SETTING_MASTER) in hdspe_sysctl_clock_source()
582 } else if (clock->status == status) in hdspe_sysctl_clock_source()
587 if (clock->name != NULL) in hdspe_sysctl_clock_source()
588 strlcpy(buf, clock->name, sizeof(buf)); in hdspe_sysctl_clock_source()
596 struct hdspe_clock_source *clock_table, *clock; in hdspe_sysctl_clock_list() local
600 sc = oidp->oid_arg1; in hdspe_sysctl_clock_list()
603 /* Select clock source table for device type. */ in hdspe_sysctl_clock_list()
604 if (sc->type == HDSPE_AIO) in hdspe_sysctl_clock_list()
606 else if (sc->type == HDSPE_RAYDAT) in hdspe_sysctl_clock_list()
611 /* List available clock sources. */ in hdspe_sysctl_clock_list()
613 for (clock = clock_table; clock->name != NULL; ++clock) { in hdspe_sysctl_clock_list()
615 n += strlcpy(buf + n, ",", sizeof(buf) - n); in hdspe_sysctl_clock_list()
616 n += strlcpy(buf + n, clock->name, sizeof(buf) - n); in hdspe_sysctl_clock_list()
625 struct hdspe_clock_source *clock_table, *clock; in hdspe_sysctl_sync_status() local
631 sc = oidp->oid_arg1; in hdspe_sysctl_sync_status()
635 if (sc->type == HDSPE_AIO) in hdspe_sysctl_sync_status()
637 else if (sc->type == HDSPE_RAYDAT) in hdspe_sysctl_sync_status()
643 snd_mtxlock(sc->lock); in hdspe_sysctl_sync_status()
645 snd_mtxunlock(sc->lock); in hdspe_sysctl_sync_status()
647 /* List clock sources with lock and sync state. */ in hdspe_sysctl_sync_status()
648 for (clock = clock_table; clock->name != NULL; ++clock) { in hdspe_sysctl_sync_status()
649 if (clock->sync_bit != 0) { in hdspe_sysctl_sync_status()
651 n += strlcpy(buf + n, ",", sizeof(buf) - n); in hdspe_sysctl_sync_status()
653 if ((clock->sync_bit & status) != 0) in hdspe_sysctl_sync_status()
655 else if ((clock->lock_bit & status) != 0) in hdspe_sysctl_sync_status()
657 n += snprintf(buf + n, sizeof(buf) - n, "%s(%s)", in hdspe_sysctl_sync_status()
658 clock->name, state); in hdspe_sysctl_sync_status()
692 sc->period = 32; in hdspe_init()
694 * The pcm channel latency settings propagate unreliable blocksizes, in hdspe_init()
699 sc->force_period = 256; in hdspe_init()
700 sc->ctrl_register = hdspe_encode_latency(7); in hdspe_init()
703 sc->speed = HDSPE_SPEED_DEFAULT; in hdspe_init()
704 sc->force_speed = 0; in hdspe_init()
705 sc->ctrl_register &= ~HDSPE_FREQ_MASK; in hdspe_init()
706 sc->ctrl_register |= HDSPE_FREQ_MASK_DEFAULT; in hdspe_init()
707 hdspe_write_4(sc, HDSPE_CONTROL_REG, sc->ctrl_register); in hdspe_init()
709 switch (sc->type) { in hdspe_init()
719 period /= sc->speed; in hdspe_init()
723 sc->settings_register = 0; in hdspe_init()
726 sc->settings_register &= ~HDSPE_INPUT_LEVEL_MASK; in hdspe_init()
727 sc->settings_register |= HDSPE_INPUT_LEVEL_LOWGAIN; in hdspe_init()
728 sc->settings_register &= ~HDSPE_OUTPUT_LEVEL_MASK; in hdspe_init()
729 sc->settings_register |= HDSPE_OUTPUT_LEVEL_MINUS10DBV; in hdspe_init()
730 sc->settings_register &= ~HDSPE_PHONES_LEVEL_MASK; in hdspe_init()
731 sc->settings_register |= HDSPE_PHONES_LEVEL_MINUS10DBV; in hdspe_init()
733 hdspe_write_4(sc, HDSPE_SETTINGS_REG, sc->settings_register); in hdspe_init()
752 sc->lock = snd_mtxcreate(device_get_nameunit(dev), in hdspe_attach()
754 sc->dev = dev; in hdspe_attach()
760 sc->type = HDSPE_AIO; in hdspe_attach()
764 sc->type = HDSPE_RAYDAT; in hdspe_attach()
783 scp->hc = &chan_map[i]; in hdspe_attach()
784 scp->sc = sc; in hdspe_attach()
785 scp->dev = device_add_child(dev, "pcm", DEVICE_UNIT_ANY); in hdspe_attach()
786 device_set_ivars(scp->dev, scp); in hdspe_attach()
795 "List clock source signal lock and sync status"); in hdspe_attach()
801 "Currently effective clock source"); in hdspe_attach()
807 "Set 'internal' (master) or preferred autosync clock source"); in hdspe_attach()
813 "List of supported clock sources"); in hdspe_attach()
827 if (sc->type == HDSPE_AIO) { in hdspe_attach()
832 "Phones output level ('HighGain', '+4dBU', '-10dBV')"); in hdspe_attach()
838 "Analog output level ('HighGain', '+4dBU', '-10dBV')"); in hdspe_attach()
844 "Analog input level ('LowGain', '+4dBU', '-10dBV')"); in hdspe_attach()
861 bus_dmamap_unload(sc->dmat, sc->rmap); in hdspe_dmafree()
862 bus_dmamap_unload(sc->dmat, sc->pmap); in hdspe_dmafree()
863 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); in hdspe_dmafree()
864 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); in hdspe_dmafree()
865 sc->rbuf = sc->pbuf = NULL; in hdspe_dmafree()
886 if (sc->ih) in hdspe_detach()
887 bus_teardown_intr(dev, sc->irq, sc->ih); in hdspe_detach()
888 if (sc->dmat) in hdspe_detach()
889 bus_dma_tag_destroy(sc->dmat); in hdspe_detach()
890 if (sc->irq) in hdspe_detach()
891 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); in hdspe_detach()
892 if (sc->cs) in hdspe_detach()
893 bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs); in hdspe_detach()
894 if (sc->lock) in hdspe_detach()
895 snd_mtxfree(sc->lock); in hdspe_detach()