- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / sound / pci / ice1712 / wtm.c
1 /*
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  */
45 static 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
51 static 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  */
59 static 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
65 static 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  */
74 static int stac9460_dac_mute_info(struct snd_kcontrol *kcontrol,
75                                 struct snd_ctl_elem_info *uinfo)
76 {
77         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
78         uinfo->count = 1;
79         uinfo->value.integer.min = 0;
80         return 0;
81 }
82
83 static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol,
84                                 struct snd_ctl_elem_value *ucontrol)
85 {
86         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
87         unsigned char val;
88         int idx, id;
89
90         if (kcontrol->private_value) {
91                 idx = STAC946X_MASTER_VOLUME;
92                 id = 0;
93         } else {
94                 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
95                 idx = id + STAC946X_LF_VOLUME;
96         }
97         if (id < 6)
98                 val = stac9460_get(ice, idx);
99         else 
100                 val = stac9460_2_get(ice,idx - 6);
101         ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
102         return 0;
103 }
104
105 static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol,
106                                 struct snd_ctl_elem_value *ucontrol)
107 {
108         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
109         unsigned char new, old;
110         int id, idx;
111         int change;
112
113         if (kcontrol->private_value) {
114                 idx = STAC946X_MASTER_VOLUME;
115                 old = stac9460_get(ice, idx);
116                 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
117                                                         (old & ~0x80);
118                 change = (new != old);
119                 if (change) {
120                         stac9460_put(ice, idx, new);
121                         stac9460_2_put(ice, idx, new);
122                 }
123         } else {
124                 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
125                 idx = id + STAC946X_LF_VOLUME;
126                 if (id < 6)
127                         old = stac9460_get(ice, idx);
128                 else 
129                         old = stac9460_2_get(ice, idx - 6);
130                 new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) |
131                                                         (old & ~0x80);
132                 change = (new != old);
133                 if (change) {
134                         if (id < 6)
135                                 stac9460_put(ice, idx, new);
136                         else
137                                 stac9460_2_put(ice, idx - 6, new);
138                 }
139         }
140         return change;
141 }
142
143 /*
144  *      DAC volume attenuation mixer control
145  */
146 static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol,
147                                 struct snd_ctl_elem_info *uinfo)
148 {
149         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
150         uinfo->count = 1;
151         uinfo->value.integer.min = 0;                   /* mute */
152         uinfo->value.integer.max = 0x7f;                /* 0dB */
153         return 0;
154 }
155
156 static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol,
157                                 struct snd_ctl_elem_value *ucontrol)
158 {
159         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
160         int idx, id;
161         unsigned char vol;
162
163         if (kcontrol->private_value) {
164                 idx = STAC946X_MASTER_VOLUME;
165                 id = 0;
166         } else {
167                 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
168                 idx = id + STAC946X_LF_VOLUME;
169         }
170         if (id < 6)
171                 vol = stac9460_get(ice, idx) & 0x7f;
172         else 
173                 vol = stac9460_2_get(ice, idx - 6) & 0x7f;
174         ucontrol->value.integer.value[0] = 0x7f - vol;
175         return 0;
176 }
177
178 static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol,
179                                 struct snd_ctl_elem_value *ucontrol)
180 {
181         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
182         int idx, id;
183         unsigned char tmp, ovol, nvol;
184         int change;
185
186         if (kcontrol->private_value) {
187                 idx = STAC946X_MASTER_VOLUME;
188                 nvol = ucontrol->value.integer.value[0];
189                 tmp = stac9460_get(ice, idx);
190                 ovol = 0x7f - (tmp & 0x7f);
191                 change = (ovol != nvol);
192                 if (change) {
193                          stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
194                          stac9460_2_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
195                 }
196         } else {
197                 id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
198                 idx = id + STAC946X_LF_VOLUME;
199                 nvol = ucontrol->value.integer.value[0];
200                 if (id < 6)
201                         tmp = stac9460_get(ice, idx);
202                 else 
203                         tmp = stac9460_2_get(ice, idx - 6);
204                 ovol = 0x7f - (tmp & 0x7f);
205                 change = (ovol != nvol);
206                 if (change) {
207                         if (id < 6)
208                                 stac9460_put(ice, idx, (0x7f - nvol) |
209                                                         (tmp & 0x80));
210                         else 
211                                 stac9460_2_put(ice, idx-6, (0x7f - nvol) |
212                                                                 (tmp & 0x80));
213                 }
214         }
215         return change;
216 }
217
218 /*
219  * ADC mute control
220  */
221 static int stac9460_adc_mute_info(struct snd_kcontrol *kcontrol,
222                                 struct snd_ctl_elem_info *uinfo)
223 {
224         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
225         uinfo->count = 2;
226         uinfo->value.integer.min = 0;
227         uinfo->value.integer.max = 1;
228         return 0;
229 }
230
231 static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol,
232                                 struct snd_ctl_elem_value *ucontrol)
233 {
234         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
235         unsigned char val;
236         int i, id;
237         
238         id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
239         if (id == 0) {
240                 for (i = 0; i < 2; ++i) {
241                         val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
242                         ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
243                 }
244         } else {
245                 for (i = 0; i < 2; ++i) {
246                         val = stac9460_2_get(ice, STAC946X_MIC_L_VOLUME + i);
247                         ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
248                 }
249         }
250         return 0;
251 }
252
253 static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol,
254                                 struct snd_ctl_elem_value *ucontrol)
255 {
256         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
257         unsigned char new, old;
258         int i, reg, id;
259         int change;
260         
261         id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
262         if (id == 0) {
263                 for (i = 0; i < 2; ++i) {
264                         reg = STAC946X_MIC_L_VOLUME + i;
265                         old = stac9460_get(ice, reg);
266                         new = (~ucontrol->value.integer.value[i]<<7&0x80) |
267                                                                 (old&~0x80);
268                         change = (new != old);
269                         if (change)
270                                 stac9460_put(ice, reg, new);
271                 }
272         } else {
273                 for (i = 0; i < 2; ++i) {
274                         reg = STAC946X_MIC_L_VOLUME + i;
275                         old = stac9460_2_get(ice, reg);
276                         new = (~ucontrol->value.integer.value[i]<<7&0x80) |
277                                                                 (old&~0x80);
278                         change = (new != old);
279                         if (change)
280                                 stac9460_2_put(ice, reg, new);
281                 }
282         }
283         return change;
284 }
285
286 /*
287  *ADC gain mixer control
288  */
289 static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol,
290                                 struct snd_ctl_elem_info *uinfo)
291 {
292         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
293         uinfo->count = 2;
294         uinfo->value.integer.min = 0;           /* 0dB */
295         uinfo->value.integer.max = 0x0f;        /* 22.5dB */
296         return 0;
297 }
298
299 static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol,
300                                 struct snd_ctl_elem_value *ucontrol)
301 {
302         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
303         int i, reg, id;
304         unsigned char vol;
305         
306         id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
307         if (id == 0) {
308                 for (i = 0; i < 2; ++i) {
309                         reg = STAC946X_MIC_L_VOLUME + i;
310                         vol = stac9460_get(ice, reg) & 0x0f;
311                         ucontrol->value.integer.value[i] = 0x0f - vol;
312                 }
313         } else {
314                 for (i = 0; i < 2; ++i) {
315                         reg = STAC946X_MIC_L_VOLUME + i;
316                         vol = stac9460_2_get(ice, reg) & 0x0f;
317                         ucontrol->value.integer.value[i] = 0x0f - vol;
318                 }
319         }
320         return 0;
321 }
322
323 static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol,
324                         struct snd_ctl_elem_value *ucontrol)
325 {
326         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
327         int i, reg, id;
328         unsigned char ovol, nvol;
329         int change;
330         
331         id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
332         if (id == 0) {
333                 for (i = 0; i < 2; ++i) {
334                         reg = STAC946X_MIC_L_VOLUME + i;
335                         nvol = ucontrol->value.integer.value[i];
336                         ovol = 0x0f - stac9460_get(ice, reg);
337                         change = ((ovol & 0x0f) != nvol);
338                         if (change)
339                                 stac9460_put(ice, reg, (0x0f - nvol) |
340                                                         (ovol & ~0x0f));
341                 }
342         } else {
343                 for (i = 0; i < 2; ++i) {
344                         reg = STAC946X_MIC_L_VOLUME + i;
345                         nvol = ucontrol->value.integer.value[i];
346                         ovol = 0x0f - stac9460_2_get(ice, reg);
347                         change = ((ovol & 0x0f) != nvol);
348                         if (change)
349                                 stac9460_2_put(ice, reg, (0x0f - nvol) |
350                                                         (ovol & ~0x0f));
351                 }
352         }
353         return change;
354 }
355
356 /*
357  * MIC / LINE switch fonction
358  */
359
360 static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
361                                 struct snd_ctl_elem_info *uinfo)
362 {
363         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
364         uinfo->count = 1;
365         uinfo->value.integer.min = 0;
366         uinfo->value.integer.max = 1;
367         return 0;
368 }
369
370 static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
371                         struct snd_ctl_elem_value *ucontrol)
372 {
373         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
374         unsigned char val;
375         int id;
376                 
377         id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
378         if (id == 0)
379                 val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
380         else
381                 val = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
382         ucontrol->value.integer.value[0] = ~val>>7 & 0x1;
383         return 0;
384 }
385
386 static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
387                         struct snd_ctl_elem_value *ucontrol)
388 {
389         struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
390         unsigned char new, old;
391         int change, id;
392
393         id = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
394         if (id == 0)
395                 old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
396         else
397                 old = stac9460_2_get(ice, STAC946X_GENERAL_PURPOSE);
398         new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80);
399         change = (new != old);
400         if (change) {
401                 if (id == 0)
402                         stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
403                 else
404                         stac9460_2_put(ice, STAC946X_GENERAL_PURPOSE, new);
405         }
406         return change;
407 }
408
409 /*
410  * Control tabs
411  */
412 static struct snd_kcontrol_new stac9640_controls[] __devinitdata = {
413         {
414                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
415                 .name = "Master Playback Switch",
416                 .info = stac9460_dac_mute_info,
417                 .get = stac9460_dac_mute_get,
418                 .put = stac9460_dac_mute_put,
419                 .private_value = 1
420         },
421         {
422                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
423                 .name = "Master Playback Volume",
424                 .info = stac9460_dac_vol_info,
425                 .get = stac9460_dac_vol_get,
426                 .put = stac9460_dac_vol_put,
427                 .private_value = 1,
428         },
429         {
430                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
431                 .name = "MIC/Line switch",
432                 .count = 2,
433                 .info = stac9460_mic_sw_info,
434                 .get = stac9460_mic_sw_get,
435                 .put = stac9460_mic_sw_put,
436
437         },
438         {
439                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
440                 .name = "DAC Switch",
441                 .count = 8,
442                 .info = stac9460_dac_mute_info,
443                 .get = stac9460_dac_mute_get,
444                 .put = stac9460_dac_mute_put,
445         },
446         {
447                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
448                 .name = "DAC Volume",
449                 .count = 8,
450                 .info = stac9460_dac_vol_info,
451                 .get = stac9460_dac_vol_get,
452                 .put = stac9460_dac_vol_put,
453         },
454         {
455                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
456                 .name = "ADC Switch",
457                 .count = 2,
458                 .info = stac9460_adc_mute_info,
459                 .get = stac9460_adc_mute_get,
460                 .put = stac9460_adc_mute_put,
461         },
462         {
463                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
464                 .name = "ADC Volume",
465                 .count = 2,
466                 .info = stac9460_adc_vol_info,
467                 .get = stac9460_adc_vol_get,
468                 .put = stac9460_adc_vol_put,
469
470         }       
471 };
472
473
474
475 /*INIT*/
476 static int __devinit wtm_add_controls(struct snd_ice1712 *ice)
477 {
478         unsigned int i;
479         int err;
480
481         for (i = 0; i < ARRAY_SIZE(stac9640_controls); i++) {
482                 err = snd_ctl_add(ice->card,
483                                 snd_ctl_new1(&stac9640_controls[i], ice));
484                 if (err < 0)
485                         return err;
486         }
487         return 0;
488 }
489
490 static int __devinit wtm_init(struct snd_ice1712 *ice)
491 {
492         static unsigned short stac_inits_prodigy[] = {
493                 STAC946X_RESET, 0,
494                 (unsigned short)-1
495         };
496         unsigned short *p;
497                 
498         /*WTM 192M*/
499         ice->num_total_dacs = 8;
500         ice->num_total_adcs = 4;
501         ice->force_rdma1 = 1;
502
503         /*initialize codec*/
504         p = stac_inits_prodigy;
505         for (; *p != (unsigned short)-1; p += 2) {
506                 stac9460_put(ice, p[0], p[1]);
507                 stac9460_2_put(ice, p[0], p[1]);
508         }
509         return 0;
510 }
511
512
513 static unsigned char wtm_eeprom[] __devinitdata = {
514         0x47,   /*SYSCONF: clock 192KHz, 4ADC, 8DAC */
515         0x80,   /* ACLINK : I2S */
516         0xf8,   /* I2S: vol; 96k, 24bit, 192k */
517         0xc1    /*SPDIF: out-en, spidf ext out*/,
518         0x9f,   /* GPIO_DIR */
519         0xff,   /* GPIO_DIR1 */
520         0x7f,   /* GPIO_DIR2 */
521         0x9f,   /* GPIO_MASK */
522         0xff,   /* GPIO_MASK1 */
523         0x7f,   /* GPIO_MASK2 */
524         0x16,   /* GPIO_STATE */
525         0x80,   /* GPIO_STATE1 */
526         0x00,   /* GPIO_STATE2 */
527 };
528
529
530 /*entry point*/
531 struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = {
532         {
533                 .subvendor = VT1724_SUBDEVICE_WTM,
534                 .name = "ESI Waveterminal 192M",
535                 .model = "WT192M",
536                 .chip_init = wtm_init,
537                 .build_controls = wtm_add_controls,
538                 .eeprom_size = sizeof(wtm_eeprom),
539                 .eeprom_data = wtm_eeprom,
540         },
541         {} /*terminator*/
542 };