diff options
author | Shin-ya Okada <sh_okada at d4.dion.ne.jp> | 2007-10-23 09:08:18 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:09 -0500 |
commit | f31639b8c5916f58441b529c9c364715921b29af (patch) | |
tree | 799ccf968dcc87215674fbb8cd686ea1ef881301 /sound/pci/ice1712/se.c | |
parent | 18fe4ac25811ff4006844b6e575acdc9103cbaba (diff) |
[ALSA] ice1724 - Add support of Onkyo SE-90PCI and SE-200PCI
Added the support for Onkyo SE-90PCI and SE-200PCI boards.
Signed-off-by: Shin-ya Okada <sh_okada at d4.dion.ne.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/ice1712/se.c')
-rw-r--r-- | sound/pci/ice1712/se.c | 700 |
1 files changed, 700 insertions, 0 deletions
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c new file mode 100644 index 000000000000..ebfe2454a08b --- /dev/null +++ b/sound/pci/ice1712/se.c | |||
@@ -0,0 +1,700 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for ONKYO WAVIO SE-90PCI and SE-200PCI | ||
5 | * | ||
6 | * Copyright (c) 2007 Shin-ya Okada sh_okada(at)d4.dion.ne.jp | ||
7 | * (at) -> @ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <sound/driver.h> | ||
26 | #include <asm/io.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <sound/core.h> | ||
32 | #include <sound/tlv.h> | ||
33 | |||
34 | #include "ice1712.h" | ||
35 | #include "envy24ht.h" | ||
36 | #include "se.h" | ||
37 | |||
38 | |||
39 | /****************************************************************************/ | ||
40 | /* ONKYO WAVIO SE-200PCI */ | ||
41 | /****************************************************************************/ | ||
42 | /* | ||
43 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
44 | * XIN1 49.152MHz | ||
45 | * not have UART | ||
46 | * one stereo ADC and a S/PDIF receiver connected | ||
47 | * four stereo DACs connected | ||
48 | * | ||
49 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
50 | * use I2C, not use AC97 | ||
51 | * | ||
52 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
53 | * I2S codec has no volume/mute control feature | ||
54 | * I2S codec supports 96KHz and 192KHz | ||
55 | * I2S codec 24bits | ||
56 | * | ||
57 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
58 | * Enable integrated S/PDIF transmitter | ||
59 | * internal S/PDIF out implemented | ||
60 | * S/PDIF is stereo | ||
61 | * External S/PDIF out implemented | ||
62 | * | ||
63 | * | ||
64 | * ** connected chips ** | ||
65 | * | ||
66 | * WM8740 | ||
67 | * A 2ch-DAC of main outputs. | ||
68 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
69 | * The sample-rate are automatically changed. | ||
70 | * ML/I2S (28pin) --------+ | ||
71 | * MC/DM1 (27pin) -- 5V | | ||
72 | * MD/DM0 (26pin) -- GND | | ||
73 | * MUTEB (25pin) -- NC | | ||
74 | * MODE (24pin) -- GND | | ||
75 | * CSBIW (23pin) --------+ | ||
76 | * | | ||
77 | * RSTB (22pin) --R(1K)-+ | ||
78 | * Probably it reduce the noise from the control line. | ||
79 | * | ||
80 | * WM8766 | ||
81 | * A 6ch-DAC for surrounds. | ||
82 | * It's control wire was connected to GPIOxx (3-wire serial interface) | ||
83 | * ML/I2S (11pin) -- GPIO18 | ||
84 | * MC/IWL (12pin) -- GPIO17 | ||
85 | * MD/DM (13pin) -- GPIO16 | ||
86 | * MUTE (14pin) -- GPIO01 | ||
87 | * | ||
88 | * WM8776 | ||
89 | * A 2ch-ADC(with 10ch-selector) plus 2ch-DAC. | ||
90 | * It's control wire was connected to SDA/SCLK (2-wire serial interface) | ||
91 | * MODE (16pin) -- R(1K) -- GND | ||
92 | * CE (17pin) -- R(1K) -- GND 2-wire mode (address=0x34) | ||
93 | * DI (18pin) -- SDA | ||
94 | * CL (19pin) -- SCLK | ||
95 | * | ||
96 | * | ||
97 | * ** output pins and device names ** | ||
98 | * | ||
99 | * 7.1ch name -- output connector color -- device (-D option) | ||
100 | * | ||
101 | * FRONT 2ch -- green -- plughw:0,0 | ||
102 | * CENTER(Lch) SUBWOOFER(Rch) -- black -- plughw:0,2,0 | ||
103 | * SURROUND 2ch -- orange -- plughw:0,2,1 | ||
104 | * SURROUND BACK 2ch -- white -- plughw:0,2,2 | ||
105 | * | ||
106 | */ | ||
107 | |||
108 | |||
109 | /****************************************************************************/ | ||
110 | /* WM8740 interface */ | ||
111 | /****************************************************************************/ | ||
112 | |||
113 | static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice) | ||
114 | { | ||
115 | /* nothing to do */ | ||
116 | } | ||
117 | |||
118 | |||
119 | static void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice, | ||
120 | unsigned int rate) | ||
121 | { | ||
122 | /* nothing to do */ | ||
123 | } | ||
124 | |||
125 | |||
126 | /****************************************************************************/ | ||
127 | /* WM8766 interface */ | ||
128 | /****************************************************************************/ | ||
129 | |||
130 | static void se200pci_WM8766_write(struct snd_ice1712 *ice, | ||
131 | unsigned int addr, unsigned int data) | ||
132 | { | ||
133 | unsigned int st; | ||
134 | unsigned int bits; | ||
135 | int i; | ||
136 | const unsigned int DATA = 0x010000; | ||
137 | const unsigned int CLOCK = 0x020000; | ||
138 | const unsigned int LOAD = 0x040000; | ||
139 | const unsigned int ALL_MASK = (DATA | CLOCK | LOAD); | ||
140 | |||
141 | snd_ice1712_save_gpio_status(ice); | ||
142 | |||
143 | st = ((addr & 0x7f) << 9) | (data & 0x1ff); | ||
144 | snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK); | ||
145 | snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK); | ||
146 | bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK; | ||
147 | |||
148 | snd_ice1712_gpio_write(ice, bits); | ||
149 | for (i = 0; i < 16; i++) { | ||
150 | udelay(1); | ||
151 | bits &= ~CLOCK; | ||
152 | st = (st << 1); | ||
153 | if (st & 0x10000) | ||
154 | bits |= DATA; | ||
155 | else | ||
156 | bits &= ~DATA; | ||
157 | |||
158 | snd_ice1712_gpio_write(ice, bits); | ||
159 | |||
160 | udelay(1); | ||
161 | bits |= CLOCK; | ||
162 | snd_ice1712_gpio_write(ice, bits); | ||
163 | } | ||
164 | |||
165 | udelay(1); | ||
166 | bits |= LOAD; | ||
167 | snd_ice1712_gpio_write(ice, bits); | ||
168 | |||
169 | udelay(1); | ||
170 | bits |= (DATA | CLOCK); | ||
171 | snd_ice1712_gpio_write(ice, bits); | ||
172 | |||
173 | snd_ice1712_restore_gpio_status(ice); | ||
174 | } | ||
175 | |||
176 | static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch, | ||
177 | unsigned int vol1, unsigned int vol2) | ||
178 | { | ||
179 | switch (ch) { | ||
180 | case 0: | ||
181 | se200pci_WM8766_write(ice, 0x000, vol1); | ||
182 | se200pci_WM8766_write(ice, 0x001, vol2 | 0x100); | ||
183 | break; | ||
184 | case 1: | ||
185 | se200pci_WM8766_write(ice, 0x004, vol1); | ||
186 | se200pci_WM8766_write(ice, 0x005, vol2 | 0x100); | ||
187 | break; | ||
188 | case 2: | ||
189 | se200pci_WM8766_write(ice, 0x006, vol1); | ||
190 | se200pci_WM8766_write(ice, 0x007, vol2 | 0x100); | ||
191 | break; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice) | ||
196 | { | ||
197 | se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */ | ||
198 | udelay(10); | ||
199 | |||
200 | se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */ | ||
201 | se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */ | ||
202 | se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */ | ||
203 | |||
204 | se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */ | ||
205 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
206 | se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */ | ||
207 | se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */ | ||
208 | se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */ | ||
209 | |||
210 | se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */ | ||
211 | se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */ | ||
212 | } | ||
213 | |||
214 | static void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice, | ||
215 | unsigned int rate) | ||
216 | { | ||
217 | if (rate > 96000) | ||
218 | se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */ | ||
219 | else | ||
220 | se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */ | ||
221 | } | ||
222 | |||
223 | |||
224 | /****************************************************************************/ | ||
225 | /* WM8776 interface */ | ||
226 | /****************************************************************************/ | ||
227 | |||
228 | static void se200pci_WM8776_write(struct snd_ice1712 *ice, | ||
229 | unsigned int addr, unsigned int data) | ||
230 | { | ||
231 | unsigned int val; | ||
232 | |||
233 | val = (addr << 9) | data; | ||
234 | snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff); | ||
235 | } | ||
236 | |||
237 | |||
238 | static void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice, | ||
239 | unsigned int vol1, unsigned int vol2) | ||
240 | { | ||
241 | se200pci_WM8776_write(ice, 0x03, vol1); | ||
242 | se200pci_WM8776_write(ice, 0x04, vol2 | 0x100); | ||
243 | } | ||
244 | |||
245 | static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice, | ||
246 | unsigned int vol1, unsigned int vol2) | ||
247 | { | ||
248 | se200pci_WM8776_write(ice, 0x0e, vol1); | ||
249 | se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100); | ||
250 | } | ||
251 | |||
252 | static const char *se200pci_sel[] = { | ||
253 | "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL | ||
254 | }; | ||
255 | |||
256 | static void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice, | ||
257 | unsigned int sel) | ||
258 | { | ||
259 | static unsigned char vals[] = { | ||
260 | /* LINE, CD, MIC, ALL, GND */ | ||
261 | 0x10, 0x04, 0x08, 0x1c, 0x03 | ||
262 | }; | ||
263 | if (sel > 4) | ||
264 | sel = 4; | ||
265 | se200pci_WM8776_write(ice, 0x15, vals[sel]); | ||
266 | } | ||
267 | |||
268 | static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl) | ||
269 | { | ||
270 | /* AFL -- After Fader Listening */ | ||
271 | if (afl) | ||
272 | se200pci_WM8776_write(ice, 0x16, 0x005); | ||
273 | else | ||
274 | se200pci_WM8776_write(ice, 0x16, 0x001); | ||
275 | } | ||
276 | |||
277 | static const char *se200pci_agc[] = { | ||
278 | "Off", "LimiterMode", "ALCMode", NULL | ||
279 | }; | ||
280 | |||
281 | static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc) | ||
282 | { | ||
283 | /* AGC -- Auto Gain Control of the input */ | ||
284 | switch (agc) { | ||
285 | case 0: | ||
286 | se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */ | ||
287 | break; | ||
288 | case 1: | ||
289 | se200pci_WM8776_write(ice, 0x10, 0x07b); | ||
290 | se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */ | ||
291 | break; | ||
292 | case 2: | ||
293 | se200pci_WM8776_write(ice, 0x10, 0x1fb); | ||
294 | se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */ | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice) | ||
300 | { | ||
301 | int i; | ||
302 | static unsigned short __devinitdata default_values[] = { | ||
303 | 0x100, 0x100, 0x100, | ||
304 | 0x100, 0x100, 0x100, | ||
305 | 0x000, 0x090, 0x000, 0x000, | ||
306 | 0x022, 0x022, 0x022, | ||
307 | 0x008, 0x0cf, 0x0cf, 0x07b, 0x000, | ||
308 | 0x032, 0x000, 0x0a6, 0x001, 0x001 | ||
309 | }; | ||
310 | |||
311 | se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */ | ||
312 | /* ADC and DAC interface is I2S 24bits mode */ | ||
313 | /* The sample-rate are automatically changed */ | ||
314 | udelay(10); | ||
315 | /* BUT my board can not do reset all, so I load all by manually. */ | ||
316 | for (i = 0; i < ARRAY_SIZE(default_values); i++) | ||
317 | se200pci_WM8776_write(ice, i, default_values[i]); | ||
318 | |||
319 | se200pci_WM8776_set_input_selector(ice, 0); | ||
320 | se200pci_WM8776_set_afl(ice, 0); | ||
321 | se200pci_WM8776_set_agc(ice, 0); | ||
322 | se200pci_WM8776_set_input_volume(ice, 0, 0); | ||
323 | se200pci_WM8776_set_output_volume(ice, 0, 0); | ||
324 | |||
325 | /* head phone mute and power down */ | ||
326 | se200pci_WM8776_write(ice, 0x00, 0); | ||
327 | se200pci_WM8776_write(ice, 0x01, 0); | ||
328 | se200pci_WM8776_write(ice, 0x02, 0x100); | ||
329 | se200pci_WM8776_write(ice, 0x0d, 0x080); | ||
330 | } | ||
331 | |||
332 | static void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice, | ||
333 | unsigned int rate) | ||
334 | { | ||
335 | /* nothing to do */ | ||
336 | } | ||
337 | |||
338 | |||
339 | /****************************************************************************/ | ||
340 | /* runtime interface */ | ||
341 | /****************************************************************************/ | ||
342 | |||
343 | static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) | ||
344 | { | ||
345 | se200pci_WM8740_set_pro_rate(ice, rate); | ||
346 | se200pci_WM8766_set_pro_rate(ice, rate); | ||
347 | se200pci_WM8776_set_pro_rate(ice, rate); | ||
348 | } | ||
349 | |||
350 | struct se200pci_control { | ||
351 | char *name; | ||
352 | enum { | ||
353 | WM8766, | ||
354 | WM8776in, | ||
355 | WM8776out, | ||
356 | WM8776sel, | ||
357 | WM8776agc, | ||
358 | WM8776afl | ||
359 | } target; | ||
360 | enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type; | ||
361 | int ch; | ||
362 | const char **member; | ||
363 | const char *comment; | ||
364 | }; | ||
365 | |||
366 | static const struct se200pci_control se200pci_cont[] = { | ||
367 | { | ||
368 | .name = "Front Playback Volume", | ||
369 | .target = WM8776out, | ||
370 | .type = VOLUME1, | ||
371 | .comment = "Front(green)" | ||
372 | }, | ||
373 | { | ||
374 | .name = "Side Playback Volume", | ||
375 | .target = WM8766, | ||
376 | .type = VOLUME1, | ||
377 | .ch = 1, | ||
378 | .comment = "Surround(orange)" | ||
379 | }, | ||
380 | { | ||
381 | .name = "Surround Playback Volume", | ||
382 | .target = WM8766, | ||
383 | .type = VOLUME1, | ||
384 | .ch = 2, | ||
385 | .comment = "SurroundBack(white)" | ||
386 | }, | ||
387 | { | ||
388 | .name = "CLFE Playback Volume", | ||
389 | .target = WM8766, | ||
390 | .type = VOLUME1, | ||
391 | .ch = 0, | ||
392 | .comment = "Center(Lch)&SubWoofer(Rch)(black)" | ||
393 | }, | ||
394 | { | ||
395 | .name = "Capture Volume", | ||
396 | .target = WM8776in, | ||
397 | .type = VOLUME2 | ||
398 | }, | ||
399 | { | ||
400 | .name = "Capture Select", | ||
401 | .target = WM8776sel, | ||
402 | .type = ENUM, | ||
403 | .member = se200pci_sel | ||
404 | }, | ||
405 | { | ||
406 | .name = "AGC Capture Mode", | ||
407 | .target = WM8776agc, | ||
408 | .type = ENUM, | ||
409 | .member = se200pci_agc | ||
410 | }, | ||
411 | { | ||
412 | .name = "AFL Bypass Playback Switch", | ||
413 | .target = WM8776afl, | ||
414 | .type = BOOLEAN | ||
415 | } | ||
416 | }; | ||
417 | |||
418 | static int se200pci_cont_info(struct snd_kcontrol *kc, | ||
419 | struct snd_ctl_elem_info *uinfo) | ||
420 | { | ||
421 | struct snd_ice1712 *ice; | ||
422 | int n; | ||
423 | int c; | ||
424 | const char **member; | ||
425 | |||
426 | ice = snd_kcontrol_chip(kc); | ||
427 | n = kc->private_value; | ||
428 | |||
429 | if (se200pci_cont[n].type == VOLUME1 || | ||
430 | se200pci_cont[n].type == VOLUME2) { | ||
431 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
432 | uinfo->count = 2; | ||
433 | uinfo->value.integer.min = 0; /* mute */ | ||
434 | uinfo->value.integer.max = 0xff; /* 0dB */ | ||
435 | |||
436 | } else if (se200pci_cont[n].type == BOOLEAN) { | ||
437 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
438 | uinfo->count = 1; | ||
439 | uinfo->value.integer.min = 0; | ||
440 | uinfo->value.integer.max = 1; | ||
441 | |||
442 | } else if (se200pci_cont[n].type == ENUM) { | ||
443 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
444 | member = se200pci_cont[n].member; | ||
445 | if (member == NULL) | ||
446 | return -EINVAL; | ||
447 | for (c = 0; member[c]; c++) | ||
448 | ; | ||
449 | |||
450 | uinfo->count = 1; | ||
451 | uinfo->value.enumerated.items = c; | ||
452 | if (uinfo->value.enumerated.item >= c) | ||
453 | uinfo->value.enumerated.item = c - 1; | ||
454 | strcpy(uinfo->value.enumerated.name, | ||
455 | member[uinfo->value.enumerated.item]); | ||
456 | } | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int se200pci_cont_get(struct snd_kcontrol *kc, | ||
462 | struct snd_ctl_elem_value *uc) | ||
463 | { | ||
464 | struct snd_ice1712 *ice; | ||
465 | int n; | ||
466 | |||
467 | ice = snd_kcontrol_chip(kc); | ||
468 | n = kc->private_value; | ||
469 | if (se200pci_cont[n].type == VOLUME1 || | ||
470 | se200pci_cont[n].type == VOLUME2) { | ||
471 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; | ||
472 | uc->value.integer.value[1] = ice->spec.se.vol[n].ch2; | ||
473 | |||
474 | } else if (se200pci_cont[n].type == BOOLEAN || | ||
475 | se200pci_cont[n].type == ENUM) | ||
476 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static int se200pci_cont_put(struct snd_kcontrol *kc, | ||
482 | struct snd_ctl_elem_value *uc) | ||
483 | { | ||
484 | struct snd_ice1712 *ice; | ||
485 | int n; | ||
486 | unsigned int vol1, vol2; | ||
487 | int changed; | ||
488 | |||
489 | ice = snd_kcontrol_chip(kc); | ||
490 | n = kc->private_value; | ||
491 | |||
492 | changed = 0; | ||
493 | vol1 = 0; vol2 = 0; | ||
494 | if (se200pci_cont[n].type == VOLUME1 || | ||
495 | se200pci_cont[n].type == VOLUME2) { | ||
496 | vol1 = uc->value.integer.value[0]; | ||
497 | vol2 = uc->value.integer.value[1]; | ||
498 | if (ice->spec.se.vol[n].ch1 != vol1) | ||
499 | changed = 1; | ||
500 | if (ice->spec.se.vol[n].ch2 != vol2) | ||
501 | changed = 1; | ||
502 | ice->spec.se.vol[n].ch1 = vol1; | ||
503 | ice->spec.se.vol[n].ch2 = vol2; | ||
504 | |||
505 | } else if (se200pci_cont[n].type == BOOLEAN || | ||
506 | se200pci_cont[n].type == ENUM) { | ||
507 | vol1 = uc->value.integer.value[0]; | ||
508 | if (ice->spec.se.vol[n].ch1 != vol1) | ||
509 | changed = 1; | ||
510 | ice->spec.se.vol[n].ch1 = vol1; | ||
511 | } | ||
512 | |||
513 | switch (se200pci_cont[n].target) { | ||
514 | case WM8766: | ||
515 | se200pci_WM8766_set_volume(ice, | ||
516 | se200pci_cont[n].ch, vol1, vol2); | ||
517 | break; | ||
518 | |||
519 | case WM8776in: | ||
520 | se200pci_WM8776_set_input_volume(ice, vol1, vol2); | ||
521 | break; | ||
522 | |||
523 | case WM8776out: | ||
524 | se200pci_WM8776_set_output_volume(ice, vol1, vol2); | ||
525 | break; | ||
526 | |||
527 | case WM8776sel: | ||
528 | se200pci_WM8776_set_input_selector(ice, vol1); | ||
529 | break; | ||
530 | |||
531 | case WM8776agc: | ||
532 | se200pci_WM8776_set_agc(ice, vol1); | ||
533 | break; | ||
534 | |||
535 | case WM8776afl: | ||
536 | se200pci_WM8776_set_afl(ice, vol1); | ||
537 | break; | ||
538 | |||
539 | default: | ||
540 | break; | ||
541 | } | ||
542 | |||
543 | return changed; | ||
544 | } | ||
545 | |||
546 | static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); | ||
547 | static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); | ||
548 | |||
549 | static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) | ||
550 | { | ||
551 | int i; | ||
552 | struct snd_kcontrol_new cont; | ||
553 | int err; | ||
554 | |||
555 | memset(&cont, 0, sizeof(cont)); | ||
556 | cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
557 | cont.info = se200pci_cont_info; | ||
558 | cont.get = se200pci_cont_get; | ||
559 | cont.put = se200pci_cont_put; | ||
560 | for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) { | ||
561 | cont.private_value = i; | ||
562 | cont.name = se200pci_cont[i].name; | ||
563 | cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
564 | cont.tlv.p = NULL; | ||
565 | if (se200pci_cont[i].type == VOLUME1 || | ||
566 | se200pci_cont[i].type == VOLUME2) { | ||
567 | |||
568 | cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
569 | |||
570 | if (se200pci_cont[i].type == VOLUME1) | ||
571 | cont.tlv.p = db_scale_gain1; | ||
572 | else | ||
573 | cont.tlv.p = db_scale_gain2; | ||
574 | } | ||
575 | err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice)); | ||
576 | if (err < 0) | ||
577 | return err; | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | |||
584 | /****************************************************************************/ | ||
585 | /* ONKYO WAVIO SE-90PCI */ | ||
586 | /****************************************************************************/ | ||
587 | /* | ||
588 | * system configuration ICE_EEP2_SYSCONF=0x4b | ||
589 | * AC-Link configuration ICE_EEP2_ACLINK=0x80 | ||
590 | * I2S converters feature ICE_EEP2_I2S=0x78 | ||
591 | * S/PDIF configuration ICE_EEP2_SPDIF=0xc3 | ||
592 | * | ||
593 | * ** connected chip ** | ||
594 | * | ||
595 | * WM8716 | ||
596 | * A 2ch-DAC of main outputs. | ||
597 | * It setuped as I2S mode by wire, so no way to setup from software. | ||
598 | * ML/I2S (28pin) -- +5V | ||
599 | * MC/DM1 (27pin) -- GND | ||
600 | * MC/DM0 (26pin) -- GND | ||
601 | * MUTEB (25pin) -- open (internal pull-up) | ||
602 | * MODE (24pin) -- GND | ||
603 | * CSBIWO (23pin) -- +5V | ||
604 | * | ||
605 | */ | ||
606 | |||
607 | /* Nothing to do for this chip. */ | ||
608 | |||
609 | |||
610 | /****************************************************************************/ | ||
611 | /* probe/initialize/setup */ | ||
612 | /****************************************************************************/ | ||
613 | |||
614 | static int __devinit se_init(struct snd_ice1712 *ice) | ||
615 | { | ||
616 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) { | ||
617 | ice->num_total_dacs = 2; | ||
618 | ice->num_total_adcs = 0; | ||
619 | ice->vt1720 = 1; | ||
620 | return 0; | ||
621 | |||
622 | } else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) { | ||
623 | ice->num_total_dacs = 8; | ||
624 | ice->num_total_adcs = 2; | ||
625 | se200pci_WM8740_init(ice); | ||
626 | se200pci_WM8766_init(ice); | ||
627 | se200pci_WM8776_init(ice); | ||
628 | ice->gpio.set_pro_rate = se200pci_set_pro_rate; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | return -ENOENT; | ||
633 | } | ||
634 | |||
635 | static int __devinit se_add_controls(struct snd_ice1712 *ice) | ||
636 | { | ||
637 | int err; | ||
638 | |||
639 | err = 0; | ||
640 | /* nothing to do for VT1724_SUBDEVICE_SE90PCI */ | ||
641 | if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) | ||
642 | err = se200pci_add_controls(ice); | ||
643 | |||
644 | return err; | ||
645 | } | ||
646 | |||
647 | |||
648 | /****************************************************************************/ | ||
649 | /* entry point */ | ||
650 | /****************************************************************************/ | ||
651 | |||
652 | static unsigned char se200pci_eeprom[] __devinitdata = { | ||
653 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
654 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
655 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
656 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
657 | |||
658 | [ICE_EEP2_GPIO_DIR] = 0x02, /* WM8766 mute 1=output */ | ||
659 | [ICE_EEP2_GPIO_DIR1] = 0x00, /* not used */ | ||
660 | [ICE_EEP2_GPIO_DIR2] = 0x07, /* WM8766 ML/MC/MD 1=output */ | ||
661 | |||
662 | [ICE_EEP2_GPIO_MASK] = 0x00, /* 0=writable */ | ||
663 | [ICE_EEP2_GPIO_MASK1] = 0x00, /* 0=writable */ | ||
664 | [ICE_EEP2_GPIO_MASK2] = 0x00, /* 0=writable */ | ||
665 | |||
666 | [ICE_EEP2_GPIO_STATE] = 0x00, /* WM8766 mute=0 */ | ||
667 | [ICE_EEP2_GPIO_STATE1] = 0x00, /* not used */ | ||
668 | [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */ | ||
669 | }; | ||
670 | |||
671 | static unsigned char se90pci_eeprom[] __devinitdata = { | ||
672 | [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ | ||
673 | [ICE_EEP2_ACLINK] = 0x80, /* I2S */ | ||
674 | [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ | ||
675 | [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ | ||
676 | |||
677 | /* ALL GPIO bits are in input mode */ | ||
678 | }; | ||
679 | |||
680 | struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = { | ||
681 | { | ||
682 | .subvendor = VT1724_SUBDEVICE_SE200PCI, | ||
683 | .name = "ONKYO SE200PCI", | ||
684 | .model = "se200pci", | ||
685 | .chip_init = se_init, | ||
686 | .build_controls = se_add_controls, | ||
687 | .eeprom_size = sizeof(se200pci_eeprom), | ||
688 | .eeprom_data = se200pci_eeprom, | ||
689 | }, | ||
690 | { | ||
691 | .subvendor = VT1724_SUBDEVICE_SE90PCI, | ||
692 | .name = "ONKYO SE90PCI", | ||
693 | .model = "se90pci", | ||
694 | .chip_init = se_init, | ||
695 | .build_controls = se_add_controls, | ||
696 | .eeprom_size = sizeof(se90pci_eeprom), | ||
697 | .eeprom_data = se90pci_eeprom, | ||
698 | }, | ||
699 | {} /*terminator*/ | ||
700 | }; | ||