1205859Sjoel/*- 2162874Snetchild * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com> 3159687Snetchild * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> 4159687Snetchild * All rights reserved. 5159687Snetchild * 6159687Snetchild * Redistribution and use in source and binary forms, with or without 7159687Snetchild * modification, are permitted provided that the following conditions 8159687Snetchild * are met: 9159687Snetchild * 1. Redistributions of source code must retain the above copyright 10159687Snetchild * notice, this list of conditions and the following disclaimer. 11159687Snetchild * 2. Redistributions in binary form must reproduce the above copyright 12159687Snetchild * notice, this list of conditions and the following disclaimer in the 13159687Snetchild * documentation and/or other materials provided with the distribution. 14159687Snetchild * 15159687Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16159687Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17159687Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18159687Snetchild * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19159687Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20159687Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21159687Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22159687Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 23159687Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24159687Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 25159687Snetchild * SUCH DAMAGE. 26159687Snetchild * 27159687Snetchild * $FreeBSD$ 28159687Snetchild */ 29159687Snetchild 30193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 31193640Sariff#include "opt_snd.h" 32193640Sariff#endif 33193640Sariff 34159687Snetchild#include <dev/sound/pcm/sound.h> 35159687Snetchild 36162874Snetchild#include <dev/sound/pci/spicds.h> 37159687Snetchild 38227293Sedstatic MALLOC_DEFINE(M_SPICDS, "spicds", "SPI codec"); 39159687Snetchild 40162874Snetchild#define SPICDS_NAMELEN 16 41162874Snetchildstruct spicds_info { 42159687Snetchild device_t dev; 43162874Snetchild spicds_ctrl ctrl; 44159687Snetchild void *devinfo; 45159687Snetchild int num; /* number of this device */ 46159687Snetchild unsigned int type; /* codec type */ 47159687Snetchild unsigned int cif; /* Controll data Interface Format (0/1) */ 48159687Snetchild unsigned int format; /* data format and master clock frequency */ 49159687Snetchild unsigned int dvc; /* De-emphasis and Volume Control */ 50159687Snetchild unsigned int left, right; 51162874Snetchild char name[SPICDS_NAMELEN]; 52166713Sariff struct mtx *lock; 53159687Snetchild}; 54159687Snetchild 55159687Snetchildstatic void 56162874Snetchildspicds_wrbit(struct spicds_info *codec, int bit) 57159687Snetchild{ 58159687Snetchild unsigned int cs, cdti; 59159687Snetchild if (codec->cif) 60159687Snetchild cs = 1; 61159687Snetchild else 62159687Snetchild cs = 0; 63159687Snetchild if (bit) 64159687Snetchild cdti = 1; 65159687Snetchild else 66159687Snetchild cdti = 0; 67159687Snetchild codec->ctrl(codec->devinfo, cs, 0, cdti); 68159687Snetchild DELAY(1); 69159687Snetchild codec->ctrl(codec->devinfo, cs, 1, cdti); 70159687Snetchild DELAY(1); 71159687Snetchild 72159687Snetchild return; 73159687Snetchild} 74159687Snetchild 75159687Snetchildstatic void 76162874Snetchildspicds_wrcd(struct spicds_info *codec, int reg, u_int16_t val) 77159687Snetchild{ 78159687Snetchild int mask; 79159687Snetchild 80159687Snetchild#if(0) 81162874Snetchild device_printf(codec->dev, "spicds_wrcd(codec, 0x%02x, 0x%02x)\n", reg, val); 82159687Snetchild#endif 83159687Snetchild /* start */ 84159687Snetchild if (codec->cif) 85159687Snetchild codec->ctrl(codec->devinfo, 1, 1, 0); 86159687Snetchild else 87159687Snetchild codec->ctrl(codec->devinfo, 0, 1, 0); 88159687Snetchild DELAY(1); 89162874Snetchild if (codec->type != SPICDS_TYPE_WM8770) { 90162874Snetchild if (codec->type == SPICDS_TYPE_AK4381) { 91162874Snetchild /* AK4381 chip address */ 92162874Snetchild spicds_wrbit(codec, 0); 93162874Snetchild spicds_wrbit(codec, 1); 94162874Snetchild } 95170031Sjoel else if (codec->type == SPICDS_TYPE_AK4396) 96170031Sjoel { 97170031Sjoel /* AK4396 chip address */ 98170031Sjoel spicds_wrbit(codec, 0); 99170031Sjoel spicds_wrbit(codec, 0); 100170031Sjoel } 101162874Snetchild else { 102159687Snetchild /* chip address */ 103162874Snetchild spicds_wrbit(codec, 1); 104162874Snetchild spicds_wrbit(codec, 0); 105162874Snetchild } 106159687Snetchild /* write */ 107162874Snetchild spicds_wrbit(codec, 1); 108159687Snetchild /* register address */ 109159687Snetchild for (mask = 0x10; mask != 0; mask >>= 1) 110162874Snetchild spicds_wrbit(codec, reg & mask); 111159687Snetchild /* data */ 112159687Snetchild for (mask = 0x80; mask != 0; mask >>= 1) 113162874Snetchild spicds_wrbit(codec, val & mask); 114159687Snetchild /* stop */ 115159687Snetchild DELAY(1); 116162874Snetchild } 117162874Snetchild else { 118162874Snetchild /* register address */ 119162874Snetchild for (mask = 0x40; mask != 0; mask >>= 1) 120162874Snetchild spicds_wrbit(codec, reg & mask); 121162874Snetchild /* data */ 122162874Snetchild for (mask = 0x100; mask != 0; mask >>= 1) 123162874Snetchild spicds_wrbit(codec, val & mask); 124162874Snetchild /* stop */ 125162874Snetchild DELAY(1); 126162874Snetchild } 127159687Snetchild if (codec->cif) { 128159687Snetchild codec->ctrl(codec->devinfo, 0, 1, 0); 129159687Snetchild DELAY(1); 130159687Snetchild codec->ctrl(codec->devinfo, 1, 1, 0); 131159687Snetchild } 132159687Snetchild else { 133159687Snetchild codec->ctrl(codec->devinfo, 1, 1, 0); 134159687Snetchild } 135159687Snetchild 136159687Snetchild return; 137159687Snetchild} 138159687Snetchild 139162874Snetchildstruct spicds_info * 140162874Snetchildspicds_create(device_t dev, void *devinfo, int num, spicds_ctrl ctrl) 141159687Snetchild{ 142162874Snetchild struct spicds_info *codec; 143159687Snetchild 144159687Snetchild#if(0) 145162874Snetchild device_printf(dev, "spicds_create(dev, devinfo, %d, ctrl)\n", num); 146159687Snetchild#endif 147162874Snetchild codec = (struct spicds_info *)malloc(sizeof *codec, M_SPICDS, M_NOWAIT); 148159687Snetchild if (codec == NULL) 149159687Snetchild return NULL; 150159687Snetchild 151162874Snetchild snprintf(codec->name, SPICDS_NAMELEN, "%s:spicds%d", device_get_nameunit(dev), num); 152159689Snetchild codec->lock = snd_mtxcreate(codec->name, codec->name); 153159687Snetchild codec->dev = dev; 154159687Snetchild codec->ctrl = ctrl; 155159687Snetchild codec->devinfo = devinfo; 156159687Snetchild codec->num = num; 157162874Snetchild codec->type = SPICDS_TYPE_AK4524; 158159687Snetchild codec->cif = 0; 159159687Snetchild codec->format = AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X; 160159687Snetchild codec->dvc = AK452X_DVC_DEMOFF | AK452X_DVC_ZTM1024 | AK452X_DVC_ZCE; 161159687Snetchild 162159687Snetchild return codec; 163159687Snetchild} 164159687Snetchild 165159687Snetchildvoid 166162874Snetchildspicds_destroy(struct spicds_info *codec) 167159687Snetchild{ 168159687Snetchild snd_mtxfree(codec->lock); 169162874Snetchild free(codec, M_SPICDS); 170159687Snetchild} 171159687Snetchild 172159687Snetchildvoid 173162874Snetchildspicds_settype(struct spicds_info *codec, unsigned int type) 174159687Snetchild{ 175159687Snetchild snd_mtxlock(codec->lock); 176159687Snetchild codec->type = type; 177159687Snetchild snd_mtxunlock(codec->lock); 178159687Snetchild} 179159687Snetchild 180159687Snetchildvoid 181162874Snetchildspicds_setcif(struct spicds_info *codec, unsigned int cif) 182159687Snetchild{ 183159687Snetchild snd_mtxlock(codec->lock); 184159687Snetchild codec->cif = cif; 185159687Snetchild snd_mtxunlock(codec->lock); 186159687Snetchild} 187159687Snetchild 188159687Snetchildvoid 189162874Snetchildspicds_setformat(struct spicds_info *codec, unsigned int format) 190159687Snetchild{ 191159687Snetchild snd_mtxlock(codec->lock); 192159687Snetchild codec->format = format; 193159687Snetchild snd_mtxunlock(codec->lock); 194159687Snetchild} 195159687Snetchild 196159687Snetchildvoid 197162874Snetchildspicds_setdvc(struct spicds_info *codec, unsigned int dvc) 198159687Snetchild{ 199159687Snetchild snd_mtxlock(codec->lock); 200159689Snetchild codec->dvc = dvc; 201159687Snetchild snd_mtxunlock(codec->lock); 202159687Snetchild} 203159687Snetchild 204159687Snetchildvoid 205162874Snetchildspicds_init(struct spicds_info *codec) 206159687Snetchild{ 207159687Snetchild#if(0) 208162874Snetchild device_printf(codec->dev, "spicds_init(codec)\n"); 209159687Snetchild#endif 210159687Snetchild snd_mtxlock(codec->lock); 211162874Snetchild if (codec->type == SPICDS_TYPE_AK4524 ||\ 212162874Snetchild codec->type == SPICDS_TYPE_AK4528) { 213159687Snetchild /* power off */ 214162874Snetchild spicds_wrcd(codec, AK4524_POWER, 0); 215159687Snetchild /* set parameter */ 216162874Snetchild spicds_wrcd(codec, AK4524_FORMAT, codec->format); 217162874Snetchild spicds_wrcd(codec, AK4524_DVC, codec->dvc); 218159687Snetchild /* power on */ 219162874Snetchild spicds_wrcd(codec, AK4524_POWER, AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR); 220159687Snetchild /* free reset register */ 221162874Snetchild spicds_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD); 222162874Snetchild } 223162874Snetchild if (codec->type == SPICDS_TYPE_WM8770) { 224162874Snetchild /* WM8770 init values are taken from ALSA */ 225162874Snetchild /* These come first to reduce init pop noise */ 226162874Snetchild spicds_wrcd(codec, 0x1b, 0x044); /* ADC Mux (AC'97 source) */ 227162874Snetchild spicds_wrcd(codec, 0x1c, 0x00B); /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ 228162874Snetchild spicds_wrcd(codec, 0x1d, 0x009); /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */ 229162874Snetchild 230162874Snetchild spicds_wrcd(codec, 0x18, 0x000); /* All power-up */ 231162874Snetchild 232162874Snetchild spicds_wrcd(codec, 0x16, 0x122); /* I2S, normal polarity, 24bit */ 233162874Snetchild spicds_wrcd(codec, 0x17, 0x022); /* 256fs, slave mode */ 234162874Snetchild 235162874Snetchild spicds_wrcd(codec, 0x19, 0x000); /* -12dB ADC/L */ 236162874Snetchild spicds_wrcd(codec, 0x1a, 0x000); /* -12dB ADC/R */ 237162874Snetchild } 238162874Snetchild if (codec->type == SPICDS_TYPE_AK4358) 239162874Snetchild spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */ 240162874Snetchild if (codec->type == SPICDS_TYPE_AK4381) 241188480Snetchild spicds_wrcd(codec, 0x00, 0x8f); /* I2S, 24bit, power-up */ 242170031Sjoel if (codec->type == SPICDS_TYPE_AK4396) 243170031Sjoel spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */ 244159687Snetchild snd_mtxunlock(codec->lock); 245159687Snetchild} 246159687Snetchild 247159687Snetchildvoid 248162874Snetchildspicds_reinit(struct spicds_info *codec) 249159687Snetchild{ 250159687Snetchild snd_mtxlock(codec->lock); 251162874Snetchild if (codec->type != SPICDS_TYPE_WM8770) { 252159687Snetchild /* reset */ 253162874Snetchild spicds_wrcd(codec, AK4524_RESET, 0); 254159687Snetchild /* set parameter */ 255162874Snetchild spicds_wrcd(codec, AK4524_FORMAT, codec->format); 256162874Snetchild spicds_wrcd(codec, AK4524_DVC, codec->dvc); 257159687Snetchild /* free reset register */ 258162874Snetchild spicds_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD); 259162874Snetchild } 260162874Snetchild else { 261162874Snetchild /* WM8770 reinit */ 262162874Snetchild /* AK4358 reinit */ 263162874Snetchild /* AK4381 reinit */ 264162874Snetchild } 265159687Snetchild snd_mtxunlock(codec->lock); 266159687Snetchild} 267159687Snetchild 268159687Snetchildvoid 269162874Snetchildspicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int right) 270159687Snetchild{ 271159687Snetchild#if(0) 272162874Snetchild device_printf(codec->dev, "spicds_set(codec, %d, %d, %d)\n", dir, left, right); 273159687Snetchild#endif 274159687Snetchild snd_mtxlock(codec->lock); 275159687Snetchild if (left >= 100) 276170031Sjoel if ((codec->type == SPICDS_TYPE_AK4381) || \ 277170031Sjoel (codec->type == SPICDS_TYPE_AK4396)) 278162874Snetchild left = 255; 279162874Snetchild else 280162874Snetchild left = 127; 281159687Snetchild else 282162874Snetchild switch (codec->type) { 283162874Snetchild case SPICDS_TYPE_WM8770: 284162874Snetchild left = left + 27; 285162874Snetchild break; 286213779Srpaulo case SPICDS_TYPE_AK4381: 287213779Srpaulo case SPICDS_TYPE_AK4396: 288162874Snetchild left = left * 255 / 100; 289162874Snetchild break; 290162874Snetchild default: 291162874Snetchild left = left * 127 / 100; 292162874Snetchild } 293159687Snetchild if (right >= 100) 294170031Sjoel if ((codec->type == SPICDS_TYPE_AK4381) || \ 295170031Sjoel (codec->type == SPICDS_TYPE_AK4396)) 296162874Snetchild right = 255; 297162874Snetchild else 298162874Snetchild right = 127; 299159687Snetchild else 300162874Snetchild switch (codec->type) { 301162874Snetchild case SPICDS_TYPE_WM8770: 302162874Snetchild right = right + 27; 303162874Snetchild break; 304188480Snetchild case SPICDS_TYPE_AK4381: 305188480Snetchild case SPICDS_TYPE_AK4396: 306162874Snetchild right = right * 255 / 100; 307162874Snetchild break; 308162874Snetchild default: 309162874Snetchild right = right * 127 / 100; 310162874Snetchild } 311162874Snetchild if (dir == PCMDIR_REC && codec->type == SPICDS_TYPE_AK4524) { 312159687Snetchild#if(0) 313162874Snetchild device_printf(codec->dev, "spicds_set(): AK4524(REC) %d/%d\n", left, right); 314159687Snetchild#endif 315162874Snetchild spicds_wrcd(codec, AK4524_LIPGA, left); 316162874Snetchild spicds_wrcd(codec, AK4524_RIPGA, right); 317159687Snetchild } 318162874Snetchild if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4524) { 319159687Snetchild#if(0) 320162874Snetchild device_printf(codec->dev, "spicds_set(): AK4524(PLAY) %d/%d\n", left, right); 321159687Snetchild#endif 322162874Snetchild spicds_wrcd(codec, AK4524_LOATT, left); 323162874Snetchild spicds_wrcd(codec, AK4524_ROATT, right); 324159687Snetchild } 325162874Snetchild if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4528) { 326159687Snetchild#if(0) 327162874Snetchild device_printf(codec->dev, "spicds_set(): AK4528(PLAY) %d/%d\n", left, right); 328159687Snetchild#endif 329162874Snetchild spicds_wrcd(codec, AK4528_LOATT, left); 330162874Snetchild spicds_wrcd(codec, AK4528_ROATT, right); 331159687Snetchild } 332162874Snetchild if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_WM8770) { 333162874Snetchild#if(0) 334162874Snetchild device_printf(codec->dev, "spicds_set(): WM8770(PLAY) %d/%d\n", left, right); 335162874Snetchild#endif 336162874Snetchild spicds_wrcd(codec, WM8770_AOATT_L1, left | WM8770_AOATT_UPDATE); 337162874Snetchild spicds_wrcd(codec, WM8770_AOATT_R1, right | WM8770_AOATT_UPDATE); 338162874Snetchild } 339162874Snetchild if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4358) { 340162874Snetchild#if(0) 341162874Snetchild device_printf(codec->dev, "spicds_set(): AK4358(PLAY) %d/%d\n", left, right); 342162874Snetchild#endif 343162874Snetchild spicds_wrcd(codec, AK4358_LO1ATT, left | AK4358_OATT_ENABLE); 344162874Snetchild spicds_wrcd(codec, AK4358_RO1ATT, right | AK4358_OATT_ENABLE); 345162874Snetchild } 346162874Snetchild if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4381) { 347162874Snetchild#if(0) 348162874Snetchild device_printf(codec->dev, "spicds_set(): AK4381(PLAY) %d/%d\n", left, right); 349162874Snetchild#endif 350162874Snetchild spicds_wrcd(codec, AK4381_LOATT, left); 351162874Snetchild spicds_wrcd(codec, AK4381_ROATT, right); 352162874Snetchild } 353162874Snetchild 354170031Sjoel if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4396) { 355170031Sjoel#if(0) 356170031Sjoel device_printf(codec->dev, "spicds_set(): AK4396(PLAY) %d/%d\n", left, right); 357170031Sjoel#endif 358170031Sjoel spicds_wrcd(codec, AK4396_LOATT, left); 359170031Sjoel spicds_wrcd(codec, AK4396_ROATT, right); 360170031Sjoel } 361170031Sjoel 362159687Snetchild snd_mtxunlock(codec->lock); 363159687Snetchild} 364159687Snetchild 365162874SnetchildMODULE_DEPEND(snd_spicds, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 366162874SnetchildMODULE_VERSION(snd_spicds, 1); 367