1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright 2012 by Andreas Tobler. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 /* 31 * Apple PCM3052 aka Onyx audio codec. 32 * 33 * Datasheet: http://www.ti.com/product/pcm3052a 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/bus.h> 41 #include <sys/malloc.h> 42 #include <sys/lock.h> 43 #include <sys/mutex.h> 44 #include <machine/dbdma.h> 45 #include <machine/intr_machdep.h> 46 #include <machine/resource.h> 47 #include <machine/bus.h> 48 #include <machine/pio.h> 49 #include <sys/rman.h> 50 51 #include <dev/iicbus/iicbus.h> 52 #include <dev/iicbus/iiconf.h> 53 #include <dev/ofw/ofw_bus.h> 54 55 #ifdef HAVE_KERNEL_OPTION_HEADERS 56 #include "opt_snd.h" 57 #endif 58 59 #include <dev/sound/pcm/sound.h> 60 61 #include "mixer_if.h" 62 63 extern kobj_class_t i2s_mixer_class; 64 extern device_t i2s_mixer; 65 66 struct onyx_softc 67 { 68 device_t sc_dev; 69 uint32_t sc_addr; 70 }; 71 72 static int onyx_probe(device_t); 73 static int onyx_attach(device_t); 74 static int onyx_init(struct snd_mixer *m); 75 static int onyx_uninit(struct snd_mixer *m); 76 static int onyx_reinit(struct snd_mixer *m); 77 static int onyx_set(struct snd_mixer *m, unsigned dev, unsigned left, 78 unsigned right); 79 static u_int32_t onyx_setrecsrc(struct snd_mixer *m, u_int32_t src); 80 81 static device_method_t onyx_methods[] = { 82 /* Device interface. */ 83 DEVMETHOD(device_probe, onyx_probe), 84 DEVMETHOD(device_attach, onyx_attach), 85 { 0, 0 } 86 }; 87 88 static driver_t onyx_driver = { 89 "onyx", 90 onyx_methods, 91 sizeof(struct onyx_softc) 92 }; 93 static devclass_t onyx_devclass; 94 95 DRIVER_MODULE(onyx, iicbus, onyx_driver, onyx_devclass, 0, 0); 96 MODULE_VERSION(onyx, 1); 97 MODULE_DEPEND(onyx, iicbus, 1, 1, 1); 98 99 static kobj_method_t onyx_mixer_methods[] = { 100 KOBJMETHOD(mixer_init, onyx_init), 101 KOBJMETHOD(mixer_uninit, onyx_uninit), 102 KOBJMETHOD(mixer_reinit, onyx_reinit), 103 KOBJMETHOD(mixer_set, onyx_set), 104 KOBJMETHOD(mixer_setrecsrc, onyx_setrecsrc), 105 KOBJMETHOD_END 106 }; 107 108 MIXER_DECLARE(onyx_mixer); 109 110 #define PCM3052_IICADDR 0x8C /* Hard-coded I2C slave addr */ 111 112 /* 113 * PCM3052 registers. 114 * Numbering in decimal as used in the data sheet. 115 */ 116 #define PCM3052_REG_LEFT_ATTN 65 117 #define PCM3052_REG_RIGHT_ATTN 66 118 #define PCM3052_REG_CONTROL 67 119 #define PCM3052_MRST (1 << 7) 120 #define PCM3052_SRST (1 << 6) 121 #define PCM3052_REG_DAC_CONTROL 68 122 #define PCM3052_OVR1 (1 << 6) 123 #define PCM3052_MUTE_L (1 << 1) 124 #define PCM3052_MUTE_R (1 << 0) 125 #define PCM3052_REG_DAC_DEEMPH 69 126 #define PCM3052_REG_DAC_FILTER 70 127 #define PCM3052_DAC_FILTER_ALWAYS (1 << 2) 128 #define PCM3052_REG_OUT_PHASE 71 129 #define PCM3052_REG_ADC_CONTROL 72 130 #define PCM3052_REG_ADC_HPF_BP 75 131 #define PCM3052_HPF_ALWAYS (1 << 2) 132 #define PCM3052_REG_INFO_1 77 133 #define PCM3052_REG_INFO_2 78 134 #define PCM3052_REG_INFO_3 79 135 #define PCM3052_REG_INFO_4 80 136 137 struct onyx_reg { 138 u_char LEFT_ATTN; 139 u_char RIGHT_ATTN; 140 u_char CONTROL; 141 u_char DAC_CONTROL; 142 u_char DAC_DEEMPH; 143 u_char DAC_FILTER; 144 u_char OUT_PHASE; 145 u_char ADC_CONTROL; 146 u_char ADC_HPF_BP; 147 u_char INFO_1; 148 u_char INFO_2; 149 u_char INFO_3; 150 u_char INFO_4; 151 }; 152 153 static const struct onyx_reg onyx_initdata = { 154 0x80, /* LEFT_ATTN, Mute default */ 155 0x80, /* RIGHT_ATTN, Mute default */ 156 PCM3052_MRST | PCM3052_SRST, /* CONTROL */ 157 0, /* DAC_CONTROL */ 158 0, /* DAC_DEEMPH */ 159 PCM3052_DAC_FILTER_ALWAYS, /* DAC_FILTER */ 160 0, /* OUT_PHASE */ 161 (-1 /* dB */ + 8) & 0xf, /* ADC_CONTROL */ 162 PCM3052_HPF_ALWAYS, /* ADC_HPF_BP */ 163 (1 << 2), /* INFO_1 */ 164 2, /* INFO_2, */ 165 0, /* INFO_3, CLK 0 (level II), 166 SF 0 (44.1 kHz) */ 167 1 /* INFO_4, VALIDL/R 0, 168 WL 24-bit depth */ 169 }; 170 171 static int 172 onyx_write(struct onyx_softc *sc, uint8_t reg, const uint8_t value) 173 { 174 u_int size; 175 uint8_t buf[16]; 176 177 struct iic_msg msg[] = { 178 { sc->sc_addr, IIC_M_WR, 0, buf } 179 }; 180 181 size = 1; 182 msg[0].len = size + 1; 183 buf[0] = reg; 184 buf[1] = value; 185 186 iicbus_transfer(sc->sc_dev, msg, 1); 187 188 return (0); 189 } 190 191 static int 192 onyx_probe(device_t dev) 193 { 194 const char *name, *compat; 195 196 name = ofw_bus_get_name(dev); 197 if (name == NULL) 198 return (ENXIO); 199 200 if (strcmp(name, "codec") == 0) { 201 if (iicbus_get_addr(dev) != PCM3052_IICADDR) 202 return (ENXIO); 203 } else if (strcmp(name, "codec") == 0) { 204 compat = ofw_bus_get_compat(dev); 205 if (compat == NULL || strcmp(compat, "pcm3052") != 0) 206 return (ENXIO); 207 } else 208 return (ENXIO); 209 210 device_set_desc(dev, "Texas Instruments PCM3052 Audio Codec"); 211 return (0); 212 } 213 214 static int 215 onyx_attach(device_t dev) 216 { 217 struct onyx_softc *sc; 218 219 sc = device_get_softc(dev); 220 sc->sc_dev = dev; 221 sc->sc_addr = iicbus_get_addr(dev); 222 223 i2s_mixer_class = &onyx_mixer_class; 224 i2s_mixer = dev; 225 226 return (0); 227 } 228 229 static int 230 onyx_init(struct snd_mixer *m) 231 { 232 struct onyx_softc *sc; 233 u_int x = 0; 234 235 sc = device_get_softc(mix_getdevinfo(m)); 236 237 onyx_write(sc, PCM3052_REG_LEFT_ATTN, onyx_initdata.LEFT_ATTN); 238 onyx_write(sc, PCM3052_REG_RIGHT_ATTN, onyx_initdata.RIGHT_ATTN); 239 onyx_write(sc, PCM3052_REG_CONTROL, onyx_initdata.CONTROL); 240 onyx_write(sc, PCM3052_REG_DAC_CONTROL, 241 onyx_initdata.DAC_CONTROL); 242 onyx_write(sc, PCM3052_REG_DAC_DEEMPH, onyx_initdata.DAC_DEEMPH); 243 onyx_write(sc, PCM3052_REG_DAC_FILTER, onyx_initdata.DAC_FILTER); 244 onyx_write(sc, PCM3052_REG_OUT_PHASE, onyx_initdata.OUT_PHASE); 245 onyx_write(sc, PCM3052_REG_ADC_CONTROL, 246 onyx_initdata.ADC_CONTROL); 247 onyx_write(sc, PCM3052_REG_ADC_HPF_BP, onyx_initdata.ADC_HPF_BP); 248 onyx_write(sc, PCM3052_REG_INFO_1, onyx_initdata.INFO_1); 249 onyx_write(sc, PCM3052_REG_INFO_2, onyx_initdata.INFO_2); 250 onyx_write(sc, PCM3052_REG_INFO_3, onyx_initdata.INFO_3); 251 onyx_write(sc, PCM3052_REG_INFO_4, onyx_initdata.INFO_4); 252 253 x |= SOUND_MASK_VOLUME; 254 mix_setdevs(m, x); 255 256 return (0); 257 } 258 259 static int 260 onyx_uninit(struct snd_mixer *m) 261 { 262 return (0); 263 } 264 265 static int 266 onyx_reinit(struct snd_mixer *m) 267 { 268 return (0); 269 } 270 271 static int 272 onyx_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 273 { 274 struct onyx_softc *sc; 275 struct mtx *mixer_lock; 276 int locked; 277 uint8_t l, r; 278 279 sc = device_get_softc(mix_getdevinfo(m)); 280 mixer_lock = mixer_get_lock(m); 281 locked = mtx_owned(mixer_lock); 282 283 switch (dev) { 284 case SOUND_MIXER_VOLUME: 285 286 /* 287 * We need to unlock the mixer lock because iicbus_transfer() 288 * may sleep. The mixer lock itself is unnecessary here 289 * because it is meant to serialize hardware access, which 290 * is taken care of by the I2C layer, so this is safe. 291 */ 292 if (left > 100 || right > 100) 293 return (0); 294 295 l = left + 128; 296 r = right + 128; 297 298 if (locked) 299 mtx_unlock(mixer_lock); 300 301 onyx_write(sc, PCM3052_REG_LEFT_ATTN, l); 302 onyx_write(sc, PCM3052_REG_RIGHT_ATTN, r); 303 304 if (locked) 305 mtx_lock(mixer_lock); 306 307 return (left | (right << 8)); 308 } 309 310 return (0); 311 } 312 313 static u_int32_t 314 onyx_setrecsrc(struct snd_mixer *m, u_int32_t src) 315 { 316 return (0); 317 } 318