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