156746Sroberto/*- 256746Sroberto * Copyright 2008 by Marco Trillo. All rights reserved. 356746Sroberto * 456746Sroberto * Redistribution and use in source and binary forms, with or without 556746Sroberto * modification, are permitted provided that the following conditions 656746Sroberto * are met: 756746Sroberto * 1. Redistributions of source code must retain the above copyright 856746Sroberto * notice, this list of conditions and the following disclaimer. 956746Sroberto * 2. Redistributions in binary form must reproduce the above copyright 1056746Sroberto * notice, this list of conditions and the following disclaimer in the 1156746Sroberto * documentation and/or other materials provided with the distribution. 1256746Sroberto * 1356746Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1456746Sroberto * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1556746Sroberto * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1656746Sroberto * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1782498Sroberto * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 1882498Sroberto * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 1982498Sroberto * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2082498Sroberto * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2182498Sroberto * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2282498Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2382498Sroberto * SUCH DAMAGE. 24132451Sroberto * 2556746Sroberto * $FreeBSD: releng/10.2/sys/dev/sound/macio/davbus.c 193640 2009-06-07 19:12:08Z ariff $ 2656746Sroberto */ 2756746Sroberto 2856746Sroberto/* 2956746Sroberto * Apple DAVbus audio controller. 3056746Sroberto */ 3156746Sroberto 3256746Sroberto#include <sys/param.h> 3356746Sroberto#include <sys/systm.h> 3456746Sroberto#include <sys/bus.h> 35132451Sroberto#include <sys/kernel.h> 36182007Sroberto#include <sys/lock.h> 37182007Sroberto#include <sys/malloc.h> 38182007Sroberto#include <sys/module.h> 39182007Sroberto#include <sys/mutex.h> 40182007Sroberto#include <sys/rman.h> 4156746Sroberto 42285612Sdelphij#include <dev/ofw/ofw_bus.h> 43285612Sdelphij 44285612Sdelphij#ifdef HAVE_KERNEL_OPTION_HEADERS 45285612Sdelphij#include "opt_snd.h" 46285612Sdelphij#endif 47285612Sdelphij 4856746Sroberto#include <dev/sound/pcm/sound.h> 4956746Sroberto 5056746Sroberto#include <dev/sound/macio/aoa.h> 5156746Sroberto#include <dev/sound/macio/davbusreg.h> 5256746Sroberto 53132451Sroberto#include <machine/intr_machdep.h> 54182007Sroberto#include <machine/resource.h> 5556746Sroberto#include <machine/bus.h> 5656746Sroberto 5756746Sroberto#include "mixer_if.h" 5856746Sroberto 5956746Srobertostruct davbus_softc { 6056746Sroberto struct aoa_softc aoa; 6156746Sroberto phandle_t node; 6256746Sroberto phandle_t soundnode; 63182007Sroberto struct resource *reg; 64182007Sroberto struct mtx mutex; 65182007Sroberto int device_id; 66285612Sdelphij u_int output_mask; 67182007Sroberto u_int (*read_status)(struct davbus_softc *, u_int); 68182007Sroberto void (*set_outputs)(struct davbus_softc *, u_int); 69182007Sroberto}; 70182007Sroberto 71182007Srobertostatic int davbus_probe(device_t); 72285612Sdelphijstatic int davbus_attach(device_t); 73285612Sdelphijstatic void davbus_cint(void *); 74285612Sdelphij 75285612Sdelphijstatic device_method_t pcm_davbus_methods[] = { 7656746Sroberto /* Device interface. */ 7756746Sroberto DEVMETHOD(device_probe, davbus_probe), 78182007Sroberto DEVMETHOD(device_attach, davbus_attach), 7956746Sroberto 8082498Sroberto { 0, 0 } 81132451Sroberto}; 8256746Sroberto 8356746Srobertostatic driver_t pcm_davbus_driver = { 84285612Sdelphij "pcm", 85285612Sdelphij pcm_davbus_methods, 8656746Sroberto PCM_SOFTC_SIZE 8756746Sroberto}; 88182007Sroberto 89132451SrobertoDRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, pcm_devclass, 0, 0); 90182007SrobertoMODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 91182007Sroberto 92182007Sroberto/***************************************************************************** 93182007Sroberto Probe and attachment routines. 94182007Sroberto *****************************************************************************/ 95182007Srobertostatic int 96182007Srobertodavbus_probe(device_t self) 97182007Sroberto{ 98132451Sroberto const char *name; 99132451Sroberto 100285612Sdelphij name = ofw_bus_get_name(self); 10156746Sroberto if (!name) 10256746Sroberto return (ENXIO); 103182007Sroberto 104182007Sroberto if (strcmp(name, "davbus") != 0) 105182007Sroberto return (ENXIO); 106182007Sroberto 107182007Sroberto device_set_desc(self, "Apple DAVBus Audio Controller"); 108182007Sroberto 109182007Sroberto return (0); 110182007Sroberto} 111285612Sdelphij 112182007Sroberto/* 113182007Sroberto * Burgundy codec control 114182007Sroberto */ 115182007Sroberto 116182007Srobertostatic int burgundy_init(struct snd_mixer *m); 11756746Srobertostatic int burgundy_uninit(struct snd_mixer *m); 11856746Srobertostatic int burgundy_reinit(struct snd_mixer *m); 119182007Srobertostatic void burgundy_write_locked(struct davbus_softc *, u_int, u_int); 120132451Srobertostatic void burgundy_set_outputs(struct davbus_softc *d, u_int mask); 121132451Srobertostatic u_int burgundy_read_status(struct davbus_softc *d, u_int status); 122182007Srobertostatic int burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, 123182007Sroberto unsigned right); 124182007Srobertostatic u_int32_t burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src); 125182007Sroberto 12656746Srobertostatic kobj_method_t burgundy_mixer_methods[] = { 127182007Sroberto KOBJMETHOD(mixer_init, burgundy_init), 128182007Sroberto KOBJMETHOD(mixer_uninit, burgundy_uninit), 129182007Sroberto KOBJMETHOD(mixer_reinit, burgundy_reinit), 130182007Sroberto KOBJMETHOD(mixer_set, burgundy_set), 131182007Sroberto KOBJMETHOD(mixer_setrecsrc, burgundy_setrecsrc), 13256746Sroberto KOBJMETHOD_END 13356746Sroberto}; 13456746Sroberto 13556746SrobertoMIXER_DECLARE(burgundy_mixer); 13656746Sroberto 137132451Srobertostatic int 138182007Srobertoburgundy_init(struct snd_mixer *m) 139182007Sroberto{ 140285612Sdelphij struct davbus_softc *d; 141182007Sroberto 14256746Sroberto d = mix_getdevinfo(m); 14356746Sroberto 144132451Sroberto d->read_status = burgundy_read_status; 14556746Sroberto d->set_outputs = burgundy_set_outputs; 14656746Sroberto 14756746Sroberto /* 14856746Sroberto * We configure the Burgundy codec as follows: 14956746Sroberto * 15056746Sroberto * o Input subframe 0 is connected to input digital 15156746Sroberto * stream A (ISA). 15256746Sroberto * o Stream A (ISA) is mixed in mixer 2 (MIX2). 15356746Sroberto * o Output of mixer 2 (MIX2) is routed to output sources 15456746Sroberto * OS0 and OS1 which can be converted to analog. 15556746Sroberto * 156182007Sroberto */ 15756746Sroberto mtx_lock(&d->mutex); 158285612Sdelphij 159285612Sdelphij burgundy_write_locked(d, 0x16700, 0x40); 160285612Sdelphij 161285612Sdelphij burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0); 16256746Sroberto burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0); 16356746Sroberto burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA); 164132451Sroberto burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0); 16556746Sroberto 16656746Sroberto burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 | 16756746Sroberto BURGUNDY_OS1_MIX2); 16856746Sroberto 16956746Sroberto burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0); 170182007Sroberto 171182007Sroberto /* Set several digital scalers to unity gain. */ 172182007Sroberto burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY); 173132451Sroberto burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY); 17456746Sroberto burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY); 17556746Sroberto burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY); 17656746Sroberto burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY); 17756746Sroberto burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY); 178132451Sroberto burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY); 17956746Sroberto burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY); 18056746Sroberto 181182007Sroberto burgundy_set_outputs(d, burgundy_read_status(d, 182182007Sroberto bus_read_4(d->reg, DAVBUS_CODEC_STATUS))); 183182007Sroberto 184182007Sroberto mtx_unlock(&d->mutex); 185182007Sroberto 186182007Sroberto mix_setdevs(m, SOUND_MASK_VOLUME); 187182007Sroberto 188182007Sroberto return (0); 189182007Sroberto} 190182007Sroberto 191182007Srobertostatic int 192182007Srobertoburgundy_uninit(struct snd_mixer *m) 193132451Sroberto{ 194132451Sroberto return (0); 195182007Sroberto} 196132451Sroberto 197182007Srobertostatic int 198182007Srobertoburgundy_reinit(struct snd_mixer *m) 19956746Sroberto{ 20056746Sroberto return (0); 201132451Sroberto} 202132451Sroberto 20356746Srobertostatic void 204285612Sdelphijburgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val) 205285612Sdelphij{ 206285612Sdelphij u_int size, addr, offset, data, i; 207285612Sdelphij 20856746Sroberto size = (reg & 0x00FF0000) >> 16; 20956746Sroberto addr = (reg & 0x0000FF00) >> 8; 210182007Sroberto offset = reg & 0xFF; 21156746Sroberto 212182007Sroberto for (i = offset; i < offset + size; ++i) { 213182007Sroberto data = BURGUNDY_CTRL_WRITE | (addr << 12) | 214182007Sroberto ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF); 215132451Sroberto if (i == offset) 21656746Sroberto data |= BURGUNDY_CTRL_RESET; 21756746Sroberto 21856746Sroberto bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data); 21956746Sroberto 22056746Sroberto while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & 22156746Sroberto DAVBUS_CODEC_BUSY) 22256746Sroberto DELAY(1); 22356746Sroberto 22456746Sroberto val >>= 8; /* next byte. */ 22556746Sroberto } 22656746Sroberto} 22756746Sroberto 228132451Sroberto/* Must be called with d->mutex held. */ 229132451Srobertostatic void 23056746Srobertoburgundy_set_outputs(struct davbus_softc *d, u_int mask) 23156746Sroberto{ 23256746Sroberto u_int x = 0; 233285612Sdelphij 234285612Sdelphij if (mask == d->output_mask) 235285612Sdelphij return; 236285612Sdelphij 237285612Sdelphij /* 238285612Sdelphij * Bordeaux card wirings: 239285612Sdelphij * Port 15: RCA out 240285612Sdelphij * Port 16: Minijack out 241285612Sdelphij * Port 17: Internal speaker 242285612Sdelphij * 243285612Sdelphij * B&W G3 wirings: 244285612Sdelphij * Port 14: Minijack out 245285612Sdelphij * Port 17: Internal speaker 24656746Sroberto */ 247285612Sdelphij 24856746Sroberto DPRINTF(("Enabled outputs:")); 24956746Sroberto if (mask & (1 << 0)) { 25056746Sroberto DPRINTF((" SPEAKER")); 251182007Sroberto x |= BURGUNDY_P17M_EN; 25256746Sroberto } 25356746Sroberto if (mask & (1 << 1)) { 254182007Sroberto DPRINTF((" HEADPHONES")); 255182007Sroberto x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN; 256182007Sroberto } 257182007Sroberto DPRINTF(("\n")); 258182007Sroberto 259182007Sroberto burgundy_write_locked(d, BURGUNDY_MUTE_REG, x); 260182007Sroberto d->output_mask = mask; 261182007Sroberto} 262182007Sroberto 263182007Srobertostatic u_int 264182007Srobertoburgundy_read_status(struct davbus_softc *d, u_int status) 265182007Sroberto{ 266182007Sroberto if (status & 0x4) 267182007Sroberto return (1 << 1); 268182007Sroberto else 269182007Sroberto return (1 << 0); 270182007Sroberto} 271182007Sroberto 272182007Srobertostatic int 273182007Srobertoburgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 27456746Sroberto{ 27556746Sroberto struct davbus_softc *d; 27656746Sroberto int lval, rval; 27756746Sroberto 27856746Sroberto lval = ((100 - left) * 15 / 100) & 0xf; 27956746Sroberto rval = ((100 - right) * 15 / 100) & 0xf; 28056746Sroberto DPRINTF(("volume %d %d\n", lval, rval)); 28156746Sroberto 28256746Sroberto d = mix_getdevinfo(m); 28356746Sroberto 28456746Sroberto switch (dev) { 28556746Sroberto case SOUND_MIXER_VOLUME: 28656746Sroberto mtx_lock(&d->mutex); 28756746Sroberto 28856746Sroberto burgundy_write_locked(d, BURGUNDY_OL13_REG, lval); 28956746Sroberto burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval); 29056746Sroberto burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval); 291132451Sroberto burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval); 292182007Sroberto burgundy_write_locked(d, BURGUNDY_OL17_REG, lval); 293182007Sroberto 294182007Sroberto mtx_unlock(&d->mutex); 295182007Sroberto 296182007Sroberto return (left | (right << 8)); 297182007Sroberto } 298182007Sroberto 299182007Sroberto return (0); 300182007Sroberto} 301182007Sroberto 302182007Srobertostatic u_int32_t 303182007Srobertoburgundy_setrecsrc(struct snd_mixer *m, u_int32_t src) 304182007Sroberto{ 30556746Sroberto return (0); 30656746Sroberto} 30756746Sroberto 30856746Sroberto/* 30956746Sroberto * Screamer Codec Control 31056746Sroberto */ 31156746Sroberto 31256746Srobertostatic int screamer_init(struct snd_mixer *m); 31356746Srobertostatic int screamer_uninit(struct snd_mixer *m); 31456746Srobertostatic int screamer_reinit(struct snd_mixer *m); 315182007Srobertostatic void screamer_write_locked(struct davbus_softc *, u_int, u_int); 316182007Srobertostatic void screamer_set_outputs(struct davbus_softc *d, u_int mask); 31756746Srobertostatic u_int screamer_read_status(struct davbus_softc *d, u_int status); 31856746Srobertostatic int screamer_set(struct snd_mixer *m, unsigned dev, unsigned left, 31956746Sroberto unsigned right); 32056746Srobertostatic u_int32_t screamer_setrecsrc(struct snd_mixer *m, u_int32_t src); 32156746Sroberto 32256746Srobertostatic kobj_method_t screamer_mixer_methods[] = { 32356746Sroberto KOBJMETHOD(mixer_init, screamer_init), 32456746Sroberto KOBJMETHOD(mixer_uninit, screamer_uninit), 325182007Sroberto KOBJMETHOD(mixer_reinit, screamer_reinit), 326182007Sroberto KOBJMETHOD(mixer_set, screamer_set), 327182007Sroberto KOBJMETHOD(mixer_setrecsrc, screamer_setrecsrc), 328182007Sroberto KOBJMETHOD_END 32956746Sroberto}; 33056746Sroberto 33156746SrobertoMIXER_DECLARE(screamer_mixer); 33256746Sroberto 33356746Srobertostatic int 33456746Srobertoscreamer_init(struct snd_mixer *m) 33556746Sroberto{ 33656746Sroberto struct davbus_softc *d; 33756746Sroberto 33856746Sroberto d = mix_getdevinfo(m); 33956746Sroberto 34056746Sroberto d->read_status = screamer_read_status; 34156746Sroberto d->set_outputs = screamer_set_outputs; 34256746Sroberto 34356746Sroberto mtx_lock(&d->mutex); 34456746Sroberto 34556746Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD | 34656746Sroberto SCREAMER_DEFAULT_CD_GAIN); 34756746Sroberto 34856746Sroberto screamer_set_outputs(d, screamer_read_status(d, 34956746Sroberto bus_read_4(d->reg, DAVBUS_CODEC_STATUS))); 35056746Sroberto 35156746Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0); 35256746Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0); 35356746Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0); 35456746Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0); 35556746Sroberto 35656746Sroberto mtx_unlock(&d->mutex); 35756746Sroberto 35856746Sroberto mix_setdevs(m, SOUND_MASK_VOLUME); 35956746Sroberto 36056746Sroberto return (0); 36156746Sroberto} 36256746Sroberto 36356746Srobertostatic int 36456746Srobertoscreamer_uninit(struct snd_mixer *m) 36556746Sroberto{ 36656746Sroberto return (0); 36756746Sroberto} 36856746Sroberto 36956746Srobertostatic int 37056746Srobertoscreamer_reinit(struct snd_mixer *m) 37156746Sroberto{ 37256746Sroberto return (0); 37356746Sroberto} 374182007Sroberto 37556746Sroberto 37656746Srobertostatic void 37756746Srobertoscreamer_write_locked(struct davbus_softc *d, u_int reg, u_int val) 37856746Sroberto{ 379285612Sdelphij u_int x; 38056746Sroberto 38156746Sroberto KASSERT(val == (val & 0xfff), ("bad val")); 38256746Sroberto 38356746Sroberto while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY) 38456746Sroberto DELAY(100); 38556746Sroberto 38656746Sroberto x = reg; 38756746Sroberto x |= SCREAMER_CODEC_EMSEL0; 38856746Sroberto x |= val; 38956746Sroberto bus_write_4(d->reg, DAVBUS_CODEC_CTRL, x); 39056746Sroberto 39156746Sroberto while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY) 39256746Sroberto DELAY(100); 39356746Sroberto} 39456746Sroberto 39556746Sroberto/* Must be called with d->mutex held. */ 39656746Srobertostatic void 39756746Srobertoscreamer_set_outputs(struct davbus_softc *d, u_int mask) 39856746Sroberto{ 39956746Sroberto u_int x; 40056746Sroberto 40156746Sroberto if (mask == d->output_mask) { 40256746Sroberto return; 40356746Sroberto } 40456746Sroberto 40556746Sroberto x = SCREAMER_MUTE_SPEAKER | SCREAMER_MUTE_HEADPHONES; 40656746Sroberto 40756746Sroberto DPRINTF(("Enabled outputs: ")); 40856746Sroberto 40956746Sroberto if (mask & (1 << 0)) { 41056746Sroberto DPRINTF(("SPEAKER ")); 41156746Sroberto x &= ~SCREAMER_MUTE_SPEAKER; 41256746Sroberto } 41356746Sroberto if (mask & (1 << 1)) { 41456746Sroberto DPRINTF(("HEADPHONES ")); 41556746Sroberto x &= ~SCREAMER_MUTE_HEADPHONES; 41656746Sroberto } 41756746Sroberto 41856746Sroberto DPRINTF(("\n")); 41956746Sroberto 42056746Sroberto if (d->device_id == 5 || d->device_id == 11) { 42156746Sroberto DPRINTF(("Enabling programmable output.\n")); 42256746Sroberto x |= SCREAMER_PROG_OUTPUT0; 42356746Sroberto } 42456746Sroberto if (d->device_id == 8 || d->device_id == 11) { 42556746Sroberto x &= ~SCREAMER_MUTE_SPEAKER; 42656746Sroberto 42756746Sroberto if (mask & (1 << 0)) 42856746Sroberto x |= SCREAMER_PROG_OUTPUT1; /* enable speaker. */ 42956746Sroberto } 43056746Sroberto 43156746Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR1, x); 43256746Sroberto d->output_mask = mask; 43356746Sroberto} 43456746Sroberto 43556746Srobertostatic u_int 43656746Srobertoscreamer_read_status(struct davbus_softc *d, u_int status) 43756746Sroberto{ 43856746Sroberto int headphones; 43956746Sroberto 44056746Sroberto switch (d->device_id) { 44156746Sroberto case 5: /* Sawtooth */ 44256746Sroberto headphones = (status & 0x4); 44356746Sroberto break; 44456746Sroberto 44556746Sroberto case 8: 44656746Sroberto case 11: /* iMac DV */ 44756746Sroberto /* The iMac DV has 2 headphone outputs. */ 44856746Sroberto headphones = (status & 0x7); 44956746Sroberto break; 45056746Sroberto 45156746Sroberto default: 45256746Sroberto headphones = (status & 0x8); 453132451Sroberto } 454132451Sroberto 45556746Sroberto if (headphones) 45656746Sroberto return (1 << 1); 45756746Sroberto else 45856746Sroberto return (1 << 0); 45956746Sroberto} 46056746Sroberto 461285612Sdelphijstatic int 462285612Sdelphijscreamer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 46356746Sroberto{ 46456746Sroberto struct davbus_softc *d; 46556746Sroberto int lval, rval; 46656746Sroberto 46756746Sroberto lval = ((100 - left) * 15 / 100) & 0xf; 46856746Sroberto rval = ((100 - right) * 15 / 100) & 0xf; 46956746Sroberto DPRINTF(("volume %d %d\n", lval, rval)); 47056746Sroberto 47156746Sroberto d = mix_getdevinfo(m); 47256746Sroberto 47356746Sroberto switch (dev) { 47456746Sroberto case SOUND_MIXER_VOLUME: 475182007Sroberto mtx_lock(&d->mutex); 476182007Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR2, (lval << 6) | 477182007Sroberto rval); 478182007Sroberto screamer_write_locked(d, SCREAMER_CODEC_ADDR4, (lval << 6) | 47956746Sroberto rval); 48056746Sroberto mtx_unlock(&d->mutex); 481132451Sroberto 482182007Sroberto return (left | (right << 8)); 483182007Sroberto } 484132451Sroberto 485132451Sroberto return (0); 486132451Sroberto} 487132451Sroberto 488182007Srobertostatic u_int32_t 489182007Srobertoscreamer_setrecsrc(struct snd_mixer *m, u_int32_t src) 490182007Sroberto{ 49156746Sroberto return (0); 492182007Sroberto} 493182007Sroberto 494132451Srobertostatic int 495182007Srobertodavbus_attach(device_t self) 49656746Sroberto{ 49756746Sroberto struct davbus_softc *sc; 49856746Sroberto struct resource *dbdma_irq, *cintr; 49956746Sroberto void *cookie; 500182007Sroberto char compat[64]; 50156746Sroberto int rid, oirq, err; 50256746Sroberto 50356746Sroberto sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 50456746Sroberto 50556746Sroberto sc->aoa.sc_dev = self; 50656746Sroberto sc->node = ofw_bus_get_node(self); 50756746Sroberto sc->soundnode = OF_child(sc->node); 50856746Sroberto 509182007Sroberto /* Map the controller register space. */ 51056746Sroberto rid = 0; 51156746Sroberto sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); 51256746Sroberto if (sc->reg == NULL) 51356746Sroberto return (ENXIO); 51456746Sroberto 51556746Sroberto /* Map the DBDMA channel register space. */ 516285612Sdelphij rid = 1; 517182007Sroberto sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY, 51856746Sroberto &rid, RF_ACTIVE); 519182007Sroberto if (sc->aoa.sc_odma == NULL) 52056746Sroberto return (ENXIO); 521132451Sroberto 522132451Sroberto /* Establish the DBDMA channel edge-triggered interrupt. */ 523132451Sroberto rid = 1; 524132451Sroberto dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, 525132451Sroberto &rid, RF_SHAREABLE | RF_ACTIVE); 526132451Sroberto if (dbdma_irq == NULL) 527285612Sdelphij return (ENXIO); 52856746Sroberto 529132451Sroberto oirq = rman_get_start(dbdma_irq); 53056746Sroberto 53156746Sroberto DPRINTF(("interrupting at irq %d\n", oirq)); 53256746Sroberto 53356746Sroberto err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); 53456746Sroberto if (err != 0) 535132451Sroberto return (err); 536132451Sroberto 537132451Sroberto snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt, 53856746Sroberto sc, &cookie); 539132451Sroberto 54056746Sroberto /* Now initialize the controller. */ 54156746Sroberto 54256746Sroberto bzero(compat, sizeof(compat)); 54356746Sroberto OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat)); 544132451Sroberto OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int)); 54556746Sroberto 54656746Sroberto mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF); 54756746Sroberto 54856746Sroberto device_printf(self, "codec: <%s>\n", compat); 54956746Sroberto 55056746Sroberto /* Setup the control interrupt. */ 55156746Sroberto rid = 0; 55256746Sroberto cintr = bus_alloc_resource_any(self, SYS_RES_IRQ, 55356746Sroberto &rid, RF_SHAREABLE | RF_ACTIVE); 55456746Sroberto if (cintr != NULL) 55556746Sroberto bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE, 55656746Sroberto NULL, davbus_cint, sc, &cookie); 55756746Sroberto 55856746Sroberto /* Initialize controller registers. */ 55956746Sroberto bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 | 560132451Sroberto DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG); 56156746Sroberto 56256746Sroberto /* Attach DBDMA engine and PCM layer */ 56356746Sroberto err = aoa_attach(sc); 56456746Sroberto if (err) 56556746Sroberto return (err); 56656746Sroberto 567182007Sroberto /* Install codec module */ 568182007Sroberto if (strcmp(compat, "screamer") == 0) 56956746Sroberto mixer_init(self, &screamer_mixer_class, sc); 57056746Sroberto else if (strcmp(compat, "burgundy") == 0) 57156746Sroberto mixer_init(self, &burgundy_mixer_class, sc); 57256746Sroberto 57356746Sroberto return (0); 57456746Sroberto} 57556746Sroberto 57656746Srobertostatic void 57756746Srobertodavbus_cint(void *ptr) 57856746Sroberto{ 57956746Sroberto struct davbus_softc *d = ptr; 58056746Sroberto u_int reg, status, mask; 58156746Sroberto 582285612Sdelphij mtx_lock(&d->mutex); 583285612Sdelphij 584285612Sdelphij reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL); 585285612Sdelphij if (reg & DAVBUS_PORTCHG) { 58656746Sroberto 58756746Sroberto status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS); 58856746Sroberto 58956746Sroberto if (d->read_status && d->set_outputs) { 590285612Sdelphij 591285612Sdelphij mask = (*d->read_status)(d, status); 592285612Sdelphij (*d->set_outputs)(d, mask); 593285612Sdelphij } 594285612Sdelphij 595285612Sdelphij /* Clear the interrupt. */ 596285612Sdelphij bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg); 597285612Sdelphij } 598285612Sdelphij 599285612Sdelphij mtx_unlock(&d->mutex); 600285612Sdelphij} 601285612Sdelphij 602285612Sdelphij