diff options
Diffstat (limited to 'sound/pci/ac97')
-rw-r--r-- | sound/pci/ac97/Makefile | 3 | ||||
-rw-r--r-- | sound/pci/ac97/ak4531_codec.c | 508 |
2 files changed, 0 insertions, 511 deletions
diff --git a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile index ae36950f2568..41fa322f0971 100644 --- a/sound/pci/ac97/Makefile +++ b/sound/pci/ac97/Makefile | |||
@@ -6,8 +6,5 @@ | |||
6 | snd-ac97-codec-y := ac97_codec.o ac97_pcm.o | 6 | snd-ac97-codec-y := ac97_codec.o ac97_pcm.o |
7 | snd-ac97-codec-$(CONFIG_PROC_FS) += ac97_proc.o | 7 | snd-ac97-codec-$(CONFIG_PROC_FS) += ac97_proc.o |
8 | 8 | ||
9 | snd-ak4531-codec-objs := ak4531_codec.o | ||
10 | |||
11 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
12 | obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o | 10 | obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o |
13 | obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o | ||
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c deleted file mode 100644 index c0c1633999ea..000000000000 --- a/sound/pci/ac97/ak4531_codec.c +++ /dev/null | |||
@@ -1,508 +0,0 @@ | |||
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 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); | ||
32 | MODULE_DESCRIPTION("Universal routines for AK4531 codec"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | |||
35 | #ifdef CONFIG_PROC_FS | ||
36 | static 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 | |||
47 | static 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 | |||
75 | static 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 | |||
86 | static 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 | |||
105 | static 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 | |||
142 | static 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 | |||
153 | static 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 | |||
177 | static 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 | |||
219 | static 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 | |||
228 | static 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 | |||
245 | static 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 | |||
269 | static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); | ||
270 | static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); | ||
271 | static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); | ||
272 | |||
273 | static struct snd_kcontrol_new snd_ak4531_controls[] = { | ||
274 | |||
275 | AK4531_DOUBLE_TLV("Master Playback Switch", 0, | ||
276 | AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, | ||
277 | db_scale_master), | ||
278 | AK4531_DOUBLE("Master Playback Volume", 0, AK4531_LMASTER, AK4531_RMASTER, 0, 0, 0x1f, 1), | ||
279 | |||
280 | AK4531_SINGLE_TLV("Master Mono Playback Switch", 0, AK4531_MONO_OUT, 7, 1, 1, | ||
281 | db_scale_mono), | ||
282 | AK4531_SINGLE("Master Mono Playback Volume", 0, AK4531_MONO_OUT, 0, 0x07, 1), | ||
283 | |||
284 | AK4531_DOUBLE("PCM Switch", 0, AK4531_LVOICE, AK4531_RVOICE, 7, 7, 1, 1), | ||
285 | AK4531_DOUBLE_TLV("PCM Volume", 0, AK4531_LVOICE, AK4531_RVOICE, 0, 0, 0x1f, 1, | ||
286 | db_scale_input), | ||
287 | AK4531_DOUBLE("PCM Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 3, 2, 1, 0), | ||
288 | AK4531_DOUBLE("PCM Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 2, 2, 1, 0), | ||
289 | |||
290 | AK4531_DOUBLE("PCM Switch", 1, AK4531_LFM, AK4531_RFM, 7, 7, 1, 1), | ||
291 | AK4531_DOUBLE_TLV("PCM Volume", 1, AK4531_LFM, AK4531_RFM, 0, 0, 0x1f, 1, | ||
292 | db_scale_input), | ||
293 | AK4531_DOUBLE("PCM Playback Switch", 1, AK4531_OUT_SW1, AK4531_OUT_SW1, 6, 5, 1, 0), | ||
294 | AK4531_INPUT_SW("PCM Capture Route", 1, AK4531_LIN_SW1, AK4531_RIN_SW1, 6, 5), | ||
295 | |||
296 | AK4531_DOUBLE("CD Switch", 0, AK4531_LCD, AK4531_RCD, 7, 7, 1, 1), | ||
297 | AK4531_DOUBLE_TLV("CD Volume", 0, AK4531_LCD, AK4531_RCD, 0, 0, 0x1f, 1, | ||
298 | db_scale_input), | ||
299 | AK4531_DOUBLE("CD Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 2, 1, 1, 0), | ||
300 | AK4531_INPUT_SW("CD Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 2, 1), | ||
301 | |||
302 | AK4531_DOUBLE("Line Switch", 0, AK4531_LLINE, AK4531_RLINE, 7, 7, 1, 1), | ||
303 | AK4531_DOUBLE_TLV("Line Volume", 0, AK4531_LLINE, AK4531_RLINE, 0, 0, 0x1f, 1, | ||
304 | db_scale_input), | ||
305 | AK4531_DOUBLE("Line Playback Switch", 0, AK4531_OUT_SW1, AK4531_OUT_SW1, 4, 3, 1, 0), | ||
306 | AK4531_INPUT_SW("Line Capture Route", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 4, 3), | ||
307 | |||
308 | AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), | ||
309 | AK4531_DOUBLE_TLV("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1, | ||
310 | db_scale_input), | ||
311 | AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), | ||
312 | AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), | ||
313 | |||
314 | AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), | ||
315 | AK4531_SINGLE_TLV("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1, db_scale_input), | ||
316 | AK4531_SINGLE("Mono Playback Switch", 0, AK4531_OUT_SW2, 0, 1, 0), | ||
317 | AK4531_DOUBLE("Mono Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 0, 0, 1, 0), | ||
318 | |||
319 | AK4531_SINGLE("Mono Switch", 1, AK4531_MONO2, 7, 1, 1), | ||
320 | AK4531_SINGLE_TLV("Mono Volume", 1, AK4531_MONO2, 0, 0x1f, 1, db_scale_input), | ||
321 | AK4531_SINGLE("Mono Playback Switch", 1, AK4531_OUT_SW2, 1, 1, 0), | ||
322 | AK4531_DOUBLE("Mono Capture Switch", 1, AK4531_LIN_SW2, AK4531_RIN_SW2, 1, 1, 1, 0), | ||
323 | |||
324 | AK4531_SINGLE_TLV("Mic Volume", 0, AK4531_MIC, 0, 0x1f, 1, db_scale_input), | ||
325 | AK4531_SINGLE("Mic Switch", 0, AK4531_MIC, 7, 1, 1), | ||
326 | AK4531_SINGLE("Mic Playback Switch", 0, AK4531_OUT_SW1, 0, 1, 0), | ||
327 | AK4531_DOUBLE("Mic Capture Switch", 0, AK4531_LIN_SW1, AK4531_RIN_SW1, 0, 0, 1, 0), | ||
328 | |||
329 | AK4531_DOUBLE("Mic Bypass Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 7, 7, 1, 0), | ||
330 | AK4531_DOUBLE("Mono1 Bypass Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 6, 6, 1, 0), | ||
331 | AK4531_DOUBLE("Mono2 Bypass Capture Switch", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 5, 5, 1, 0), | ||
332 | |||
333 | AK4531_SINGLE("AD Input Select", 0, AK4531_AD_IN, 0, 1, 0), | ||
334 | AK4531_SINGLE("Mic Boost (+30dB)", 0, AK4531_MIC_GAIN, 0, 1, 0) | ||
335 | }; | ||
336 | |||
337 | static 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 | |||
347 | static 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 | |||
353 | static 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 | |||
382 | int snd_ak4531_mixer(struct snd_card *card, struct snd_ak4531 *_ak4531, | ||
383 | struct snd_ak4531 **rak4531) | ||
384 | { | ||
385 | unsigned int idx; | ||
386 | int err; | ||
387 | struct snd_ak4531 *ak4531; | ||
388 | static struct snd_device_ops ops = { | ||
389 | .dev_free = snd_ak4531_dev_free, | ||
390 | }; | ||
391 | |||
392 | snd_assert(rak4531 != NULL, return -EINVAL); | ||
393 | *rak4531 = NULL; | ||
394 | snd_assert(card != NULL && _ak4531 != NULL, return -EINVAL); | ||
395 | ak4531 = kzalloc(sizeof(*ak4531), GFP_KERNEL); | ||
396 | if (ak4531 == NULL) | ||
397 | return -ENOMEM; | ||
398 | *ak4531 = *_ak4531; | ||
399 | mutex_init(&ak4531->reg_mutex); | ||
400 | if ((err = snd_component_add(card, "AK4531")) < 0) { | ||
401 | snd_ak4531_free(ak4531); | ||
402 | return err; | ||
403 | } | ||
404 | strcpy(card->mixername, "Asahi Kasei AK4531"); | ||
405 | ak4531->write(ak4531, AK4531_RESET, 0x03); /* no RST, PD */ | ||
406 | udelay(100); | ||
407 | ak4531->write(ak4531, AK4531_CLOCK, 0x00); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off LRCLK2 PLL */ | ||
408 | for (idx = 0; idx <= 0x19; idx++) { | ||
409 | if (idx == AK4531_RESET || idx == AK4531_CLOCK) | ||
410 | continue; | ||
411 | ak4531->write(ak4531, idx, ak4531->regs[idx] = snd_ak4531_initial_map[idx]); /* recording source is mixer */ | ||
412 | } | ||
413 | for (idx = 0; idx < ARRAY_SIZE(snd_ak4531_controls); idx++) { | ||
414 | if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ak4531_controls[idx], ak4531))) < 0) { | ||
415 | snd_ak4531_free(ak4531); | ||
416 | return err; | ||
417 | } | ||
418 | } | ||
419 | snd_ak4531_proc_init(card, ak4531); | ||
420 | if ((err = snd_device_new(card, SNDRV_DEV_CODEC, ak4531, &ops)) < 0) { | ||
421 | snd_ak4531_free(ak4531); | ||
422 | return err; | ||
423 | } | ||
424 | |||
425 | #if 0 | ||
426 | snd_ak4531_dump(ak4531); | ||
427 | #endif | ||
428 | *rak4531 = ak4531; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * power management | ||
434 | */ | ||
435 | #ifdef CONFIG_PM | ||
436 | void snd_ak4531_suspend(struct snd_ak4531 *ak4531) | ||
437 | { | ||
438 | /* mute */ | ||
439 | ak4531->write(ak4531, AK4531_LMASTER, 0x9f); | ||
440 | ak4531->write(ak4531, AK4531_RMASTER, 0x9f); | ||
441 | /* powerdown */ | ||
442 | ak4531->write(ak4531, AK4531_RESET, 0x01); | ||
443 | } | ||
444 | |||
445 | void snd_ak4531_resume(struct snd_ak4531 *ak4531) | ||
446 | { | ||
447 | int idx; | ||
448 | |||
449 | /* initialize */ | ||
450 | ak4531->write(ak4531, AK4531_RESET, 0x03); | ||
451 | udelay(100); | ||
452 | ak4531->write(ak4531, AK4531_CLOCK, 0x00); | ||
453 | /* restore mixer registers */ | ||
454 | for (idx = 0; idx <= 0x19; idx++) { | ||
455 | if (idx == AK4531_RESET || idx == AK4531_CLOCK) | ||
456 | continue; | ||
457 | ak4531->write(ak4531, idx, ak4531->regs[idx]); | ||
458 | } | ||
459 | } | ||
460 | #endif | ||
461 | |||
462 | #ifdef CONFIG_PROC_FS | ||
463 | /* | ||
464 | * /proc interface | ||
465 | */ | ||
466 | |||
467 | static void snd_ak4531_proc_read(struct snd_info_entry *entry, | ||
468 | struct snd_info_buffer *buffer) | ||
469 | { | ||
470 | struct snd_ak4531 *ak4531 = entry->private_data; | ||
471 | |||
472 | snd_iprintf(buffer, "Asahi Kasei AK4531\n\n"); | ||
473 | snd_iprintf(buffer, "Recording source : %s\n" | ||
474 | "MIC gain : %s\n", | ||
475 | ak4531->regs[AK4531_AD_IN] & 1 ? "external" : "mixer", | ||
476 | ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); | ||
477 | } | ||
478 | |||
479 | static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) | ||
480 | { | ||
481 | struct snd_info_entry *entry; | ||
482 | |||
483 | if (! snd_card_proc_new(card, "ak4531", &entry)) | ||
484 | snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); | ||
485 | } | ||
486 | #endif | ||
487 | |||
488 | EXPORT_SYMBOL(snd_ak4531_mixer); | ||
489 | #ifdef CONFIG_PM | ||
490 | EXPORT_SYMBOL(snd_ak4531_suspend); | ||
491 | EXPORT_SYMBOL(snd_ak4531_resume); | ||
492 | #endif | ||
493 | |||
494 | /* | ||
495 | * INIT part | ||
496 | */ | ||
497 | |||
498 | static int __init alsa_ak4531_init(void) | ||
499 | { | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static void __exit alsa_ak4531_exit(void) | ||
504 | { | ||
505 | } | ||
506 | |||
507 | module_init(alsa_ak4531_init) | ||
508 | module_exit(alsa_ak4531_exit) | ||