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
37struct 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
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
422static 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
435static 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
447static 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
466static 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
477static 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
487static 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
497static 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
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);
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
564static 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
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);
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
600static 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;
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
681static 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
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};
775