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