1 /* 2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 3 * Universal routines for AK4531 codec 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <linux/delay.h> 23 #include <linux/init.h> 24 #include <linux/slab.h> 25 #include <linux/mutex.h> 26 27 #include <sound/core.h> 28 #include <sound/ak4531_codec.h> 29 #include <sound/tlv.h> 30 31 /* 32 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 33 MODULE_DESCRIPTION("Universal routines for AK4531 codec"); 34 MODULE_LICENSE("GPL"); 35 */ 36 37 #ifdef CONFIG_PROC_FS 38 static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531); 39 #else 40 #define snd_ak4531_proc_init(card,ak) 41 #endif 42 43 /* 44 * 45 */ 46 47 #if 0 48 49 static void snd_ak4531_dump(struct snd_ak4531 *ak4531) 50 { 51 int idx; 52 53 for (idx = 0; idx < 0x19; idx++) 54 printk(KERN_DEBUG "ak4531 0x%x: 0x%x\n", 55 idx, ak4531->regs[idx]); 56 } 57 58 #endif 59 60 /* 61 * 62 */ 63 64 #define AK4531_SINGLE(xname, xindex, reg, shift, mask, invert) \ 65 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 66 .info = snd_ak4531_info_single, \ 67 .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ 68 .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22) } 69 #define AK4531_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ 70 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 71 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 72 .name = xname, .index = xindex, \ 73 .info = snd_ak4531_info_single, \ 74 .get = snd_ak4531_get_single, .put = snd_ak4531_put_single, \ 75 .private_value = reg | (shift << 16) | (mask << 24) | (invert << 22), \ 76 .tlv = { .p = (xtlv) } } 77 78 static int snd_ak4531_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 79 { 80 int mask = (kcontrol->private_value >> 24) & 0xff; 81 82 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 83 uinfo->count = 1; 84 uinfo->value.integer.min = 0; 85 uinfo->value.integer.max = mask; 86 return 0; 87 } 88 89 static int snd_ak4531_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 90 { 91 struct snd_ak4531 *ak4531 = snd_kcontrol_chip(kcontrol); 92 int reg = kcontrol->private_value & 0xff; 93 int shift = (kcontrol->private_value >> 16) & 0x07; 94 int mask = (kcontrol->private_value >> 24) & 0xff; 95 int invert = (kcontrol->private_value >> 22) & 1; 96 int val; 97 98 mutex_lock(&ak4531->reg_mutex); 99 val = (ak4531->regs[reg] >> shift) & mask; 100 mutex_unlock(&ak4531->reg_mutex); 101 if (invert) { 102 val = mask - val; 103 } 104 ucontrol->value.integer.value[0] = val; 105 return 0; 106 } 107 108 static int snd_ak4531_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 109 { 110 struct snd_ak4531 *ak4531 = snd_kcontrol_chip(kcontrol); 111 int reg = kcontrol->private_value & 0xff; 112 int shift = (kcontrol->private_value >> 16) & 0x07; 113 int mask = (kcontrol->private_value >> 24) & 0xff; 114 int invert = (kcontrol->private_value >> 22) & 1; 115 int change; 116 int val; 117 118 val = ucontrol->value.integer.value[0] & mask; 119 if (invert) { 120 val = mask - val; 121 } 122 val <<= shift; 123 mutex_lock(&ak4531->reg_mutex); 124 val = (ak4531->regs[reg] & ~(mask << shift)) | val; 125 change = val != ak4531->regs[reg]; 126 ak4531->write(ak4531, reg, ak4531->regs[reg] = val); 127 mutex_unlock(&ak4531->reg_mutex); 128 return change; 129 } 130 131 #define AK4531_DOUBLE(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert) \ 132 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 133 .info = snd_ak4531_info_double, \ 134 .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ 135 .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22) } 136 #define AK4531_DOUBLE_TLV(xname, xindex, left_reg, right_reg, left_shift, right_shift, mask, invert, xtlv) \ 137 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ 138 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 139 .name = xname, .index = xindex, \ 140 .info = snd_ak4531_info_double, \ 141 .get = snd_ak4531_get_double, .put = snd_ak4531_put_double, \ 142 .private_value = left_reg | (right_reg << 8) | (left_shift << 16) | (right_shift << 19) | (mask << 24) | (invert << 22), \ 143 .tlv = { .p = (xtlv) } } 144 145 static int snd_ak4531_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 146 { 147 int mask = (kcontrol->private_value >> 24) & 0xff; 148 149 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; 150 uinfo->count = 2; 151 uinfo->value.integer.min = 0; 152 uinfo->value.integer.max = mask; 153 return 0; 154 } 155 156 static int snd_ak4531_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 157 { 158 struct snd_ak4531 *ak4531 = snd_kcontrol_chip(kcontrol); 159 int left_reg = kcontrol->private_value & 0xff; 160 int right_reg = (kcontrol->private_value >> 8) & 0xff; 161 int left_shift = (kcontrol->private_value >> 16) & 0x07; 162 int right_shift = (kcontrol->private_value >> 19) & 0x07; 163 int mask = (kcontrol->private_value >> 24) & 0xff; 164 int invert = (kcontrol->private_value >> 22) & 1; 165 int left, right; 166 167 mutex_lock(&ak4531->reg_mutex); 168 left = (ak4531->regs[left_reg] >> left_shift) & mask; 169 right = (ak4531->regs[right_reg] >> right_shift) & mask; 170 mutex_unlock(&ak4531->reg_mutex); 171 if (invert) { 172 left = mask - left; 173 right = mask - right; 174 } 175 ucontrol->value.integer.value[0] = left; 176 ucontrol->value.integer.value[1] = right; 177 return 0; 178 } 179 180 static int snd_ak4531_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 181 { 182 struct snd_ak4531 *ak4531 = snd_kcontrol_chip(kcontrol); 183 int left_reg = kcontrol->private_value & 0xff; 184 int right_reg = (kcontrol->private_value >> 8) & 0xff; 185 int left_shift = (kcontrol->private_value >> 16) & 0x07; 186 int right_shift = (kcontrol->private_value >> 19) & 0x07; 187 int mask = (kcontrol->private_value >> 24) & 0xff; 188 int invert = (kcontrol->private_value >> 22) & 1; 189 int change; 190 int left, right; 191 192 left = ucontrol->value.integer.value[0] & mask; 193 right = ucontrol->value.integer.value[1] & mask; 194 if (invert) { 195 left = mask - left; 196 right = mask - right; 197 } 198 left <<= left_shift; 199 right <<= right_shift; 200 mutex_lock(&ak4531->reg_mutex); 201 if (left_reg == right_reg) { 202 left = (ak4531->regs[left_reg] & ~((mask << left_shift) | (mask << right_shift))) | left | right; 203 change = left != ak4531->regs[left_reg]; 204 ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left); 205 } else { 206 left = (ak4531->regs[left_reg] & ~(mask << left_shift)) | left; 207 right = (ak4531->regs[right_reg] & ~(mask << right_shift)) | right; 208 change = left != ak4531->regs[left_reg] || right != ak4531->regs[right_reg]; 209 ak4531->write(ak4531, left_reg, ak4531->regs[left_reg] = left); 210 ak4531->write(ak4531, right_reg, ak4531->regs[right_reg] = right); 211 } 212 mutex_unlock(&ak4531->reg_mutex); 213 return change; 214 } 215 216 #define AK4531_INPUT_SW(xname, xindex, reg1, reg2, left_shift, right_shift) \ 217 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 218 .info = snd_ak4531_info_input_sw, \ 219 .get = snd_ak4531_get_input_sw, .put = snd_ak4531_put_input_sw, \ 220 .private_value = reg1 | (reg2 << 8) | (left_shift << 16) | (right_shift << 24) } 221 222 static int snd_ak4531_info_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 223 { 224 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 225 uinfo->count = 4; 226 uinfo->value.integer.min = 0; 227 uinfo->value.integer.max = 1; 228 return 0; 229 } 230 231 static int snd_ak4531_get_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 232 { 233 struct snd_ak4531 *ak4531 = snd_kcontrol_chip(kcontrol); 234 int reg1 = kcontrol->private_value & 0xff; 235 int reg2 = (kcontrol->private_value >> 8) & 0xff; 236 int left_shift = (kcontrol->private_value >> 16) & 0x0f; 237 int right_shift = (kcontrol->private_value >> 24) & 0x0f; 238 239 mutex_lock(&ak4531->reg_mutex); 240 ucontrol->value.integer.value[0] = (ak4531->regs[reg1] >> left_shift) & 1; 241 ucontrol->value.integer.value[1] = (ak4531->regs[reg2] >> left_shift) & 1; 242 ucontrol->value.integer.value[2] = (ak4531->regs[reg1] >> right_shift) & 1; 243 ucontrol->value.integer.value[3] = (ak4531->regs[reg2] >> right_shift) & 1; 244 mutex_unlock(&ak4531->reg_mutex); 245 return 0; 246 } 247 248 static int snd_ak4531_put_input_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 249 { 250 struct snd_ak4531 *ak4531 = snd_kcontrol_chip(kcontrol); 251 int reg1 = kcontrol->private_value & 0xff; 252 int reg2 = (kcontrol->private_value >> 8) & 0xff; 253 int left_shift = (kcontrol->private_value >> 16) & 0x0f; 254 int right_shift = (kcontrol->private_value >> 24) & 0x0f; 255 int change; 256 int val1, val2; 257 258 mutex_lock(&ak4531->reg_mutex); 259 val1 = ak4531->regs[reg1] & ~((1 << left_shift) | (1 << right_shift)); 260 val2 = ak4531->regs[reg2] & ~((1 << left_shift) | (1 << right_shift)); 261 val1 |= (ucontrol->value.integer.value[0] & 1) << left_shift; 262 val2 |= (ucontrol->value.integer.value[1] & 1) << left_shift; 263 val1 |= (ucontrol->value.integer.value[2] & 1) << right_shift; 264 val2 |= (ucontrol->value.integer.value[3] & 1) << right_shift; 265 change = val1 != ak4531->regs[reg1] || val2 != ak4531->regs[reg2]; 266 ak4531->write(ak4531, reg1, ak4531->regs[reg1] = val1); 267 ak4531->write(ak4531, reg2, ak4531->regs[reg2] = val2); 268 mutex_unlock(&ak4531->reg_mutex); 269 return change; 270 } 271 272 static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); 273 static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); 274 static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); 275 276 static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = { 277 278 AK4531_DOUBLE_TLV("Master Playback Switch", 0, 279 AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, 280 db_scale_master), 281 AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), 282 283 AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1, 284 db_scale_mono), 285 AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), 286 287 AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), 288 AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1, 289 db_scale_input), 290 AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), 291 AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), 292 293 AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), 294 AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1, 295 db_scale_input), 296 AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), 297 AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), 298 299 AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), 300 AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1, 301 db_scale_input), 302 AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), 303 AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), 304 305 AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), 306 AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1, 307 db_scale_input), 308 AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), 309 AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), 310 311 AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), 312 AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1, 313 db_scale_input), 314 AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), 315 AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), 316 317 AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), 318 AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input), 319 AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), 320 AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), 321 322 AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), 323 AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input), 324 AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), 325 AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), 326 327 AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input), 328 AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), 329 AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), 330 AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), 331 332 AK4531_DOUBLE("Mic Bypass Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 7, 7, 1, 0), 333 AK4531_DOUBLE("Mono1 Bypass Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 6, 6, 1, 0), 334 AK4531_DOUBLE("Mono2 Bypass Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 5, 5, 1, 0), 335 336 AK4531_SINGLE("AD Input Select", 0, AK4531_AD_IN, 0, 1, 0), 337 AK4531_SINGLE("Mic Boost (+30dB)", 0, AK4531_MIC_GAIN, 0, 1, 0) 338 }; 339 340 static int snd_ak4531_free(struct snd_ak4531 *ak4531) 341 { 342 if (ak4531) { 343 if (ak4531->private_free) 344 ak4531->private_free(ak4531); 345 kfree(ak4531); 346 } 347 return 0; 348 } 349 350 static int snd_ak4531_dev_free(struct snd_device *device) 351 { 352 struct snd_ak4531 *ak4531 = device->device_data; 353 return snd_ak4531_free(ak4531); 354 } 355 356 static u8 snd_ak4531_initial_map[0x19 + 1] = { 357 0x9f, /* 00: Master Volume Lch */ 358 0x9f, /* 01: Master Volume Rch */ 359 0x9f, /* 02: Voice Volume Lch */ 360 0x9f, /* 03: Voice Volume Rch */ 361 0x9f, /* 04: FM Volume Lch */ 362 0x9f, /* 05: FM Volume Rch */ 363 0x9f, /* 06: CD Audio Volume Lch */ 364 0x9f, /* 07: CD Audio Volume Rch */ 365 0x9f, /* 08: Line Volume Lch */ 366 0x9f, /* 09: Line Volume Rch */ 367 0x9f, /* 0a: Aux Volume Lch */ 368 0x9f, /* 0b: Aux Volume Rch */ 369 0x9f, /* 0c: Mono1 Volume */ 370 0x9f, /* 0d: Mono2 Volume */ 371 0x9f, /* 0e: Mic Volume */ 372 0x87, /* 0f: Mono-out Volume */ 373 0x00, /* 10: Output Mixer SW1 */ 374 0x00, /* 11: Output Mixer SW2 */ 375 0x00, /* 12: Lch Input Mixer SW1 */ 376 0x00, /* 13: Rch Input Mixer SW1 */ 377 0x00, /* 14: Lch Input Mixer SW2 */ 378 0x00, /* 15: Rch Input Mixer SW2 */ 379 0x00, /* 16: Reset & Power Down */ 380 0x00, /* 17: Clock Select */ 381 0x00, /* 18: AD Input Select */ 382 0x01 /* 19: Mic Amp Setup */ 383 }; 384 385 int __devinit snd_ak4531_mixer(struct snd_card *card, 386 struct snd_ak4531 *_ak4531, 387 struct snd_ak4531 **rak4531) 388 { 389 unsigned int idx; 390 int err; 391 struct snd_ak4531 *ak4531; 392 static struct snd_device_ops ops = { 393 .dev_free = snd_ak4531_dev_free, 394 }; 395 396 if (snd_BUG_ON(!card || !_ak4531)) 397 return -EINVAL; 398 if (rak4531) 399 *rak4531 = NULL; 400 ak4531 = kzalloc(sizeof(*ak4531), GFP_KERNEL); 401 if (ak4531 == NULL) 402 return -ENOMEM; 403 *ak4531 = *_ak4531; 404 mutex_init(&ak4531->reg_mutex); 405 if ((err = snd_component_add(card, "AK4531")) < 0) { 406 snd_ak4531_free(ak4531); 407 return err; 408 } 409 strcpy(card->mixername, "Asahi Kasei AK4531"); 410 ak4531->write(ak4531, AK4531_RESET, 0x03); /* no RST, PD */ 411 udelay(100); 412 ak4531->write(ak4531, AK4531_CLOCK, 0x00); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off LRCLK2 PLL */ 413 for (idx = 0; idx <= 0x19; idx++) { 414 if (idx == AK4531_RESET || idx == AK4531_CLOCK) 415 continue; 416 ak4531->write(ak4531, idx, ak4531->regs[idx] = snd_ak4531_initial_map[idx]); /* recording source is mixer */ 417 } 418 for (idx = 0; idx < ARRAY_SIZE(snd_ak4531_controls); idx++) { 419 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ak4531_controls[idx], ak4531))) < 0) { 420 snd_ak4531_free(ak4531); 421 return err; 422 } 423 } 424 snd_ak4531_proc_init(card, ak4531); 425 if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ak4531, &ops)) < 0) { 426 snd_ak4531_free(ak4531); 427 return err; 428 } 429 430 #if 0 431 snd_ak4531_dump(ak4531); 432 #endif 433 if (rak4531) 434 *rak4531 = ak4531; 435 return 0; 436 } 437 438 /* 439 * power management 440 */ 441 #ifdef CONFIG_PM 442 void snd_ak4531_suspend(struct snd_ak4531 *ak4531) 443 { 444 /* mute */ 445 ak4531->write(ak4531, AK4531_LMASTER, 0x9f); 446 ak4531->write(ak4531, AK4531_RMASTER, 0x9f); 447 /* powerdown */ 448 ak4531->write(ak4531, AK4531_RESET, 0x01); 449 } 450 451 void snd_ak4531_resume(struct snd_ak4531 *ak4531) 452 { 453 int idx; 454 455 /* initialize */ 456 ak4531->write(ak4531, AK4531_RESET, 0x03); 457 udelay(100); 458 ak4531->write(ak4531, AK4531_CLOCK, 0x00); 459 /* restore mixer registers */ 460 for (idx = 0; idx <= 0x19; idx++) { 461 if (idx == AK4531_RESET || idx == AK4531_CLOCK) 462 continue; 463 ak4531->write(ak4531, idx, ak4531->regs[idx]); 464 } 465 } 466 #endif 467 468 #ifdef CONFIG_PROC_FS 469 /* 470 * /proc interface 471 */ 472 473 static void snd_ak4531_proc_read(struct snd_info_entry *entry, 474 struct snd_info_buffer *buffer) 475 { 476 struct snd_ak4531 *ak4531 = entry->private_data; 477 478 snd_iprintf(buffer, "Asahi Kasei AK4531\n\n"); 479 snd_iprintf(buffer, "Recording source : %s\n" 480 "MIC gain : %s\n", 481 ak4531->regs[AK4531_AD_IN] & 1 ? "external" : "mixer", 482 ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); 483 } 484 485 static void __devinit 486 snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) 487 { 488 struct snd_info_entry *entry; 489 490 if (! snd_card_proc_new(card, "ak4531", &entry)) 491 snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); 492 } 493 #endif 494