aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShin-ya Okada <sh_okada at d4.dion.ne.jp>2007-10-23 09:08:18 -0400
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:09 -0500
commitf31639b8c5916f58441b529c9c364715921b29af (patch)
tree799ccf968dcc87215674fbb8cd686ea1ef881301
parent18fe4ac25811ff4006844b6e575acdc9103cbaba (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>
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt5
-rw-r--r--sound/pci/ice1712/Makefile2
-rw-r--r--sound/pci/ice1712/ice1712.h6
-rw-r--r--sound/pci/ice1712/ice1724.c3
-rw-r--r--sound/pci/ice1712/se.c700
-rw-r--r--sound/pci/ice1712/se.h15
6 files changed, 729 insertions, 2 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 7b064f2c2a63..69ab91c991a6 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1157,11 +1157,14 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
1157 * Chaintech 9CJS 1157 * Chaintech 9CJS
1158 * Chaintech AV-710 1158 * Chaintech AV-710
1159 * Shuttle SN25P 1159 * Shuttle SN25P
1160 * Onkyo SE-90PCI
1161 * Onkyo SE-200PCI
1160 1162
1161 model - Use the given board model, one of the following: 1163 model - Use the given board model, one of the following:
1162 revo51, revo71, amp2000, prodigy71, prodigy71lt, 1164 revo51, revo71, amp2000, prodigy71, prodigy71lt,
1163 prodigy192, aureon51, aureon71, universe, ap192, 1165 prodigy192, aureon51, aureon71, universe, ap192,
1164 k8x800, phase22, phase28, ms300, av710 1166 k8x800, phase22, phase28, ms300, av710, se200pci,
1167 se90pci
1165 1168
1166 This module supports multiple cards and autoprobe. 1169 This module supports multiple cards and autoprobe.
1167 1170
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile
index 65ce66adba5a..ee86a1de72f8 100644
--- a/sound/pci/ice1712/Makefile
+++ b/sound/pci/ice1712/Makefile
@@ -5,7 +5,7 @@
5 5
6snd-ice17xx-ak4xxx-objs := ak4xxx.o 6snd-ice17xx-ak4xxx-objs := ak4xxx.o
7snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o 7snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o
8snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o 8snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o juli.o phase.o wtm.o se.o
9 9
10# Toplevel Module Dependency 10# Toplevel Module Dependency
11obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o 11obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
index 58640afa5404..3c3cac3dc08b 100644
--- a/sound/pci/ice1712/ice1712.h
+++ b/sound/pci/ice1712/ice1712.h
@@ -400,6 +400,12 @@ struct snd_ice1712 {
400 struct { 400 struct {
401 struct ak4114 *ak4114; 401 struct ak4114 *ak4114;
402 } prodigy192; 402 } prodigy192;
403 struct {
404 struct {
405 unsigned char ch1, ch2;
406 } vol[8];
407 } se;
408
403 } spec; 409 } spec;
404 410
405}; 411};
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 0b0bbb0d96b9..357bdbe21c8f 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -51,6 +51,7 @@
51#include "juli.h" 51#include "juli.h"
52#include "phase.h" 52#include "phase.h"
53#include "wtm.h" 53#include "wtm.h"
54#include "se.h"
54 55
55MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 56MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
56MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); 57MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)");
@@ -65,6 +66,7 @@ MODULE_SUPPORTED_DEVICE("{"
65 JULI_DEVICE_DESC 66 JULI_DEVICE_DESC
66 PHASE_DEVICE_DESC 67 PHASE_DEVICE_DESC
67 WTM_DEVICE_DESC 68 WTM_DEVICE_DESC
69 SE_DEVICE_DESC
68 "{VIA,VT1720}," 70 "{VIA,VT1720},"
69 "{VIA,VT1724}," 71 "{VIA,VT1724},"
70 "{ICEnsemble,Generic ICE1724}," 72 "{ICEnsemble,Generic ICE1724},"
@@ -1933,6 +1935,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = {
1933 snd_vt1724_juli_cards, 1935 snd_vt1724_juli_cards,
1934 snd_vt1724_phase_cards, 1936 snd_vt1724_phase_cards,
1935 snd_vt1724_wtm_cards, 1937 snd_vt1724_wtm_cards,
1938 snd_vt1724_se_cards,
1936 NULL, 1939 NULL,
1937}; 1940};
1938 1941
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
113static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice)
114{
115 /* nothing to do */
116}
117
118
119static 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
130static 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
176static 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
195static 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
214static 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
228static 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
238static 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
245static 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
252static const char *se200pci_sel[] = {
253 "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL
254};
255
256static 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
268static 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
277static const char *se200pci_agc[] = {
278 "Off", "LimiterMode", "ALCMode", NULL
279};
280
281static 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
299static 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
332static 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
343static 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
350struct 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
366static 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
418static 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
461static 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
481static 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
546static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1);
547static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1);
548
549static 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
614static 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
635static 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
652static 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
671static 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
680struct 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};
diff --git a/sound/pci/ice1712/se.h b/sound/pci/ice1712/se.h
new file mode 100644
index 000000000000..0b0a9dabdcfb
--- /dev/null
+++ b/sound/pci/ice1712/se.h
@@ -0,0 +1,15 @@
1#ifndef __SOUND_SE_H
2#define __SOUND_SE_H
3
4/* ID */
5#define SE_DEVICE_DESC \
6 "{ONKYO INC,SE-90PCI},"\
7 "{ONKYO INC,SE-200PCI},"
8
9#define VT1724_SUBDEVICE_SE90PCI 0xb161000
10#define VT1724_SUBDEVICE_SE200PCI 0xb160100
11
12/* entry struct */
13extern struct snd_ice1712_card_info snd_vt1724_se_cards[];
14
15#endif /* __SOUND_SE_H */