1239401Sandreast/*- 2239401Sandreast * Copyright 2012 by Andreas Tobler. All rights reserved. 3239401Sandreast * 4239401Sandreast * Redistribution and use in source and binary forms, with or without 5239401Sandreast * modification, are permitted provided that the following conditions 6239401Sandreast * are met: 7239401Sandreast * 1. Redistributions of source code must retain the above copyright 8239401Sandreast * notice, this list of conditions and the following disclaimer. 9239401Sandreast * 2. Redistributions in binary form must reproduce the above copyright 10239401Sandreast * notice, this list of conditions and the following disclaimer in the 11239401Sandreast * documentation and/or other materials provided with the distribution. 12239401Sandreast * 13239401Sandreast * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14239401Sandreast * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15239401Sandreast * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16239401Sandreast * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17239401Sandreast * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18239401Sandreast * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19239401Sandreast * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20239401Sandreast * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21239401Sandreast * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22239401Sandreast * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23239401Sandreast * SUCH DAMAGE. 24239401Sandreast * 25239401Sandreast * $FreeBSD$ 26239401Sandreast */ 27239401Sandreast 28239401Sandreast/* 29239401Sandreast * Apple PCM3052 aka Onyx audio codec. 30239401Sandreast * 31239401Sandreast * Datasheet: http://www.ti.com/product/pcm3052a 32239401Sandreast */ 33239401Sandreast 34239401Sandreast#include <sys/param.h> 35239401Sandreast#include <sys/systm.h> 36239401Sandreast#include <sys/kernel.h> 37239401Sandreast#include <sys/module.h> 38239401Sandreast#include <sys/bus.h> 39239401Sandreast#include <sys/malloc.h> 40239401Sandreast#include <sys/lock.h> 41239401Sandreast#include <sys/mutex.h> 42239401Sandreast#include <machine/dbdma.h> 43239401Sandreast#include <machine/intr_machdep.h> 44239401Sandreast#include <machine/resource.h> 45239401Sandreast#include <machine/bus.h> 46239401Sandreast#include <machine/pio.h> 47239401Sandreast#include <sys/rman.h> 48239401Sandreast 49239401Sandreast#include <dev/iicbus/iicbus.h> 50239401Sandreast#include <dev/iicbus/iiconf.h> 51239401Sandreast#include <dev/ofw/ofw_bus.h> 52239401Sandreast 53239401Sandreast#ifdef HAVE_KERNEL_OPTION_HEADERS 54239401Sandreast#include "opt_snd.h" 55239401Sandreast#endif 56239401Sandreast 57239401Sandreast#include <dev/sound/pcm/sound.h> 58239401Sandreast 59239401Sandreast#include "mixer_if.h" 60239401Sandreast 61239401Sandreastextern kobj_class_t i2s_mixer_class; 62239401Sandreastextern device_t i2s_mixer; 63239401Sandreast 64239401Sandreaststruct onyx_softc 65239401Sandreast{ 66239401Sandreast device_t sc_dev; 67239401Sandreast uint32_t sc_addr; 68239401Sandreast}; 69239401Sandreast 70239401Sandreaststatic int onyx_probe(device_t); 71239401Sandreaststatic int onyx_attach(device_t); 72239401Sandreaststatic int onyx_init(struct snd_mixer *m); 73239401Sandreaststatic int onyx_uninit(struct snd_mixer *m); 74239401Sandreaststatic int onyx_reinit(struct snd_mixer *m); 75239401Sandreaststatic int onyx_set(struct snd_mixer *m, unsigned dev, unsigned left, 76239401Sandreast unsigned right); 77239401Sandreaststatic u_int32_t onyx_setrecsrc(struct snd_mixer *m, u_int32_t src); 78239401Sandreast 79239401Sandreaststatic device_method_t onyx_methods[] = { 80239401Sandreast /* Device interface. */ 81239401Sandreast DEVMETHOD(device_probe, onyx_probe), 82239401Sandreast DEVMETHOD(device_attach, onyx_attach), 83239401Sandreast { 0, 0 } 84239401Sandreast}; 85239401Sandreast 86239401Sandreaststatic driver_t onyx_driver = { 87239401Sandreast "onyx", 88239401Sandreast onyx_methods, 89239401Sandreast sizeof(struct onyx_softc) 90239401Sandreast}; 91239401Sandreaststatic devclass_t onyx_devclass; 92239401Sandreast 93239401SandreastDRIVER_MODULE(onyx, iicbus, onyx_driver, onyx_devclass, 0, 0); 94239401SandreastMODULE_VERSION(onyx, 1); 95239401SandreastMODULE_DEPEND(onyx, iicbus, 1, 1, 1); 96239401Sandreast 97239401Sandreaststatic kobj_method_t onyx_mixer_methods[] = { 98239401Sandreast KOBJMETHOD(mixer_init, onyx_init), 99239401Sandreast KOBJMETHOD(mixer_uninit, onyx_uninit), 100239401Sandreast KOBJMETHOD(mixer_reinit, onyx_reinit), 101239401Sandreast KOBJMETHOD(mixer_set, onyx_set), 102239401Sandreast KOBJMETHOD(mixer_setrecsrc, onyx_setrecsrc), 103239401Sandreast KOBJMETHOD_END 104239401Sandreast}; 105239401Sandreast 106239401SandreastMIXER_DECLARE(onyx_mixer); 107239401Sandreast 108239401Sandreast#define PCM3052_IICADDR 0x8C /* Hard-coded I2C slave addr */ 109239401Sandreast 110239401Sandreast/* 111239401Sandreast * PCM3052 registers. 112239401Sandreast * Numbering in decimal as used in the data sheet. 113239401Sandreast */ 114239401Sandreast#define PCM3052_REG_LEFT_ATTN 65 115239401Sandreast#define PCM3052_REG_RIGHT_ATTN 66 116239401Sandreast#define PCM3052_REG_CONTROL 67 117239401Sandreast#define PCM3052_MRST (1 << 7) 118239401Sandreast#define PCM3052_SRST (1 << 6) 119239401Sandreast#define PCM3052_REG_DAC_CONTROL 68 120239401Sandreast#define PCM3052_OVR1 (1 << 6) 121239401Sandreast#define PCM3052_MUTE_L (1 << 1) 122239401Sandreast#define PCM3052_MUTE_R (1 << 0) 123239401Sandreast#define PCM3052_REG_DAC_DEEMPH 69 124239401Sandreast#define PCM3052_REG_DAC_FILTER 70 125239401Sandreast#define PCM3052_DAC_FILTER_ALWAYS (1 << 2) 126239401Sandreast#define PCM3052_REG_OUT_PHASE 71 127239401Sandreast#define PCM3052_REG_ADC_CONTROL 72 128239401Sandreast#define PCM3052_REG_ADC_HPF_BP 75 129239401Sandreast#define PCM3052_HPF_ALWAYS (1 << 2) 130239401Sandreast#define PCM3052_REG_INFO_1 77 131239401Sandreast#define PCM3052_REG_INFO_2 78 132239401Sandreast#define PCM3052_REG_INFO_3 79 133239401Sandreast#define PCM3052_REG_INFO_4 80 134239401Sandreast 135239401Sandreaststruct onyx_reg { 136239401Sandreast u_char LEFT_ATTN; 137239401Sandreast u_char RIGHT_ATTN; 138239401Sandreast u_char CONTROL; 139239401Sandreast u_char DAC_CONTROL; 140239401Sandreast u_char DAC_DEEMPH; 141239401Sandreast u_char DAC_FILTER; 142239401Sandreast u_char OUT_PHASE; 143239401Sandreast u_char ADC_CONTROL; 144239401Sandreast u_char ADC_HPF_BP; 145239401Sandreast u_char INFO_1; 146239401Sandreast u_char INFO_2; 147239401Sandreast u_char INFO_3; 148239401Sandreast u_char INFO_4; 149239401Sandreast}; 150239401Sandreast 151239401Sandreaststatic const struct onyx_reg onyx_initdata = { 152239401Sandreast 0x80, /* LEFT_ATTN, Mute default */ 153239401Sandreast 0x80, /* RIGHT_ATTN, Mute default */ 154239401Sandreast PCM3052_MRST | PCM3052_SRST, /* CONTROL */ 155239401Sandreast 0, /* DAC_CONTROL */ 156239401Sandreast 0, /* DAC_DEEMPH */ 157239401Sandreast PCM3052_DAC_FILTER_ALWAYS, /* DAC_FILTER */ 158239401Sandreast 0, /* OUT_PHASE */ 159239401Sandreast (-1 /* dB */ + 8) & 0xf, /* ADC_CONTROL */ 160239401Sandreast PCM3052_HPF_ALWAYS, /* ADC_HPF_BP */ 161239401Sandreast (1 << 2), /* INFO_1 */ 162239401Sandreast 2, /* INFO_2, */ 163239401Sandreast 0, /* INFO_3, CLK 0 (level II), 164239401Sandreast SF 0 (44.1 kHz) */ 165239401Sandreast 1 /* INFO_4, VALIDL/R 0, 166239401Sandreast WL 24-bit depth */ 167239401Sandreast}; 168239401Sandreast 169239401Sandreaststatic int 170239401Sandreastonyx_write(struct onyx_softc *sc, uint8_t reg, const uint8_t value) 171239401Sandreast{ 172239401Sandreast u_int size; 173239401Sandreast uint8_t buf[16]; 174239401Sandreast 175239401Sandreast struct iic_msg msg[] = { 176239401Sandreast { sc->sc_addr, IIC_M_WR, 0, buf } 177239401Sandreast }; 178239401Sandreast 179239401Sandreast size = 1; 180239401Sandreast msg[0].len = size + 1; 181239401Sandreast buf[0] = reg; 182239401Sandreast buf[1] = value; 183239401Sandreast 184239401Sandreast iicbus_transfer(sc->sc_dev, msg, 1); 185239401Sandreast 186239401Sandreast return (0); 187239401Sandreast} 188239401Sandreast 189239401Sandreaststatic int 190239401Sandreastonyx_probe(device_t dev) 191239401Sandreast{ 192239401Sandreast const char *name, *compat; 193239401Sandreast 194239401Sandreast name = ofw_bus_get_name(dev); 195239401Sandreast if (name == NULL) 196239401Sandreast return (ENXIO); 197239401Sandreast 198239401Sandreast if (strcmp(name, "codec") == 0) { 199239401Sandreast if (iicbus_get_addr(dev) != PCM3052_IICADDR) 200239401Sandreast return (ENXIO); 201239401Sandreast } else if (strcmp(name, "codec") == 0) { 202239401Sandreast compat = ofw_bus_get_compat(dev); 203239401Sandreast if (compat == NULL || strcmp(compat, "pcm3052") != 0) 204239401Sandreast return (ENXIO); 205239401Sandreast } else 206239401Sandreast return (ENXIO); 207239401Sandreast 208239401Sandreast device_set_desc(dev, "Texas Instruments PCM3052 Audio Codec"); 209239401Sandreast return (0); 210239401Sandreast} 211239401Sandreast 212239401Sandreaststatic int 213239401Sandreastonyx_attach(device_t dev) 214239401Sandreast{ 215239401Sandreast struct onyx_softc *sc; 216239401Sandreast 217239401Sandreast sc = device_get_softc(dev); 218239401Sandreast sc->sc_dev = dev; 219239401Sandreast sc->sc_addr = iicbus_get_addr(dev); 220239401Sandreast 221239401Sandreast i2s_mixer_class = &onyx_mixer_class; 222239401Sandreast i2s_mixer = dev; 223239401Sandreast 224239401Sandreast return (0); 225239401Sandreast} 226239401Sandreast 227239401Sandreaststatic int 228239401Sandreastonyx_init(struct snd_mixer *m) 229239401Sandreast{ 230239401Sandreast struct onyx_softc *sc; 231239401Sandreast u_int x = 0; 232239401Sandreast 233239401Sandreast sc = device_get_softc(mix_getdevinfo(m)); 234239401Sandreast 235239401Sandreast onyx_write(sc, PCM3052_REG_LEFT_ATTN, onyx_initdata.LEFT_ATTN); 236239401Sandreast onyx_write(sc, PCM3052_REG_RIGHT_ATTN, onyx_initdata.RIGHT_ATTN); 237239401Sandreast onyx_write(sc, PCM3052_REG_CONTROL, onyx_initdata.CONTROL); 238239401Sandreast onyx_write(sc, PCM3052_REG_DAC_CONTROL, 239239401Sandreast onyx_initdata.DAC_CONTROL); 240239401Sandreast onyx_write(sc, PCM3052_REG_DAC_DEEMPH, onyx_initdata.DAC_DEEMPH); 241239401Sandreast onyx_write(sc, PCM3052_REG_DAC_FILTER, onyx_initdata.DAC_FILTER); 242239401Sandreast onyx_write(sc, PCM3052_REG_OUT_PHASE, onyx_initdata.OUT_PHASE); 243239401Sandreast onyx_write(sc, PCM3052_REG_ADC_CONTROL, 244239401Sandreast onyx_initdata.ADC_CONTROL); 245239401Sandreast onyx_write(sc, PCM3052_REG_ADC_HPF_BP, onyx_initdata.ADC_HPF_BP); 246239401Sandreast onyx_write(sc, PCM3052_REG_INFO_1, onyx_initdata.INFO_1); 247239401Sandreast onyx_write(sc, PCM3052_REG_INFO_2, onyx_initdata.INFO_2); 248239401Sandreast onyx_write(sc, PCM3052_REG_INFO_3, onyx_initdata.INFO_3); 249239401Sandreast onyx_write(sc, PCM3052_REG_INFO_4, onyx_initdata.INFO_4); 250239401Sandreast 251239401Sandreast x |= SOUND_MASK_VOLUME; 252239401Sandreast mix_setdevs(m, x); 253239401Sandreast 254239401Sandreast return (0); 255239401Sandreast} 256239401Sandreast 257239401Sandreaststatic int 258239401Sandreastonyx_uninit(struct snd_mixer *m) 259239401Sandreast{ 260239401Sandreast return (0); 261239401Sandreast} 262239401Sandreast 263239401Sandreaststatic int 264239401Sandreastonyx_reinit(struct snd_mixer *m) 265239401Sandreast{ 266239401Sandreast return (0); 267239401Sandreast} 268239401Sandreast 269239401Sandreaststatic int 270239401Sandreastonyx_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 271239401Sandreast{ 272239401Sandreast struct onyx_softc *sc; 273239401Sandreast struct mtx *mixer_lock; 274239401Sandreast int locked; 275239401Sandreast uint8_t l, r; 276239401Sandreast 277239401Sandreast sc = device_get_softc(mix_getdevinfo(m)); 278239401Sandreast mixer_lock = mixer_get_lock(m); 279239401Sandreast locked = mtx_owned(mixer_lock); 280239401Sandreast 281239401Sandreast switch (dev) { 282239401Sandreast case SOUND_MIXER_VOLUME: 283239401Sandreast 284239401Sandreast /* 285239401Sandreast * We need to unlock the mixer lock because iicbus_transfer() 286239401Sandreast * may sleep. The mixer lock itself is unnecessary here 287239401Sandreast * because it is meant to serialize hardware access, which 288239401Sandreast * is taken care of by the I2C layer, so this is safe. 289239401Sandreast */ 290239401Sandreast if (left > 100 || right > 100) 291239401Sandreast return (0); 292239401Sandreast 293239401Sandreast l = left + 128; 294239401Sandreast r = right + 128; 295239401Sandreast 296239401Sandreast if (locked) 297239401Sandreast mtx_unlock(mixer_lock); 298239401Sandreast 299239401Sandreast onyx_write(sc, PCM3052_REG_LEFT_ATTN, l); 300239401Sandreast onyx_write(sc, PCM3052_REG_RIGHT_ATTN, r); 301239401Sandreast 302239401Sandreast if (locked) 303239401Sandreast mtx_lock(mixer_lock); 304239401Sandreast 305239401Sandreast return (left | (right << 8)); 306239401Sandreast } 307239401Sandreast 308239401Sandreast return (0); 309239401Sandreast} 310239401Sandreast 311239401Sandreaststatic u_int32_t 312239401Sandreastonyx_setrecsrc(struct snd_mixer *m, u_int32_t src) 313239401Sandreast{ 314239401Sandreast return (0); 315239401Sandreast} 316