cs4231.c revision 193667
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: head/sys/dev/sound/sbus/cs4231.c 193667 2009-06-07 23:38:16Z ariff $"); 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 73136944Syongari * driver. The EBDMA infomation 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); 176136944Syongaristatic int 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); 180136944Syongaristatic int cs4231_chan_setspeed(kobj_t, void *, u_int32_t); 181136944Syongaristatic void cs4231_chan_fs(struct cs4231_softc *, int, u_int8_t); 182136944Syongaristatic int cs4231_chan_setblocksize(kobj_t, void *, u_int32_t); 183136944Syongaristatic int cs4231_chan_trigger(kobj_t, void *, int); 184136944Syongaristatic int 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), 234136944Syongari {0, 0} 235136944Syongari}; 236136944Syongari 237136944Syongaristatic driver_t cs4231_sbus_driver = { 238136944Syongari "pcm", 239136944Syongari cs4231_sbus_methods, 240136944Syongari PCM_SOFTC_SIZE 241136944Syongari}; 242136944Syongari 243136944SyongariDRIVER_MODULE(snd_audiocs, sbus, cs4231_sbus_driver, pcm_devclass, 0, 0); 244136944Syongari 245136944Syongari/* EBus */ 246136944Syongaristatic device_method_t cs4231_ebus_methods[] = { 247136944Syongari DEVMETHOD(device_probe, cs4231_bus_probe), 248136944Syongari DEVMETHOD(device_attach, cs4231_ebus_attach), 249136944Syongari DEVMETHOD(device_detach, cs4231_bus_detach), 250136944Syongari DEVMETHOD(device_suspend, cs4231_bus_suspend), 251136944Syongari DEVMETHOD(device_resume, cs4231_bus_resume), 252136944Syongari {0, 0} 253136944Syongari}; 254136944Syongari 255136944Syongaristatic driver_t cs4231_ebus_driver = { 256136944Syongari "pcm", 257136944Syongari cs4231_ebus_methods, 258136944Syongari PCM_SOFTC_SIZE 259136944Syongari}; 260136944Syongari 261136944SyongariDRIVER_MODULE(snd_audiocs, ebus, cs4231_ebus_driver, pcm_devclass, 0, 0); 262136944SyongariMODULE_DEPEND(snd_audiocs, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 263136944SyongariMODULE_VERSION(snd_audiocs, 1); 264136944Syongari 265136944Syongari 266136944Syongaristatic u_int32_t cs4231_fmt[] = { 267193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 268193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 269193640Sariff SND_FORMAT(AFMT_MU_LAW, 1, 0), 270193640Sariff SND_FORMAT(AFMT_MU_LAW, 2, 0), 271193640Sariff SND_FORMAT(AFMT_A_LAW, 1, 0), 272193640Sariff SND_FORMAT(AFMT_A_LAW, 2, 0), 273193640Sariff SND_FORMAT(AFMT_IMA_ADPCM, 1, 0), 274193640Sariff SND_FORMAT(AFMT_IMA_ADPCM, 2, 0), 275193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 276193667Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 277193640Sariff SND_FORMAT(AFMT_S16_BE, 1, 0), 278193640Sariff SND_FORMAT(AFMT_S16_BE, 2, 0), 279136944Syongari 0 280136944Syongari}; 281136944Syongari 282136944Syongaristatic struct pcmchan_caps cs4231_caps = {5510, 48000, cs4231_fmt, 0}; 283136944Syongari 284136944Syongari/* 285136944Syongari * sound(4) channel interface 286136944Syongari */ 287136944Syongaristatic kobj_method_t cs4231_chan_methods[] = { 288136944Syongari KOBJMETHOD(channel_init, cs4231_chan_init), 289136944Syongari KOBJMETHOD(channel_setformat, cs4231_chan_setformat), 290136944Syongari KOBJMETHOD(channel_setspeed, cs4231_chan_setspeed), 291136944Syongari KOBJMETHOD(channel_setblocksize, cs4231_chan_setblocksize), 292136944Syongari KOBJMETHOD(channel_trigger, cs4231_chan_trigger), 293136944Syongari KOBJMETHOD(channel_getptr, cs4231_chan_getptr), 294136944Syongari KOBJMETHOD(channel_getcaps, cs4231_chan_getcaps), 295193640Sariff KOBJMETHOD_END 296136944Syongari}; 297136944SyongariCHANNEL_DECLARE(cs4231_chan); 298136944Syongari 299136944Syongari/* 300136944Syongari * sound(4) mixer interface 301136944Syongari */ 302136944Syongaristatic kobj_method_t cs4231_mixer_methods[] = { 303136944Syongari KOBJMETHOD(mixer_init, cs4231_mixer_init), 304136944Syongari KOBJMETHOD(mixer_set, cs4231_mixer_set), 305136944Syongari KOBJMETHOD(mixer_setrecsrc, cs4231_mixer_setrecsrc), 306193640Sariff KOBJMETHOD_END 307136944Syongari}; 308136944SyongariMIXER_DECLARE(cs4231_mixer); 309136944Syongari 310136944Syongaristatic int 311136944Syongarics4231_bus_probe(device_t dev) 312136944Syongari{ 313166098Smarius const char *compat, *name; 314136944Syongari 315166098Smarius compat = ofw_bus_get_compat(dev); 316136944Syongari name = ofw_bus_get_name(dev); 317166098Smarius if (strcmp("SUNW,CS4231", name) == 0 || 318166098Smarius (compat != NULL && strcmp("SUNW,CS4231", compat) == 0)) { 319136944Syongari device_set_desc(dev, "Sun Audiocs"); 320142890Simp return (BUS_PROBE_DEFAULT); 321136944Syongari } 322136944Syongari return (ENXIO); 323136944Syongari} 324136944Syongari 325136944Syongaristatic int 326136944Syongarics4231_sbus_attach(device_t dev) 327136944Syongari{ 328136944Syongari struct cs4231_softc *sc; 329136944Syongari int burst; 330136944Syongari 331170873Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 332136944Syongari sc->sc_dev = dev; 333136944Syongari /* 334136944Syongari * XXX 335136944Syongari * No public documentation exists on programming burst size of APCDMA. 336136944Syongari */ 337136944Syongari burst = sbus_get_burstsz(sc->sc_dev); 338136944Syongari if ((burst & SBUS_BURST_64)) 339136944Syongari sc->sc_burst = 64; 340136944Syongari else if ((burst & SBUS_BURST_32)) 341136944Syongari sc->sc_burst = 32; 342136944Syongari else if ((burst & SBUS_BURST_16)) 343136944Syongari sc->sc_burst = 16; 344136944Syongari else 345136944Syongari sc->sc_burst = 0; 346136944Syongari sc->sc_flags = CS4231_SBUS; 347136944Syongari sc->sc_nmres = 1; 348136944Syongari sc->sc_nires = 1; 349136944Syongari return cs4231_attach_common(sc); 350136944Syongari} 351136944Syongari 352136944Syongaristatic int 353136944Syongarics4231_ebus_attach(device_t dev) 354136944Syongari{ 355136944Syongari struct cs4231_softc *sc; 356136944Syongari 357136944Syongari sc = malloc(sizeof(struct cs4231_softc), M_DEVBUF, M_NOWAIT | M_ZERO); 358136944Syongari if (sc == NULL) { 359136944Syongari device_printf(dev, "cannot allocate softc\n"); 360136944Syongari return (ENOMEM); 361136944Syongari } 362136944Syongari sc->sc_dev = dev; 363136944Syongari sc->sc_burst = EBDCSR_BURST_1; 364136944Syongari sc->sc_nmres = CS4231_RES_MEM_MAX; 365136944Syongari sc->sc_nires = CS4231_RES_IRQ_MAX; 366136944Syongari sc->sc_flags = CS4231_EBUS; 367136944Syongari return cs4231_attach_common(sc); 368136944Syongari} 369136944Syongari 370136944Syongaristatic int 371136944Syongarics4231_attach_common(struct cs4231_softc *sc) 372136944Syongari{ 373136944Syongari char status[SND_STATUSLEN]; 374136944Syongari driver_intr_t *ihandler; 375136944Syongari int i; 376136944Syongari 377136944Syongari sc->sc_lock = snd_mtxcreate(device_get_nameunit(sc->sc_dev), 378167608Sariff "snd_cs4231 softc"); 379136944Syongari 380136944Syongari for (i = 0; i < sc->sc_nmres; i++) { 381136944Syongari sc->sc_rid[i] = i; 382136944Syongari if ((sc->sc_res[i] = bus_alloc_resource_any(sc->sc_dev, 383146410Smarius SYS_RES_MEMORY, &sc->sc_rid[i], RF_ACTIVE)) == NULL) { 384136944Syongari device_printf(sc->sc_dev, 385136944Syongari "cannot map register %d\n", i); 386136944Syongari goto fail; 387136944Syongari } 388136944Syongari sc->sc_regt[i] = rman_get_bustag(sc->sc_res[i]); 389136944Syongari sc->sc_regh[i] = rman_get_bushandle(sc->sc_res[i]); 390136944Syongari } 391136944Syongari for (i = 0; i < sc->sc_nires; i++) { 392136944Syongari sc->sc_irqrid[i] = i; 393136944Syongari if ((sc->sc_irqres[i] = bus_alloc_resource_any(sc->sc_dev, 394136944Syongari SYS_RES_IRQ, &sc->sc_irqrid[i], RF_SHAREABLE | RF_ACTIVE)) 395136944Syongari == NULL) { 396136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 397136944Syongari device_printf(sc->sc_dev, 398136944Syongari "cannot allocate interrupt\n"); 399136944Syongari else 400136944Syongari device_printf(sc->sc_dev, "cannot allocate %s " 401136944Syongari "interrupt\n", i == 0 ? "capture" : 402136944Syongari "playback"); 403136944Syongari goto fail; 404136944Syongari } 405136944Syongari } 406136944Syongari 407136944Syongari ihandler = cs4231_sbus_intr; 408136944Syongari for (i = 0; i < sc->sc_nires; i++) { 409136944Syongari if ((sc->sc_flags & CS4231_EBUS) != 0) { 410136944Syongari if (i == 0) 411136944Syongari ihandler = cs4231_ebus_cintr; 412136944Syongari else 413136944Syongari ihandler = cs4231_ebus_pintr; 414136944Syongari } 415136944Syongari if (snd_setup_intr(sc->sc_dev, sc->sc_irqres[i], INTR_MPSAFE, 416136944Syongari ihandler, sc, &sc->sc_ih[i])) { 417136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 418136944Syongari device_printf(sc->sc_dev, 419136944Syongari "cannot set up interrupt\n"); 420136944Syongari else 421136944Syongari device_printf(sc->sc_dev, "cannot set up %s " 422136944Syongari " interrupt\n", i == 0 ? "capture" : 423136944Syongari "playback"); 424136944Syongari goto fail; 425136944Syongari } 426136944Syongari } 427136944Syongari 428136944Syongari sc->sc_bufsz = pcm_getbuffersize(sc->sc_dev, CS4231_MIN_BUF_SZ, 429136944Syongari CS4231_DEFAULT_BUF_SZ, CS4231_MAX_BUF_SZ); 430136944Syongari for (i = 0; i < sc->sc_nires; i++) { 431136944Syongari if (bus_dma_tag_create( 432166165Smarius bus_get_dma_tag(sc->sc_dev),/* parent */ 433136944Syongari 64, 0, /* alignment, boundary */ 434136944Syongari BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 435136944Syongari BUS_SPACE_MAXADDR, /* highaddr */ 436136944Syongari NULL, NULL, /* filtfunc, filtfuncarg */ 437136944Syongari sc->sc_bufsz, /* maxsize */ 438136944Syongari 1, /* nsegments */ 439136944Syongari sc->sc_bufsz, /* maxsegsz */ 440136944Syongari BUS_DMA_ALLOCNOW, /* flags */ 441136944Syongari NULL, /* lockfunc */ 442136944Syongari NULL, /* lockfuncarg */ 443136944Syongari &sc->sc_dmat[i])) { 444136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 445136944Syongari device_printf(sc->sc_dev, 446136944Syongari "cannot allocate DMA tag\n"); 447136944Syongari else 448136944Syongari device_printf(sc->sc_dev, "cannot allocate %s " 449136944Syongari "DMA tag\n", i == 0 ? "capture" : 450136944Syongari "playback"); 451136944Syongari goto fail; 452136944Syongari } 453136944Syongari } 454136944Syongari cs4231_enable(sc, CODEC_WARM_RESET); 455136944Syongari cs4231_getversion(sc); 456136944Syongari if (mixer_init(sc->sc_dev, &cs4231_mixer_class, sc) != 0) 457136944Syongari goto fail; 458136944Syongari if (pcm_register(sc->sc_dev, sc, 1, 1)) { 459136944Syongari device_printf(sc->sc_dev, "cannot register to pcm\n"); 460136944Syongari goto fail; 461136944Syongari } 462136944Syongari if (pcm_addchan(sc->sc_dev, PCMDIR_REC, &cs4231_chan_class, sc) != 0) 463136944Syongari goto chan_fail; 464136944Syongari if (pcm_addchan(sc->sc_dev, PCMDIR_PLAY, &cs4231_chan_class, sc) != 0) 465136944Syongari goto chan_fail; 466136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 467136944Syongari snprintf(status, SND_STATUSLEN, "at mem 0x%lx irq %ld bufsz %u", 468136944Syongari rman_get_start(sc->sc_res[0]), 469136944Syongari rman_get_start(sc->sc_irqres[0]), sc->sc_bufsz); 470136944Syongari else 471136944Syongari snprintf(status, SND_STATUSLEN, "at io 0x%lx 0x%lx 0x%lx 0x%lx " 472136944Syongari "irq %ld %ld bufsz %u", rman_get_start(sc->sc_res[0]), 473136944Syongari rman_get_start(sc->sc_res[1]), 474136944Syongari rman_get_start(sc->sc_res[2]), 475136944Syongari rman_get_start(sc->sc_res[3]), 476136944Syongari rman_get_start(sc->sc_irqres[0]), 477136944Syongari rman_get_start(sc->sc_irqres[1]), sc->sc_bufsz); 478136944Syongari pcm_setstatus(sc->sc_dev, status); 479136944Syongari return (0); 480136944Syongari 481136944Syongarichan_fail: 482136944Syongari pcm_unregister(sc->sc_dev); 483136944Syongarifail: 484136944Syongari cs4231_free_resource(sc); 485136944Syongari return (ENXIO); 486136944Syongari} 487136944Syongari 488136944Syongaristatic int 489136944Syongarics4231_bus_detach(device_t dev) 490136944Syongari{ 491136944Syongari struct cs4231_softc *sc; 492136944Syongari struct cs4231_channel *pch, *rch; 493136944Syongari int error; 494136944Syongari 495136944Syongari sc = pcm_getdevinfo(dev); 496136944Syongari CS4231_LOCK(sc); 497136944Syongari pch = &sc->sc_pch; 498136944Syongari rch = &sc->sc_pch; 499136944Syongari if (pch->locked || rch->locked) { 500136944Syongari CS4231_UNLOCK(sc); 501136944Syongari return (EBUSY); 502136944Syongari } 503136944Syongari /* 504136944Syongari * Since EBDMA requires valid DMA buffer to drain its FIFO, we need 505136944Syongari * real DMA buffer for draining. 506136944Syongari */ 507136944Syongari if ((sc->sc_flags & CS4231_EBUS) != 0) 508136944Syongari cs4231_ebdma_reset(sc); 509136944Syongari CS4231_UNLOCK(sc); 510136944Syongari error = pcm_unregister(dev); 511136944Syongari if (error) 512136944Syongari return (error); 513136944Syongari cs4231_free_resource(sc); 514136944Syongari return (0); 515136944Syongari} 516136944Syongari 517136944Syongaristatic int 518136944Syongarics4231_bus_suspend(device_t dev) 519136944Syongari{ 520136944Syongari 521136944Syongari return (ENXIO); 522136944Syongari} 523136944Syongari 524136944Syongaristatic int 525136944Syongarics4231_bus_resume(device_t dev) 526136944Syongari{ 527136944Syongari 528136944Syongari return (ENXIO); 529136944Syongari} 530136944Syongari 531136944Syongaristatic void 532136944Syongarics4231_getversion(struct cs4231_softc *sc) 533136944Syongari{ 534136944Syongari u_int8_t v; 535136944Syongari 536136944Syongari v = cs4231_read(sc, CS_MISC_INFO); 537136944Syongari sc->sc_codecv = v & CS_CODEC_ID_MASK; 538136944Syongari v = cs4231_read(sc, CS_VERSION_ID); 539136944Syongari v &= (CS_VERSION_NUMBER | CS_VERSION_CHIPID); 540136944Syongari sc->sc_chipvid = v; 541136944Syongari switch(v) { 542136944Syongari case 0x80: 543136944Syongari device_printf(sc->sc_dev, "<CS4231 Codec Id. %d>\n", 544136944Syongari sc->sc_codecv); 545136944Syongari break; 546136944Syongari case 0xa0: 547136944Syongari device_printf(sc->sc_dev, "<CS4231A Codec Id. %d>\n", 548136944Syongari sc->sc_codecv); 549136944Syongari break; 550136944Syongari case 0x82: 551136944Syongari device_printf(sc->sc_dev, "<CS4232 Codec Id. %d>\n", 552136944Syongari sc->sc_codecv); 553136944Syongari break; 554136944Syongari default: 555136944Syongari device_printf(sc->sc_dev, 556136944Syongari "<Unknown 0x%x Codec Id. %d\n", v, sc->sc_codecv); 557136944Syongari break; 558136944Syongari } 559136944Syongari} 560136944Syongari 561136944Syongaristatic void 562136944Syongarics4231_ebdma_reset(struct cs4231_softc *sc) 563136944Syongari{ 564136944Syongari int i; 565136944Syongari 566136944Syongari /* playback */ 567136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, 568136944Syongari EBDMA_P_READ(sc, EBDMA_DCSR) & ~(EBDCSR_INTEN | EBDCSR_NEXTEN)); 569136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 570136944Syongari for (i = CS_TIMEOUT; 571136944Syongari i && EBDMA_P_READ(sc, EBDMA_DCSR) & EBDCSR_DRAIN; i--) 572136944Syongari DELAY(1); 573136944Syongari if (i == 0) 574136944Syongari device_printf(sc->sc_dev, 575136944Syongari "timeout waiting for playback DMA reset\n"); 576136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 577136944Syongari /* capture */ 578136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, 579136944Syongari EBDMA_C_READ(sc, EBDMA_DCSR) & ~(EBDCSR_INTEN | EBDCSR_NEXTEN)); 580136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 581136944Syongari for (i = CS_TIMEOUT; 582136944Syongari i && EBDMA_C_READ(sc, EBDMA_DCSR) & EBDCSR_DRAIN; i--) 583136944Syongari DELAY(1); 584136944Syongari if (i == 0) 585136944Syongari device_printf(sc->sc_dev, 586136944Syongari "timeout waiting for capture DMA reset\n"); 587136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 588136944Syongari} 589136944Syongari 590136944Syongaristatic void 591136944Syongarics4231_power_reset(struct cs4231_softc *sc, int how) 592136944Syongari{ 593136944Syongari u_int32_t v; 594136944Syongari int i; 595136944Syongari 596136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 597136944Syongari APC_WRITE(sc, APC_CSR, APC_CSR_RESET); 598136944Syongari DELAY(10); 599136944Syongari APC_WRITE(sc, APC_CSR, 0); 600136944Syongari DELAY(10); 601136944Syongari APC_WRITE(sc, 602136944Syongari APC_CSR, APC_READ(sc, APC_CSR) | APC_CSR_CODEC_RESET); 603136944Syongari DELAY(20); 604136944Syongari APC_WRITE(sc, 605136944Syongari APC_CSR, APC_READ(sc, APC_CSR) & (~APC_CSR_CODEC_RESET)); 606136944Syongari } else { 607136944Syongari v = AUXIO_READ(sc, AUXIO_CODEC); 608136944Syongari if (how == CODEC_WARM_RESET && v != 0) { 609136944Syongari AUXIO_WRITE(sc, AUXIO_CODEC, 0); 610136944Syongari DELAY(20); 611136944Syongari } else if (how == CODEC_COLD_RESET){ 612136944Syongari AUXIO_WRITE(sc, AUXIO_CODEC, 1); 613136944Syongari DELAY(20); 614136944Syongari AUXIO_WRITE(sc, AUXIO_CODEC, 0); 615136944Syongari DELAY(20); 616136944Syongari } 617136944Syongari cs4231_ebdma_reset(sc); 618136944Syongari } 619136944Syongari 620136944Syongari for (i = CS_TIMEOUT; 621136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 622136944Syongari DELAY(10); 623136944Syongari if (i == 0) 624136944Syongari device_printf(sc->sc_dev, "timeout waiting for reset\n"); 625136944Syongari 626136944Syongari /* turn on cs4231 mode */ 627136944Syongari cs4231_write(sc, CS_MISC_INFO, 628136944Syongari cs4231_read(sc, CS_MISC_INFO) | CS_MODE2); 629172568Skevlo /* enable interrupts & clear CSR */ 630136944Syongari cs4231_write(sc, CS_PIN_CONTROL, 631136944Syongari cs4231_read(sc, CS_PIN_CONTROL) | INTERRUPT_ENABLE); 632136944Syongari CS_WRITE(sc, CS4231_STATUS, 0); 633136944Syongari /* enable DAC output */ 634136944Syongari cs4231_write(sc, CS_LEFT_OUTPUT_CONTROL, 635136944Syongari cs4231_read(sc, CS_LEFT_OUTPUT_CONTROL) & ~OUTPUT_MUTE); 636136944Syongari cs4231_write(sc, CS_RIGHT_OUTPUT_CONTROL, 637136944Syongari cs4231_read(sc, CS_RIGHT_OUTPUT_CONTROL) & ~OUTPUT_MUTE); 638136944Syongari /* mute AUX1 since it generates noises */ 639136944Syongari cs4231_write(sc, CS_LEFT_AUX1_CONTROL, 640136944Syongari cs4231_read(sc, CS_LEFT_AUX1_CONTROL) | AUX_INPUT_MUTE); 641136944Syongari cs4231_write(sc, CS_RIGHT_AUX1_CONTROL, 642136944Syongari cs4231_read(sc, CS_RIGHT_AUX1_CONTROL) | AUX_INPUT_MUTE); 643136944Syongari /* protect buffer underrun and set output level to 0dB */ 644136944Syongari cs4231_write(sc, CS_ALT_FEATURE1, 645136944Syongari cs4231_read(sc, CS_ALT_FEATURE1) | CS_DAC_ZERO | CS_OUTPUT_LVL); 646136944Syongari /* enable high pass filter, dual xtal was disabled due to noises */ 647136944Syongari cs4231_write(sc, CS_ALT_FEATURE2, 648136944Syongari cs4231_read(sc, CS_ALT_FEATURE2) | CS_HPF_ENABLE); 649136944Syongari} 650136944Syongari 651136944Syongaristatic int 652136944Syongarics4231_enable(struct cs4231_softc *sc, int how) 653136944Syongari{ 654136944Syongari cs4231_power_reset(sc, how); 655136944Syongari sc->sc_enabled = 1; 656136944Syongari return (0); 657136944Syongari} 658136944Syongari 659136944Syongaristatic void 660136944Syongarics4231_disable(struct cs4231_softc *sc) 661136944Syongari{ 662136944Syongari u_int8_t v; 663136944Syongari 664136944Syongari CS4231_LOCK_ASSERT(sc); 665136944Syongari 666136944Syongari if (sc->sc_enabled == 0) 667136944Syongari return; 668136944Syongari sc->sc_enabled = 0; 669136944Syongari CS4231_UNLOCK(sc); 670136944Syongari cs4231_halt(&sc->sc_pch); 671136944Syongari cs4231_halt(&sc->sc_rch); 672136944Syongari CS4231_LOCK(sc); 673136944Syongari v = cs4231_read(sc, CS_PIN_CONTROL) & ~INTERRUPT_ENABLE; 674136944Syongari cs4231_write(sc, CS_PIN_CONTROL, v); 675136944Syongari 676136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 677136944Syongari APC_WRITE(sc, APC_CSR, APC_CSR_RESET); 678136944Syongari DELAY(10); 679136944Syongari APC_WRITE(sc, APC_CSR, 0); 680136944Syongari DELAY(10); 681136944Syongari } else 682136944Syongari cs4231_ebdma_reset(sc); 683136944Syongari} 684136944Syongari 685136944Syongaristatic void 686136944Syongarics4231_free_resource(struct cs4231_softc *sc) 687136944Syongari{ 688136944Syongari int i; 689136944Syongari 690136944Syongari CS4231_LOCK(sc); 691136944Syongari cs4231_disable(sc); 692136944Syongari CS4231_UNLOCK(sc); 693136944Syongari for (i = 0; i < sc->sc_nires; i++) { 694136944Syongari if (sc->sc_irqres[i]) { 695136944Syongari if (sc->sc_ih[i]) { 696136944Syongari bus_teardown_intr(sc->sc_dev, sc->sc_irqres[i], 697136944Syongari sc->sc_ih[i]); 698136944Syongari sc->sc_ih[i] = NULL; 699136944Syongari } 700136944Syongari bus_release_resource(sc->sc_dev, SYS_RES_IRQ, 701136944Syongari sc->sc_irqrid[i], sc->sc_irqres[i]); 702136944Syongari sc->sc_irqres[i] = NULL; 703136944Syongari } 704136944Syongari } 705136944Syongari for (i = 0; i < sc->sc_nires; i++) { 706136944Syongari if (sc->sc_dmat[i]) 707136944Syongari bus_dma_tag_destroy(sc->sc_dmat[i]); 708136944Syongari } 709136944Syongari for (i = 0; i < sc->sc_nmres; i++) { 710136944Syongari if (sc->sc_res[i]) 711146410Smarius bus_release_resource(sc->sc_dev, SYS_RES_MEMORY, 712136944Syongari sc->sc_rid[i], sc->sc_res[i]); 713136944Syongari } 714136944Syongari snd_mtxfree(sc->sc_lock); 715136944Syongari free(sc, M_DEVBUF); 716136944Syongari} 717136944Syongari 718136944Syongaristatic void 719136944Syongarics4231_write(struct cs4231_softc *sc, u_int8_t r, u_int8_t v) 720136944Syongari{ 721136944Syongari CS_WRITE(sc, CS4231_IADDR, r); 722136944Syongari CS_WRITE(sc, CS4231_IDATA, v); 723136944Syongari} 724136944Syongari 725136944Syongaristatic u_int8_t 726136944Syongarics4231_read(struct cs4231_softc *sc, u_int8_t r) 727136944Syongari{ 728136944Syongari CS_WRITE(sc, CS4231_IADDR, r); 729136944Syongari return (CS_READ(sc, CS4231_IDATA)); 730136944Syongari} 731136944Syongari 732136944Syongaristatic void 733136944Syongarics4231_sbus_intr(void *arg) 734136944Syongari{ 735136944Syongari struct cs4231_softc *sc; 736136944Syongari struct cs4231_channel *pch, *rch; 737136944Syongari u_int32_t csr; 738136944Syongari u_int8_t status; 739136944Syongari 740136944Syongari sc = arg; 741136944Syongari CS4231_LOCK(sc); 742136944Syongari 743136944Syongari csr = APC_READ(sc, APC_CSR); 744136944Syongari if ((csr & APC_CSR_GI) == 0) { 745136944Syongari CS4231_UNLOCK(sc); 746136944Syongari return; 747136944Syongari } 748136944Syongari APC_WRITE(sc, APC_CSR, csr); 749136944Syongari 750136944Syongari if ((csr & APC_CSR_EIE) && (csr & APC_CSR_EI)) { 751136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 752136944Syongari device_printf(sc->sc_dev, 753136944Syongari "apc error interrupt : stat = 0x%x\n", status); 754136944Syongari } 755136944Syongari 756136944Syongari pch = rch = NULL; 757136944Syongari if ((csr & APC_CSR_PMIE) && (csr & APC_CSR_PMI)) { 758136944Syongari u_long nextaddr, saddr; 759136944Syongari u_int32_t togo; 760136944Syongari 761136944Syongari pch = &sc->sc_pch; 762136944Syongari togo = pch->togo; 763136944Syongari saddr = sndbuf_getbufaddr(pch->buffer); 764136944Syongari nextaddr = pch->nextaddr + togo; 765136944Syongari if (nextaddr >= saddr + sndbuf_getsize(pch->buffer)) 766136944Syongari nextaddr = saddr; 767136944Syongari APC_WRITE(sc, APC_PNVA, nextaddr); 768136944Syongari APC_WRITE(sc, APC_PNC, togo); 769136944Syongari pch->nextaddr = nextaddr; 770136944Syongari } 771136944Syongari 772136944Syongari if ((csr & APC_CSR_CIE) && (csr & APC_CSR_CI) && (csr & APC_CSR_CD)) { 773136944Syongari u_long nextaddr, saddr; 774136944Syongari u_int32_t togo; 775136944Syongari 776136944Syongari rch = &sc->sc_rch; 777136944Syongari togo = rch->togo; 778136944Syongari saddr = sndbuf_getbufaddr(rch->buffer); 779136944Syongari nextaddr = rch->nextaddr + togo; 780136944Syongari if (nextaddr >= saddr + sndbuf_getsize(rch->buffer)) 781136944Syongari nextaddr = saddr; 782136944Syongari APC_WRITE(sc, APC_CNVA, nextaddr); 783136944Syongari APC_WRITE(sc, APC_CNC, togo); 784136944Syongari rch->nextaddr = nextaddr; 785136944Syongari } 786136944Syongari CS4231_UNLOCK(sc); 787136944Syongari if (pch) 788136944Syongari chn_intr(pch->channel); 789136944Syongari if (rch) 790136944Syongari chn_intr(rch->channel); 791136944Syongari} 792136944Syongari 793136944Syongari/* playback interrupt handler */ 794136944Syongaristatic void 795136944Syongarics4231_ebus_pintr(void *arg) 796136944Syongari{ 797136944Syongari struct cs4231_softc *sc; 798136944Syongari struct cs4231_channel *ch; 799136944Syongari u_int32_t csr; 800136944Syongari u_int8_t status; 801136944Syongari 802136944Syongari sc = arg; 803136944Syongari CS4231_LOCK(sc); 804136944Syongari 805136944Syongari csr = EBDMA_P_READ(sc, EBDMA_DCSR); 806136944Syongari if ((csr & EBDCSR_INT) == 0) { 807136944Syongari CS4231_UNLOCK(sc); 808136944Syongari return; 809136944Syongari } 810136944Syongari 811136944Syongari if ((csr & EBDCSR_ERR)) { 812136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 813136944Syongari device_printf(sc->sc_dev, 814136944Syongari "ebdma error interrupt : stat = 0x%x\n", status); 815136944Syongari } 816136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, csr | EBDCSR_TC); 817136944Syongari 818136944Syongari ch = NULL; 819136944Syongari if (csr & EBDCSR_TC) { 820136944Syongari u_long nextaddr, saddr; 821136944Syongari u_int32_t togo; 822136944Syongari 823136944Syongari ch = &sc->sc_pch; 824136944Syongari togo = ch->togo; 825136944Syongari saddr = sndbuf_getbufaddr(ch->buffer); 826136944Syongari nextaddr = ch->nextaddr + togo; 827136944Syongari if (nextaddr >= saddr + sndbuf_getsize(ch->buffer)) 828136944Syongari nextaddr = saddr; 829136944Syongari /* 830136944Syongari * EBDMA_DCNT is loaded automatically 831136944Syongari * EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 832136944Syongari */ 833136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 834136944Syongari ch->nextaddr = nextaddr; 835136944Syongari } 836136944Syongari CS4231_UNLOCK(sc); 837136944Syongari if (ch) 838136944Syongari chn_intr(ch->channel); 839136944Syongari} 840136944Syongari 841136944Syongari/* capture interrupt handler */ 842136944Syongaristatic void 843136944Syongarics4231_ebus_cintr(void *arg) 844136944Syongari{ 845136944Syongari struct cs4231_softc *sc; 846136944Syongari struct cs4231_channel *ch; 847136944Syongari u_int32_t csr; 848136944Syongari u_int8_t status; 849136944Syongari 850136944Syongari sc = arg; 851136944Syongari CS4231_LOCK(sc); 852136944Syongari 853136944Syongari csr = EBDMA_C_READ(sc, EBDMA_DCSR); 854136944Syongari if ((csr & EBDCSR_INT) == 0) { 855136944Syongari CS4231_UNLOCK(sc); 856136944Syongari return; 857136944Syongari } 858136944Syongari if ((csr & EBDCSR_ERR)) { 859136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 860136944Syongari device_printf(sc->sc_dev, 861136944Syongari "dma error interrupt : stat = 0x%x\n", status); 862136944Syongari } 863136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, csr | EBDCSR_TC); 864136944Syongari 865136944Syongari ch = NULL; 866136944Syongari if (csr & EBDCSR_TC) { 867136944Syongari u_long nextaddr, saddr; 868136944Syongari u_int32_t togo; 869136944Syongari 870136944Syongari ch = &sc->sc_rch; 871136944Syongari togo = ch->togo; 872136944Syongari saddr = sndbuf_getbufaddr(ch->buffer); 873136944Syongari nextaddr = ch->nextaddr + togo; 874136944Syongari if (nextaddr >= saddr + sndbuf_getblksz(ch->buffer)) 875136944Syongari nextaddr = saddr; 876136944Syongari /* 877136944Syongari * EBDMA_DCNT is loaded automatically 878136944Syongari * EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 879136944Syongari */ 880136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 881136944Syongari ch->nextaddr = nextaddr; 882136944Syongari } 883136944Syongari CS4231_UNLOCK(sc); 884136944Syongari if (ch) 885136944Syongari chn_intr(ch->channel); 886136944Syongari} 887136944Syongari 888136944Syongaristatic const struct mix_table cs4231_mix_table[SOUND_MIXER_NRDEVICES][2] = { 889136944Syongari [SOUND_MIXER_PCM] = { 890136944Syongari { CS_LEFT_OUTPUT_CONTROL, 6, OUTPUT_MUTE, 0, 1, 1, 0 }, 891136944Syongari { CS_RIGHT_OUTPUT_CONTROL, 6, OUTPUT_MUTE, 0, 1, 1, 0 } 892136944Syongari }, 893136944Syongari [SOUND_MIXER_SPEAKER] = { 894136944Syongari { CS_MONO_IO_CONTROL, 4, MONO_OUTPUT_MUTE, 0, 1, 1, 0 }, 895136944Syongari { CS_REG_NONE, 0, 0, 0, 0, 1, 0 } 896136944Syongari }, 897136944Syongari [SOUND_MIXER_LINE] = { 898136944Syongari { CS_LEFT_LINE_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 }, 899136944Syongari { CS_RIGHT_LINE_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 } 900136944Syongari }, 901136944Syongari /* 902136944Syongari * AUX1 : removed intentionally since it generates noises 903136944Syongari * AUX2 : Ultra1/Ultra2 has no internal CD-ROM audio in 904136944Syongari */ 905136944Syongari [SOUND_MIXER_CD] = { 906136944Syongari { CS_LEFT_AUX2_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 }, 907136944Syongari { CS_RIGHT_AUX2_CONTROL, 5, LINE_INPUT_MUTE, 0, 1, 1, 1 } 908136944Syongari }, 909136944Syongari [SOUND_MIXER_MIC] = { 910136944Syongari { CS_LEFT_INPUT_CONTROL, 4, 0, 0, 0, 1, 1 }, 911136944Syongari { CS_RIGHT_INPUT_CONTROL, 4, 0, 0, 0, 1, 1 } 912136944Syongari }, 913136944Syongari [SOUND_MIXER_IGAIN] = { 914136944Syongari { CS_LEFT_INPUT_CONTROL, 4, 0, 0, 1, 0 }, 915136944Syongari { CS_RIGHT_INPUT_CONTROL, 4, 0, 0, 1, 0 } 916136944Syongari } 917136944Syongari}; 918136944Syongari 919136944Syongaristatic int 920136944Syongarics4231_mixer_init(struct snd_mixer *m) 921136944Syongari{ 922136944Syongari u_int32_t v; 923136944Syongari int i; 924136944Syongari 925136944Syongari v = 0; 926136944Syongari for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 927136944Syongari if (cs4231_mix_table[i][0].avail != 0) 928136944Syongari v |= (1 << i); 929136944Syongari mix_setdevs(m, v); 930136944Syongari v = 0; 931136944Syongari for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 932136944Syongari if (cs4231_mix_table[i][0].recdev != 0) 933136944Syongari v |= (1 << i); 934136944Syongari mix_setrecdevs(m, v); 935136944Syongari return (0); 936136944Syongari} 937136944Syongari 938136944Syongaristatic void 939136944Syongarics4231_mixer_set_value(struct cs4231_softc *sc, const struct mix_table *mt, 940136944Syongari u_int8_t v) 941136944Syongari{ 942136944Syongari u_int8_t mask, reg; 943136944Syongari u_int8_t old, shift, val; 944136944Syongari 945136944Syongari if (mt->avail == 0 || mt->reg == CS_REG_NONE) 946136944Syongari return; 947136944Syongari reg = mt->reg; 948136944Syongari if (mt->neg != 0) 949136944Syongari val = 100 - v; 950136944Syongari else 951136944Syongari val = v; 952136944Syongari mask = (1 << mt->bits) - 1; 953136944Syongari val = ((val * mask) + 50) / 100; 954136944Syongari shift = mt->shift; 955136944Syongari val <<= shift; 956136944Syongari if (v == 0) 957136944Syongari val |= mt->mute; 958136944Syongari old = cs4231_read(sc, reg); 959136944Syongari old &= ~(mt->mute | (mask << shift)); 960136944Syongari val |= old; 961136944Syongari if (reg == CS_LEFT_INPUT_CONTROL || reg == CS_RIGHT_INPUT_CONTROL) { 962136944Syongari if ((val & (mask << shift)) != 0) 963136944Syongari val |= ADC_INPUT_GAIN_ENABLE; 964136944Syongari else 965136944Syongari val &= ~ADC_INPUT_GAIN_ENABLE; 966136944Syongari } 967136944Syongari cs4231_write(sc, reg, val); 968136944Syongari} 969136944Syongari 970136944Syongaristatic int 971136944Syongarics4231_mixer_set(struct snd_mixer *m, u_int32_t dev, u_int32_t left, 972136944Syongari u_int32_t right) 973136944Syongari{ 974136944Syongari struct cs4231_softc *sc; 975136944Syongari 976136944Syongari sc = mix_getdevinfo(m); 977136944Syongari CS4231_LOCK(sc); 978136944Syongari cs4231_mixer_set_value(sc, &cs4231_mix_table[dev][0], left); 979136944Syongari cs4231_mixer_set_value(sc, &cs4231_mix_table[dev][1], right); 980136944Syongari CS4231_UNLOCK(sc); 981136944Syongari 982136944Syongari return (left | (right << 8)); 983136944Syongari} 984136944Syongari 985136944Syongaristatic int 986136944Syongarics4231_mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 987136944Syongari{ 988136944Syongari struct cs4231_softc *sc; 989136944Syongari u_int8_t v; 990136944Syongari 991136944Syongari sc = mix_getdevinfo(m); 992136944Syongari switch (src) { 993136944Syongari case SOUND_MASK_LINE: 994136944Syongari v = CS_IN_LINE; 995136944Syongari break; 996136944Syongari 997136944Syongari case SOUND_MASK_CD: 998136944Syongari v = CS_IN_DAC; 999136944Syongari break; 1000136944Syongari 1001136944Syongari case SOUND_MASK_MIC: 1002136944Syongari default: 1003136944Syongari v = CS_IN_MIC; 1004136944Syongari src = SOUND_MASK_MIC; 1005136944Syongari break; 1006136944Syongari } 1007136944Syongari CS4231_LOCK(sc); 1008136944Syongari cs4231_write(sc, CS_LEFT_INPUT_CONTROL, 1009136944Syongari (cs4231_read(sc, CS_LEFT_INPUT_CONTROL) & CS_IN_MASK) | v); 1010136944Syongari cs4231_write(sc, CS_RIGHT_INPUT_CONTROL, 1011136944Syongari (cs4231_read(sc, CS_RIGHT_INPUT_CONTROL) & CS_IN_MASK) | v); 1012136944Syongari CS4231_UNLOCK(sc); 1013136944Syongari 1014136944Syongari return (src); 1015136944Syongari} 1016136944Syongari 1017136944Syongaristatic void * 1018136944Syongarics4231_chan_init(kobj_t obj, void *dev, struct snd_dbuf *b, 1019136944Syongari struct pcm_channel *c, int dir) 1020136944Syongari{ 1021136944Syongari struct cs4231_softc *sc; 1022136944Syongari struct cs4231_channel *ch; 1023136944Syongari bus_dma_tag_t dmat; 1024136944Syongari 1025136944Syongari sc = dev; 1026136944Syongari ch = (dir == PCMDIR_PLAY) ? &sc->sc_pch : &sc->sc_rch; 1027136944Syongari ch->parent = sc; 1028136944Syongari ch->channel = c; 1029136944Syongari ch->dir = dir; 1030136944Syongari ch->buffer = b; 1031136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 1032136944Syongari dmat = sc->sc_dmat[0]; 1033136944Syongari else { 1034136944Syongari if (dir == PCMDIR_PLAY) 1035136944Syongari dmat = sc->sc_dmat[1]; 1036136944Syongari else 1037136944Syongari dmat = sc->sc_dmat[0]; 1038136944Syongari } 1039168847Sariff if (sndbuf_alloc(ch->buffer, dmat, 0, sc->sc_bufsz) != 0) 1040136944Syongari return (NULL); 1041136944Syongari DPRINTF(("%s channel addr: 0x%lx\n", dir == PCMDIR_PLAY ? "playback" : 1042136944Syongari "capture", sndbuf_getbufaddr(ch->buffer))); 1043136944Syongari 1044136944Syongari return (ch); 1045136944Syongari} 1046136944Syongari 1047136944Syongaristatic int 1048136944Syongarics4231_chan_setformat(kobj_t obj, void *data, u_int32_t format) 1049136944Syongari{ 1050136944Syongari struct cs4231_softc *sc; 1051136944Syongari struct cs4231_channel *ch; 1052136944Syongari u_int32_t encoding; 1053136944Syongari u_int8_t fs, v; 1054136944Syongari 1055136944Syongari ch = data; 1056136944Syongari sc = ch->parent; 1057136944Syongari 1058136944Syongari CS4231_LOCK(sc); 1059136944Syongari if (ch->format == format) { 1060136944Syongari CS4231_UNLOCK(sc); 1061136944Syongari return (0); 1062136944Syongari } 1063136944Syongari 1064193640Sariff encoding = AFMT_ENCODING(format); 1065136944Syongari fs = 0; 1066136944Syongari switch (encoding) { 1067136944Syongari case AFMT_U8: 1068136944Syongari fs = CS_AFMT_U8; 1069136944Syongari break; 1070136944Syongari case AFMT_MU_LAW: 1071136944Syongari fs = CS_AFMT_MU_LAW; 1072136944Syongari break; 1073136944Syongari case AFMT_S16_LE: 1074136944Syongari fs = CS_AFMT_S16_LE; 1075136944Syongari break; 1076136944Syongari case AFMT_A_LAW: 1077136944Syongari fs = CS_AFMT_A_LAW; 1078136944Syongari break; 1079136944Syongari case AFMT_IMA_ADPCM: 1080136944Syongari fs = CS_AFMT_IMA_ADPCM; 1081136944Syongari break; 1082136944Syongari case AFMT_S16_BE: 1083136944Syongari fs = CS_AFMT_S16_BE; 1084136944Syongari break; 1085136944Syongari default: 1086136944Syongari fs = CS_AFMT_U8; 1087136944Syongari format = AFMT_U8; 1088136944Syongari break; 1089136944Syongari } 1090136944Syongari 1091193640Sariff if (AFMT_CHANNEL(format) > 1) 1092136944Syongari fs |= CS_AFMT_STEREO; 1093136944Syongari 1094136944Syongari DPRINTF(("FORMAT: %s : 0x%x\n", ch->dir == PCMDIR_PLAY ? "playback" : 1095136944Syongari "capture", format)); 1096136944Syongari v = cs4231_read(sc, CS_CLOCK_DATA_FORMAT); 1097136944Syongari v &= CS_CLOCK_DATA_FORMAT_MASK; 1098136944Syongari fs |= v; 1099136944Syongari cs4231_chan_fs(sc, ch->dir, fs); 1100136944Syongari ch->format = format; 1101136944Syongari CS4231_UNLOCK(sc); 1102136944Syongari 1103136944Syongari return (0); 1104136944Syongari} 1105136944Syongari 1106136944Syongaristatic int 1107136944Syongarics4231_chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1108136944Syongari{ 1109136944Syongari typedef struct { 1110136944Syongari u_int32_t speed; 1111136944Syongari u_int8_t bits; 1112136944Syongari } speed_struct; 1113136944Syongari 1114136944Syongari const static speed_struct speed_table[] = { 1115136944Syongari {5510, (0 << 1) | CLOCK_XTAL2}, 1116136944Syongari {5510, (0 << 1) | CLOCK_XTAL2}, 1117136944Syongari {6620, (7 << 1) | CLOCK_XTAL2}, 1118136944Syongari {8000, (0 << 1) | CLOCK_XTAL1}, 1119136944Syongari {9600, (7 << 1) | CLOCK_XTAL1}, 1120136944Syongari {11025, (1 << 1) | CLOCK_XTAL2}, 1121136944Syongari {16000, (1 << 1) | CLOCK_XTAL1}, 1122136944Syongari {18900, (2 << 1) | CLOCK_XTAL2}, 1123136944Syongari {22050, (3 << 1) | CLOCK_XTAL2}, 1124136944Syongari {27420, (2 << 1) | CLOCK_XTAL1}, 1125136944Syongari {32000, (3 << 1) | CLOCK_XTAL1}, 1126136944Syongari {33075, (6 << 1) | CLOCK_XTAL2}, 1127136944Syongari {33075, (4 << 1) | CLOCK_XTAL2}, 1128136944Syongari {44100, (5 << 1) | CLOCK_XTAL2}, 1129136944Syongari {48000, (6 << 1) | CLOCK_XTAL1}, 1130136944Syongari }; 1131136944Syongari 1132136944Syongari struct cs4231_softc *sc; 1133136944Syongari struct cs4231_channel *ch; 1134136944Syongari int i, n, sel; 1135136944Syongari u_int8_t fs; 1136136944Syongari 1137136944Syongari ch = data; 1138136944Syongari sc = ch->parent; 1139136944Syongari CS4231_LOCK(sc); 1140136944Syongari if (ch->speed == speed) { 1141136944Syongari CS4231_UNLOCK(sc); 1142136944Syongari return (speed); 1143136944Syongari } 1144136944Syongari n = sizeof(speed_table) / sizeof(speed_struct); 1145136944Syongari 1146136944Syongari for (i = 1, sel =0; i < n - 1; i++) 1147136944Syongari if (abs(speed - speed_table[i].speed) < 1148136944Syongari abs(speed - speed_table[sel].speed)) 1149136944Syongari sel = i; 1150136944Syongari DPRINTF(("SPEED: %s : %dHz -> %dHz\n", ch->dir == PCMDIR_PLAY ? 1151136944Syongari "playback" : "capture", speed, speed_table[sel].speed)); 1152136944Syongari speed = speed_table[sel].speed; 1153136944Syongari 1154136944Syongari fs = cs4231_read(sc, CS_CLOCK_DATA_FORMAT); 1155136944Syongari fs &= ~CS_CLOCK_DATA_FORMAT_MASK; 1156136944Syongari fs |= speed_table[sel].bits; 1157136944Syongari cs4231_chan_fs(sc, ch->dir, fs); 1158136944Syongari ch->speed = speed; 1159136944Syongari CS4231_UNLOCK(sc); 1160136944Syongari 1161136944Syongari return (speed); 1162136944Syongari} 1163136944Syongari 1164136944Syongaristatic void 1165136944Syongarics4231_chan_fs(struct cs4231_softc *sc, int dir, u_int8_t fs) 1166136944Syongari{ 1167136944Syongari int i, doreset; 1168136944Syongari#ifdef CS4231_AUTO_CALIBRATION 1169136944Syongari u_int8_t v; 1170136944Syongari#endif 1171136944Syongari 1172136944Syongari CS4231_LOCK_ASSERT(sc); 1173136944Syongari 1174136944Syongari /* set autocalibration */ 1175136944Syongari doreset = 0; 1176136944Syongari#ifdef CS4231_AUTO_CALIBRATION 1177136944Syongari v = cs4231_read(sc, CS_INTERFACE_CONFIG) | AUTO_CAL_ENABLE; 1178136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE); 1179136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE | CS_INTERFACE_CONFIG); 1180136944Syongari CS_WRITE(sc, CS4231_IDATA, v); 1181136944Syongari#endif 1182136944Syongari 1183136944Syongari /* 1184136944Syongari * We always need to write CS_CLOCK_DATA_FORMAT register since 1185136944Syongari * the clock frequency is shared with playback/capture. 1186136944Syongari */ 1187136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE | CS_CLOCK_DATA_FORMAT); 1188136944Syongari CS_WRITE(sc, CS4231_IDATA, fs); 1189136944Syongari CS_READ(sc, CS4231_IDATA); 1190136944Syongari CS_READ(sc, CS4231_IDATA); 1191136944Syongari for (i = CS_TIMEOUT; 1192136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 1193136944Syongari DELAY(10); 1194136944Syongari if (i == 0) { 1195136944Syongari device_printf(sc->sc_dev, "timeout setting playback speed\n"); 1196136944Syongari doreset++; 1197136944Syongari } 1198136944Syongari 1199136944Syongari /* 1200136944Syongari * capture channel 1201136944Syongari * cs4231 doesn't allow seperate fs setup for playback/capture. 1202136944Syongari * I believe this will break full-duplex operation. 1203136944Syongari */ 1204136944Syongari if (dir == PCMDIR_REC) { 1205136944Syongari CS_WRITE(sc, CS4231_IADDR, MODE_CHANGE_ENABLE | CS_REC_FORMAT); 1206136944Syongari CS_WRITE(sc, CS4231_IDATA, fs); 1207136944Syongari CS_READ(sc, CS4231_IDATA); 1208136944Syongari CS_READ(sc, CS4231_IDATA); 1209136944Syongari for (i = CS_TIMEOUT; 1210136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 1211136944Syongari DELAY(10); 1212136944Syongari if (i == 0) { 1213136944Syongari device_printf(sc->sc_dev, 1214136944Syongari "timeout setting capture format\n"); 1215136944Syongari doreset++; 1216136944Syongari } 1217136944Syongari } 1218136944Syongari 1219136944Syongari CS_WRITE(sc, CS4231_IADDR, 0); 1220136944Syongari for (i = CS_TIMEOUT; 1221136944Syongari i && CS_READ(sc, CS4231_IADDR) == CS_IN_INIT; i--) 1222136944Syongari DELAY(10); 1223136944Syongari if (i == 0) { 1224136944Syongari device_printf(sc->sc_dev, "timeout waiting for !MCE\n"); 1225136944Syongari doreset++; 1226136944Syongari } 1227136944Syongari 1228136944Syongari#ifdef CS4231_AUTO_CALIBRATION 1229136944Syongari CS_WRITE(sc, CS4231_IADDR, CS_TEST_AND_INIT); 1230136944Syongari for (i = CS_TIMEOUT; 1231136944Syongari i && CS_READ(sc, CS4231_IDATA) & AUTO_CAL_IN_PROG; i--) 1232136944Syongari DELAY(10); 1233136944Syongari if (i == 0) { 1234136944Syongari device_printf(sc->sc_dev, 1235136944Syongari "timeout waiting for autocalibration\n"); 1236136944Syongari doreset++; 1237136944Syongari } 1238136944Syongari#endif 1239136944Syongari if (doreset) { 1240136944Syongari /* 1241136944Syongari * Maybe the last resort to avoid a dreadful message like 1242136944Syongari * "pcm0:play:0: play interrupt timeout, channel dead" would 1243136944Syongari * be hardware reset. 1244136944Syongari */ 1245136944Syongari device_printf(sc->sc_dev, "trying to hardware reset\n"); 1246136944Syongari cs4231_disable(sc); 1247136944Syongari cs4231_enable(sc, CODEC_COLD_RESET); 1248136944Syongari CS4231_UNLOCK(sc); /* XXX */ 1249136944Syongari if (mixer_reinit(sc->sc_dev) != 0) 1250136944Syongari device_printf(sc->sc_dev, 1251136944Syongari "unable to reinitialize the mixer\n"); 1252136944Syongari CS4231_LOCK(sc); 1253136944Syongari } 1254136944Syongari} 1255136944Syongari 1256136944Syongaristatic int 1257136944Syongarics4231_chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1258136944Syongari{ 1259136944Syongari struct cs4231_softc *sc; 1260136944Syongari struct cs4231_channel *ch; 1261136944Syongari int nblks, error; 1262136944Syongari 1263136944Syongari ch = data; 1264136944Syongari sc = ch->parent; 1265136944Syongari 1266136944Syongari if (blocksize > CS4231_MAX_BLK_SZ) 1267136944Syongari blocksize = CS4231_MAX_BLK_SZ; 1268136944Syongari nblks = sc->sc_bufsz / blocksize; 1269136944Syongari error = sndbuf_resize(ch->buffer, nblks, blocksize); 1270136944Syongari if (error != 0) 1271136944Syongari device_printf(sc->sc_dev, 1272136944Syongari "unable to block size, blksz = %d, error = %d\n", 1273136944Syongari blocksize, error); 1274136944Syongari 1275136944Syongari return (blocksize); 1276136944Syongari} 1277136944Syongari 1278136944Syongaristatic int 1279136944Syongarics4231_chan_trigger(kobj_t obj, void *data, int go) 1280136944Syongari{ 1281136944Syongari struct cs4231_channel *ch; 1282136944Syongari 1283136944Syongari ch = data; 1284136944Syongari switch (go) { 1285136944Syongari case PCMTRIG_EMLDMAWR: 1286136944Syongari case PCMTRIG_EMLDMARD: 1287136944Syongari break; 1288136944Syongari case PCMTRIG_START: 1289136944Syongari cs4231_trigger(ch); 1290136944Syongari break; 1291136944Syongari case PCMTRIG_ABORT: 1292136944Syongari case PCMTRIG_STOP: 1293136944Syongari cs4231_halt(ch); 1294136944Syongari break; 1295136944Syongari default: 1296136944Syongari break; 1297136944Syongari } 1298136944Syongari 1299136944Syongari return (0); 1300136944Syongari} 1301136944Syongari 1302136944Syongaristatic int 1303136944Syongarics4231_chan_getptr(kobj_t obj, void *data) 1304136944Syongari{ 1305136944Syongari struct cs4231_softc *sc; 1306136944Syongari struct cs4231_channel *ch; 1307136944Syongari u_int32_t cur; 1308136944Syongari int ptr, sz; 1309136944Syongari 1310136944Syongari ch = data; 1311136944Syongari sc = ch->parent; 1312136944Syongari 1313136944Syongari CS4231_LOCK(sc); 1314136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 1315136944Syongari cur = (ch->dir == PCMDIR_PLAY) ? APC_READ(sc, APC_PVA) : 1316136944Syongari APC_READ(sc, APC_CVA); 1317136944Syongari else 1318136944Syongari cur = (ch->dir == PCMDIR_PLAY) ? EBDMA_P_READ(sc, EBDMA_DADDR) : 1319136944Syongari EBDMA_C_READ(sc, EBDMA_DADDR); 1320136944Syongari sz = sndbuf_getsize(ch->buffer); 1321136944Syongari ptr = cur - sndbuf_getbufaddr(ch->buffer) + sz; 1322136944Syongari CS4231_UNLOCK(sc); 1323136944Syongari 1324136944Syongari ptr %= sz; 1325136944Syongari return (ptr); 1326136944Syongari} 1327136944Syongari 1328136944Syongaristatic struct pcmchan_caps * 1329136944Syongarics4231_chan_getcaps(kobj_t obj, void *data) 1330136944Syongari{ 1331136944Syongari 1332136944Syongari return (&cs4231_caps); 1333136944Syongari} 1334136944Syongari 1335136944Syongaristatic void 1336136944Syongarics4231_trigger(struct cs4231_channel *ch) 1337136944Syongari{ 1338136944Syongari struct cs4231_softc *sc; 1339136944Syongari 1340136944Syongari sc = ch->parent; 1341136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) 1342136944Syongari cs4231_apcdma_trigger(sc, ch); 1343136944Syongari else 1344136944Syongari cs4231_ebdma_trigger(sc, ch); 1345136944Syongari} 1346136944Syongari 1347136944Syongaristatic void 1348136944Syongarics4231_apcdma_trigger(struct cs4231_softc *sc, struct cs4231_channel *ch) 1349136944Syongari{ 1350136944Syongari u_int32_t csr, togo; 1351136944Syongari u_int32_t nextaddr; 1352136944Syongari 1353136944Syongari CS4231_LOCK(sc); 1354136944Syongari if (ch->locked) { 1355136944Syongari device_printf(sc->sc_dev, "%s channel already triggered\n", 1356136944Syongari ch->dir == PCMDIR_PLAY ? "playback" : "capture"); 1357136944Syongari CS4231_UNLOCK(sc); 1358136944Syongari return; 1359136944Syongari } 1360136944Syongari 1361136944Syongari nextaddr = sndbuf_getbufaddr(ch->buffer); 1362136944Syongari togo = sndbuf_getsize(ch->buffer) / 2; 1363136944Syongari if (togo > CS4231_MAX_APC_DMA_SZ) 1364136944Syongari togo = CS4231_MAX_APC_DMA_SZ; 1365136944Syongari ch->togo = togo; 1366136944Syongari if (ch->dir == PCMDIR_PLAY) { 1367136944Syongari DPRINTF(("TRG: PNVA = 0x%x, togo = 0x%x\n", nextaddr, togo)); 1368136944Syongari 1369136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1370136944Syongari csr = APC_READ(sc, APC_CSR); 1371136944Syongari APC_WRITE(sc, APC_PNVA, nextaddr); 1372136944Syongari APC_WRITE(sc, APC_PNC, togo); 1373136944Syongari 1374136944Syongari if ((csr & APC_CSR_PDMA_GO) == 0 || 1375136944Syongari (csr & APC_CSR_PPAUSE) != 0) { 1376136944Syongari APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & 1377136944Syongari ~(APC_CSR_PIE | APC_CSR_PPAUSE)); 1378136944Syongari APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) | 1379136944Syongari APC_CSR_GIE | APC_CSR_PIE | APC_CSR_EIE | 1380136944Syongari APC_CSR_EI | APC_CSR_PMIE | APC_CSR_PDMA_GO); 1381136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1382136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1383136944Syongari PLAYBACK_ENABLE); 1384136944Syongari } 1385136944Syongari /* load next address */ 1386136944Syongari if (APC_READ(sc, APC_CSR) & APC_CSR_PD) { 1387136944Syongari nextaddr += togo; 1388136944Syongari APC_WRITE(sc, APC_PNVA, nextaddr); 1389136944Syongari APC_WRITE(sc, APC_PNC, togo); 1390136944Syongari } 1391136944Syongari } else { 1392136944Syongari DPRINTF(("TRG: CNVA = 0x%x, togo = 0x%x\n", nextaddr, togo)); 1393136944Syongari 1394136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1395136944Syongari APC_WRITE(sc, APC_CNVA, nextaddr); 1396136944Syongari APC_WRITE(sc, APC_CNC, togo); 1397136944Syongari csr = APC_READ(sc, APC_CSR); 1398136944Syongari if ((csr & APC_CSR_CDMA_GO) == 0 || 1399136944Syongari (csr & APC_CSR_CPAUSE) != 0) { 1400136944Syongari csr &= APC_CSR_CPAUSE; 1401136944Syongari csr |= APC_CSR_GIE | APC_CSR_CMIE | APC_CSR_CIE | 1402136944Syongari APC_CSR_EI | APC_CSR_CDMA_GO; 1403136944Syongari APC_WRITE(sc, APC_CSR, csr); 1404136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1405136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1406136944Syongari CAPTURE_ENABLE); 1407136944Syongari } 1408136944Syongari /* load next address */ 1409136944Syongari if (APC_READ(sc, APC_CSR) & APC_CSR_CD) { 1410136944Syongari nextaddr += togo; 1411136944Syongari APC_WRITE(sc, APC_CNVA, nextaddr); 1412136944Syongari APC_WRITE(sc, APC_CNC, togo); 1413136944Syongari } 1414136944Syongari } 1415136944Syongari ch->nextaddr = nextaddr; 1416136944Syongari ch->locked = 1; 1417136944Syongari CS4231_UNLOCK(sc); 1418136944Syongari} 1419136944Syongari 1420136944Syongaristatic void 1421136944Syongarics4231_ebdma_trigger(struct cs4231_softc *sc, struct cs4231_channel *ch) 1422136944Syongari{ 1423136944Syongari u_int32_t csr, togo; 1424136944Syongari u_int32_t nextaddr; 1425136944Syongari 1426136944Syongari CS4231_LOCK(sc); 1427136944Syongari if (ch->locked) { 1428136944Syongari device_printf(sc->sc_dev, "%s channel already triggered\n", 1429136944Syongari ch->dir == PCMDIR_PLAY ? "playback" : "capture"); 1430136944Syongari CS4231_UNLOCK(sc); 1431136944Syongari return; 1432136944Syongari } 1433136944Syongari 1434136944Syongari nextaddr = sndbuf_getbufaddr(ch->buffer); 1435136944Syongari togo = sndbuf_getsize(ch->buffer) / 2; 1436136944Syongari if (togo % 64 == 0) 1437136944Syongari sc->sc_burst = EBDCSR_BURST_16; 1438136944Syongari else if (togo % 32 == 0) 1439136944Syongari sc->sc_burst = EBDCSR_BURST_8; 1440136944Syongari else if (togo % 16 == 0) 1441136944Syongari sc->sc_burst = EBDCSR_BURST_4; 1442136944Syongari else 1443136944Syongari sc->sc_burst = EBDCSR_BURST_1; 1444136944Syongari ch->togo = togo; 1445136944Syongari DPRINTF(("TRG: DNAR = 0x%x, togo = 0x%x\n", nextaddr, togo)); 1446136944Syongari if (ch->dir == PCMDIR_PLAY) { 1447136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1448136944Syongari csr = EBDMA_P_READ(sc, EBDMA_DCSR); 1449136944Syongari 1450136944Syongari if (csr & EBDCSR_DMAEN) { 1451136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 1452136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 1453136944Syongari } else { 1454136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 1455136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 1456136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 1457136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 1458136944Syongari 1459136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, sc->sc_burst | 1460136944Syongari EBDCSR_DMAEN | EBDCSR_INTEN | EBDCSR_CNTEN | 1461136944Syongari EBDCSR_NEXTEN); 1462136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1463136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1464136944Syongari PLAYBACK_ENABLE); 1465136944Syongari } 1466136944Syongari /* load next address */ 1467136944Syongari if (EBDMA_P_READ(sc, EBDMA_DCSR) & EBDCSR_A_LOADED) { 1468136944Syongari nextaddr += togo; 1469136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCNT, togo); 1470136944Syongari EBDMA_P_WRITE(sc, EBDMA_DADDR, nextaddr); 1471136944Syongari } 1472136944Syongari } else { 1473136944Syongari cs4231_read(sc, CS_TEST_AND_INIT); /* clear pending error */ 1474136944Syongari csr = EBDMA_C_READ(sc, EBDMA_DCSR); 1475136944Syongari 1476136944Syongari if (csr & EBDCSR_DMAEN) { 1477136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 1478136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 1479136944Syongari } else { 1480136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, EBDCSR_RESET); 1481136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, sc->sc_burst); 1482136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 1483136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 1484136944Syongari 1485136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, sc->sc_burst | 1486136944Syongari EBDCSR_WRITE | EBDCSR_DMAEN | EBDCSR_INTEN | 1487136944Syongari EBDCSR_CNTEN | EBDCSR_NEXTEN); 1488136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1489136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) | 1490136944Syongari CAPTURE_ENABLE); 1491136944Syongari } 1492136944Syongari /* load next address */ 1493136944Syongari if (EBDMA_C_READ(sc, EBDMA_DCSR) & EBDCSR_A_LOADED) { 1494136944Syongari nextaddr += togo; 1495136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCNT, togo); 1496136944Syongari EBDMA_C_WRITE(sc, EBDMA_DADDR, nextaddr); 1497136944Syongari } 1498136944Syongari } 1499136944Syongari ch->nextaddr = nextaddr; 1500136944Syongari ch->locked = 1; 1501136944Syongari CS4231_UNLOCK(sc); 1502136944Syongari} 1503136944Syongari 1504136944Syongaristatic void 1505136944Syongarics4231_halt(struct cs4231_channel *ch) 1506136944Syongari{ 1507136944Syongari struct cs4231_softc *sc; 1508136944Syongari u_int8_t status; 1509136944Syongari int i; 1510136944Syongari 1511136944Syongari sc = ch->parent; 1512136944Syongari CS4231_LOCK(sc); 1513136944Syongari if (ch->locked == 0) { 1514136944Syongari CS4231_UNLOCK(sc); 1515136944Syongari return; 1516136944Syongari } 1517136944Syongari 1518136944Syongari if (ch->dir == PCMDIR_PLAY ) { 1519136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 1520136944Syongari /* XXX Kills some capture bits */ 1521136944Syongari APC_WRITE(sc, APC_CSR, APC_READ(sc, APC_CSR) & 1522136944Syongari ~(APC_CSR_EI | APC_CSR_GIE | APC_CSR_PIE | 1523136944Syongari APC_CSR_EIE | APC_CSR_PDMA_GO | APC_CSR_PMIE)); 1524136944Syongari } else { 1525136944Syongari EBDMA_P_WRITE(sc, EBDMA_DCSR, 1526136944Syongari EBDMA_P_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN); 1527136944Syongari } 1528136944Syongari /* Waiting for playback FIFO to empty */ 1529136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1530136944Syongari for (i = CS_TIMEOUT; 1531136944Syongari i && (status & PLAYBACK_UNDERRUN) == 0; i--) { 1532136944Syongari DELAY(5); 1533136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1534136944Syongari } 1535136944Syongari if (i == 0) 1536136944Syongari device_printf(sc->sc_dev, "timeout waiting for " 1537136944Syongari "playback FIFO drain\n"); 1538136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1539136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) & (~PLAYBACK_ENABLE)); 1540136944Syongari } else { 1541136944Syongari if ((sc->sc_flags & CS4231_SBUS) != 0) { 1542136944Syongari /* XXX Kills some playback bits */ 1543136944Syongari APC_WRITE(sc, APC_CSR, APC_CSR_CAPTURE_PAUSE); 1544136944Syongari } else { 1545136944Syongari EBDMA_C_WRITE(sc, EBDMA_DCSR, 1546136944Syongari EBDMA_C_READ(sc, EBDMA_DCSR) & ~EBDCSR_DMAEN); 1547136944Syongari } 1548136944Syongari /* Waiting for capture FIFO to empty */ 1549136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1550136944Syongari for (i = CS_TIMEOUT; 1551136944Syongari i && (status & CAPTURE_OVERRUN) == 0; i--) { 1552136944Syongari DELAY(5); 1553136944Syongari status = cs4231_read(sc, CS_TEST_AND_INIT); 1554136944Syongari } 1555136944Syongari if (i == 0) 1556136944Syongari device_printf(sc->sc_dev, "timeout waiting for " 1557136944Syongari "capture FIFO drain\n"); 1558136944Syongari cs4231_write(sc, CS_INTERFACE_CONFIG, 1559136944Syongari cs4231_read(sc, CS_INTERFACE_CONFIG) & (~CAPTURE_ENABLE)); 1560136944Syongari } 1561136944Syongari ch->locked = 0; 1562136944Syongari CS4231_UNLOCK(sc); 1563136944Syongari} 1564