blob: 7fcce0a506d65e516e272f901b49d97fac6022af [file] [log] [blame]
Clement Guedezf6cdab52007-01-08 10:48:41 +01001/*
2 * ALSA driver for ICEnsemble VT1724 (Envy24HT)
3 *
4 * Lowlevel functions for Ego Sys Waveterminal 192M
5 *
6 * Copyright (c) 2006 Guedez Clement <klem.dev@gmail.com>
7 * Some functions are taken from the Prodigy192 driver
8 * source
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26
27
28#include <sound/driver.h>
29#include <asm/io.h>
30#include <linux/delay.h>
31#include <linux/interrupt.h>
32#include <linux/init.h>
33#include <linux/slab.h>
34#include <sound/core.h>
35
36#include "ice1712.h"
37#include "envy24ht.h"
38#include "wtm.h"
39#include "stac946x.h"
40
41
42/*
43 * 2*ADC 6*DAC no1 ringbuffer r/w on i2c bus
44 */
45static inline void stac9460_put(struct snd_ice1712 *ice, int reg,
46 unsigned char val)
47{
48 snd_vt1724_write_i2c(ice, STAC9460_I2C_ADDR, reg, val);
49}
50
51static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
52{
53 return snd_vt1724_read_i2c(ice, STAC9460_I2C_ADDR, reg);
54}
55
56/*
57 * 2*ADC 2*DAC no2 ringbuffer r/w on i2c bus
58 */
59static inline void stac9460_2_put(struct snd_ice1712 *ice, int reg,
60 unsigned char val)
61{
62 snd_vt1724_write_i2c(ice, STAC9460_2_I2C_ADDR, reg, val);
63}
64
65static inline unsigned char stac9460_2_get(struct snd_ice1712 *ice, int reg)
66{
67 return snd_vt1724_read_i2c(ice, STAC9460_2_I2C_ADDR, reg);
68}
69
70
71/*
72 * DAC mute control
73 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +020074#define stac9460_dac_mute_info snd_ctl_boolean_mono_info
Clement Guedezf6cdab52007-01-08 10:48:41 +010075
76static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
77 struct snd_ctl_elem_value *ucontrol)
78{
79 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
80 unsigned char val;
81 int idx, id;
82
83 if (kcontrol->private_value) {
84 idx = STAC946X_MASTER_VOLUME;
85 id = 0;
86 } else {
87 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
88 idx = id + STAC946X_LF_VOLUME;
89 }
90 if (id < 6)
91 val = stac9460_get(ice, idx);
92 else
93 val = stac9460_2_get(ice,idx - 6);
94 ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
95 return 0;
96}
97
98static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
99 struct snd_ctl_elem_value *ucontrol)
100{
101 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
102 unsigned char new, old;
103 int id, idx;
104 int change;
105
106 if (kcontrol->private_value) {
107 idx = STAC946X_MASTER_VOLUME;
108 old = stac9460_get(ice, idx);
109 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
110 (old & ~0x80);
111 change = (new != old);
112 if (change) {
113 stac9460_put(ice, idx, new);
114 stac9460_2_put(ice, idx, new);
115 }
116 } else {
117 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
118 idx = id + STAC946X_LF_VOLUME;
119 if (id < 6)
120 old = stac9460_get(ice, idx);
121 else
122 old = stac9460_2_get(ice, idx - 6);
123 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
124 (old & ~0x80);
125 change = (new != old);
126 if (change) {
127 if (id < 6)
128 stac9460_put(ice, idx, new);
129 else
130 stac9460_2_put(ice, idx - 6, new);
131 }
132 }
133 return change;
134}
135
136/*
137 * DAC volume attenuation mixer control
138 */
139static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
140 struct snd_ctl_elem_info *uinfo)
141{
142 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
143 uinfo->count = 1;
144 uinfo->value.integer.min = 0; /* mute */
145 uinfo->value.integer.max = 0x7f; /* 0dB */
146 return 0;
147}
148
149static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
150 struct snd_ctl_elem_value *ucontrol)
151{
152 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
153 int idx, id;
154 unsigned char vol;
155
156 if (kcontrol->private_value) {
157 idx = STAC946X_MASTER_VOLUME;
158 id = 0;
159 } else {
160 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
161 idx = id + STAC946X_LF_VOLUME;
162 }
163 if (id < 6)
164 vol = stac9460_get(ice, idx) & 0x7f;
165 else
166 vol = stac9460_2_get(ice, idx - 6) & 0x7f;
167 ucontrol->value.integer.value[0] = 0x7f - vol;
168 return 0;
169}
170
171static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
173{
174 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
175 int idx, id;
176 unsigned char tmp, ovol, nvol;
177 int change;
178
179 if (kcontrol->private_value) {
180 idx = STAC946X_MASTER_VOLUME;
181 nvol = ucontrol->value.integer.value[0];
182 tmp = stac9460_get(ice, idx);
183 ovol = 0x7f - (tmp & 0x7f);
184 change = (ovol != nvol);
185 if (change) {
186 stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
187 stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
188 }
189 } else {
190 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
191 idx = id + STAC946X_LF_VOLUME;
192 nvol = ucontrol->value.integer.value[0];
193 if (id < 6)
194 tmp = stac9460_get(ice, idx);
195 else
196 tmp = stac9460_2_get(ice, idx - 6);
197 ovol = 0x7f - (tmp & 0x7f);
198 change = (ovol != nvol);
199 if (change) {
200 if (id < 6)
201 stac9460_put(ice, idx, (0x7f - nvol) |
202 (tmp & 0x80));
203 else
204 stac9460_2_put(ice, idx-6, (0x7f - nvol) |
205 (tmp & 0x80));
206 }
207 }
208 return change;
209}
210
211/*
212 * ADC mute control
213 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200214#define stac9460_adc_mute_info snd_ctl_boolean_stereo_info
Clement Guedezf6cdab52007-01-08 10:48:41 +0100215
216static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
217 struct snd_ctl_elem_value *ucontrol)
218{
219 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
220 unsigned char val;
221 int i, id;
222
223 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
224 if (id == 0) {
225 for (i = 0; i < 2; ++i) {
226 val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
227 ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
228 }
229 } else {
230 for (i = 0; i < 2; ++i) {
231 val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
232 ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
233 }
234 }
235 return 0;
236}
237
238static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
239 struct snd_ctl_elem_value *ucontrol)
240{
241 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
242 unsigned char new, old;
243 int i, reg, id;
244 int change;
245
246 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
247 if (id == 0) {
248 for (i = 0; i < 2; ++i) {
249 reg = STAC946X_MIC_L_VOLUME + i;
250 old = stac9460_get(ice, reg);
251 new = (~ucontrol->value.integer.value[i]<<7&0x80) |
252 (old&~0x80);
253 change = (new != old);
254 if (change)
255 stac9460_put(ice, reg, new);
256 }
257 } else {
258 for (i = 0; i < 2; ++i) {
259 reg = STAC946X_MIC_L_VOLUME + i;
260 old = stac9460_2_get(ice, reg);
261 new = (~ucontrol->value.integer.value[i]<<7&0x80) |
262 (old&~0x80);
263 change = (new != old);
264 if (change)
265 stac9460_2_put(ice, reg, new);
266 }
267 }
268 return change;
269}
270
271/*
272 *ADC gain mixer control
273 */
274static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
275 struct snd_ctl_elem_info *uinfo)
276{
277 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
278 uinfo->count = 2;
279 uinfo->value.integer.min = 0; /* 0dB */
280 uinfo->value.integer.max = 0x0f; /* 22.5dB */
281 return 0;
282}
283
284static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
285 struct snd_ctl_elem_value *ucontrol)
286{
287 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
288 int i, reg, id;
289 unsigned char vol;
290
291 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
292 if (id == 0) {
293 for (i = 0; i < 2; ++i) {
294 reg = STAC946X_MIC_L_VOLUME + i;
295 vol = stac9460_get(ice, reg) & 0x0f;
296 ucontrol->value.integer.value[i] = 0x0f - vol;
297 }
298 } else {
299 for (i = 0; i < 2; ++i) {
300 reg = STAC946X_MIC_L_VOLUME + i;
301 vol = stac9460_2_get(ice, reg) & 0x0f;
302 ucontrol->value.integer.value[i] = 0x0f - vol;
303 }
304 }
305 return 0;
306}
307
308static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
309 struct snd_ctl_elem_value *ucontrol)
310{
311 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
312 int i, reg, id;
313 unsigned char ovol, nvol;
314 int change;
315
316 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
317 if (id == 0) {
318 for (i = 0; i < 2; ++i) {
319 reg = STAC946X_MIC_L_VOLUME + i;
320 nvol = ucontrol->value.integer.value[i];
321 ovol = 0x0f - stac9460_get(ice, reg);
322 change = ((ovol & 0x0f) != nvol);
323 if (change)
324 stac9460_put(ice, reg, (0x0f - nvol) |
325 (ovol & ~0x0f));
326 }
327 } else {
328 for (i = 0; i < 2; ++i) {
329 reg = STAC946X_MIC_L_VOLUME + i;
330 nvol = ucontrol->value.integer.value[i];
331 ovol = 0x0f - stac9460_2_get(ice, reg);
332 change = ((ovol & 0x0f) != nvol);
333 if (change)
334 stac9460_2_put(ice, reg, (0x0f - nvol) |
335 (ovol & ~0x0f));
336 }
337 }
338 return change;
339}
340
341/*
342 * MIC / LINE switch fonction
343 */
344
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200345#define stac9460_mic_sw_info snd_ctl_boolean_mono_info
Clement Guedezf6cdab52007-01-08 10:48:41 +0100346
347static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
348 struct snd_ctl_elem_value *ucontrol)
349{
350 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
351 unsigned char val;
352 int id;
353
354 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
355 if (id == 0)
356 val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
357 else
358 val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
359 ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
360 return 0;
361}
362
363static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
364 struct snd_ctl_elem_value *ucontrol)
365{
366 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
367 unsigned char new, old;
368 int change, id;
369
370 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
371 if (id == 0)
372 old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
373 else
374 old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
375 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
376 change = (new != old);
377 if (change) {
378 if (id == 0)
379 stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
380 else
381 stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
382 }
383 return change;
384}
385
386/*
387 * Control tabs
388 */
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100389static struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
Clement Guedezf6cdab52007-01-08 10:48:41 +0100390 {
391 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
392 .name = "Master Playback Switch",
393 .info = stac9460_dac_mute_info,
394 .get = stac9460_dac_mute_get,
395 .put = stac9460_dac_mute_put,
396 .private_value = 1
397 },
398 {
399 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
400 .name = "Master Playback Volume",
401 .info = stac9460_dac_vol_info,
402 .get = stac9460_dac_vol_get,
403 .put = stac9460_dac_vol_put,
404 .private_value = 1,
405 },
406 {
407 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
408 .name = "MIC/Line switch",
409 .count = 2,
410 .info = stac9460_mic_sw_info,
411 .get = stac9460_mic_sw_get,
412 .put = stac9460_mic_sw_put,
413
414 },
415 {
416 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
417 .name = "DAC Switch",
418 .count = 8,
419 .info = stac9460_dac_mute_info,
420 .get = stac9460_dac_mute_get,
421 .put = stac9460_dac_mute_put,
422 },
423 {
424 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
425 .name = "DAC Volume",
426 .count = 8,
427 .info = stac9460_dac_vol_info,
428 .get = stac9460_dac_vol_get,
429 .put = stac9460_dac_vol_put,
430 },
431 {
432 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
433 .name = "ADC Switch",
434 .count = 2,
435 .info = stac9460_adc_mute_info,
436 .get = stac9460_adc_mute_get,
437 .put = stac9460_adc_mute_put,
438 },
439 {
440 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
441 .name = "ADC Volume",
442 .count = 2,
443 .info = stac9460_adc_vol_info,
444 .get = stac9460_adc_vol_get,
445 .put = stac9460_adc_vol_put,
446
447 }
448};
449
450
451
452/*INIT*/
453static int __devinit wtm_add_controls(struct snd_ice1712 *ice)
454{
455 unsigned int i;
456 int err;
457
458 for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
459 err = snd_ctl_add(ice->card,
460 snd_ctl_new1(&stac9640_controls[i], ice));
461 if (err < 0)
462 return err;
463 }
464 return 0;
465}
466
467static int __devinit wtm_init(struct snd_ice1712 *ice)
468{
469 static unsigned short stac_inits_prodigy[] = {
470 STAC946X_RESET, 0,
471 (unsigned short)-1
472 };
473 unsigned short *p;
474
475 /*WTM 192M*/
476 ice->num_total_dacs = 8;
477 ice->num_total_adcs = 4;
478 ice->force_rdma1 = 1;
479
480 /*initialize codec*/
481 p = stac_inits_prodigy;
482 for (; *p != (unsigned short)-1; p += 2) {
483 stac9460_put(ice, p[0], p[1]);
484 stac9460_2_put(ice, p[0], p[1]);
485 }
486 return 0;
487}
488
489
490static unsigned char wtm_eeprom[] __devinitdata = {
491 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */
492 0x80, /* ACLINK : I2S */
493 0xf8, /* I2S: vol; 96k, 24bit, 192k */
494 0xc1 /*SPDIF: out-en, spidf ext out*/,
495 0x9f, /* GPIO_DIR */
496 0xff, /* GPIO_DIR1 */
497 0x7f, /* GPIO_DIR2 */
498 0x9f, /* GPIO_MASK */
499 0xff, /* GPIO_MASK1 */
500 0x7f, /* GPIO_MASK2 */
501 0x16, /* GPIO_STATE */
502 0x80, /* GPIO_STATE1 */
503 0x00, /* GPIO_STATE2 */
504};
505
506
507/*entry point*/
508struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = {
509 {
510 .subvendor = VT1724_SUBDEVICE_WTM,
511 .name = "ESI Waveterminal 192M",
512 .model = "WT192M",
513 .chip_init = wtm_init,
514 .build_controls = wtm_add_controls,
515 .eeprom_size = sizeof(wtm_eeprom),
516 .eeprom_data = wtm_eeprom,
517 },
518 {} /*terminator*/
519};