1139749Simp/*- 2136944Syongari * Copyright (c) 1999 Jason L. Wright (jason@thought.net) 3136944Syongari * Copyright (c) 2004 Pyun YongHyeon 4136944Syongari * All rights reserved. 5136944Syongari * 6136944Syongari * Redistribution and use in source and binary forms, with or without 7136944Syongari * modification, are permitted provided that the following conditions 8136944Syongari * are met: 9136944Syongari * 1. Redistributions of source code must retain the above copyright 10136944Syongari * notice, this list of conditions and the following disclaimer. 11136944Syongari * 2. Redistributions in binary form must reproduce the above copyright 12136944Syongari * notice, this list of conditions and the following disclaimer in the 13136944Syongari * documentation and/or other materials provided with the distribution. 14136944Syongari * 15136944Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16136944Syongari * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17136944Syongari * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18136944Syongari * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19136944Syongari * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20136944Syongari * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21136944Syongari * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22136944Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23136944Syongari * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24136944Syongari * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25136944Syongari * POSSIBILITY OF SUCH DAMAGE. 26136944Syongari * 27136944Syongari * Effort sponsored in part by the Defense Advanced Research Projects 28136944Syongari * Agency (DARPA) and Air Force Research Laboratory, Air Force 29136944Syongari * Materiel Command, USAF, under agreement number F30602-01-2-0537. 30136944Syongari * 31136944Syongari * from: OpenBSD: cs4231.c,v 1.21 2003/07/03 20:36:07 jason Exp 32136944Syongari */ 33136944Syongari 34136944Syongari/* 35136944Syongari * Driver for CS4231 based audio found in some sun4m systems (cs4231) 36136944Syongari * based on ideas from the S/Linux project and the NetBSD project. 37136944Syongari */ 38136944Syongari 39136944Syongari#include <sys/cdefs.h> 40136944Syongari__FBSDID("$FreeBSD$"); 41136944Syongari 42136944Syongari#include <sys/param.h> 43136944Syongari#include <sys/systm.h> 44136944Syongari#include <sys/bus.h> 45136944Syongari#include <sys/kernel.h> 46136944Syongari#include <sys/resource.h> 47136944Syongari 48136944Syongari#include <dev/ofw/ofw_bus.h> 49136944Syongari#include <dev/ofw/openfirm.h> 50136944Syongari#include <machine/bus.h> 51136944Syongari#include <machine/ofw_machdep.h> 52136944Syongari 53193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 54193640Sariff#include "opt_snd.h" 55193640Sariff#endif 56193640Sariff 57136944Syongari#include <dev/sound/pcm/sound.h> 58136944Syongari#include <dev/sound/sbus/apcdmareg.h> 59136944Syongari#include <dev/sound/sbus/cs4231.h> 60136944Syongari 61136944Syongari#include <sparc64/sbus/sbusvar.h> 62136944Syongari#include <sparc64/ebus/ebusreg.h> 63136944Syongari 64136944Syongari#include "mixer_if.h" 65136944Syongari 66136944Syongari/* 67136944Syongari * The driver supports CS4231A audio chips found on Sbus/Ebus based 68136944Syongari * UltraSPARCs. Though, CS4231A says it supports full-duplex mode, I 69136944Syongari * doubt it due to the lack of independent sampling frequency register 70136944Syongari * for playback/capture. 71136944Syongari * Since I couldn't find any documentation for APCDMA programming 72136944Syongari * information, I guessed the usage of APCDMA from that of OpenBSD's 73215034Sbrucec * driver. The EBDMA information of PCIO can be obtained from 74136944Syongari * http://solutions.sun.com/embedded/databook/web/microprocessors/pcio.html 75136944Syongari * And CS4231A datasheet can also be obtained from 76136944Syongari * ftp://ftp.alsa-project.org/pub/manuals/cirrus/4231a.pdf 77136944Syongari * 78136944Syongari * Audio capture(recording) was not tested at all and may have bugs. 79136944Syongari * Sorry, I don't have microphone. Don't try to use full-duplex mode. 80136944Syongari * It wouldn't work. 81136944Syongari */ 82136944Syongari#define CS_TIMEOUT 90000 83136944Syongari 84136944Syongari#define CS4231_MIN_BUF_SZ (16*1024) 85136944Syongari#define CS4231_DEFAULT_BUF_SZ (32*1024) 86136944Syongari#define CS4231_MAX_BUF_SZ (64*1024) 87136944Syongari#define CS4231_MAX_BLK_SZ (8*1024) 88136944Syongari#define CS4231_MAX_APC_DMA_SZ (8*1024) 89136944Syongari 90136944Syongari 91136944Syongari#undef CS4231_DEBUG 92136944Syongari#ifdef CS4231_DEBUG 93136944Syongari#define DPRINTF(x) printf x 94136944Syongari#else 95136944Syongari#define DPRINTF(x) 96136944Syongari#endif 97136944Syongari#define CS4231_AUTO_CALIBRATION 98136944Syongari 99136944Syongaristruct cs4231_softc; 100136944Syongari 101136944Syongaristruct cs4231_channel { 102136944Syongari struct cs4231_softc *parent; 103136944Syongari struct pcm_channel *channel; 104136944Syongari struct snd_dbuf *buffer; 105136944Syongari u_int32_t format; 106136944Syongari u_int32_t speed; 107136944Syongari u_int32_t nextaddr; 108136944Syongari u_int32_t togo; 109136944Syongari int dir; 110136944Syongari int locked; 111136944Syongari}; 112136944Syongari 113136944Syongari#define CS4231_RES_MEM_MAX 4 114136944Syongari#define CS4231_RES_IRQ_MAX 2 115136944Syongaristruct cs4231_softc { 116136944Syongari struct device *sc_dev; 117136944Syongari int sc_rid[CS4231_RES_MEM_MAX]; 118136944Syongari struct resource *sc_res[CS4231_RES_MEM_MAX]; 119136944Syongari bus_space_handle_t sc_regh[CS4231_RES_MEM_MAX]; 120136944Syongari bus_space_tag_t sc_regt[CS4231_RES_MEM_MAX]; 121136944Syongari 122136944Syongari int sc_irqrid[CS4231_RES_IRQ_MAX]; 123136944Syongari struct resource *sc_irqres[CS4231_RES_IRQ_MAX]; 124136944Syongari void *sc_ih[CS4231_RES_IRQ_MAX]; 125136944Syongari bus_dma_tag_t sc_dmat[CS4231_RES_IRQ_MAX]; 126136944Syongari int sc_burst; 127136944Syongari 128136944Syongari u_int32_t sc_bufsz; 129136944Syongari struct cs4231_channel sc_pch; 130136944Syongari struct cs4231_channel sc_rch; 131136944Syongari int sc_enabled; 132136944Syongari int sc_nmres; 133136944Syongari int sc_nires; 134136944Syongari int sc_codecv; 135136944Syongari int sc_chipvid; 136136944Syongari int sc_flags; 137136944Syongari#define CS4231_SBUS 0x01 138136944Syongari#define CS4231_EBUS 0x02 139136944Syongari 140136944Syongari struct mtx *sc_lock; 141136944Syongari}; 142136944Syongari 143136944Syongaristruct mix_table { 144136944Syongari u_int32_t reg:8; 145136944Syongari u_int32_t bits:8; 146136944Syongari u_int32_t mute:8; 147136944Syongari u_int32_t shift:4; 148136944Syongari u_int32_t neg:1; 149136944Syongari u_int32_t avail:1; 150136944Syongari u_int32_t recdev:1; 151136944Syongari}; 152136944Syongari 153136944Syongaristatic int cs4231_bus_probe(device_t); 154136944Syongaristatic int cs4231_sbus_attach(device_t); 155136944Syongaristatic int cs4231_ebus_attach(device_t); 156136944Syongaristatic int cs4231_attach_common(struct cs4231_softc *); 157136944Syongaristatic int cs4231_bus_detach(device_t); 158136944Syongaristatic int cs4231_bus_suspend(device_t); 159136944Syongaristatic int cs4231_bus_resume(device_t); 160136944Syongaristatic void cs4231_getversion(struct cs4231_softc *); 161136944Syongaristatic void cs4231_free_resource(struct cs4231_softc *); 162136944Syongaristatic void cs4231_ebdma_reset(struct cs4231_softc *); 163136944Syongaristatic void cs4231_power_reset(struct cs4231_softc *, int); 164136944Syongaristatic int cs4231_enable(struct cs4231_softc *, int); 165136944Syongaristatic void cs4231_disable(struct cs4231_softc *); 166136944Syongaristatic void cs4231_write(struct cs4231_softc *, u_int8_t, u_int8_t); 167136944Syongaristatic u_int8_t cs4231_read(struct cs4231_softc *, u_int8_t); 168136944Syongaristatic void cs4231_sbus_intr(void *); 169136944Syongaristatic void cs4231_ebus_pintr(void *arg); 170136944Syongaristatic void cs4231_ebus_cintr(void *arg); 171136944Syongaristatic int cs4231_mixer_init(struct snd_mixer *); 172136944Syongaristatic void cs4231_mixer_set_value(struct cs4231_softc *, 173136944Syongari const struct mix_table *, u_int8_t); 174136944Syongaristatic int cs4231_mixer_set(struct snd_mixer *, u_int32_t, u_int32_t, 175136944Syongari u_int32_t); 176193779Sariffstatic u_int32_t cs4231_mixer_setrecsrc(struct snd_mixer *, u_int32_t); 177136944Syongaristatic void *cs4231_chan_init(kobj_t, void *, struct snd_dbuf *, 178136944Syongari struct pcm_channel *, int); 179136944Syongaristatic int cs4231_chan_setformat(kobj_t, void *, u_int32_t); 180193779Sariffstatic u_int32_t cs4231_chan_setspeed(kobj_t, void *, u_int32_t); 181136944Syongaristatic void cs4231_chan_fs(struct cs4231_softc *, int, u_int8_t); 182193779Sariffstatic u_int32_t cs4231_chan_setblocksize(kobj_t, void *, u_int32_t); 183136944Syongaristatic int cs4231_chan_trigger(kobj_t, void *, int); 184193779Sariffstatic u_int32_t cs4231_chan_getptr(kobj_t, void *); 185136944Syongaristatic struct pcmchan_caps * 186136944Syongari cs4231_chan_getcaps(kobj_t, void *); 187136944Syongaristatic void cs4231_trigger(struct cs4231_channel *); 188136944Syongaristatic void cs4231_apcdma_trigger(struct cs4231_softc *, 189136944Syongari struct cs4231_channel *); 190136944Syongaristatic void cs4231_ebdma_trigger(struct cs4231_softc *, 191136944Syongari struct cs4231_channel *); 192136944Syongaristatic void cs4231_halt(struct cs4231_channel *); 193136944Syongari 194136944Syongari#define CS4231_LOCK(sc) snd_mtxlock(sc->sc_lock) 195136944Syongari#define CS4231_UNLOCK(sc) snd_mtxunlock(sc->sc_lock) 196136944Syongari#define CS4231_LOCK_ASSERT(sc) snd_mtxassert(sc->sc_lock) 197136944Syongari 198136944Syongari#define CS_WRITE(sc,r,v) \ 199136944Syongari bus_space_write_1((sc)->sc_regt[0], (sc)->sc_regh[0], (r) << 2, (v)) 200136944Syongari#define CS_READ(sc,r) \ 201136944Syongari bus_space_read_1((sc)->sc_regt[0], (sc)->sc_regh[0], (r) << 2) 202136944Syongari 203136944Syongari#define APC_WRITE(sc,r,v) \ 204136944Syongari bus_space_write_4(sc->sc_regt[0], sc->sc_regh[0], r, v) 205136944Syongari#define APC_READ(sc,r) \ 206136944Syongari bus_space_read_4(sc->sc_regt[0], sc->sc_regh[0], r) 207136944Syongari 208136944Syongari#define EBDMA_P_WRITE(sc,r,v) \ 209136944Syongari bus_space_write_4((sc)->sc_regt[1], (sc)->sc_regh[1], (r), (v)) 210136944Syongari#define EBDMA_P_READ(sc,r) \ 211136944Syongari bus_space_read_4((sc)->sc_regt[1], (sc)->sc_regh[1], (r)) 212136944Syongari 213136944Syongari#define EBDMA_C_WRITE(sc,r,v) \ 214136944Syongari bus_space_write_4((sc)->sc_regt[2], (sc)->sc_regh[2], (r), (v)) 215136944Syongari#define EBDMA_C_READ(sc,r) \ 216136944Syongari bus_space_read_4((sc)->sc_regt[2], (sc)->sc_regh[2], (r)) 217136944Syongari 218136944Syongari#define AUXIO_CODEC 0x00 219136944Syongari#define AUXIO_WRITE(sc,r,v) \ 220136944Syongari bus_space_write_4((sc)->sc_regt[3], (sc)->sc_regh[3], (r), (v)) 221136944Syongari#define AUXIO_READ(sc,r) \ 222136944Syongari bus_space_read_4((sc)->sc_regt[3], (sc)->sc_regh[3], (r)) 223136944Syongari 224136944Syongari#define CODEC_WARM_RESET 0 225136944Syongari#define CODEC_COLD_RESET 1 226136944Syongari 227136944Syongari/* SBus */ 228136944Syongaristatic device_method_t cs4231_sbus_methods[] = { 229136944Syongari DEVMETHOD(device_probe, cs4231_bus_probe), 230136944Syongari DEVMETHOD(device_attach, cs4231_sbus_attach), 231136944Syongari DEVMETHOD(device_detach, cs4231_bus_detach), 232136944Syongari DEVMETHOD(device_suspend, cs4231_bus_suspend), 233136944Syongari DEVMETHOD(device_resume, cs4231_bus_resume), 234246128Ssbz 235246128Ssbz DEVMETHOD_END 236136944Syongari}; 237136944Syongari 238136944Syongaristatic driver_t cs4231_sbus_driver = { 239136944Syongari "pcm", 240136944Syongari cs4231_sbus_methods, 241136944Syongari PCM_SOFTC_SIZE 242136944Syongari}; 243136944Syongari 244136944SyongariDRIVER_MODULE(snd_audiocs, sbus, cs4231_sbus_driver, pcm_devclass, 0, 0); 245136944Syongari 246136944Syongari/* EBus */ 247136944Syongaristatic device_method_t cs4231_ebus_methods[] = { 248136944Syongari DEVMETHOD(device_probe, cs4231_bus_probe), 249136944Syongari DEVMETHOD(device_attach, cs4231_ebus_attach), 250136944Syongari DEVMETHOD(device_detach, cs4231_bus_detach), 251136944Syongari DEVMETHOD(device_suspend, cs4231_bus_suspend), 252136944Syongari DEVMETHOD(device_resume, cs4231_bus_resume), 253246128Ssbz 254246128Ssbz DEVMETHOD_END 255136944Syongari}; 256136944Syongari 257136944Syongaristatic driver_t cs4231_ebus_driver = { 258136944Syongari "pcm", 259136944Syongari cs4231_ebus_methods, 260136944Syongari PCM_SOFTC_SIZE 261136944Syongari}; 262136944Syongari 263136944SyongariDRIVER_MODULE(snd_audiocs, ebus, cs4231_ebus_driver, pcm_devclass, 0, 0); 264136944SyongariMODULE_DEPEND(snd_audiocs, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 265136944SyongariMODULE_VERSION(snd_audiocs, 1); 266136944Syongari 267136944Syongari 268136944Syongaristatic u_int32_t cs4231_fmt[] = { 269193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 270193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 271193640Sariff SND_FORMAT(AFMT_MU_LAW, 1, 0), 272193640Sariff SND_FORMAT(AFMT_MU_LAW, 2, 0), 273193640Sariff SND_FORMAT(AFMT_A_LAW, 1, 0), 274193640Sariff SND_FORMAT(AFMT_A_LAW, 2, 0), 275193640Sariff SND_FORMAT(AFMT_IMA_ADPCM, 1, 0), 276193640Sariff SND_FORMAT(AFMT_IMA_ADPCM, 2, 0), 277193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 278193667Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 279193640Sariff SND_FORMAT(AFMT_S16_BE, 1, 0), 280193640Sariff SND_FORMAT(AFMT_S16_BE, 2, 0), 281136944Syongari 0 282136944Syongari}; 283136944Syongari 284136944Syongaristatic struct pcmchan_caps cs4231_caps = {5510, 48000, cs4231_fmt, 0}; 285136944Syongari 286136944Syongari/* 287136944Syongari * sound(4) channel interface 288136944Syongari */ 289136944Syongaristatic kobj_method_t cs4231_chan_methods[] = { 290136944Syongari KOBJMETHOD(channel_init, cs4231_chan_init), 291136944Syongari KOBJMETHOD(channel_setformat, cs4231_chan_setformat), 292136944Syongari KOBJMETHOD(channel_setspeed, cs4231_chan_setspeed), 293136944Syongari KOBJMETHOD(channel_setblocksize, cs4231_chan_setblocksize), 294136944Syongari KOBJMETHOD(channel_trigger, cs4231_chan_trigger), 295136944Syongari KOBJMETHOD(channel_getptr, cs4231_chan_getptr), 296136944Syongari KOBJMETHOD(channel_getcaps, cs4231_chan_getcaps), 297193640Sariff KOBJMETHOD_END 298136944Syongari}; 299136944SyongariCHANNEL_DECLARE(cs4231_chan); 300136944Syongari 301136944Syongari/* 302136944Syongari * sound(4) mixer interface 303136944Syongari */ 304136944Syongaristatic kobj_method_t cs4231_mixer_methods[] = { 305136944Syongari KOBJMETHOD(mixer_init, cs4231_mixer_init), 306136944Syongari KOBJMETHOD(mixer_set, cs4231_mixer_set), 307136944Syongari KOBJMETHOD(mixer_setrecsrc, cs4231_mixer_setrecsrc), 308193640Sariff KOBJMETHOD_END 309136944Syongari}; 310136944SyongariMIXER_DECLARE(cs4231_mixer); 311136944Syongari 312136944Syongaristatic int 313136944Syongarics4231_bus_probe(device_t dev) 314136944Syongari{ 315166098Smarius const char *compat, *name; 316136944Syongari 317166098Smarius compat = ofw_bus_get_compat(dev); 318136944Syongari name = ofw_bus_get_name(dev); 319166098Smarius if (strcmp("SUNW,CS4231", name) == 0 || 320166098Smarius (compat != NULL && strcmp("SUNW,CS4231", compat) == 0)) { 321136944Syongari device_set_desc(dev, "Sun Audiocs"); 322142890Simp return (BUS_PROBE_DEFAULT); 323136944Syongari } 324136944Syongari return (ENXIO); 325136944Syongari} 326136944Syongari 327136944Syongaristatic int 328136944Syongarics4231_sbus_attach(device_t dev) 329136944Syongari{ 330136944Syongari struct cs4231_softc *sc; 331136944Syongari int burst; 332136944Syongari 333170873Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 334136944Syongari sc->sc_dev = dev; 335136944Syongari /* 336136944Syongari * XXX 337136944Syongari * No public documentation exists on programming burst size of APCDMA. 338136944Syongari */ 339136944Syongari burst = sbus_get_burstsz(sc->sc_dev); 340136944Syongari if ((burst & SBUS_BURST_64)) 341136944Syongari sc->sc_burst = 64; 342136944Syongari else if ((burst & SBUS_BURST_32)) 343136944Syongari sc->sc_burst = 32; 344136944Syongari else if ((burst & SBUS_BURST_16)) 345136944Syongari sc->sc_burst = 16; 346136944Syongari else 347136944Syongari sc->sc_burst = 0; 348136944Syongari sc->sc_flags = CS4231_SBUS; 349136944Syongari sc->sc_nmres = 1; 350136944Syongari sc->sc_nires = 1; 351136944Syongari return cs4231_attach_common(sc); 352136944Syongari} 353136944Syongari 354136944Syongaristatic int 355136944Syongarics4231_ebus_attach(device_t dev) 356136944Syongari{ 357136944Syongari struct cs4231_softc *sc; 358136944Syongari 359136944Syongari sc = malloc(sizeof(struct cs4231_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 360136944Syongari if (sc == NULL) { 361136944Syongari device_printf(dev, "cannot allocate softc\n"); 362136944Syongari return (ENOMEM); 363136944Syongari } 364136944Syongari sc->sc_dev = dev; 365136944Syongari sc->sc_burst = EBDCSR_BURST_1; 366136944Syongari sc->sc_nmres = CS4231_RES_MEM_MAX; 367136944Syongari sc->sc_nires = CS4231_RES_IRQ_MAX; 368136944Syongari sc->sc_flags = CS4231_EBUS; 369136944Syongari return cs4231_attach_common(sc); 370136944Syongari} 371136944Syongari 372136944Syongaristatic int 373136944Syongarics4231_attach_common(struct cs4231_softc *sc) 374136944Syongari{ 375136944Syongari char status[SND_STATUSLEN]; 376136944Syongari driver_intr_t *ihandler; 377136944Syongari int i; 378136944Syongari 379136944Syongari sc->sc_lock = snd_mtxcreate(device_get_nameunit(sc->sc_dev), 380167608Sariff "snd_cs4231 softc"); 381136944Syongari 382136944Syongari for (i = 0; i < sc->sc_nmres; i++) { 383136944Syongari sc->sc_rid[i] = i; 384136944Syongari if ((sc->sc_res[i] = bus_alloc_resource_any(sc->sc_dev, 385146410Smarius SYS_RES_MEMORY, &sc->sc_rid[i], RF_ACTIVE)) == NULL) { 386136944Syongari device_printf(sc->sc_dev, 387136944Syongari "cannot map register %d\n", i); 388136944Syongari goto fail; 389136944Syongari } 390136944Syongari sc->sc_regt[i] = rman_get_bustag(sc->sc_res[i]); 391136944Syongari sc->sc_regh[i] = rman_get_bushandle(sc->sc_res[i]); 392136944Syongari } 393136944Syongari for (i = 0; i < sc->sc_nires; i++) { 394136944Syongari sc->sc_irqrid[i] = i; 395136944Syongari if ((sc->sc_irqres[i] = bus_alloc_resource_any(sc->sc_dev, 396136944Syongari SYS_RES_IRQ, &sc->sc_irqrid[i], RF_SHAREABLE | RF_ACTIVE)) 397136944Syongari == NULL) { 398136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 399136944Syongari device_printf(sc->sc_dev, 400136944Syongari "cannot allocate interrupt\n"); 401136944Syongari else 402136944Syongari device_printf(sc->sc_dev, "cannot allocate %s " 403136944Syongari "interrupt\n", i == 0 ? "capture" : 404136944Syongari "playback"); 405136944Syongari goto fail; 406136944Syongari } 407136944Syongari } 408136944Syongari 409136944Syongari ihandler = cs4231_sbus_intr; 410136944Syongari for (i = 0; i < sc->sc_nires; i++) { 411136944Syongari if ((sc->sc_flags & CS4231_EBUS) != 0) { 412136944Syongari if (i == 0) 413136944Syongari ihandler = cs4231_ebus_cintr; 414136944Syongari else 415136944Syongari ihandler = cs4231_ebus_pintr; 416136944Syongari } 417136944Syongari if (snd_setup_intr(sc->sc_dev, sc->sc_irqres[i], INTR_MPSAFE, 418136944Syongari ihandler, sc, &sc->sc_ih[i])) { 419136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 420136944Syongari device_printf(sc->sc_dev, 421136944Syongari "cannot set up interrupt\n"); 422136944Syongari else 423136944Syongari device_printf(sc->sc_dev, "cannot set up %s " 424136944Syongari " interrupt\n", i == 0 ? "capture" : 425136944Syongari "playback"); 426136944Syongari goto fail; 427136944Syongari } 428136944Syongari } 429136944Syongari 430136944Syongari sc->sc_bufsz = pcm_getbuffersize(sc->sc_dev, CS4231_MIN_BUF_SZ, 431136944Syongari CS4231_DEFAULT_BUF_SZ, CS4231_MAX_BUF_SZ); 432136944Syongari for (i = 0; i < sc->sc_nires; i++) { 433136944Syongari if (bus_dma_tag_create( 434166165Smarius bus_get_dma_tag(sc->sc_dev),/* parent */ 435136944Syongari 64, 0, /* alignment, boundary */ 436136944Syongari BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 437136944Syongari BUS_SPACE_MAXADDR, /* highaddr */ 438136944Syongari NULL, NULL, /* filtfunc, filtfuncarg */ 439136944Syongari sc->sc_bufsz, /* maxsize */ 440136944Syongari 1, /* nsegments */ 441136944Syongari sc->sc_bufsz, /* maxsegsz */ 442136944Syongari BUS_DMA_ALLOCNOW, /* flags */ 443136944Syongari NULL, /* lockfunc */ 444136944Syongari NULL, /* lockfuncarg */ 445136944Syongari &sc->sc_dmat[i])) { 446136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 447136944Syongari device_printf(sc->sc_dev, 448136944Syongari "cannot allocate DMA tag\n"); 449136944Syongari else 450136944Syongari device_printf(sc->sc_dev, "cannot allocate %s " 451136944Syongari "DMA tag\n", i == 0 ? "capture" : 452136944Syongari "playback"); 453136944Syongari goto fail; 454136944Syongari } 455136944Syongari } 456136944Syongari cs4231_enable(sc, CODEC_WARM_RESET); 457136944Syongari cs4231_getversion(sc); 458136944Syongari if (mixer_init(sc->sc_dev, &cs4231_mixer_class, sc) != 0) 459136944Syongari goto fail; 460136944Syongari if (pcm_register(sc->sc_dev, sc, 1, 1)) { 461136944Syongari device_printf(sc->sc_dev, "cannot register to pcm\n"); 462136944Syongari goto fail; 463136944Syongari } 464136944Syongari if (pcm_addchan(sc->sc_dev, PCMDIR_REC, &cs4231_chan_class, sc) != 0) 465136944Syongari goto chan_fail; 466136944Syongari if (pcm_addchan(sc->sc_dev, PCMDIR_PLAY, &cs4231_chan_class, sc) != 0) 467136944Syongari goto chan_fail; 468136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 469136944Syongari snprintf(status, SND_STATUSLEN, "at mem 0x%lx irq %ld bufsz %u", 470136944Syongari rman_get_start(sc->sc_res[0]), 471136944Syongari rman_get_start(sc->sc_irqres[0]), sc->sc_bufsz); 472136944Syongari else 473136944Syongari snprintf(status, SND_STATUSLEN, "at io 0x%lx 0x%lx 0x%lx 0x%lx " 474136944Syongari "irq %ld %ld bufsz %u", rman_get_start(sc->sc_res[0]), 475136944Syongari rman_get_start(sc->sc_res[1]), 476136944Syongari rman_get_start(sc->sc_res[2]), 477136944Syongari rman_get_start(sc->sc_res[3]), 478136944Syongari rman_get_start(sc->sc_irqres[0]), 479136944Syongari rman_get_start(sc->sc_irqres[1]), sc->sc_bufsz); 480136944Syongari pcm_setstatus(sc->sc_dev, status); 481136944Syongari return (0); 482136944Syongari 483136944Syongarichan_fail: 484136944Syongari pcm_unregister(sc->sc_dev); 485136944Syongarifail: 486136944Syongari cs4231_free_resource(sc); 487136944Syongari return (ENXIO); 488136944Syongari} 489136944Syongari 490136944Syongaristatic int 491136944Syongarics4231_bus_detach(device_t dev) 492136944Syongari{ 493136944Syongari struct cs4231_softc *sc; 494136944Syongari struct cs4231_channel *pch, *rch; 495136944Syongari int error; 496136944Syongari 497136944Syongari sc = pcm_getdevinfo(dev); 498136944Syongari CS4231_LOCK(sc); 499136944Syongari pch = &sc->sc_pch; 500136944Syongari rch = &sc->sc_pch; 501136944Syongari if (pch->locked || rch->locked) { 502136944Syongari CS4231_UNLOCK(sc); 503136944Syongari return (EBUSY); 504136944Syongari } 505136944Syongari /* 506136944Syongari * Since EBDMA requires valid DMA buffer to drain its FIFO, we need 507136944Syongari * real DMA buffer for draining. 508136944Syongari */ 509136944Syongari if ((sc->sc_flags & CS4231_EBUS) != 0) 510136944Syongari cs4231_ebdma_reset(sc); 511136944Syongari CS4231_UNLOCK(sc); 512136944Syongari error = pcm_unregister(dev); 513136944Syongari if (error) 514136944Syongari return (error); 515136944Syongari cs4231_free_resource(sc); 516136944Syongari return (0); 517136944Syongari} 518136944Syongari 519136944Syongaristatic int 520136944Syongarics4231_bus_suspend(device_t dev) 521136944Syongari{ 522136944Syongari 523136944Syongari return (ENXIO); 524136944Syongari} 525136944Syongari 526136944Syongaristatic int 527136944Syongarics4231_bus_resume(device_t dev) 528136944Syongari{ 529136944Syongari 530136944Syongari return (ENXIO); 531136944Syongari} 532136944Syongari 533136944Syongaristatic void 534136944Syongarics4231_getversion(struct cs4231_softc *sc) 535136944Syongari{ 536136944Syongari u_int8_t v; 537136944Syongari 538136944Syongari v = cs4231_read(sc, CS_MISC_INFO); 539136944Syongari sc->sc_codecv = v & CS_CODEC_ID_MASK; 540136944Syongari v = cs4231_read(sc, CS_VERSION_ID); 541136944Syongari v &= (CS_VERSION_NUMBER | CS_VERSION_CHIPID); 542136944Syongari sc->sc_chipvid = v; 543136944Syongari switch(v) { 544136944Syongari case 0x80: 545136944Syongari device_printf(sc->sc_dev, "<CS4231 Codec Id. %d>\n", 546136944Syongari sc->sc_codecv); 547136944Syongari break; 548136944Syongari case 0xa0: 549136944Syongari device_printf(sc->sc_dev, "<CS4231A Codec Id. %d>\n", 550136944Syongari sc->sc_codecv); 551136944Syongari break; 552136944Syongari case 0x82: 553136944Syongari device_printf(sc->sc_dev, "<CS4232 Codec Id. %d>\n", 554136944Syongari sc->sc_codecv); 555136944Syongari break; 556136944Syongari default: 557136944Syongari device_printf(sc->sc_dev, 558136944Syongari "<Unknown 0x%x Codec Id. %d\n", v, sc->sc_codecv); 559136944Syongari break; 560136944Syongari } 561136944Syongari} 562136944Syongari 563136944Syongaristatic void 564136944Syongarics4231_ebdma_reset(struct cs4231_softc *sc) 565136944Syongari{ 566136944Syongari int i; 567136944Syongari 568136944Syongari /* playback */ 569136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, 570136944Syongari EBDMA_P_READ(sc, EBDMA_DCSR) & ~(EBDCSR_INTEN | EBDCSR_NEXTEN)); 571136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 572136944Syongari for (i = CS_TIMEOUT; 573136944Syongari i && EBDMA_P_READ(sc, EBDMA_DCSR) & EBDCSR_DRAIN; i--) 574136944Syongari DELAY(1); 575136944Syongari if (i == 0) 576136944Syongari device_printf(sc->sc_dev, 577136944Syongari "timeout waiting for playback DMA reset\n"); 578136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 579136944Syongari /* capture */ 580136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, 581136944Syongari EBDMA_C_READ(sc, EBDMA_DCSR) & ~(EBDCSR_INTEN | EBDCSR_NEXTEN)); 582136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 583136944Syongari for (i = CS_TIMEOUT; 584136944Syongari i && EBDMA_C_READ(sc, EBDMA_DCSR) & EBDCSR_DRAIN; i--) 585136944Syongari DELAY(1); 586136944Syongari if (i == 0) 587136944Syongari device_printf(sc->sc_dev, 588136944Syongari "timeout waiting for capture DMA reset\n"); 589136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 590136944Syongari} 591136944Syongari 592136944Syongaristatic void 593136944Syongarics4231_power_reset(struct cs4231_softc *sc, int how) 594136944Syongari{ 595136944Syongari u_int32_t v; 596136944Syongari int i; 597136944Syongari 598136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 599136944Syongari APC_WRITE(sc, APC_CSR, APC_CSR_RESET); 600136944Syongari DELAY(10); 601136944Syongari APC_WRITE(sc, APC_CSR, 0); 602136944Syongari DELAY(10); 603136944Syongari APC_WRITE(sc, 604136944Syongari APC_CSR, APC_READ(sc, APC_CSR) | APC_CSR_CODEC_RESET); 605136944Syongari DELAY(20); 606136944Syongari APC_WRITE(sc, 607136944Syongari APC_CSR, APC_READ(sc, APC_CSR) & (~APC_CSR_CODEC_RESET)); 608136944Syongari } else { 609136944Syongari v = AUXIO_READ(sc, AUXIO_CODEC); 610136944Syongari if (how == CODEC_WARM_RESET && v != 0) { 611136944Syongari AUXIO_WRITE(sc, AUXIO_CODEC, 0); 612136944Syongari DELAY(20); 613136944Syongari } else if (how == CODEC_COLD_RESET){ 614136944Syongari AUXIO_WRITE(sc, AUXIO_CODEC, 1); 615136944Syongari DELAY(20); 616136944Syongari AUXIO_WRITE(sc, AUXIO_CODEC, 0); 617136944Syongari DELAY(20); 618136944Syongari } 619136944Syongari cs4231_ebdma_reset(sc); 620136944Syongari } 621136944Syongari 622136944Syongari for (i = CS_TIMEOUT; 623136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 624136944Syongari DELAY(10); 625136944Syongari if (i == 0) 626136944Syongari device_printf(sc->sc_dev, "timeout waiting for reset\n"); 627136944Syongari 628136944Syongari /* turn on cs4231 mode */ 629136944Syongari cs4231_write(sc, CS_MISC_INFO, 630136944Syongari cs4231_read(sc, CS_MISC_INFO) | CS_MODE2); 631172568Skevlo /* enable interrupts & clear CSR */ 632136944Syongari cs4231_write(sc, CS_PIN_CONTROL, 633136944Syongari cs4231_read(sc, CS_PIN_CONTROL) | INTERRUPT_ENABLE); 634136944Syongari CS_WRITE(sc, CS4231_STATUS, 0); 635136944Syongari /* enable DAC output */ 636136944Syongari cs4231_write(sc, CS_LEFT_OUTPUT_CONTROL, 637136944Syongari cs4231_read(sc, CS_LEFT_OUTPUT_CONTROL) & ~OUTPUT_MUTE); 638136944Syongari cs4231_write(sc, CS_RIGHT_OUTPUT_CONTROL, 639136944Syongari cs4231_read(sc, CS_RIGHT_OUTPUT_CONTROL) & ~OUTPUT_MUTE); 640136944Syongari /* mute AUX1 since it generates noises */ 641136944Syongari cs4231_write(sc, CS_LEFT_AUX1_CONTROL, 642136944Syongari cs4231_read(sc, CS_LEFT_AUX1_CONTROL) | AUX_INPUT_MUTE); 643136944Syongari cs4231_write(sc, CS_RIGHT_AUX1_CONTROL, 644136944Syongari cs4231_read(sc, CS_RIGHT_AUX1_CONTROL) | AUX_INPUT_MUTE); 645136944Syongari /* protect buffer underrun and set output level to 0dB */ 646136944Syongari cs4231_write(sc, CS_ALT_FEATURE1, 647136944Syongari cs4231_read(sc, CS_ALT_FEATURE1) | CS_DAC_ZERO | CS_OUTPUT_LVL); 648136944Syongari /* enable high pass filter, dual xtal was disabled due to noises */ 649136944Syongari cs4231_write(sc, CS_ALT_FEATURE2, 650136944Syongari cs4231_read(sc, CS_ALT_FEATURE2) | CS_HPF_ENABLE); 651136944Syongari} 652136944Syongari 653136944Syongaristatic int 654136944Syongarics4231_enable(struct cs4231_softc *sc, int how) 655136944Syongari{ 656136944Syongari cs4231_power_reset(sc, how); 657136944Syongari sc->sc_enabled = 1; 658136944Syongari return (0); 659136944Syongari} 660136944Syongari 661136944Syongaristatic void 662136944Syongarics4231_disable(struct cs4231_softc *sc) 663136944Syongari{ 664136944Syongari u_int8_t v; 665136944Syongari 666136944Syongari CS4231_LOCK_ASSERT(sc); 667136944Syongari 668136944Syongari if (sc->sc_enabled == 0) 669136944Syongari return; 670136944Syongari sc->sc_enabled = 0; 671136944Syongari CS4231_UNLOCK(sc); 672136944Syongari cs4231_halt(&sc->sc_pch); 673136944Syongari cs4231_halt(&sc->sc_rch); 674136944Syongari CS4231_LOCK(sc); 675136944Syongari v = cs4231_read(sc, CS_PIN_CONTROL) & ~INTERRUPT_ENABLE; 676136944Syongari cs4231_write(sc, CS_PIN_CONTROL, v); 677136944Syongari 678136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 679136944Syongari APC_WRITE(sc, APC_CSR, APC_CSR_RESET); 680136944Syongari DELAY(10); 681136944Syongari APC_WRITE(sc, APC_CSR, 0); 682136944Syongari DELAY(10); 683136944Syongari } else 684136944Syongari cs4231_ebdma_reset(sc); 685136944Syongari} 686136944Syongari 687136944Syongaristatic void 688136944Syongarics4231_free_resource(struct cs4231_softc *sc) 689136944Syongari{ 690136944Syongari int i; 691136944Syongari 692136944Syongari CS4231_LOCK(sc); 693136944Syongari cs4231_disable(sc); 694136944Syongari CS4231_UNLOCK(sc); 695136944Syongari for (i = 0; i < sc->sc_nires; i++) { 696136944Syongari if (sc->sc_irqres[i]) { 697136944Syongari if (sc->sc_ih[i]) { 698136944Syongari bus_teardown_intr(sc->sc_dev, sc->sc_irqres[i], 699136944Syongari sc->sc_ih[i]); 700136944Syongari sc->sc_ih[i] = NULL; 701136944Syongari } 702136944Syongari bus_release_resource(sc->sc_dev, SYS_RES_IRQ, 703136944Syongari sc->sc_irqrid[i], sc->sc_irqres[i]); 704136944Syongari sc->sc_irqres[i] = NULL; 705136944Syongari } 706136944Syongari } 707136944Syongari for (i = 0; i < sc->sc_nires; i++) { 708136944Syongari if (sc->sc_dmat[i]) 709136944Syongari bus_dma_tag_destroy(sc->sc_dmat[i]); 710136944Syongari } 711136944Syongari for (i = 0; i < sc->sc_nmres; i++) { 712136944Syongari if (sc->sc_res[i]) 713146410Smarius bus_release_resource(sc->sc_dev, SYS_RES_MEMORY, 714136944Syongari sc->sc_rid[i], sc->sc_res[i]); 715136944Syongari } 716136944Syongari snd_mtxfree(sc->sc_lock); 717136944Syongari free(sc, M_DEVBUF); 718136944Syongari} 719136944Syongari 720136944Syongaristatic void 721136944Syongarics4231_write(struct cs4231_softc *sc, u_int8_t r, u_int8_t v) 722136944Syongari{ 723136944Syongari CS_WRITE(sc, CS4231_IADDR, r); 724136944Syongari CS_WRITE(sc, CS4231_IDATA, v); 725136944Syongari} 726136944Syongari 727136944Syongaristatic u_int8_t 728136944Syongarics4231_read(struct cs4231_softc *sc, u_int8_t r) 729136944Syongari{ 730136944Syongari CS_WRITE(sc, CS4231_IADDR, r); 731136944Syongari return (CS_READ(sc, CS4231_IDATA)); 732136944Syongari} 733136944Syongari 734136944Syongaristatic void 735136944Syongarics4231_sbus_intr(void *arg) 736136944Syongari{ 737136944Syongari struct cs4231_softc *sc; 738136944Syongari struct cs4231_channel *pch, *rch; 739136944Syongari u_int32_t csr; 740136944Syongari u_int8_t status; 741136944Syongari 742136944Syongari sc = arg; 743136944Syongari CS4231_LOCK(sc); 744136944Syongari 745136944Syongari csr = APC_READ(sc, APC_CSR); 746136944Syongari if ((csr & APC_CSR_GI) == 0) { 747136944Syongari CS4231_UNLOCK(sc); 748136944Syongari return; 749136944Syongari } 750136944Syongari APC_WRITE(sc, APC_CSR, csr); 751136944Syongari 752136944Syongari if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) { 753136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 754136944Syongari device_printf(sc->sc_dev, 755136944Syongari "apc error interrupt : stat = 0x%x\n", status); 756136944Syongari } 757136944Syongari 758136944Syongari pch = rch = NULL; 759136944Syongari if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) { 760136944Syongari u_long nextaddr, saddr; 761136944Syongari u_int32_t togo; 762136944Syongari 763136944Syongari pch = &sc->sc_pch; 764136944Syongari togo = pch->togo; 765136944Syongari saddr = sndbuf_getbufaddr(pch->buffer); 766136944Syongari nextaddr = pch->nextaddr + togo; 767136944Syongari if (nextaddr >= saddr + sndbuf_getsize(pch->buffer)) 768136944Syongari nextaddr = saddr; 769136944Syongari APC_WRITE(sc, APC_PNVA, nextaddr); 770136944Syongari APC_WRITE(sc, APC_PNC, togo); 771136944Syongari pch->nextaddr = nextaddr; 772136944Syongari } 773136944Syongari 774136944Syongari if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI) && (csr & APC_CSR_CD)) { 775136944Syongari u_long nextaddr, saddr; 776136944Syongari u_int32_t togo; 777136944Syongari 778136944Syongari rch = &sc->sc_rch; 779136944Syongari togo = rch->togo; 780136944Syongari saddr = sndbuf_getbufaddr(rch->buffer); 781136944Syongari nextaddr = rch->nextaddr + togo; 782136944Syongari if (nextaddr >= saddr + sndbuf_getsize(rch->buffer)) 783136944Syongari nextaddr = saddr; 784136944Syongari APC_WRITE(sc, APC_CNVA, nextaddr); 785136944Syongari APC_WRITE(sc, APC_CNC, togo); 786136944Syongari rch->nextaddr = nextaddr; 787136944Syongari } 788136944Syongari CS4231_UNLOCK(sc); 789136944Syongari if (pch) 790136944Syongari chn_intr(pch->channel); 791136944Syongari if (rch) 792136944Syongari chn_intr(rch->channel); 793136944Syongari} 794136944Syongari 795136944Syongari/* playback interrupt handler */ 796136944Syongaristatic void 797136944Syongarics4231_ebus_pintr(void *arg) 798136944Syongari{ 799136944Syongari struct cs4231_softc *sc; 800136944Syongari struct cs4231_channel *ch; 801136944Syongari u_int32_t csr; 802136944Syongari u_int8_t status; 803136944Syongari 804136944Syongari sc = arg; 805136944Syongari CS4231_LOCK(sc); 806136944Syongari 807136944Syongari csr = EBDMA_P_READ(sc, EBDMA_DCSR); 808136944Syongari if ((csr & EBDCSR_INT) == 0) { 809136944Syongari CS4231_UNLOCK(sc); 810136944Syongari return; 811136944Syongari } 812136944Syongari 813136944Syongari if ((csr & EBDCSR_ERR)) { 814136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 815136944Syongari device_printf(sc->sc_dev, 816136944Syongari "ebdma error interrupt : stat = 0x%x\n", status); 817136944Syongari } 818136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, csr | EBDCSR_TC); 819136944Syongari 820136944Syongari ch = NULL; 821136944Syongari if (csr & EBDCSR_TC) { 822136944Syongari u_long nextaddr, saddr; 823136944Syongari u_int32_t togo; 824136944Syongari 825136944Syongari ch = &sc->sc_pch; 826136944Syongari togo = ch->togo; 827136944Syongari saddr = sndbuf_getbufaddr(ch->buffer); 828136944Syongari nextaddr = ch->nextaddr + togo; 829136944Syongari if (nextaddr >= saddr + sndbuf_getsize(ch->buffer)) 830136944Syongari nextaddr = saddr; 831136944Syongari /* 832136944Syongari * EBDMA_DCNT is loaded automatically 833136944Syongari * EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 834136944Syongari */ 835136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 836136944Syongari ch->nextaddr = nextaddr; 837136944Syongari } 838136944Syongari CS4231_UNLOCK(sc); 839136944Syongari if (ch) 840136944Syongari chn_intr(ch->channel); 841136944Syongari} 842136944Syongari 843136944Syongari/* capture interrupt handler */ 844136944Syongaristatic void 845136944Syongarics4231_ebus_cintr(void *arg) 846136944Syongari{ 847136944Syongari struct cs4231_softc *sc; 848136944Syongari struct cs4231_channel *ch; 849136944Syongari u_int32_t csr; 850136944Syongari u_int8_t status; 851136944Syongari 852136944Syongari sc = arg; 853136944Syongari CS4231_LOCK(sc); 854136944Syongari 855136944Syongari csr = EBDMA_C_READ(sc, EBDMA_DCSR); 856136944Syongari if ((csr & EBDCSR_INT) == 0) { 857136944Syongari CS4231_UNLOCK(sc); 858136944Syongari return; 859136944Syongari } 860136944Syongari if ((csr & EBDCSR_ERR)) { 861136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 862136944Syongari device_printf(sc->sc_dev, 863136944Syongari "dma error interrupt : stat = 0x%x\n", status); 864136944Syongari } 865136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, csr | EBDCSR_TC); 866136944Syongari 867136944Syongari ch = NULL; 868136944Syongari if (csr & EBDCSR_TC) { 869136944Syongari u_long nextaddr, saddr; 870136944Syongari u_int32_t togo; 871136944Syongari 872136944Syongari ch = &sc->sc_rch; 873136944Syongari togo = ch->togo; 874136944Syongari saddr = sndbuf_getbufaddr(ch->buffer); 875136944Syongari nextaddr = ch->nextaddr + togo; 876136944Syongari if (nextaddr >= saddr + sndbuf_getblksz(ch->buffer)) 877136944Syongari nextaddr = saddr; 878136944Syongari /* 879136944Syongari * EBDMA_DCNT is loaded automatically 880136944Syongari * EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 881136944Syongari */ 882136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 883136944Syongari ch->nextaddr = nextaddr; 884136944Syongari } 885136944Syongari CS4231_UNLOCK(sc); 886136944Syongari if (ch) 887136944Syongari chn_intr(ch->channel); 888136944Syongari} 889136944Syongari 890136944Syongaristatic const struct mix_table cs4231_mix_table[SOUND_MIXER_NRDEVICES][2] = { 891136944Syongari [SOUND_MIXER_PCM] = { 892136944Syongari { CS_LEFT_OUTPUT_CONTROL, 6, OUTPUT_MUTE, 0, 1, 1, 0 }, 893136944Syongari { CS_RIGHT_OUTPUT_CONTROL, 6, OUTPUT_MUTE, 0, 1, 1, 0 } 894136944Syongari }, 895136944Syongari [SOUND_MIXER_SPEAKER] = { 896136944Syongari { CS_MONO_IO_CONTROL, 4, MONO_OUTPUT_MUTE, 0, 1, 1, 0 }, 897136944Syongari { CS_REG_NONE, 0, 0, 0, 0, 1, 0 } 898136944Syongari }, 899136944Syongari [SOUND_MIXER_LINE] = { 900136944Syongari { CS_LEFT_LINE_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 }, 901136944Syongari { CS_RIGHT_LINE_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 } 902136944Syongari }, 903136944Syongari /* 904136944Syongari * AUX1 : removed intentionally since it generates noises 905136944Syongari * AUX2 : Ultra1/Ultra2 has no internal CD-ROM audio in 906136944Syongari */ 907136944Syongari [SOUND_MIXER_CD] = { 908136944Syongari { CS_LEFT_AUX2_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 }, 909136944Syongari { CS_RIGHT_AUX2_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 } 910136944Syongari }, 911136944Syongari [SOUND_MIXER_MIC] = { 912136944Syongari { CS_LEFT_INPUT_CONTROL, 4, 0, 0, 0, 1, 1 }, 913136944Syongari { CS_RIGHT_INPUT_CONTROL, 4, 0, 0, 0, 1, 1 } 914136944Syongari }, 915136944Syongari [SOUND_MIXER_IGAIN] = { 916136944Syongari { CS_LEFT_INPUT_CONTROL, 4, 0, 0, 1, 0 }, 917136944Syongari { CS_RIGHT_INPUT_CONTROL, 4, 0, 0, 1, 0 } 918136944Syongari } 919136944Syongari}; 920136944Syongari 921136944Syongaristatic int 922136944Syongarics4231_mixer_init(struct snd_mixer *m) 923136944Syongari{ 924136944Syongari u_int32_t v; 925136944Syongari int i; 926136944Syongari 927136944Syongari v = 0; 928136944Syongari for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 929136944Syongari if (cs4231_mix_table[i][0].avail != 0) 930136944Syongari v |= (1 << i); 931136944Syongari mix_setdevs(m, v); 932136944Syongari v = 0; 933136944Syongari for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 934136944Syongari if (cs4231_mix_table[i][0].recdev != 0) 935136944Syongari v |= (1 << i); 936136944Syongari mix_setrecdevs(m, v); 937136944Syongari return (0); 938136944Syongari} 939136944Syongari 940136944Syongaristatic void 941136944Syongarics4231_mixer_set_value(struct cs4231_softc *sc, const struct mix_table *mt, 942136944Syongari u_int8_t v) 943136944Syongari{ 944136944Syongari u_int8_t mask, reg; 945136944Syongari u_int8_t old, shift, val; 946136944Syongari 947136944Syongari if (mt->avail == 0 || mt->reg == CS_REG_NONE) 948136944Syongari return; 949136944Syongari reg = mt->reg; 950136944Syongari if (mt->neg != 0) 951136944Syongari val = 100 - v; 952136944Syongari else 953136944Syongari val = v; 954136944Syongari mask = (1 << mt->bits) - 1; 955136944Syongari val = ((val * mask) + 50) / 100; 956136944Syongari shift = mt->shift; 957136944Syongari val <<= shift; 958136944Syongari if (v == 0) 959136944Syongari val |= mt->mute; 960136944Syongari old = cs4231_read(sc, reg); 961136944Syongari old &= ~(mt->mute | (mask << shift)); 962136944Syongari val |= old; 963136944Syongari if (reg == CS_LEFT_INPUT_CONTROL || reg == CS_RIGHT_INPUT_CONTROL) { 964136944Syongari if ((val & (mask << shift)) != 0) 965136944Syongari val |= ADC_INPUT_GAIN_ENABLE; 966136944Syongari else 967136944Syongari val &= ~ADC_INPUT_GAIN_ENABLE; 968136944Syongari } 969136944Syongari cs4231_write(sc, reg, val); 970136944Syongari} 971136944Syongari 972136944Syongaristatic int 973136944Syongarics4231_mixer_set(struct snd_mixer *m, u_int32_t dev, u_int32_t left, 974136944Syongari u_int32_t right) 975136944Syongari{ 976136944Syongari struct cs4231_softc *sc; 977136944Syongari 978136944Syongari sc = mix_getdevinfo(m); 979136944Syongari CS4231_LOCK(sc); 980136944Syongari cs4231_mixer_set_value(sc, &cs4231_mix_table[dev][0], left); 981136944Syongari cs4231_mixer_set_value(sc, &cs4231_mix_table[dev][1], right); 982136944Syongari CS4231_UNLOCK(sc); 983136944Syongari 984136944Syongari return (left | (right << 8)); 985136944Syongari} 986136944Syongari 987193779Sariffstatic u_int32_t 988136944Syongarics4231_mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 989136944Syongari{ 990136944Syongari struct cs4231_softc *sc; 991136944Syongari u_int8_t v; 992136944Syongari 993136944Syongari sc = mix_getdevinfo(m); 994136944Syongari switch (src) { 995136944Syongari case SOUND_MASK_LINE: 996136944Syongari v = CS_IN_LINE; 997136944Syongari break; 998136944Syongari 999136944Syongari case SOUND_MASK_CD: 1000136944Syongari v = CS_IN_DAC; 1001136944Syongari break; 1002136944Syongari 1003136944Syongari case SOUND_MASK_MIC: 1004136944Syongari default: 1005136944Syongari v = CS_IN_MIC; 1006136944Syongari src = SOUND_MASK_MIC; 1007136944Syongari break; 1008136944Syongari } 1009136944Syongari CS4231_LOCK(sc); 1010136944Syongari cs4231_write(sc, CS_LEFT_INPUT_CONTROL, 1011136944Syongari (cs4231_read(sc, CS_LEFT_INPUT_CONTROL) & CS_IN_MASK) | v); 1012136944Syongari cs4231_write(sc, CS_RIGHT_INPUT_CONTROL, 1013136944Syongari (cs4231_read(sc, CS_RIGHT_INPUT_CONTROL) & CS_IN_MASK) | v); 1014136944Syongari CS4231_UNLOCK(sc); 1015136944Syongari 1016136944Syongari return (src); 1017136944Syongari} 1018136944Syongari 1019136944Syongaristatic void * 1020136944Syongarics4231_chan_init(kobj_t obj, void *dev, struct snd_dbuf *b, 1021136944Syongari struct pcm_channel *c, int dir) 1022136944Syongari{ 1023136944Syongari struct cs4231_softc *sc; 1024136944Syongari struct cs4231_channel *ch; 1025136944Syongari bus_dma_tag_t dmat; 1026136944Syongari 1027136944Syongari sc = dev; 1028136944Syongari ch = (dir == PCMDIR_PLAY) ? &sc->sc_pch : &sc->sc_rch; 1029136944Syongari ch->parent = sc; 1030136944Syongari ch->channel = c; 1031136944Syongari ch->dir = dir; 1032136944Syongari ch->buffer = b; 1033136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 1034136944Syongari dmat = sc->sc_dmat[0]; 1035136944Syongari else { 1036136944Syongari if (dir == PCMDIR_PLAY) 1037136944Syongari dmat = sc->sc_dmat[1]; 1038136944Syongari else 1039136944Syongari dmat = sc->sc_dmat[0]; 1040136944Syongari } 1041168847Sariff if (sndbuf_alloc(ch->buffer, dmat, 0, sc->sc_bufsz) != 0) 1042136944Syongari return (NULL); 1043136944Syongari DPRINTF(("%s channel addr: 0x%lx\n", dir == PCMDIR_PLAY ? "playback" : 1044136944Syongari "capture", sndbuf_getbufaddr(ch->buffer))); 1045136944Syongari 1046136944Syongari return (ch); 1047136944Syongari} 1048136944Syongari 1049136944Syongaristatic int 1050136944Syongarics4231_chan_setformat(kobj_t obj, void *data, u_int32_t format) 1051136944Syongari{ 1052136944Syongari struct cs4231_softc *sc; 1053136944Syongari struct cs4231_channel *ch; 1054136944Syongari u_int32_t encoding; 1055136944Syongari u_int8_t fs, v; 1056136944Syongari 1057136944Syongari ch = data; 1058136944Syongari sc = ch->parent; 1059136944Syongari 1060136944Syongari CS4231_LOCK(sc); 1061136944Syongari if (ch->format == format) { 1062136944Syongari CS4231_UNLOCK(sc); 1063136944Syongari return (0); 1064136944Syongari } 1065136944Syongari 1066193640Sariff encoding = AFMT_ENCODING(format); 1067136944Syongari fs = 0; 1068136944Syongari switch (encoding) { 1069136944Syongari case AFMT_U8: 1070136944Syongari fs = CS_AFMT_U8; 1071136944Syongari break; 1072136944Syongari case AFMT_MU_LAW: 1073136944Syongari fs = CS_AFMT_MU_LAW; 1074136944Syongari break; 1075136944Syongari case AFMT_S16_LE: 1076136944Syongari fs = CS_AFMT_S16_LE; 1077136944Syongari break; 1078136944Syongari case AFMT_A_LAW: 1079136944Syongari fs = CS_AFMT_A_LAW; 1080136944Syongari break; 1081136944Syongari case AFMT_IMA_ADPCM: 1082136944Syongari fs = CS_AFMT_IMA_ADPCM; 1083136944Syongari break; 1084136944Syongari case AFMT_S16_BE: 1085136944Syongari fs = CS_AFMT_S16_BE; 1086136944Syongari break; 1087136944Syongari default: 1088136944Syongari fs = CS_AFMT_U8; 1089136944Syongari format = AFMT_U8; 1090136944Syongari break; 1091136944Syongari } 1092136944Syongari 1093193640Sariff if (AFMT_CHANNEL(format) > 1) 1094136944Syongari fs |= CS_AFMT_STEREO; 1095136944Syongari 1096136944Syongari DPRINTF(("FORMAT: %s : 0x%x\n", ch->dir == PCMDIR_PLAY ? "playback" : 1097136944Syongari "capture", format)); 1098136944Syongari v = cs4231_read(sc, CS_CLOCK_DATA_FORMAT); 1099136944Syongari v &= CS_CLOCK_DATA_FORMAT_MASK; 1100136944Syongari fs |= v; 1101136944Syongari cs4231_chan_fs(sc, ch->dir, fs); 1102136944Syongari ch->format = format; 1103136944Syongari CS4231_UNLOCK(sc); 1104136944Syongari 1105136944Syongari return (0); 1106136944Syongari} 1107136944Syongari 1108193779Sariffstatic u_int32_t 1109136944Syongarics4231_chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1110136944Syongari{ 1111136944Syongari typedef struct { 1112136944Syongari u_int32_t speed; 1113136944Syongari u_int8_t bits; 1114136944Syongari } speed_struct; 1115136944Syongari 1116136944Syongari const static speed_struct speed_table[] = { 1117136944Syongari {5510, (0 << 1) | CLOCK_XTAL2}, 1118136944Syongari {5510, (0 << 1) | CLOCK_XTAL2}, 1119136944Syongari {6620, (7 << 1) | CLOCK_XTAL2}, 1120136944Syongari {8000, (0 << 1) | CLOCK_XTAL1}, 1121136944Syongari {9600, (7 << 1) | CLOCK_XTAL1}, 1122136944Syongari {11025, (1 << 1) | CLOCK_XTAL2}, 1123136944Syongari {16000, (1 << 1) | CLOCK_XTAL1}, 1124136944Syongari {18900, (2 << 1) | CLOCK_XTAL2}, 1125136944Syongari {22050, (3 << 1) | CLOCK_XTAL2}, 1126136944Syongari {27420, (2 << 1) | CLOCK_XTAL1}, 1127136944Syongari {32000, (3 << 1) | CLOCK_XTAL1}, 1128136944Syongari {33075, (6 << 1) | CLOCK_XTAL2}, 1129136944Syongari {33075, (4 << 1) | CLOCK_XTAL2}, 1130136944Syongari {44100, (5 << 1) | CLOCK_XTAL2}, 1131136944Syongari {48000, (6 << 1) | CLOCK_XTAL1}, 1132136944Syongari }; 1133136944Syongari 1134136944Syongari struct cs4231_softc *sc; 1135136944Syongari struct cs4231_channel *ch; 1136136944Syongari int i, n, sel; 1137136944Syongari u_int8_t fs; 1138136944Syongari 1139136944Syongari ch = data; 1140136944Syongari sc = ch->parent; 1141136944Syongari CS4231_LOCK(sc); 1142136944Syongari if (ch->speed == speed) { 1143136944Syongari CS4231_UNLOCK(sc); 1144136944Syongari return (speed); 1145136944Syongari } 1146136944Syongari n = sizeof(speed_table) / sizeof(speed_struct); 1147136944Syongari 1148136944Syongari for (i = 1, sel =0; i < n - 1; i++) 1149136944Syongari if (abs(speed - speed_table[i].speed) < 1150136944Syongari abs(speed - speed_table[sel].speed)) 1151136944Syongari sel = i; 1152136944Syongari DPRINTF(("SPEED: %s : %dHz -> %dHz\n", ch->dir == PCMDIR_PLAY ? 1153136944Syongari "playback" : "capture", speed, speed_table[sel].speed)); 1154136944Syongari speed = speed_table[sel].speed; 1155136944Syongari 1156136944Syongari fs = cs4231_read(sc, CS_CLOCK_DATA_FORMAT); 1157136944Syongari fs &= ~CS_CLOCK_DATA_FORMAT_MASK; 1158136944Syongari fs |= speed_table[sel].bits; 1159136944Syongari cs4231_chan_fs(sc, ch->dir, fs); 1160136944Syongari ch->speed = speed; 1161136944Syongari CS4231_UNLOCK(sc); 1162136944Syongari 1163136944Syongari return (speed); 1164136944Syongari} 1165136944Syongari 1166136944Syongaristatic void 1167136944Syongarics4231_chan_fs(struct cs4231_softc *sc, int dir, u_int8_t fs) 1168136944Syongari{ 1169136944Syongari int i, doreset; 1170136944Syongari#ifdef CS4231_AUTO_CALIBRATION 1171136944Syongari u_int8_t v; 1172136944Syongari#endif 1173136944Syongari 1174136944Syongari CS4231_LOCK_ASSERT(sc); 1175136944Syongari 1176136944Syongari /* set autocalibration */ 1177136944Syongari doreset = 0; 1178136944Syongari#ifdef CS4231_AUTO_CALIBRATION 1179136944Syongari v = cs4231_read(sc, CS_INTERFACE_CONFIG) | AUTO_CAL_ENABLE; 1180136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE); 1181136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE | CS_INTERFACE_CONFIG); 1182136944Syongari CS_WRITE(sc, CS4231_IDATA, v); 1183136944Syongari#endif 1184136944Syongari 1185136944Syongari /* 1186136944Syongari * We always need to write CS_CLOCK_DATA_FORMAT register since 1187136944Syongari * the clock frequency is shared with playback/capture. 1188136944Syongari */ 1189136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE | CS_CLOCK_DATA_FORMAT); 1190136944Syongari CS_WRITE(sc, CS4231_IDATA, fs); 1191136944Syongari CS_READ(sc, CS4231_IDATA); 1192136944Syongari CS_READ(sc, CS4231_IDATA); 1193136944Syongari for (i = CS_TIMEOUT; 1194136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 1195136944Syongari DELAY(10); 1196136944Syongari if (i == 0) { 1197136944Syongari device_printf(sc->sc_dev, "timeout setting playback speed\n"); 1198136944Syongari doreset++; 1199136944Syongari } 1200136944Syongari 1201136944Syongari /* 1202136944Syongari * capture channel 1203215034Sbrucec * cs4231 doesn't allow separate fs setup for playback/capture. 1204136944Syongari * I believe this will break full-duplex operation. 1205136944Syongari */ 1206136944Syongari if (dir == PCMDIR_REC) { 1207136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT); 1208136944Syongari CS_WRITE(sc, CS4231_IDATA, fs); 1209136944Syongari CS_READ(sc, CS4231_IDATA); 1210136944Syongari CS_READ(sc, CS4231_IDATA); 1211136944Syongari for (i = CS_TIMEOUT; 1212136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 1213136944Syongari DELAY(10); 1214136944Syongari if (i == 0) { 1215136944Syongari device_printf(sc->sc_dev, 1216136944Syongari "timeout setting capture format\n"); 1217136944Syongari doreset++; 1218136944Syongari } 1219136944Syongari } 1220136944Syongari 1221136944Syongari CS_WRITE(sc, CS4231_IADDR, 0); 1222136944Syongari for (i = CS_TIMEOUT; 1223136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 1224136944Syongari DELAY(10); 1225136944Syongari if (i == 0) { 1226136944Syongari device_printf(sc->sc_dev, "timeout waiting for !MCE\n"); 1227136944Syongari doreset++; 1228136944Syongari } 1229136944Syongari 1230136944Syongari#ifdef CS4231_AUTO_CALIBRATION 1231136944Syongari CS_WRITE(sc, CS4231_IADDR, CS_TEST_AND_INIT); 1232136944Syongari for (i = CS_TIMEOUT; 1233136944Syongari i && CS_READ(sc, CS4231_IDATA) & AUTO_CAL_IN_PROG; i--) 1234136944Syongari DELAY(10); 1235136944Syongari if (i == 0) { 1236136944Syongari device_printf(sc->sc_dev, 1237136944Syongari "timeout waiting for autocalibration\n"); 1238136944Syongari doreset++; 1239136944Syongari } 1240136944Syongari#endif 1241136944Syongari if (doreset) { 1242136944Syongari /* 1243136944Syongari * Maybe the last resort to avoid a dreadful message like 1244136944Syongari * "pcm0:play:0: play interrupt timeout, channel dead" would 1245136944Syongari * be hardware reset. 1246136944Syongari */ 1247136944Syongari device_printf(sc->sc_dev, "trying to hardware reset\n"); 1248136944Syongari cs4231_disable(sc); 1249136944Syongari cs4231_enable(sc, CODEC_COLD_RESET); 1250136944Syongari CS4231_UNLOCK(sc); /* XXX */ 1251136944Syongari if (mixer_reinit(sc->sc_dev) != 0) 1252136944Syongari device_printf(sc->sc_dev, 1253136944Syongari "unable to reinitialize the mixer\n"); 1254136944Syongari CS4231_LOCK(sc); 1255136944Syongari } 1256136944Syongari} 1257136944Syongari 1258193779Sariffstatic u_int32_t 1259136944Syongarics4231_chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1260136944Syongari{ 1261136944Syongari struct cs4231_softc *sc; 1262136944Syongari struct cs4231_channel *ch; 1263136944Syongari int nblks, error; 1264136944Syongari 1265136944Syongari ch = data; 1266136944Syongari sc = ch->parent; 1267136944Syongari 1268136944Syongari if (blocksize > CS4231_MAX_BLK_SZ) 1269136944Syongari blocksize = CS4231_MAX_BLK_SZ; 1270136944Syongari nblks = sc->sc_bufsz / blocksize; 1271136944Syongari error = sndbuf_resize(ch->buffer, nblks, blocksize); 1272136944Syongari if (error != 0) 1273136944Syongari device_printf(sc->sc_dev, 1274136944Syongari "unable to block size, blksz = %d, error = %d\n", 1275136944Syongari blocksize, error); 1276136944Syongari 1277136944Syongari return (blocksize); 1278136944Syongari} 1279136944Syongari 1280136944Syongaristatic int 1281136944Syongarics4231_chan_trigger(kobj_t obj, void *data, int go) 1282136944Syongari{ 1283136944Syongari struct cs4231_channel *ch; 1284136944Syongari 1285136944Syongari ch = data; 1286136944Syongari switch (go) { 1287136944Syongari case PCMTRIG_EMLDMAWR: 1288136944Syongari case PCMTRIG_EMLDMARD: 1289136944Syongari break; 1290136944Syongari case PCMTRIG_START: 1291136944Syongari cs4231_trigger(ch); 1292136944Syongari break; 1293136944Syongari case PCMTRIG_ABORT: 1294136944Syongari case PCMTRIG_STOP: 1295136944Syongari cs4231_halt(ch); 1296136944Syongari break; 1297136944Syongari default: 1298136944Syongari break; 1299136944Syongari } 1300136944Syongari 1301136944Syongari return (0); 1302136944Syongari} 1303136944Syongari 1304193779Sariffstatic u_int32_t 1305136944Syongarics4231_chan_getptr(kobj_t obj, void *data) 1306136944Syongari{ 1307136944Syongari struct cs4231_softc *sc; 1308136944Syongari struct cs4231_channel *ch; 1309193779Sariff u_int32_t cur, ptr, sz; 1310136944Syongari 1311136944Syongari ch = data; 1312136944Syongari sc = ch->parent; 1313136944Syongari 1314136944Syongari CS4231_LOCK(sc); 1315136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 1316136944Syongari cur = (ch->dir == PCMDIR_PLAY) ? APC_READ(sc, APC_PVA) : 1317136944Syongari APC_READ(sc, APC_CVA); 1318136944Syongari else 1319136944Syongari cur = (ch->dir == PCMDIR_PLAY) ? EBDMA_P_READ(sc, EBDMA_DADDR) : 1320136944Syongari EBDMA_C_READ(sc, EBDMA_DADDR); 1321136944Syongari sz = sndbuf_getsize(ch->buffer); 1322136944Syongari ptr = cur - sndbuf_getbufaddr(ch->buffer) + sz; 1323136944Syongari CS4231_UNLOCK(sc); 1324136944Syongari 1325136944Syongari ptr %= sz; 1326136944Syongari return (ptr); 1327136944Syongari} 1328136944Syongari 1329136944Syongaristatic struct pcmchan_caps * 1330136944Syongarics4231_chan_getcaps(kobj_t obj, void *data) 1331136944Syongari{ 1332136944Syongari 1333136944Syongari return (&cs4231_caps); 1334136944Syongari} 1335136944Syongari 1336136944Syongaristatic void 1337136944Syongarics4231_trigger(struct cs4231_channel *ch) 1338136944Syongari{ 1339136944Syongari struct cs4231_softc *sc; 1340136944Syongari 1341136944Syongari sc = ch->parent; 1342136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 1343136944Syongari cs4231_apcdma_trigger(sc, ch); 1344136944Syongari else 1345136944Syongari cs4231_ebdma_trigger(sc, ch); 1346136944Syongari} 1347136944Syongari 1348136944Syongaristatic void 1349136944Syongarics4231_apcdma_trigger(struct cs4231_softc *sc, struct cs4231_channel *ch) 1350136944Syongari{ 1351136944Syongari u_int32_t csr, togo; 1352136944Syongari u_int32_t nextaddr; 1353136944Syongari 1354136944Syongari CS4231_LOCK(sc); 1355136944Syongari if (ch->locked) { 1356136944Syongari device_printf(sc->sc_dev, "%s channel already triggered\n", 1357136944Syongari ch->dir == PCMDIR_PLAY ? "playback" : "capture"); 1358136944Syongari CS4231_UNLOCK(sc); 1359136944Syongari return; 1360136944Syongari } 1361136944Syongari 1362136944Syongari nextaddr = sndbuf_getbufaddr(ch->buffer); 1363136944Syongari togo = sndbuf_getsize(ch->buffer) / 2; 1364136944Syongari if (togo > CS4231_MAX_APC_DMA_SZ) 1365136944Syongari togo = CS4231_MAX_APC_DMA_SZ; 1366136944Syongari ch->togo = togo; 1367136944Syongari if (ch->dir == PCMDIR_PLAY) { 1368136944Syongari DPRINTF(("TRG: PNVA = 0x%x, togo = 0x%x\n", nextaddr, togo)); 1369136944Syongari 1370136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1371136944Syongari csr = APC_READ(sc, APC_CSR); 1372136944Syongari APC_WRITE(sc, APC_PNVA, nextaddr); 1373136944Syongari APC_WRITE(sc, APC_PNC, togo); 1374136944Syongari 1375136944Syongari if ((csr & APC_CSR_PDMA_GO) == 0 || 1376136944Syongari (csr & APC_CSR_PPAUSE) != 0) { 1377136944Syongari APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & 1378136944Syongari ~(APC_CSR_PIE | APC_CSR_PPAUSE)); 1379136944Syongari APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) | 1380136944Syongari APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE | 1381136944Syongari APC_CSR_EI | APC_CSR_PMIE | APC_CSR_PDMA_GO); 1382136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1383136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1384136944Syongari PLAYBACK_ENABLE); 1385136944Syongari } 1386136944Syongari /* load next address */ 1387136944Syongari if (APC_READ(sc, APC_CSR) & APC_CSR_PD) { 1388136944Syongari nextaddr += togo; 1389136944Syongari APC_WRITE(sc, APC_PNVA, nextaddr); 1390136944Syongari APC_WRITE(sc, APC_PNC, togo); 1391136944Syongari } 1392136944Syongari } else { 1393136944Syongari DPRINTF(("TRG: CNVA = 0x%x, togo = 0x%x\n", nextaddr, togo)); 1394136944Syongari 1395136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1396136944Syongari APC_WRITE(sc, APC_CNVA, nextaddr); 1397136944Syongari APC_WRITE(sc, APC_CNC, togo); 1398136944Syongari csr = APC_READ(sc, APC_CSR); 1399136944Syongari if ((csr & APC_CSR_CDMA_GO) == 0 || 1400136944Syongari (csr & APC_CSR_CPAUSE) != 0) { 1401136944Syongari csr &= APC_CSR_CPAUSE; 1402136944Syongari csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | 1403136944Syongari APC_CSR_EI | APC_CSR_CDMA_GO; 1404136944Syongari APC_WRITE(sc, APC_CSR, csr); 1405136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1406136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1407136944Syongari CAPTURE_ENABLE); 1408136944Syongari } 1409136944Syongari /* load next address */ 1410136944Syongari if (APC_READ(sc, APC_CSR) & APC_CSR_CD) { 1411136944Syongari nextaddr += togo; 1412136944Syongari APC_WRITE(sc, APC_CNVA, nextaddr); 1413136944Syongari APC_WRITE(sc, APC_CNC, togo); 1414136944Syongari } 1415136944Syongari } 1416136944Syongari ch->nextaddr = nextaddr; 1417136944Syongari ch->locked = 1; 1418136944Syongari CS4231_UNLOCK(sc); 1419136944Syongari} 1420136944Syongari 1421136944Syongaristatic void 1422136944Syongarics4231_ebdma_trigger(struct cs4231_softc *sc, struct cs4231_channel *ch) 1423136944Syongari{ 1424136944Syongari u_int32_t csr, togo; 1425136944Syongari u_int32_t nextaddr; 1426136944Syongari 1427136944Syongari CS4231_LOCK(sc); 1428136944Syongari if (ch->locked) { 1429136944Syongari device_printf(sc->sc_dev, "%s channel already triggered\n", 1430136944Syongari ch->dir == PCMDIR_PLAY ? "playback" : "capture"); 1431136944Syongari CS4231_UNLOCK(sc); 1432136944Syongari return; 1433136944Syongari } 1434136944Syongari 1435136944Syongari nextaddr = sndbuf_getbufaddr(ch->buffer); 1436136944Syongari togo = sndbuf_getsize(ch->buffer) / 2; 1437136944Syongari if (togo % 64 == 0) 1438136944Syongari sc->sc_burst = EBDCSR_BURST_16; 1439136944Syongari else if (togo % 32 == 0) 1440136944Syongari sc->sc_burst = EBDCSR_BURST_8; 1441136944Syongari else if (togo % 16 == 0) 1442136944Syongari sc->sc_burst = EBDCSR_BURST_4; 1443136944Syongari else 1444136944Syongari sc->sc_burst = EBDCSR_BURST_1; 1445136944Syongari ch->togo = togo; 1446136944Syongari DPRINTF(("TRG: DNAR = 0x%x, togo = 0x%x\n", nextaddr, togo)); 1447136944Syongari if (ch->dir == PCMDIR_PLAY) { 1448136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1449136944Syongari csr = EBDMA_P_READ(sc, EBDMA_DCSR); 1450136944Syongari 1451136944Syongari if (csr & EBDCSR_DMAEN) { 1452136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 1453136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 1454136944Syongari } else { 1455136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 1456136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 1457136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 1458136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 1459136944Syongari 1460136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, sc->sc_burst | 1461136944Syongari EBDCSR_DMAEN | EBDCSR_INTEN | EBDCSR_CNTEN | 1462136944Syongari EBDCSR_NEXTEN); 1463136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1464136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1465136944Syongari PLAYBACK_ENABLE); 1466136944Syongari } 1467136944Syongari /* load next address */ 1468136944Syongari if (EBDMA_P_READ(sc, EBDMA_DCSR) & EBDCSR_A_LOADED) { 1469136944Syongari nextaddr += togo; 1470136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 1471136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 1472136944Syongari } 1473136944Syongari } else { 1474136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1475136944Syongari csr = EBDMA_C_READ(sc, EBDMA_DCSR); 1476136944Syongari 1477136944Syongari if (csr & EBDCSR_DMAEN) { 1478136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 1479136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 1480136944Syongari } else { 1481136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 1482136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 1483136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 1484136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 1485136944Syongari 1486136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, sc->sc_burst | 1487136944Syongari EBDCSR_WRITE | EBDCSR_DMAEN | EBDCSR_INTEN | 1488136944Syongari EBDCSR_CNTEN | EBDCSR_NEXTEN); 1489136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1490136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1491136944Syongari CAPTURE_ENABLE); 1492136944Syongari } 1493136944Syongari /* load next address */ 1494136944Syongari if (EBDMA_C_READ(sc, EBDMA_DCSR) & EBDCSR_A_LOADED) { 1495136944Syongari nextaddr += togo; 1496136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 1497136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 1498136944Syongari } 1499136944Syongari } 1500136944Syongari ch->nextaddr = nextaddr; 1501136944Syongari ch->locked = 1; 1502136944Syongari CS4231_UNLOCK(sc); 1503136944Syongari} 1504136944Syongari 1505136944Syongaristatic void 1506136944Syongarics4231_halt(struct cs4231_channel *ch) 1507136944Syongari{ 1508136944Syongari struct cs4231_softc *sc; 1509136944Syongari u_int8_t status; 1510136944Syongari int i; 1511136944Syongari 1512136944Syongari sc = ch->parent; 1513136944Syongari CS4231_LOCK(sc); 1514136944Syongari if (ch->locked == 0) { 1515136944Syongari CS4231_UNLOCK(sc); 1516136944Syongari return; 1517136944Syongari } 1518136944Syongari 1519136944Syongari if (ch->dir == PCMDIR_PLAY ) { 1520136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 1521136944Syongari /* XXX Kills some capture bits */ 1522136944Syongari APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & 1523136944Syongari ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | 1524136944Syongari APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE)); 1525136944Syongari } else { 1526136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, 1527136944Syongari EBDMA_P_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN); 1528136944Syongari } 1529136944Syongari /* Waiting for playback FIFO to empty */ 1530136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1531136944Syongari for (i = CS_TIMEOUT; 1532136944Syongari i && (status & PLAYBACK_UNDERRUN) == 0; i--) { 1533136944Syongari DELAY(5); 1534136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1535136944Syongari } 1536136944Syongari if (i == 0) 1537136944Syongari device_printf(sc->sc_dev, "timeout waiting for " 1538136944Syongari "playback FIFO drain\n"); 1539136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1540136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE)); 1541136944Syongari } else { 1542136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 1543136944Syongari /* XXX Kills some playback bits */ 1544136944Syongari APC_WRITE(sc, APC_CSR, APC_CSR_CAPTURE_PAUSE); 1545136944Syongari } else { 1546136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, 1547136944Syongari EBDMA_C_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN); 1548136944Syongari } 1549136944Syongari /* Waiting for capture FIFO to empty */ 1550136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1551136944Syongari for (i = CS_TIMEOUT; 1552136944Syongari i && (status & CAPTURE_OVERRUN) == 0; i--) { 1553136944Syongari DELAY(5); 1554136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1555136944Syongari } 1556136944Syongari if (i == 0) 1557136944Syongari device_printf(sc->sc_dev, "timeout waiting for " 1558136944Syongari "capture FIFO drain\n"); 1559136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1560136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) & (~CAPTURE_ENABLE)); 1561136944Syongari } 1562136944Syongari ch->locked = 0; 1563136944Syongari CS4231_UNLOCK(sc); 1564136944Syongari} 1565