blob: 69673b95869da9bfd855aa4aa05acdf24f4c6835 [file] [log] [blame]
Shin-ya Okadaf31639b2007-10-23 15:08:18 +02001/*
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
Shin-ya Okadaf31639b2007-10-23 15:08:18 +020025#include <asm/io.h>
26#include <linux/delay.h>
27#include <linux/interrupt.h>
28#include <linux/init.h>
29#include <linux/slab.h>
30#include <sound/core.h>
31#include <sound/tlv.h>
32
33#include "ice1712.h"
34#include "envy24ht.h"
35#include "se.h"
36
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010037struct se_spec {
38 struct {
39 unsigned char ch1, ch2;
40 } vol[8];
41};
Shin-ya Okadaf31639b2007-10-23 15:08:18 +020042
43/****************************************************************************/
44/* ONKYO WAVIO SE-200PCI */
45/****************************************************************************/
46/*
47 * system configuration ICE_EEP2_SYSCONF=0x4b
48 * XIN1 49.152MHz
49 * not have UART
50 * one stereo ADC and a S/PDIF receiver connected
51 * four stereo DACs connected
52 *
53 * AC-Link configuration ICE_EEP2_ACLINK=0x80
54 * use I2C, not use AC97
55 *
56 * I2S converters feature ICE_EEP2_I2S=0x78
57 * I2S codec has no volume/mute control feature
58 * I2S codec supports 96KHz and 192KHz
59 * I2S codec 24bits
60 *
61 * S/PDIF configuration ICE_EEP2_SPDIF=0xc3
62 * Enable integrated S/PDIF transmitter
63 * internal S/PDIF out implemented
64 * S/PDIF is stereo
65 * External S/PDIF out implemented
66 *
67 *
68 * ** connected chips **
69 *
70 * WM8740
71 * A 2ch-DAC of main outputs.
72 * It setuped as I2S mode by wire, so no way to setup from software.
73 * The sample-rate are automatically changed.
74 * ML/I2S (28pin) --------+
75 * MC/DM1 (27pin) -- 5V |
76 * MD/DM0 (26pin) -- GND |
77 * MUTEB (25pin) -- NC |
78 * MODE (24pin) -- GND |
79 * CSBIW (23pin) --------+
80 * |
81 * RSTB (22pin) --R(1K)-+
82 * Probably it reduce the noise from the control line.
83 *
84 * WM8766
85 * A 6ch-DAC for surrounds.
86 * It's control wire was connected to GPIOxx (3-wire serial interface)
87 * ML/I2S (11pin) -- GPIO18
88 * MC/IWL (12pin) -- GPIO17
89 * MD/DM (13pin) -- GPIO16
90 * MUTE (14pin) -- GPIO01
91 *
92 * WM8776
93 * A 2ch-ADC(with 10ch-selector) plus 2ch-DAC.
94 * It's control wire was connected to SDA/SCLK (2-wire serial interface)
95 * MODE (16pin) -- R(1K) -- GND
96 * CE (17pin) -- R(1K) -- GND 2-wire mode (address=0x34)
97 * DI (18pin) -- SDA
98 * CL (19pin) -- SCLK
99 *
100 *
101 * ** output pins and device names **
102 *
103 * 7.1ch name -- output connector color -- device (-D option)
104 *
105 * FRONT 2ch -- green -- plughw:0,0
106 * CENTER(Lch) SUBWOOFER(Rch) -- black -- plughw:0,2,0
107 * SURROUND 2ch -- orange -- plughw:0,2,1
108 * SURROUND BACK 2ch -- white -- plughw:0,2,2
109 *
110 */
111
112
113/****************************************************************************/
114/* WM8740 interface */
115/****************************************************************************/
116
117static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice)
118{
119 /* nothing to do */
120}
121
122
123static void se200pci_WM8740_set_pro_rate(struct snd_ice1712 *ice,
124 unsigned int rate)
125{
126 /* nothing to do */
127}
128
129
130/****************************************************************************/
131/* WM8766 interface */
132/****************************************************************************/
133
134static void se200pci_WM8766_write(struct snd_ice1712 *ice,
135 unsigned int addr, unsigned int data)
136{
137 unsigned int st;
138 unsigned int bits;
139 int i;
140 const unsigned int DATA = 0x010000;
141 const unsigned int CLOCK = 0x020000;
142 const unsigned int LOAD = 0x040000;
143 const unsigned int ALL_MASK = (DATA | CLOCK | LOAD);
144
145 snd_ice1712_save_gpio_status(ice);
146
147 st = ((addr & 0x7f) << 9) | (data & 0x1ff);
148 snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | ALL_MASK);
149 snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~ALL_MASK);
150 bits = snd_ice1712_gpio_read(ice) & ~ALL_MASK;
151
152 snd_ice1712_gpio_write(ice, bits);
153 for (i = 0; i < 16; i++) {
154 udelay(1);
155 bits &= ~CLOCK;
156 st = (st << 1);
157 if (st & 0x10000)
158 bits |= DATA;
159 else
160 bits &= ~DATA;
161
162 snd_ice1712_gpio_write(ice, bits);
163
164 udelay(1);
165 bits |= CLOCK;
166 snd_ice1712_gpio_write(ice, bits);
167 }
168
169 udelay(1);
170 bits |= LOAD;
171 snd_ice1712_gpio_write(ice, bits);
172
173 udelay(1);
174 bits |= (DATA | CLOCK);
175 snd_ice1712_gpio_write(ice, bits);
176
177 snd_ice1712_restore_gpio_status(ice);
178}
179
180static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch,
181 unsigned int vol1, unsigned int vol2)
182{
183 switch (ch) {
184 case 0:
185 se200pci_WM8766_write(ice, 0x000, vol1);
186 se200pci_WM8766_write(ice, 0x001, vol2 | 0x100);
187 break;
188 case 1:
189 se200pci_WM8766_write(ice, 0x004, vol1);
190 se200pci_WM8766_write(ice, 0x005, vol2 | 0x100);
191 break;
192 case 2:
193 se200pci_WM8766_write(ice, 0x006, vol1);
194 se200pci_WM8766_write(ice, 0x007, vol2 | 0x100);
195 break;
196 }
197}
198
199static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice)
200{
201 se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */
202 udelay(10);
203
204 se200pci_WM8766_set_volume(ice, 0, 0, 0); /* volume L=0 R=0 */
205 se200pci_WM8766_set_volume(ice, 1, 0, 0); /* volume L=0 R=0 */
206 se200pci_WM8766_set_volume(ice, 2, 0, 0); /* volume L=0 R=0 */
207
208 se200pci_WM8766_write(ice, 0x03, 0x022); /* serial mode I2S-24bits */
209 se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */
210 se200pci_WM8766_write(ice, 0x12, 0x000); /* MDP=0 */
211 se200pci_WM8766_write(ice, 0x15, 0x000); /* MDP=0 */
212 se200pci_WM8766_write(ice, 0x09, 0x000); /* demp=off mute=off */
213
214 se200pci_WM8766_write(ice, 0x02, 0x124); /* ch-assign L=L R=R RESET */
215 se200pci_WM8766_write(ice, 0x02, 0x120); /* ch-assign L=L R=R */
216}
217
218static void se200pci_WM8766_set_pro_rate(struct snd_ice1712 *ice,
219 unsigned int rate)
220{
221 if (rate > 96000)
222 se200pci_WM8766_write(ice, 0x0a, 0x000); /* MCLK=128fs */
223 else
224 se200pci_WM8766_write(ice, 0x0a, 0x080); /* MCLK=256fs */
225}
226
227
228/****************************************************************************/
229/* WM8776 interface */
230/****************************************************************************/
231
232static void se200pci_WM8776_write(struct snd_ice1712 *ice,
233 unsigned int addr, unsigned int data)
234{
235 unsigned int val;
236
237 val = (addr << 9) | data;
238 snd_vt1724_write_i2c(ice, 0x34, val >> 8, val & 0xff);
239}
240
241
242static void se200pci_WM8776_set_output_volume(struct snd_ice1712 *ice,
243 unsigned int vol1, unsigned int vol2)
244{
245 se200pci_WM8776_write(ice, 0x03, vol1);
246 se200pci_WM8776_write(ice, 0x04, vol2 | 0x100);
247}
248
249static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice,
250 unsigned int vol1, unsigned int vol2)
251{
252 se200pci_WM8776_write(ice, 0x0e, vol1);
253 se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100);
254}
255
256static const char *se200pci_sel[] = {
257 "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL
258};
259
260static void se200pci_WM8776_set_input_selector(struct snd_ice1712 *ice,
261 unsigned int sel)
262{
263 static unsigned char vals[] = {
264 /* LINE, CD, MIC, ALL, GND */
265 0x10, 0x04, 0x08, 0x1c, 0x03
266 };
267 if (sel > 4)
268 sel = 4;
269 se200pci_WM8776_write(ice, 0x15, vals[sel]);
270}
271
272static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl)
273{
274 /* AFL -- After Fader Listening */
275 if (afl)
276 se200pci_WM8776_write(ice, 0x16, 0x005);
277 else
278 se200pci_WM8776_write(ice, 0x16, 0x001);
279}
280
281static const char *se200pci_agc[] = {
282 "Off", "LimiterMode", "ALCMode", NULL
283};
284
285static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc)
286{
287 /* AGC -- Auto Gain Control of the input */
288 switch (agc) {
289 case 0:
290 se200pci_WM8776_write(ice, 0x11, 0x000); /* Off */
291 break;
292 case 1:
293 se200pci_WM8776_write(ice, 0x10, 0x07b);
294 se200pci_WM8776_write(ice, 0x11, 0x100); /* LimiterMode */
295 break;
296 case 2:
297 se200pci_WM8776_write(ice, 0x10, 0x1fb);
298 se200pci_WM8776_write(ice, 0x11, 0x100); /* ALCMode */
299 break;
300 }
301}
302
303static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice)
304{
305 int i;
306 static unsigned short __devinitdata default_values[] = {
307 0x100, 0x100, 0x100,
308 0x100, 0x100, 0x100,
309 0x000, 0x090, 0x000, 0x000,
310 0x022, 0x022, 0x022,
311 0x008, 0x0cf, 0x0cf, 0x07b, 0x000,
312 0x032, 0x000, 0x0a6, 0x001, 0x001
313 };
314
315 se200pci_WM8776_write(ice, 0x17, 0x000); /* reset all */
316 /* ADC and DAC interface is I2S 24bits mode */
317 /* The sample-rate are automatically changed */
318 udelay(10);
319 /* BUT my board can not do reset all, so I load all by manually. */
320 for (i = 0; i < ARRAY_SIZE(default_values); i++)
321 se200pci_WM8776_write(ice, i, default_values[i]);
322
323 se200pci_WM8776_set_input_selector(ice, 0);
324 se200pci_WM8776_set_afl(ice, 0);
325 se200pci_WM8776_set_agc(ice, 0);
326 se200pci_WM8776_set_input_volume(ice, 0, 0);
327 se200pci_WM8776_set_output_volume(ice, 0, 0);
328
329 /* head phone mute and power down */
330 se200pci_WM8776_write(ice, 0x00, 0);
331 se200pci_WM8776_write(ice, 0x01, 0);
332 se200pci_WM8776_write(ice, 0x02, 0x100);
333 se200pci_WM8776_write(ice, 0x0d, 0x080);
334}
335
336static void se200pci_WM8776_set_pro_rate(struct snd_ice1712 *ice,
337 unsigned int rate)
338{
339 /* nothing to do */
340}
341
342
343/****************************************************************************/
344/* runtime interface */
345/****************************************************************************/
346
347static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate)
348{
349 se200pci_WM8740_set_pro_rate(ice, rate);
350 se200pci_WM8766_set_pro_rate(ice, rate);
351 se200pci_WM8776_set_pro_rate(ice, rate);
352}
353
354struct se200pci_control {
355 char *name;
356 enum {
357 WM8766,
358 WM8776in,
359 WM8776out,
360 WM8776sel,
361 WM8776agc,
362 WM8776afl
363 } target;
364 enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type;
365 int ch;
366 const char **member;
367 const char *comment;
368};
369
370static const struct se200pci_control se200pci_cont[] = {
371 {
372 .name = "Front Playback Volume",
373 .target = WM8776out,
374 .type = VOLUME1,
375 .comment = "Front(green)"
376 },
377 {
378 .name = "Side Playback Volume",
379 .target = WM8766,
380 .type = VOLUME1,
381 .ch = 1,
382 .comment = "Surround(orange)"
383 },
384 {
385 .name = "Surround Playback Volume",
386 .target = WM8766,
387 .type = VOLUME1,
388 .ch = 2,
389 .comment = "SurroundBack(white)"
390 },
391 {
392 .name = "CLFE Playback Volume",
393 .target = WM8766,
394 .type = VOLUME1,
395 .ch = 0,
396 .comment = "Center(Lch)&SubWoofer(Rch)(black)"
397 },
398 {
399 .name = "Capture Volume",
400 .target = WM8776in,
401 .type = VOLUME2
402 },
403 {
404 .name = "Capture Select",
405 .target = WM8776sel,
406 .type = ENUM,
407 .member = se200pci_sel
408 },
409 {
410 .name = "AGC Capture Mode",
411 .target = WM8776agc,
412 .type = ENUM,
413 .member = se200pci_agc
414 },
415 {
416 .name = "AFL Bypass Playback Switch",
417 .target = WM8776afl,
418 .type = BOOLEAN
419 }
420};
421
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100422static int se200pci_get_enum_count(int n)
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200423{
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200424 const char **member;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100425 int c;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200426
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100427 member = se200pci_cont[n].member;
428 if (!member)
429 return 0;
430 for (c = 0; member[c]; c++)
431 ;
432 return c;
433}
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200434
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100435static int se200pci_cont_volume_info(struct snd_kcontrol *kc,
436 struct snd_ctl_elem_info *uinfo)
437{
438 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
439 uinfo->count = 2;
440 uinfo->value.integer.min = 0; /* mute */
441 uinfo->value.integer.max = 0xff; /* 0dB */
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200442 return 0;
443}
444
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100445#define se200pci_cont_boolean_info snd_ctl_boolean_mono_info
446
447static int se200pci_cont_enum_info(struct snd_kcontrol *kc,
448 struct snd_ctl_elem_info *uinfo)
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200449{
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100450 int n, c;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200451
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200452 n = kc->private_value;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100453 c = se200pci_get_enum_count(n);
454 if (!c)
455 return -EINVAL;
456 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
457 uinfo->count = 1;
458 uinfo->value.enumerated.items = c;
459 if (uinfo->value.enumerated.item >= c)
460 uinfo->value.enumerated.item = c - 1;
461 strcpy(uinfo->value.enumerated.name,
462 se200pci_cont[n].member[uinfo->value.enumerated.item]);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200463 return 0;
464}
465
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100466static int se200pci_cont_volume_get(struct snd_kcontrol *kc,
467 struct snd_ctl_elem_value *uc)
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200468{
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100469 struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100470 struct se_spec *spec = ice->spec;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100471 int n = kc->private_value;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100472 uc->value.integer.value[0] = spec->vol[n].ch1;
473 uc->value.integer.value[1] = spec->vol[n].ch2;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100474 return 0;
475}
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200476
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100477static int se200pci_cont_boolean_get(struct snd_kcontrol *kc,
478 struct snd_ctl_elem_value *uc)
479{
480 struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100481 struct se_spec *spec = ice->spec;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100482 int n = kc->private_value;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100483 uc->value.integer.value[0] = spec->vol[n].ch1;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100484 return 0;
485}
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200486
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100487static int se200pci_cont_enum_get(struct snd_kcontrol *kc,
488 struct snd_ctl_elem_value *uc)
489{
490 struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100491 struct se_spec *spec = ice->spec;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100492 int n = kc->private_value;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100493 uc->value.enumerated.item[0] = spec->vol[n].ch1;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100494 return 0;
495}
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200496
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100497static void se200pci_cont_update(struct snd_ice1712 *ice, int n)
498{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100499 struct se_spec *spec = ice->spec;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200500 switch (se200pci_cont[n].target) {
501 case WM8766:
502 se200pci_WM8766_set_volume(ice,
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100503 se200pci_cont[n].ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100504 spec->vol[n].ch1,
505 spec->vol[n].ch2);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200506 break;
507
508 case WM8776in:
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100509 se200pci_WM8776_set_input_volume(ice,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100510 spec->vol[n].ch1,
511 spec->vol[n].ch2);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200512 break;
513
514 case WM8776out:
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100515 se200pci_WM8776_set_output_volume(ice,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100516 spec->vol[n].ch1,
517 spec->vol[n].ch2);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200518 break;
519
520 case WM8776sel:
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100521 se200pci_WM8776_set_input_selector(ice,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100522 spec->vol[n].ch1);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200523 break;
524
525 case WM8776agc:
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100526 se200pci_WM8776_set_agc(ice, spec->vol[n].ch1);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200527 break;
528
529 case WM8776afl:
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100530 se200pci_WM8776_set_afl(ice, spec->vol[n].ch1);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200531 break;
532
533 default:
534 break;
535 }
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100536}
537
538static int se200pci_cont_volume_put(struct snd_kcontrol *kc,
539 struct snd_ctl_elem_value *uc)
540{
541 struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100542 struct se_spec *spec = ice->spec;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100543 int n = kc->private_value;
544 unsigned int vol1, vol2;
545 int changed;
546
547 changed = 0;
548 vol1 = uc->value.integer.value[0] & 0xff;
549 vol2 = uc->value.integer.value[1] & 0xff;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100550 if (spec->vol[n].ch1 != vol1) {
551 spec->vol[n].ch1 = vol1;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100552 changed = 1;
553 }
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100554 if (spec->vol[n].ch2 != vol2) {
555 spec->vol[n].ch2 = vol2;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100556 changed = 1;
557 }
558 if (changed)
559 se200pci_cont_update(ice, n);
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200560
561 return changed;
562}
563
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100564static int se200pci_cont_boolean_put(struct snd_kcontrol *kc,
565 struct snd_ctl_elem_value *uc)
566{
567 struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100568 struct se_spec *spec = ice->spec;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100569 int n = kc->private_value;
570 unsigned int vol1;
571
572 vol1 = !!uc->value.integer.value[0];
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100573 if (spec->vol[n].ch1 != vol1) {
574 spec->vol[n].ch1 = vol1;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100575 se200pci_cont_update(ice, n);
576 return 1;
577 }
578 return 0;
579}
580
581static int se200pci_cont_enum_put(struct snd_kcontrol *kc,
582 struct snd_ctl_elem_value *uc)
583{
584 struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100585 struct se_spec *spec = ice->spec;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100586 int n = kc->private_value;
587 unsigned int vol1;
588
589 vol1 = uc->value.enumerated.item[0];
590 if (vol1 >= se200pci_get_enum_count(n))
591 return -EINVAL;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100592 if (spec->vol[n].ch1 != vol1) {
593 spec->vol[n].ch1 = vol1;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100594 se200pci_cont_update(ice, n);
595 return 1;
596 }
597 return 0;
598}
599
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200600static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1);
601static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1);
602
603static int __devinit se200pci_add_controls(struct snd_ice1712 *ice)
604{
605 int i;
606 struct snd_kcontrol_new cont;
607 int err;
608
609 memset(&cont, 0, sizeof(cont));
610 cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200611 for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) {
612 cont.private_value = i;
613 cont.name = se200pci_cont[i].name;
614 cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
615 cont.tlv.p = NULL;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100616 switch (se200pci_cont[i].type) {
617 case VOLUME1:
618 case VOLUME2:
619 cont.info = se200pci_cont_volume_info;
620 cont.get = se200pci_cont_volume_get;
621 cont.put = se200pci_cont_volume_put;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200622 cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200623 if (se200pci_cont[i].type == VOLUME1)
624 cont.tlv.p = db_scale_gain1;
625 else
626 cont.tlv.p = db_scale_gain2;
Takashi Iwai9c45ba12007-11-15 16:05:26 +0100627 break;
628 case BOOLEAN:
629 cont.info = se200pci_cont_boolean_info;
630 cont.get = se200pci_cont_boolean_get;
631 cont.put = se200pci_cont_boolean_put;
632 break;
633 case ENUM:
634 cont.info = se200pci_cont_enum_info;
635 cont.get = se200pci_cont_enum_get;
636 cont.put = se200pci_cont_enum_put;
637 break;
638 default:
639 snd_BUG();
640 return -EINVAL;
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200641 }
642 err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice));
643 if (err < 0)
644 return err;
645 }
646
647 return 0;
648}
649
650
651/****************************************************************************/
652/* ONKYO WAVIO SE-90PCI */
653/****************************************************************************/
654/*
655 * system configuration ICE_EEP2_SYSCONF=0x4b
656 * AC-Link configuration ICE_EEP2_ACLINK=0x80
657 * I2S converters feature ICE_EEP2_I2S=0x78
658 * S/PDIF configuration ICE_EEP2_SPDIF=0xc3
659 *
660 * ** connected chip **
661 *
662 * WM8716
663 * A 2ch-DAC of main outputs.
664 * It setuped as I2S mode by wire, so no way to setup from software.
665 * ML/I2S (28pin) -- +5V
666 * MC/DM1 (27pin) -- GND
667 * MC/DM0 (26pin) -- GND
668 * MUTEB (25pin) -- open (internal pull-up)
669 * MODE (24pin) -- GND
670 * CSBIWO (23pin) -- +5V
671 *
672 */
673
674 /* Nothing to do for this chip. */
675
676
677/****************************************************************************/
678/* probe/initialize/setup */
679/****************************************************************************/
680
681static int __devinit se_init(struct snd_ice1712 *ice)
682{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100683 struct se_spec *spec;
684
685 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
686 if (!spec)
687 return -ENOMEM;
688 ice->spec = spec;
689
Shin-ya Okadaf31639b2007-10-23 15:08:18 +0200690 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE90PCI) {
691 ice->num_total_dacs = 2;
692 ice->num_total_adcs = 0;
693 ice->vt1720 = 1;
694 return 0;
695
696 } else if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI) {
697 ice->num_total_dacs = 8;
698 ice->num_total_adcs = 2;
699 se200pci_WM8740_init(ice);
700 se200pci_WM8766_init(ice);
701 se200pci_WM8776_init(ice);
702 ice->gpio.set_pro_rate = se200pci_set_pro_rate;
703 return 0;
704 }
705
706 return -ENOENT;
707}
708
709static int __devinit se_add_controls(struct snd_ice1712 *ice)
710{
711 int err;
712
713 err = 0;
714 /* nothing to do for VT1724_SUBDEVICE_SE90PCI */
715 if (ice->eeprom.subvendor == VT1724_SUBDEVICE_SE200PCI)
716 err = se200pci_add_controls(ice);
717
718 return err;
719}
720
721
722/****************************************************************************/
723/* entry point */
724/****************************************************************************/
725
726static unsigned char se200pci_eeprom[] __devinitdata = {
727 [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */
728 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
729 [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */
730 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
731
732 [ICE_EEP2_GPIO_DIR] = 0x02, /* WM8766 mute 1=output */
733 [ICE_EEP2_GPIO_DIR1] = 0x00, /* not used */
734 [ICE_EEP2_GPIO_DIR2] = 0x07, /* WM8766 ML/MC/MD 1=output */
735
736 [ICE_EEP2_GPIO_MASK] = 0x00, /* 0=writable */
737 [ICE_EEP2_GPIO_MASK1] = 0x00, /* 0=writable */
738 [ICE_EEP2_GPIO_MASK2] = 0x00, /* 0=writable */
739
740 [ICE_EEP2_GPIO_STATE] = 0x00, /* WM8766 mute=0 */
741 [ICE_EEP2_GPIO_STATE1] = 0x00, /* not used */
742 [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */
743};
744
745static unsigned char se90pci_eeprom[] __devinitdata = {
746 [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */
747 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
748 [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */
749 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
750
751 /* ALL GPIO bits are in input mode */
752};
753
754struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = {
755 {
756 .subvendor = VT1724_SUBDEVICE_SE200PCI,
757 .name = "ONKYO SE200PCI",
758 .model = "se200pci",
759 .chip_init = se_init,
760 .build_controls = se_add_controls,
761 .eeprom_size = sizeof(se200pci_eeprom),
762 .eeprom_data = se200pci_eeprom,
763 },
764 {
765 .subvendor = VT1724_SUBDEVICE_SE90PCI,
766 .name = "ONKYO SE90PCI",
767 .model = "se90pci",
768 .chip_init = se_init,
769 .build_controls = se_add_controls,
770 .eeprom_size = sizeof(se90pci_eeprom),
771 .eeprom_data = se90pci_eeprom,
772 },
773 {} /*terminator*/
774};