1187692Snwhitehorn/*- 2187692Snwhitehorn * Copyright 2008 by Marco Trillo. All rights reserved. 3187692Snwhitehorn * 4187692Snwhitehorn * Redistribution and use in source and binary forms, with or without 5187692Snwhitehorn * modification, are permitted provided that the following conditions 6187692Snwhitehorn * are met: 7187692Snwhitehorn * 1. Redistributions of source code must retain the above copyright 8187692Snwhitehorn * notice, this list of conditions and the following disclaimer. 9187692Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 10187692Snwhitehorn * notice, this list of conditions and the following disclaimer in the 11187692Snwhitehorn * documentation and/or other materials provided with the distribution. 12187692Snwhitehorn * 13187692Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14187692Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15187692Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16187692Snwhitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17187692Snwhitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18187692Snwhitehorn * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19187692Snwhitehorn * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20187692Snwhitehorn * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21187692Snwhitehorn * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22187692Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23187692Snwhitehorn * SUCH DAMAGE. 24187692Snwhitehorn * 25187692Snwhitehorn * $FreeBSD: releng/11.0/sys/dev/sound/macio/davbus.c 193640 2009-06-07 19:12:08Z ariff $ 26187692Snwhitehorn */ 27187692Snwhitehorn 28187692Snwhitehorn/* 29187692Snwhitehorn * Apple DAVbus audio controller. 30187692Snwhitehorn */ 31187692Snwhitehorn 32187692Snwhitehorn#include <sys/param.h> 33187692Snwhitehorn#include <sys/systm.h> 34187692Snwhitehorn#include <sys/bus.h> 35187692Snwhitehorn#include <sys/kernel.h> 36187692Snwhitehorn#include <sys/lock.h> 37187692Snwhitehorn#include <sys/malloc.h> 38187692Snwhitehorn#include <sys/module.h> 39187692Snwhitehorn#include <sys/mutex.h> 40187692Snwhitehorn#include <sys/rman.h> 41187692Snwhitehorn 42187692Snwhitehorn#include <dev/ofw/ofw_bus.h> 43193640Sariff 44193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 45193640Sariff#include "opt_snd.h" 46193640Sariff#endif 47193640Sariff 48187692Snwhitehorn#include <dev/sound/pcm/sound.h> 49193640Sariff 50187692Snwhitehorn#include <dev/sound/macio/aoa.h> 51187692Snwhitehorn#include <dev/sound/macio/davbusreg.h> 52187692Snwhitehorn 53187692Snwhitehorn#include <machine/intr_machdep.h> 54187692Snwhitehorn#include <machine/resource.h> 55187692Snwhitehorn#include <machine/bus.h> 56187692Snwhitehorn 57187692Snwhitehorn#include "mixer_if.h" 58187692Snwhitehorn 59187692Snwhitehornstruct davbus_softc { 60187692Snwhitehorn struct aoa_softc aoa; 61187692Snwhitehorn phandle_t node; 62187692Snwhitehorn phandle_t soundnode; 63187692Snwhitehorn struct resource *reg; 64187692Snwhitehorn struct mtx mutex; 65187692Snwhitehorn int device_id; 66187692Snwhitehorn u_int output_mask; 67187692Snwhitehorn u_int (*read_status)(struct davbus_softc *, u_int); 68187692Snwhitehorn void (*set_outputs)(struct davbus_softc *, u_int); 69187692Snwhitehorn}; 70187692Snwhitehorn 71187692Snwhitehornstatic int davbus_probe(device_t); 72187692Snwhitehornstatic int davbus_attach(device_t); 73187692Snwhitehornstatic void davbus_cint(void *); 74187692Snwhitehorn 75187692Snwhitehornstatic device_method_t pcm_davbus_methods[] = { 76187692Snwhitehorn /* Device interface. */ 77187692Snwhitehorn DEVMETHOD(device_probe, davbus_probe), 78187692Snwhitehorn DEVMETHOD(device_attach, davbus_attach), 79187692Snwhitehorn 80187692Snwhitehorn { 0, 0 } 81187692Snwhitehorn}; 82187692Snwhitehorn 83187692Snwhitehornstatic driver_t pcm_davbus_driver = { 84187692Snwhitehorn "pcm", 85187692Snwhitehorn pcm_davbus_methods, 86187717Snwhitehorn PCM_SOFTC_SIZE 87187692Snwhitehorn}; 88187692Snwhitehorn 89187692SnwhitehornDRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0); 90187692SnwhitehornMODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 91187692Snwhitehorn 92187692Snwhitehorn/***************************************************************************** 93187692Snwhitehorn Probe and attachment routines. 94187692Snwhitehorn *****************************************************************************/ 95187692Snwhitehornstatic int 96187692Snwhitehorndavbus_probe(device_t self) 97187692Snwhitehorn{ 98187692Snwhitehorn const char *name; 99187692Snwhitehorn 100187692Snwhitehorn name = ofw_bus_get_name(self); 101187692Snwhitehorn if (!name) 102187692Snwhitehorn return (ENXIO); 103187692Snwhitehorn 104187692Snwhitehorn if (strcmp(name, "davbus") != 0) 105187692Snwhitehorn return (ENXIO); 106187692Snwhitehorn 107187692Snwhitehorn device_set_desc(self, "Apple DAVBus Audio Controller"); 108187692Snwhitehorn 109187692Snwhitehorn return (0); 110187692Snwhitehorn} 111187692Snwhitehorn 112187692Snwhitehorn/* 113187692Snwhitehorn * Burgundy codec control 114187692Snwhitehorn */ 115187692Snwhitehorn 116187692Snwhitehornstatic int burgundy_init(struct snd_mixer *m); 117187692Snwhitehornstatic int burgundy_uninit(struct snd_mixer *m); 118187692Snwhitehornstatic int burgundy_reinit(struct snd_mixer *m); 119187692Snwhitehornstatic void burgundy_write_locked(struct davbus_softc *, u_int, u_int); 120187692Snwhitehornstatic void burgundy_set_outputs(struct davbus_softc *d, u_int mask); 121187692Snwhitehornstatic u_int burgundy_read_status(struct davbus_softc *d, u_int status); 122187692Snwhitehornstatic int burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, 123187692Snwhitehorn unsigned right); 124193640Sariffstatic u_int32_t burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src); 125187692Snwhitehorn 126187692Snwhitehornstatic kobj_method_t burgundy_mixer_methods[] = { 127187692Snwhitehorn KOBJMETHOD(mixer_init, burgundy_init), 128187692Snwhitehorn KOBJMETHOD(mixer_uninit, burgundy_uninit), 129187692Snwhitehorn KOBJMETHOD(mixer_reinit, burgundy_reinit), 130187692Snwhitehorn KOBJMETHOD(mixer_set, burgundy_set), 131187692Snwhitehorn KOBJMETHOD(mixer_setrecsrc, burgundy_setrecsrc), 132193640Sariff KOBJMETHOD_END 133187692Snwhitehorn}; 134187692Snwhitehorn 135187692SnwhitehornMIXER_DECLARE(burgundy_mixer); 136187692Snwhitehorn 137187692Snwhitehornstatic int 138187692Snwhitehornburgundy_init(struct snd_mixer *m) 139187692Snwhitehorn{ 140187692Snwhitehorn struct davbus_softc *d; 141187692Snwhitehorn 142187692Snwhitehorn d = mix_getdevinfo(m); 143187692Snwhitehorn 144187692Snwhitehorn d->read_status = burgundy_read_status; 145187692Snwhitehorn d->set_outputs = burgundy_set_outputs; 146187692Snwhitehorn 147187692Snwhitehorn /* 148187692Snwhitehorn * We configure the Burgundy codec as follows: 149187692Snwhitehorn * 150187692Snwhitehorn * o Input subframe 0 is connected to input digital 151187692Snwhitehorn * stream A (ISA). 152187692Snwhitehorn * o Stream A (ISA) is mixed in mixer 2 (MIX2). 153187692Snwhitehorn * o Output of mixer 2 (MIX2) is routed to output sources 154187692Snwhitehorn * OS0 and OS1 which can be converted to analog. 155187692Snwhitehorn * 156187692Snwhitehorn */ 157187692Snwhitehorn mtx_lock(&d->mutex); 158187692Snwhitehorn 159187692Snwhitehorn burgundy_write_locked(d, 0x16700, 0x40); 160187692Snwhitehorn 161187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0); 162187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0); 163187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA); 164187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0); 165187692Snwhitehorn 166187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 | 167187692Snwhitehorn BURGUNDY_OS1_MIX2); 168187692Snwhitehorn 169187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0); 170187692Snwhitehorn 171187692Snwhitehorn /* Set several digital scalers to unity gain. */ 172187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY); 173187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY); 174187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY); 175187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY); 176187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY); 177187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY); 178187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY); 179187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY); 180187692Snwhitehorn 181187692Snwhitehorn burgundy_set_outputs(d, burgundy_read_status(d, 182187692Snwhitehorn bus_read_4(d->reg, DAVBUS_CODEC_STATUS))); 183187692Snwhitehorn 184187692Snwhitehorn mtx_unlock(&d->mutex); 185187692Snwhitehorn 186187692Snwhitehorn mix_setdevs(m, SOUND_MASK_VOLUME); 187187692Snwhitehorn 188187692Snwhitehorn return (0); 189187692Snwhitehorn} 190187692Snwhitehorn 191187692Snwhitehornstatic int 192187692Snwhitehornburgundy_uninit(struct snd_mixer *m) 193187692Snwhitehorn{ 194187692Snwhitehorn return (0); 195187692Snwhitehorn} 196187692Snwhitehorn 197187692Snwhitehornstatic int 198187692Snwhitehornburgundy_reinit(struct snd_mixer *m) 199187692Snwhitehorn{ 200187692Snwhitehorn return (0); 201187692Snwhitehorn} 202187692Snwhitehorn 203187692Snwhitehornstatic void 204187692Snwhitehornburgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val) 205187692Snwhitehorn{ 206187692Snwhitehorn u_int size, addr, offset, data, i; 207187692Snwhitehorn 208187692Snwhitehorn size = (reg & 0x00FF0000) >> 16; 209187692Snwhitehorn addr = (reg & 0x0000FF00) >> 8; 210187692Snwhitehorn offset = reg & 0xFF; 211187692Snwhitehorn 212187692Snwhitehorn for (i = offset; i < offset + size; ++i) { 213187692Snwhitehorn data = BURGUNDY_CTRL_WRITE | (addr << 12) | 214187692Snwhitehorn ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF); 215187692Snwhitehorn if (i == offset) 216187692Snwhitehorn data |= BURGUNDY_CTRL_RESET; 217187692Snwhitehorn 218187692Snwhitehorn bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data); 219187692Snwhitehorn 220187692Snwhitehorn while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & 221187692Snwhitehorn DAVBUS_CODEC_BUSY) 222187692Snwhitehorn DELAY(1); 223187692Snwhitehorn 224187692Snwhitehorn val >>= 8; /* next byte. */ 225187692Snwhitehorn } 226187692Snwhitehorn} 227187692Snwhitehorn 228187692Snwhitehorn/* Must be called with d->mutex held. */ 229187692Snwhitehornstatic void 230187692Snwhitehornburgundy_set_outputs(struct davbus_softc *d, u_int mask) 231187692Snwhitehorn{ 232187692Snwhitehorn u_int x = 0; 233187692Snwhitehorn 234187692Snwhitehorn if (mask == d->output_mask) 235187692Snwhitehorn return; 236187692Snwhitehorn 237187692Snwhitehorn /* 238187692Snwhitehorn * Bordeaux card wirings: 239187692Snwhitehorn * Port 15: RCA out 240187692Snwhitehorn * Port 16: Minijack out 241187692Snwhitehorn * Port 17: Internal speaker 242187692Snwhitehorn * 243187692Snwhitehorn * B&W G3 wirings: 244187692Snwhitehorn * Port 14: Minijack out 245187692Snwhitehorn * Port 17: Internal speaker 246187692Snwhitehorn */ 247187692Snwhitehorn 248187692Snwhitehorn DPRINTF(("Enabled outputs:")); 249187692Snwhitehorn if (mask & (1 << 0)) { 250187692Snwhitehorn DPRINTF((" SPEAKER")); 251187692Snwhitehorn x |= BURGUNDY_P17M_EN; 252187692Snwhitehorn } 253187692Snwhitehorn if (mask & (1 << 1)) { 254187692Snwhitehorn DPRINTF((" HEADPHONES")); 255187692Snwhitehorn x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN; 256187692Snwhitehorn } 257187692Snwhitehorn DPRINTF(("\n")); 258187692Snwhitehorn 259187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_MUTE_REG, x); 260187692Snwhitehorn d->output_mask = mask; 261187692Snwhitehorn} 262187692Snwhitehorn 263187692Snwhitehornstatic u_int 264187692Snwhitehornburgundy_read_status(struct davbus_softc *d, u_int status) 265187692Snwhitehorn{ 266187692Snwhitehorn if (status & 0x4) 267187692Snwhitehorn return (1 << 1); 268187692Snwhitehorn else 269187692Snwhitehorn return (1 << 0); 270187692Snwhitehorn} 271187692Snwhitehorn 272187692Snwhitehornstatic int 273187692Snwhitehornburgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 274187692Snwhitehorn{ 275187692Snwhitehorn struct davbus_softc *d; 276187692Snwhitehorn int lval, rval; 277187692Snwhitehorn 278187692Snwhitehorn lval = ((100 - left) * 15 / 100) & 0xf; 279187692Snwhitehorn rval = ((100 - right) * 15 / 100) & 0xf; 280187692Snwhitehorn DPRINTF(("volume %d %d\n", lval, rval)); 281187692Snwhitehorn 282187692Snwhitehorn d = mix_getdevinfo(m); 283187692Snwhitehorn 284187692Snwhitehorn switch (dev) { 285187692Snwhitehorn case SOUND_MIXER_VOLUME: 286187692Snwhitehorn mtx_lock(&d->mutex); 287187692Snwhitehorn 288187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OL13_REG, lval); 289187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval); 290187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval); 291187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval); 292187692Snwhitehorn burgundy_write_locked(d, BURGUNDY_OL17_REG, lval); 293187692Snwhitehorn 294187692Snwhitehorn mtx_unlock(&d->mutex); 295187692Snwhitehorn 296187692Snwhitehorn return (left | (right << 8)); 297187692Snwhitehorn } 298187692Snwhitehorn 299187692Snwhitehorn return (0); 300187692Snwhitehorn} 301187692Snwhitehorn 302193640Sariffstatic u_int32_t 303187692Snwhitehornburgundy_setrecsrc(struct snd_mixer *m, u_int32_t src) 304187692Snwhitehorn{ 305187692Snwhitehorn return (0); 306187692Snwhitehorn} 307187692Snwhitehorn 308187692Snwhitehorn/* 309187692Snwhitehorn * Screamer Codec Control 310187692Snwhitehorn */ 311187692Snwhitehorn 312187692Snwhitehornstatic int screamer_init(struct snd_mixer *m); 313187692Snwhitehornstatic int screamer_uninit(struct snd_mixer *m); 314187692Snwhitehornstatic int screamer_reinit(struct snd_mixer *m); 315187692Snwhitehornstatic void screamer_write_locked(struct davbus_softc *, u_int, u_int); 316187692Snwhitehornstatic void screamer_set_outputs(struct davbus_softc *d, u_int mask); 317187692Snwhitehornstatic u_int screamer_read_status(struct davbus_softc *d, u_int status); 318187692Snwhitehornstatic int screamer_set(struct snd_mixer *m, unsigned dev, unsigned left, 319187692Snwhitehorn unsigned right); 320193640Sariffstatic u_int32_t screamer_setrecsrc(struct snd_mixer *m, u_int32_t src); 321187692Snwhitehorn 322187692Snwhitehornstatic kobj_method_t screamer_mixer_methods[] = { 323187692Snwhitehorn KOBJMETHOD(mixer_init, screamer_init), 324187692Snwhitehorn KOBJMETHOD(mixer_uninit, screamer_uninit), 325187692Snwhitehorn KOBJMETHOD(mixer_reinit, screamer_reinit), 326187692Snwhitehorn KOBJMETHOD(mixer_set, screamer_set), 327187692Snwhitehorn KOBJMETHOD(mixer_setrecsrc, screamer_setrecsrc), 328193640Sariff KOBJMETHOD_END 329187692Snwhitehorn}; 330187692Snwhitehorn 331187692SnwhitehornMIXER_DECLARE(screamer_mixer); 332187692Snwhitehorn 333187692Snwhitehornstatic int 334187692Snwhitehornscreamer_init(struct snd_mixer *m) 335187692Snwhitehorn{ 336187692Snwhitehorn struct davbus_softc *d; 337187692Snwhitehorn 338187692Snwhitehorn d = mix_getdevinfo(m); 339187692Snwhitehorn 340187692Snwhitehorn d->read_status = screamer_read_status; 341187692Snwhitehorn d->set_outputs = screamer_set_outputs; 342187692Snwhitehorn 343187692Snwhitehorn mtx_lock(&d->mutex); 344187692Snwhitehorn 345187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD | 346187692Snwhitehorn SCREAMER_DEFAULT_CD_GAIN); 347187692Snwhitehorn 348187692Snwhitehorn screamer_set_outputs(d, screamer_read_status(d, 349187692Snwhitehorn bus_read_4(d->reg, DAVBUS_CODEC_STATUS))); 350187692Snwhitehorn 351187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0); 352187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0); 353187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0); 354187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0); 355187692Snwhitehorn 356187692Snwhitehorn mtx_unlock(&d->mutex); 357187692Snwhitehorn 358187692Snwhitehorn mix_setdevs(m, SOUND_MASK_VOLUME); 359187692Snwhitehorn 360187692Snwhitehorn return (0); 361187692Snwhitehorn} 362187692Snwhitehorn 363187692Snwhitehornstatic int 364187692Snwhitehornscreamer_uninit(struct snd_mixer *m) 365187692Snwhitehorn{ 366187692Snwhitehorn return (0); 367187692Snwhitehorn} 368187692Snwhitehorn 369187692Snwhitehornstatic int 370187692Snwhitehornscreamer_reinit(struct snd_mixer *m) 371187692Snwhitehorn{ 372187692Snwhitehorn return (0); 373187692Snwhitehorn} 374187692Snwhitehorn 375187692Snwhitehorn 376187692Snwhitehornstatic void 377187692Snwhitehornscreamer_write_locked(struct davbus_softc *d, u_int reg, u_int val) 378187692Snwhitehorn{ 379187692Snwhitehorn u_int x; 380187692Snwhitehorn 381187692Snwhitehorn KASSERT(val == (val & 0xfff), ("bad val")); 382187692Snwhitehorn 383187692Snwhitehorn while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY) 384187692Snwhitehorn DELAY(100); 385187692Snwhitehorn 386187692Snwhitehorn x = reg; 387187692Snwhitehorn x |= SCREAMER_CODEC_EMSEL0; 388187692Snwhitehorn x |= val; 389187692Snwhitehorn bus_write_4(d->reg, DAVBUS_CODEC_CTRL, x); 390187692Snwhitehorn 391187692Snwhitehorn while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY) 392187692Snwhitehorn DELAY(100); 393187692Snwhitehorn} 394187692Snwhitehorn 395187692Snwhitehorn/* Must be called with d->mutex held. */ 396187692Snwhitehornstatic void 397187692Snwhitehornscreamer_set_outputs(struct davbus_softc *d, u_int mask) 398187692Snwhitehorn{ 399187692Snwhitehorn u_int x; 400187692Snwhitehorn 401187692Snwhitehorn if (mask == d->output_mask) { 402187692Snwhitehorn return; 403187692Snwhitehorn } 404187692Snwhitehorn 405187692Snwhitehorn x = SCREAMER_MUTE_SPEAKER | SCREAMER_MUTE_HEADPHONES; 406187692Snwhitehorn 407187692Snwhitehorn DPRINTF(("Enabled outputs: ")); 408187692Snwhitehorn 409187692Snwhitehorn if (mask & (1 << 0)) { 410187692Snwhitehorn DPRINTF(("SPEAKER ")); 411187692Snwhitehorn x &= ~SCREAMER_MUTE_SPEAKER; 412187692Snwhitehorn } 413187692Snwhitehorn if (mask & (1 << 1)) { 414187692Snwhitehorn DPRINTF(("HEADPHONES ")); 415187692Snwhitehorn x &= ~SCREAMER_MUTE_HEADPHONES; 416187692Snwhitehorn } 417187692Snwhitehorn 418187692Snwhitehorn DPRINTF(("\n")); 419187692Snwhitehorn 420187692Snwhitehorn if (d->device_id == 5 || d->device_id == 11) { 421187692Snwhitehorn DPRINTF(("Enabling programmable output.\n")); 422187692Snwhitehorn x |= SCREAMER_PROG_OUTPUT0; 423187692Snwhitehorn } 424187692Snwhitehorn if (d->device_id == 8 || d->device_id == 11) { 425187692Snwhitehorn x &= ~SCREAMER_MUTE_SPEAKER; 426187692Snwhitehorn 427187692Snwhitehorn if (mask & (1 << 0)) 428187692Snwhitehorn x |= SCREAMER_PROG_OUTPUT1; /* enable speaker. */ 429187692Snwhitehorn } 430187692Snwhitehorn 431187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR1, x); 432187692Snwhitehorn d->output_mask = mask; 433187692Snwhitehorn} 434187692Snwhitehorn 435187692Snwhitehornstatic u_int 436187692Snwhitehornscreamer_read_status(struct davbus_softc *d, u_int status) 437187692Snwhitehorn{ 438187692Snwhitehorn int headphones; 439187692Snwhitehorn 440187692Snwhitehorn switch (d->device_id) { 441187692Snwhitehorn case 5: /* Sawtooth */ 442187692Snwhitehorn headphones = (status & 0x4); 443187692Snwhitehorn break; 444187692Snwhitehorn 445187692Snwhitehorn case 8: 446187692Snwhitehorn case 11: /* iMac DV */ 447187692Snwhitehorn /* The iMac DV has 2 headphone outputs. */ 448187692Snwhitehorn headphones = (status & 0x7); 449187692Snwhitehorn break; 450187692Snwhitehorn 451187692Snwhitehorn default: 452187692Snwhitehorn headphones = (status & 0x8); 453187692Snwhitehorn } 454187692Snwhitehorn 455187692Snwhitehorn if (headphones) 456187692Snwhitehorn return (1 << 1); 457187692Snwhitehorn else 458187692Snwhitehorn return (1 << 0); 459187692Snwhitehorn} 460187692Snwhitehorn 461187692Snwhitehornstatic int 462187692Snwhitehornscreamer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 463187692Snwhitehorn{ 464187692Snwhitehorn struct davbus_softc *d; 465187692Snwhitehorn int lval, rval; 466187692Snwhitehorn 467187692Snwhitehorn lval = ((100 - left) * 15 / 100) & 0xf; 468187692Snwhitehorn rval = ((100 - right) * 15 / 100) & 0xf; 469187692Snwhitehorn DPRINTF(("volume %d %d\n", lval, rval)); 470187692Snwhitehorn 471187692Snwhitehorn d = mix_getdevinfo(m); 472187692Snwhitehorn 473187692Snwhitehorn switch (dev) { 474187692Snwhitehorn case SOUND_MIXER_VOLUME: 475187692Snwhitehorn mtx_lock(&d->mutex); 476187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR2, (lval << 6) | 477187692Snwhitehorn rval); 478187692Snwhitehorn screamer_write_locked(d, SCREAMER_CODEC_ADDR4, (lval << 6) | 479187692Snwhitehorn rval); 480187692Snwhitehorn mtx_unlock(&d->mutex); 481187692Snwhitehorn 482187692Snwhitehorn return (left | (right << 8)); 483187692Snwhitehorn } 484187692Snwhitehorn 485187692Snwhitehorn return (0); 486187692Snwhitehorn} 487187692Snwhitehorn 488193640Sariffstatic u_int32_t 489187692Snwhitehornscreamer_setrecsrc(struct snd_mixer *m, u_int32_t src) 490187692Snwhitehorn{ 491187692Snwhitehorn return (0); 492187692Snwhitehorn} 493187692Snwhitehorn 494187692Snwhitehornstatic int 495187692Snwhitehorndavbus_attach(device_t self) 496187692Snwhitehorn{ 497187717Snwhitehorn struct davbus_softc *sc; 498187692Snwhitehorn struct resource *dbdma_irq, *cintr; 499187692Snwhitehorn void *cookie; 500187692Snwhitehorn char compat[64]; 501187692Snwhitehorn int rid, oirq, err; 502187692Snwhitehorn 503187717Snwhitehorn sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 504187717Snwhitehorn 505188259Snwhitehorn sc->aoa.sc_dev = self; 506187692Snwhitehorn sc->node = ofw_bus_get_node(self); 507187692Snwhitehorn sc->soundnode = OF_child(sc->node); 508187692Snwhitehorn 509187692Snwhitehorn /* Map the controller register space. */ 510187692Snwhitehorn rid = 0; 511187692Snwhitehorn sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); 512187692Snwhitehorn if (sc->reg == NULL) 513187692Snwhitehorn return (ENXIO); 514187692Snwhitehorn 515187692Snwhitehorn /* Map the DBDMA channel register space. */ 516187692Snwhitehorn rid = 1; 517187692Snwhitehorn sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY, 518187692Snwhitehorn &rid, RF_ACTIVE); 519187692Snwhitehorn if (sc->aoa.sc_odma == NULL) 520187692Snwhitehorn return (ENXIO); 521187692Snwhitehorn 522187692Snwhitehorn /* Establish the DBDMA channel edge-triggered interrupt. */ 523187692Snwhitehorn rid = 1; 524187692Snwhitehorn dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, 525187692Snwhitehorn &rid, RF_SHAREABLE | RF_ACTIVE); 526187692Snwhitehorn if (dbdma_irq == NULL) 527187692Snwhitehorn return (ENXIO); 528187692Snwhitehorn 529187692Snwhitehorn oirq = rman_get_start(dbdma_irq); 530187692Snwhitehorn 531187692Snwhitehorn DPRINTF(("interrupting at irq %d\n", oirq)); 532187692Snwhitehorn 533187692Snwhitehorn err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); 534187692Snwhitehorn if (err != 0) 535187692Snwhitehorn return (err); 536187692Snwhitehorn 537188259Snwhitehorn snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt, 538188259Snwhitehorn sc, &cookie); 539187692Snwhitehorn 540187692Snwhitehorn /* Now initialize the controller. */ 541187692Snwhitehorn 542187692Snwhitehorn bzero(compat, sizeof(compat)); 543187692Snwhitehorn OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat)); 544187692Snwhitehorn OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int)); 545187692Snwhitehorn 546187692Snwhitehorn mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF); 547187692Snwhitehorn 548187692Snwhitehorn device_printf(self, "codec: <%s>\n", compat); 549187692Snwhitehorn 550187692Snwhitehorn /* Setup the control interrupt. */ 551187692Snwhitehorn rid = 0; 552187692Snwhitehorn cintr = bus_alloc_resource_any(self, SYS_RES_IRQ, 553187692Snwhitehorn &rid, RF_SHAREABLE | RF_ACTIVE); 554187692Snwhitehorn if (cintr != NULL) 555187692Snwhitehorn bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE, 556187692Snwhitehorn NULL, davbus_cint, sc, &cookie); 557187692Snwhitehorn 558187692Snwhitehorn /* Initialize controller registers. */ 559187692Snwhitehorn bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 | 560187692Snwhitehorn DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG); 561187692Snwhitehorn 562187692Snwhitehorn /* Attach DBDMA engine and PCM layer */ 563188259Snwhitehorn err = aoa_attach(sc); 564187692Snwhitehorn if (err) 565187692Snwhitehorn return (err); 566187692Snwhitehorn 567187692Snwhitehorn /* Install codec module */ 568187692Snwhitehorn if (strcmp(compat, "screamer") == 0) 569187692Snwhitehorn mixer_init(self, &screamer_mixer_class, sc); 570187692Snwhitehorn else if (strcmp(compat, "burgundy") == 0) 571187692Snwhitehorn mixer_init(self, &burgundy_mixer_class, sc); 572187692Snwhitehorn 573187692Snwhitehorn return (0); 574187692Snwhitehorn} 575187692Snwhitehorn 576187692Snwhitehornstatic void 577187692Snwhitehorndavbus_cint(void *ptr) 578187692Snwhitehorn{ 579187692Snwhitehorn struct davbus_softc *d = ptr; 580187692Snwhitehorn u_int reg, status, mask; 581187692Snwhitehorn 582187692Snwhitehorn mtx_lock(&d->mutex); 583187692Snwhitehorn 584187692Snwhitehorn reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL); 585187692Snwhitehorn if (reg & DAVBUS_PORTCHG) { 586187692Snwhitehorn 587187692Snwhitehorn status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS); 588187692Snwhitehorn 589187692Snwhitehorn if (d->read_status && d->set_outputs) { 590187692Snwhitehorn 591187692Snwhitehorn mask = (*d->read_status)(d, status); 592187692Snwhitehorn (*d->set_outputs)(d, mask); 593187692Snwhitehorn } 594187692Snwhitehorn 595187692Snwhitehorn /* Clear the interrupt. */ 596187692Snwhitehorn bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg); 597187692Snwhitehorn } 598187692Snwhitehorn 599187692Snwhitehorn mtx_unlock(&d->mutex); 600187692Snwhitehorn} 601187692Snwhitehorn 602