Merge git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched
[linux-2.6] / sound / pci / ice1712 / se.c
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 <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
37 struct se_spec {
38         struct {
39                 unsigned char ch1, ch2;
40         } vol[8];
41 };
42
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
117 static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice)
118 {
119         /* nothing to do */
120 }
121
122
123 static 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
134 static 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
180 static 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
199 static 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
218 static 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
232 static 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
242 static 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
249 static 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
256 static const char *se200pci_sel[] = {
257         "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL
258 };
259
260 static 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
272 static 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
281 static const char *se200pci_agc[] = {
282         "Off", "LimiterMode", "ALCMode", NULL
283 };
284
285 static 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
303 static 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
336 static 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
347 static 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
354 struct 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
370 static 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
422 static int se200pci_get_enum_count(int n)
423 {
424         const char **member;
425         int c;
426
427         member = se200pci_cont[n].member;
428         if (!member)
429                 return 0;
430         for (c = 0; member[c]; c++)
431                 ;
432         return c;
433 }
434
435 static 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 */
442         return 0;
443 }
444
445 #define se200pci_cont_boolean_info      snd_ctl_boolean_mono_info
446
447 static int se200pci_cont_enum_info(struct snd_kcontrol *kc,
448                                    struct snd_ctl_elem_info *uinfo)
449 {
450         int n, c;
451
452         n = kc->private_value;
453         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]);
463         return 0;
464 }
465
466 static int se200pci_cont_volume_get(struct snd_kcontrol *kc,
467                                     struct snd_ctl_elem_value *uc)
468 {
469         struct snd_ice1712 *ice = snd_kcontrol_chip(kc);
470         struct se_spec *spec = ice->spec;
471         int n = kc->private_value;
472         uc->value.integer.value[0] = spec->vol[n].ch1;
473         uc->value.integer.value[1] = spec->vol[n].ch2;
474         return 0;
475 }
476
477 static 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);
481         struct se_spec *spec = ice->spec;
482         int n = kc->private_value;
483         uc->value.integer.value[0] = spec->vol[n].ch1;
484         return 0;
485 }
486
487 static 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);
491         struct se_spec *spec = ice->spec;
492         int n = kc->private_value;
493         uc->value.enumerated.item[0] = spec->vol[n].ch1;
494         return 0;
495 }
496
497 static void se200pci_cont_update(struct snd_ice1712 *ice, int n)
498 {
499         struct se_spec *spec = ice->spec;
500         switch (se200pci_cont[n].target) {
501         case WM8766:
502                 se200pci_WM8766_set_volume(ice,
503                                            se200pci_cont[n].ch,
504                                            spec->vol[n].ch1,
505                                            spec->vol[n].ch2);
506                 break;
507
508         case WM8776in:
509                 se200pci_WM8776_set_input_volume(ice,
510                                                  spec->vol[n].ch1,
511                                                  spec->vol[n].ch2);
512                 break;
513
514         case WM8776out:
515                 se200pci_WM8776_set_output_volume(ice,
516                                                   spec->vol[n].ch1,
517                                                   spec->vol[n].ch2);
518                 break;
519
520         case WM8776sel:
521                 se200pci_WM8776_set_input_selector(ice,
522                                                    spec->vol[n].ch1);
523                 break;
524
525         case WM8776agc:
526                 se200pci_WM8776_set_agc(ice, spec->vol[n].ch1);
527                 break;
528
529         case WM8776afl:
530                 se200pci_WM8776_set_afl(ice, spec->vol[n].ch1);
531                 break;
532
533         default:
534                 break;
535         }
536 }
537
538 static 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);
542         struct se_spec *spec = ice->spec;
543         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;
550         if (spec->vol[n].ch1 != vol1) {
551                 spec->vol[n].ch1 = vol1;
552                 changed = 1;
553         }
554         if (spec->vol[n].ch2 != vol2) {
555                 spec->vol[n].ch2 = vol2;
556                 changed = 1;
557         }
558         if (changed)
559                 se200pci_cont_update(ice, n);
560
561         return changed;
562 }
563
564 static 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);
568         struct se_spec *spec = ice->spec;
569         int n = kc->private_value;
570         unsigned int vol1;
571
572         vol1 = !!uc->value.integer.value[0];
573         if (spec->vol[n].ch1 != vol1) {
574                 spec->vol[n].ch1 = vol1;
575                 se200pci_cont_update(ice, n);
576                 return 1;
577         }
578         return 0;
579 }
580
581 static 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);
585         struct se_spec *spec = ice->spec;
586         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;
592         if (spec->vol[n].ch1 != vol1) {
593                 spec->vol[n].ch1 = vol1;
594                 se200pci_cont_update(ice, n);
595                 return 1;
596         }
597         return 0;
598 }
599
600 static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1);
601 static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1);
602
603 static 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;
611         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;
616                 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;
622                         cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
623                         if (se200pci_cont[i].type == VOLUME1)
624                                 cont.tlv.p = db_scale_gain1;
625                         else
626                                 cont.tlv.p = db_scale_gain2;
627                         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;
641                 }
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
681 static int __devinit se_init(struct snd_ice1712 *ice)
682 {
683         struct se_spec *spec;
684
685         spec = kzalloc(sizeof(*spec), GFP_KERNEL);
686         if (!spec)
687                 return -ENOMEM;
688         ice->spec = spec;
689
690         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
709 static 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
726 static 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
745 static 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
754 struct 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 };