]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-tsc2101-mixer.c
h63xx: tsc2101 alsa sound support
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa-tsc2101-mixer.c
1 /*
2  * sound/arm/omap/omap-alsa-tsc2101-mixer.c
3  * 
4  * Alsa Driver for TSC2101 codec for OMAP platform boards.
5  *
6  * Copyright (C) 2005 Mika Laitio <lamikr@cc.jyu.fi> and 
7  *                   Everett Coleman II <gcc80x86@fuzzyneural.net>
8  *
9  * Board initialization code is based on the code in TSC2101 OSS driver.
10  * Copyright (C) 2004 Texas Instruments, Inc.
11  *      Written by Nishanth Menon and Sriram Kannan
12  * 
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the
15  * Free Software Foundation; either version 2 of the License, or (at your
16  * option) any later version.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
21  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * You should have received a copy of the  GNU General Public License along
30  * with this program; if not, write  to the Free Software Foundation, Inc.,
31  * 675 Mass Ave, Cambridge, MA 02139, USA.
32  *
33  * History:
34  *
35  * 2006-03-01   Mika Laitio - Mixer for the tsc2101 driver used in omap boards.
36  *              Can switch between headset and loudspeaker playback, 
37  *              mute and unmute dgc, set dgc volume. Record source switch,
38  *              keyclick, buzzer and headset volume and handset volume control 
39  *              are still missing.
40  *              
41  */
42  
43 #include "omap-alsa-tsc2101.h"
44 #include "omap-alsa-tsc2101-mixer.h"
45
46 #include <linux/types.h>
47 #include <sound/initval.h>
48 #include <sound/control.h>
49
50 //#define M_DPRINTK(ARGS...)  printk(KERN_INFO "<%s>: ",__FUNCTION__);printk(ARGS)
51 #define M_DPRINTK(ARGS...)              /* nop */
52
53 #define CHECK_BIT(INDX, ARG) (((ARG) & TSC2101_BIT(INDX)) >> INDX)
54 #define IS_UNMUTED(INDX, ARG) (((CHECK_BIT(INDX, ARG)) == 0))
55
56 #define DGC_DALVL_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
57 #define DGC_DARVL_EXTRACT(ARG) ((ARG & 0x007f))
58
59 #define HGC_ADPGA_HED_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
60 #define HNGC_ADPGA_HND_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
61 #define BGC_ADPGA_BGC_EXTRACT(ARG) ((ARG & 0x7f00) >> 8)
62
63 static int current_playback_target      = PLAYBACK_TARGET_LOUDSPEAKER;
64 static int current_rec_src              = REC_SRC_SINGLE_ENDED_MICIN_HED;
65
66 /* 
67  * Simplified write for the tsc2101 audio registers.
68  */
69 inline void omap_tsc2101_audio_write(u8 address, u16 data)
70 {
71         omap_tsc2101_write(PAGE2_AUDIO_CODEC_REGISTERS, address, data);
72 }
73
74 /* 
75  * Simplified read for the tsc2101 audio registers.
76  */
77 inline u16 omap_tsc2101_audio_read(u8 address)
78 {
79         return (omap_tsc2101_read(PAGE2_AUDIO_CODEC_REGISTERS, address));
80 }
81
82 /*
83  * For selecting tsc2101 recourd source.
84  */
85 static void set_record_source(int val)
86 {
87         u16     data;
88         
89         /* Mute Analog Sidetone
90          * Analog sidetone gain db?
91          * Input selected by MICSEL connected to ADC
92          */
93         data    = MPC_ASTMU | MPC_ASTG(0x45);
94         data    &= ~MPC_MICSEL(7); /* clear all MICSEL bits */
95         data    |= MPC_MICSEL(val);
96         data    |= MPC_MICADC;
97         omap_tsc2101_audio_write(TSC2101_MIXER_PGA_CTRL, data);
98         
99         current_rec_src = val;
100 }
101
102 /*
103  * Converts the Alsa mixer volume (0 - 100) to real 
104  * Digital Gain Control (DGC) value that can be written
105  * or read from the TSC2101 registry.
106  * 
107  * Note that the number "OUTPUT_VOLUME_MAX" is smaller than OUTPUT_VOLUME_MIN
108  * because DGC works as a volume decreaser. (The more bigger value is put
109  * to DGC, the more the volume of controlled channel is decreased)
110  * 
111  * In addition the TCS2101 chip would allow the maximum volume reduction be 63.5 DB
112  * but according to some tests user can not hear anything with this chip
113  * when the volume is set to be less than 25 db.
114  * Therefore this function will return a value that means 38.5 db (63.5 db - 25 db) 
115  * reduction in the channel volume, when mixer is set to 0.
116  * For mixer value 100, this will return a value that means 0 db volume reduction.
117  * ([mute_left_bit]0000000[mute_right_bit]0000000)
118 */
119 int get_mixer_volume_as_dac_gain_control_volume(int vol)
120 {
121         u16 retVal;
122
123         /* Convert 0 -> 100 volume to 0x7F(min) -> y(max) volume range */
124         retVal  = ((vol * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MAX;
125         /* invert the value for getting the proper range 0 min and 100 max */
126         retVal  = OUTPUT_VOLUME_MIN - retVal;
127         
128         return retVal;
129 }
130
131 /*
132  * Converts the Alsa mixer volume (0 - 100) to TSC2101 
133  * Digital Gain Control (DGC) volume. Alsa mixer volume 0
134  * is converted to value meaning the volume reduction of -38.5 db
135  * and Alsa mixer volume 100 is converted to value meaning the
136  * reduction of 0 db.
137  */
138 int set_mixer_volume_as_dac_gain_control_volume(int mixerVolL, int mixerVolR) 
139 {
140         u16 val;
141         int retVal;
142         int volL;
143         int volR;
144         
145         if ((mixerVolL < 0) || 
146             (mixerVolL > 100) ||
147             (mixerVolR < 0) ||
148             (mixerVolR > 100)) {
149                 printk(KERN_ERR "Trying a bad mixer volume as dac gain control volume value, left (%d), right (%d)!\n", mixerVolL, mixerVolR);
150                 return -EPERM;
151         }
152         M_DPRINTK("mixer volume left = %d, right = %d\n", mixerVolL, mixerVolR);        
153         volL    = get_mixer_volume_as_dac_gain_control_volume(mixerVolL);
154         volR    = get_mixer_volume_as_dac_gain_control_volume(mixerVolR);
155         
156         val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
157         /* keep the old mute bit settings */
158         val     &= ~(DGC_DALVL(OUTPUT_VOLUME_MIN) | DGC_DARVL(OUTPUT_VOLUME_MIN));
159         val     |= DGC_DALVL(volL) | DGC_DARVL(volR);
160         retVal  = 2;
161         if (retVal) {
162                 omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
163         }
164         M_DPRINTK("to registry: left = %d, right = %d, total = %d\n", DGC_DALVL_EXTRACT(val), DGC_DARVL_EXTRACT(val), val);
165         return retVal;
166 }
167
168 /**
169  * If unmuteLeft/unmuteRight == 0  --> mute
170  * If unmuteLeft/unmuteRight == 1 --> unmute
171  */
172 int dac_gain_control_unmute(int unmuteLeft, int unmuteRight)
173 {
174         u16 val;
175         int count;
176
177         count   = 0;
178         val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
179         /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
180          * so if values are same, it's time to change the registry value.
181          */
182         if (unmuteLeft != IS_UNMUTED(15, val)) {
183                 if (unmuteLeft == 0) {
184                         /* mute --> turn bit on */
185                         val     = val | DGC_DALMU;
186                 }
187                 else {
188                         /* unmute --> turn bit off */
189                         val     = val & ~DGC_DALMU;
190                 }
191                 count++;
192         } /* L */
193         if (unmuteRight != IS_UNMUTED(7, val)) {
194                 if (unmuteRight == 0) {
195                         /* mute --> turn bit on */
196                         val     = val | DGC_DARMU;
197                 }
198                 else {
199                         /* unmute --> turn bit off */
200                         val     = val & ~DGC_DARMU;
201                 }               
202                 count++;
203         } /* R */
204         if (count) {
205                 omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);
206                 M_DPRINTK("changed value, is_unmuted left = %d, right = %d\n", 
207                         IS_UNMUTED(15, val),
208                         IS_UNMUTED(7, val));
209         }
210         return count;   
211 }
212
213 /**
214  * unmute: 0 --> mute, 1 --> unmute
215  * page2RegIndx: Registry index in tsc2101 page2.
216  * muteBitIndx: Index number for the bit in registry that indicates whether muted or unmuted.
217  */
218 int adc_pga_unmute_control(int unmute, int page2regIndx, int muteBitIndx)
219 {
220         int count;
221         u16 val;
222         
223         count   = 0;
224         val     = omap_tsc2101_audio_read(page2regIndx);
225         /* in alsa mixer 1 --> on, 0 == off. In tsc2101 registry 1 --> off, 0 --> on
226          * so if the values are same, it's time to change the registry value...
227          */
228         if (unmute != IS_UNMUTED(muteBitIndx, val)) {
229                 if (unmute == 0) {
230                         /* mute --> turn bit on */
231                         val     = val | TSC2101_BIT(muteBitIndx);
232                 }
233                 else {
234                         /* unmute --> turn bit off */
235                         val     = val & ~TSC2101_BIT(muteBitIndx);
236                 }
237                 M_DPRINTK("changed value, is_unmuted = %d\n", IS_UNMUTED(muteBitIndx, val));
238                 count++;
239         }
240         if (count) {
241                 omap_tsc2101_audio_write(page2regIndx, val);
242         }
243         return count;
244 }
245
246 /*
247  * Converts the DGC registry value read from the TSC2101 registry to 
248  * Alsa mixer volume format (0 - 100).
249  */
250 int get_dac_gain_control_volume_as_mixer_volume(u16 vol) 
251 {
252         u16 retVal;     
253
254         retVal  = OUTPUT_VOLUME_MIN - vol;
255         retVal  = ((retVal - OUTPUT_VOLUME_MAX) * 100) / OUTPUT_VOLUME_RANGE;
256         /* fix scaling error */
257         if ((retVal > 0) && (retVal < 100)) {
258                 retVal++;
259         }
260         return retVal;
261 }
262
263 /*
264  * Converts the headset gain control volume (0 - 63.5 db)
265  * to Alsa mixer volume (0 - 100)
266  */
267 int get_headset_gain_control_volume_as_mixer_volume(u16 registerVal) 
268 {
269         u16 retVal;
270         
271         retVal  = ((registerVal * 100) / INPUT_VOLUME_RANGE);
272         return retVal;
273 }
274
275 /*
276  * Converts the handset gain control volume (0 - 63.5 db)
277  * to Alsa mixer volume (0 - 100)
278  */
279 int get_handset_gain_control_volume_as_mixer_volume(u16 registerVal) 
280 {
281         return get_headset_gain_control_volume_as_mixer_volume(registerVal);
282 }
283
284 /*
285  * Converts the Alsa mixer volume (0 - 100) to 
286  * headset gain control volume (0 - 63.5 db)
287  */
288 int get_mixer_volume_as_headset_gain_control_volume(u16 mixerVal) 
289 {
290         u16 retVal;
291         
292         retVal  = ((mixerVal * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;   
293         return retVal;
294 }
295
296 /*
297  * Writes Alsa mixer volume (0 - 100) to TSC2101 headset volume registry in
298  * a TSC2101 format. (0 - 63.5 db)
299  * In TSC2101 OSS driver this functionality was controlled with "SET_LINE" parameter.
300  */
301 int set_mixer_volume_as_headset_gain_control_volume(int mixerVol) 
302 {
303         int volume;
304         int retVal;
305         u16 val;
306
307         if (mixerVol < 0 || mixerVol > 100) {
308                 M_DPRINTK("Trying a bad headset mixer volume value(%d)!\n", mixerVol);
309                 return -EPERM;
310         }
311         M_DPRINTK("mixer volume = %d\n", mixerVol);
312         /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range */
313         /* NOTE: 0 is minimum volume and not mute */
314         volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);    
315         val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
316         /* preserve the old mute settings */
317         val     &= ~(HGC_ADPGA_HED(INPUT_VOLUME_MAX));
318         val     |= HGC_ADPGA_HED(volume);
319         omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);       
320         retVal  = 1;
321         
322         M_DPRINTK("to registry = %d\n", val);   
323         return retVal;
324 }
325
326 /*
327  * Writes Alsa mixer volume (0 - 100) to TSC2101 handset volume registry in
328  * a TSC2101 format. (0 - 63.5 db)
329  * In TSC2101 OSS driver this functionality was controlled with "SET_MIC" parameter.
330  */
331 int set_mixer_volume_as_handset_gain_control_volume(int mixerVol) 
332 {
333         int volume;
334         int retVal;
335         u16 val;        
336
337         if (mixerVol < 0 || mixerVol > 100) {
338                 M_DPRINTK("Trying a bad mic mixer volume value(%d)!\n", mixerVol);
339                 return -EPERM;
340         }
341         M_DPRINTK("mixer volume = %d\n", mixerVol);
342         /* Convert 0 -> 100 volume to 0x0(min) -> 0x7D(max) volume range
343          * NOTE: 0 is minimum volume and not mute 
344          */
345         volume  = get_mixer_volume_as_headset_gain_control_volume(mixerVol);
346         val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
347         /* preserve the old mute settigns */
348         val     &= ~(HNGC_ADPGA_HND(INPUT_VOLUME_MAX));
349         val     |= HNGC_ADPGA_HND(volume);
350         omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
351         retVal  = 1;
352         
353         M_DPRINTK("to registry = %d\n", val);   
354         return retVal;
355 }
356
357 void set_loudspeaker_to_playback_target(void)
358 {
359         /* power down SPK1, SPK2 and loudspeaker */
360         omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
361                         CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);       
362         /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
363          * 1dB AGC hysteresis
364          * MICes bias 2V
365          */
366         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
367
368         /* DAC left and right routed to SPK1/SPK2
369          * SPK1/SPK2 unmuted
370          * Keyclicks routed to SPK1/SPK2 */
371         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5, 
372                         AC5_DIFFIN |
373                         AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
374                         AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2);
375         
376         /* routing selected to SPK1 goes also to OUT8P/OUT8N. (loudspeaker)
377          * analog sidetone routed to loudspeaker
378          * buzzer pga routed to loudspeaker
379          * keyclick routing to loudspeaker
380          * cellphone input routed to loudspeaker
381          * mic selection (control register 04h/page2) routed to cell phone output (CP_OUT)
382          * routing selected for SPK1 goes also to cellphone output (CP_OUT)
383          * OUT8P/OUT8N (loudspeakers) unmuted (0 = unmuted)
384          * Cellphone output is not muted (0 = unmuted)
385          * Enable loudspeaker short protection control (0 = enable protection)
386          * VGND short protection control (0 = enable protection)
387          */
388         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
389                         AC6_SPL2LSK | AC6_AST2LSK | AC6_BUZ2LSK | AC6_KCL2LSK |
390                         AC6_CPI2LSK | AC6_MIC2CPO | AC6_SPL2CPO);
391         current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
392 }
393
394 void set_headphone_to_playback_target(void)
395 {
396         /* power down SPK1, SPK2 and loudspeaker */
397         omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
398                         CPC_SP1PWDN | CPC_SP2PWDN | CPC_LDAPWDF);
399         /* ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled */
400         /* 1dB AGC hysteresis */
401         /* MICes bias 2V */
402         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, AC4_MB_HED(0));
403                                 
404         /* DAC left and right routed to SPK1/SPK2
405          * SPK1/SPK2 unmuted
406          * Keyclicks routed to SPK1/SPK2 */
407         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
408                         AC5_DAC2SPK1(3) | AC5_AST2SPK1 | AC5_KCL2SPK1 |
409                         AC5_DAC2SPK2(3) | AC5_AST2SPK2 | AC5_KCL2SPK2 |
410                         AC5_HDSCPTC);
411                         
412         /* OUT8P/OUT8N muted, CPOUT muted */
413         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
414                         AC6_MUTLSPK | AC6_MUTSPK2 | AC6_LDSCPTC |
415                         AC6_VGNDSCPTC);
416         current_playback_target = PLAYBACK_TARGET_HEADPHONE;
417 }
418
419 void set_telephone_to_playback_target(void)
420 {
421         /* 
422          * 0110 1101 0101 1100
423          * power down MICBIAS_HED, Analog sidetone, SPK2, DAC, 
424          * Driver virtual ground, loudspeaker. Values D2-d5 are flags.
425          */      
426         omap_tsc2101_audio_write(TSC2101_CODEC_POWER_CTRL,
427                         CPC_MBIAS_HED | CPC_ASTPWD | CPC_SP2PWDN | CPC_DAPWDN |
428                         CPC_VGPWDN | CPC_LSPWDN);
429                         
430         /* 
431          * 0010 1010 0100 0000
432          * ADC, DAC, Analog Sidetone, cellphone, buzzer softstepping enabled
433          * 1dB AGC hysteresis
434          * MICes bias 2V
435          */
436         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4,
437                         AC4_MB_HND | AC4_MB_HED(0) | AC4_AGCHYS(1) | 
438                         AC4_BISTPD | AC4_ASSTPD | AC4_DASTPD);
439         printk("set_telephone_to_playback_target(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
440                         
441         /* 
442          * 1110 0010 0000 0010
443          * DAC left and right routed to SPK1/SPK2
444          * SPK1/SPK2 unmuted
445          * keyclicks routed to SPK1/SPK2
446          */      
447         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_5,
448                         AC5_DIFFIN | AC5_DAC2SPK1(3) | 
449                         AC5_CPI2SPK1 | AC5_MUTSPK2);
450         
451         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_6,
452                         AC6_MIC2CPO | AC6_MUTLSPK | 
453                         AC6_LDSCPTC | AC6_VGNDSCPTC | AC6_CAPINTF);
454         current_playback_target = PLAYBACK_TARGET_CELLPHONE;
455 }
456
457 /*
458  * 1100 0101 1101 0000
459  * 
460  * #define MPC_ASTMU           TSC2101_BIT(15)
461  * #define MPC_ASTG(ARG)       (((ARG) & 0x7F) << 8)
462  * #define MPC_MICSEL(ARG)     (((ARG) & 0x07) << 5)
463  * #define MPC_MICADC          TSC2101_BIT(4)
464  * #define MPC_CPADC           TSC2101_BIT(3)
465  * #define MPC_ASTGF           (0x01)
466  */
467 static void set_telephone_to_record_source(void)
468 {
469         u16     val;
470         
471         /* 
472          * D0       = 0: 
473          *              --> AGC is off for handset input.
474          *              --> ADC PGA is controlled by the ADMUT_HDN + ADPGA_HND
475          *          (D15, D14-D8)
476          * D4 - D1  = 0000 
477          *              --> AGC time constant for handset input, 
478          *              attack time = 8 mc, decay time = 100 ms
479          * D7 - D5  = 000
480          *              --> AGC Target gain for handset input = -5.5 db
481          * D14 - D8 = 011 1100
482          *              --> ADC handset PGA settings = 60 = 30 db
483          * D15          = 0
484          *              --> Handset input ON (unmuted)
485          */
486         val     = 0x3c00;       // 0011 1100 0000 0000 = 60 = 30
487         omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);
488         
489         /*
490          * D0           = 0
491          *              --> AGC is off for headset/Aux input
492          *              --> ADC headset/Aux PGA is contoller by ADMUT_HED + ADPGA_HED
493          *          (D15, D14-D8)
494          * D4 - D1      = 0000 
495          *              --> Agc constant for headset/Aux input,
496          *              attack time = 8 mc, decay time = 100 ms      
497          * D7 - D5      = 000
498          *              --> AGC target gain for headset input = -5.5 db
499          * D14 - D8 = 000 0000
500          *              --> Adc headset/AUX pga settings = 0 db
501          * D15          = 1
502          *              --> Headset/AUX input muted
503          * 
504          * Mute headset aux input
505          */
506         val     = 0x8000;       // 1000 0000 0000 0000
507         omap_tsc2101_audio_write(TSC2101_HEADSET_GAIN_CTRL, val);
508         set_record_source(REC_SRC_MICIN_HND_AND_AUX1);
509
510         // hacks start
511         /* D0           = flag, Headset/Aux or handset PGA flag
512          *              --> & with 1 (= 1 -->gain applied == pga register settings)
513          * D1           = 0, DAC channel PGA soft stepping control
514          *              --> 0.5 db change every WCLK
515          * D2           = flag, DAC right channel PGA flag
516          *              --> & with 1
517          * D3           = flag, DAC left channel PGA flag
518          *              -- > & with 1
519          * D7 - D4      = 0001, keyclick length
520          *              --> 4 periods key clicks
521          * D10 - D8 = 100, keyclick frequenzy
522          *              --> 1 kHz, 
523          * D11          = 0, Headset/Aux or handset soft stepping control
524          *              --> 0,5 db change every WCLK or ADWS
525          * D14 -D12 = 100, Keyclick applitude control
526          *              --> Medium amplitude
527          * D15          = 0, keyclick disabled
528          */
529         val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_2);
530         val     = val & 0x441d;
531         val     = val | 0x4410; // D14, D10, D4 bits == 1
532         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_2, val);
533
534         /*
535          * D0           = 0     (reserved, write always 0)
536          * D1           = flag,
537          *                      --> & with 1
538          * D2 - D5      = 0000 (reserved, write always 0000)
539          * D6           = 1
540          *                      --> MICBIAS_HND = 2.0 v
541          * D8 - D7      = 00
542          *                      --> MICBIAS_HED = 3.3 v
543          * D10 - D9     = 01, 
544          *                      --> Mic AGC hysteric selection = 2 db
545          * D11          = 1, 
546          *                      --> Disable buzzer PGA soft stepping
547          * D12          = 0,
548          *                      --> Enable CELL phone PGA soft stepping control
549          * D13          = 1
550          *                      --> Disable analog sidetone soft stepping control
551          * D14          = 0
552          *                      --> Enable DAC PGA soft stepping control
553          * D15          = 0,
554          *                      --> Enable headset/Aux or Handset soft stepping control
555          */
556         val     = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4);
557         val     = val & 0x2a42; // 0010 1010 0100 0010
558         val     = val | 0x2a40; // bits D13, D11, D9, D6 == 1
559         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_4, val);
560         printk("set_telephone_to_record_source(), TSC2101_AUDIO_CTRL_4 = %d\n", omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_4));
561         /*
562          * D0           = 0
563          *              --> reserved, write always = 0
564          * D1           = flag, read only
565          *              --> & with 1
566          * D5 - D2      = 1111, Buzzer input PGA settings
567          *              --> 0 db
568          * D6           = 1,
569          *              --> power down buzzer input pga
570          * D7           = flag, read only
571          *              --> & with 1
572          * D14 - D8     = 101 1101
573          *              --> 12 DB
574          * D15          = 0
575          *              --> power up cell phone input PGA
576          */
577         val     = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
578         val     = val & 0x5dfe;
579         val     = val | 0x5dfe; // bits, D14, D12, D11, D10, D8, D6, D5,D4,D3,D2
580         omap_tsc2101_audio_write(TSC2101_BUZZER_GAIN_CTRL, val);
581         
582         /* D6 - D0      = 000 1001
583          *              --> -4.5 db for DAC right channel volume control
584          * D7           = 1
585          *              -->  DAC right channel muted
586          * D14 - D8 = 000 1001
587          *              --> -4.5 db for DAC left channel volume control
588          * D15          = 1
589          *              --> DAC left channel muted
590          */
591         //val   = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
592         val     = 0x8989;
593         omap_tsc2101_audio_write(TSC2101_DAC_GAIN_CTRL, val);   
594         
595         /*  0000 0000 0100 0000
596          * 
597          * D1 - D0      = 0
598          *              --> GPIO 1 pin output is three stated
599          * D2           = 0
600          *              --> Disaple GPIO2 for CLKOUT mode
601          * D3           = 0
602          *              --> Disable GPUI1 for interrupt detection
603          * D4           = 0
604          *              --> Disable GPIO2 for headset detection interrupt
605          * D5           = reserved, always 0
606          * D7 - D6      = 01
607          *              --> 8 ms clitch detection
608          * D8           = reserved, write only 0
609          * D10 -D9      = 00
610          *              --> 16 ms de bouncing programmatitily 
611          *          for glitch detection during headset detection
612          * D11          = flag for button press
613          * D12          = flag for headset detection
614          * D14-D13      = 00
615          *              --> type of headset detected = 00 == no stereo headset deected
616          * D15          = 0
617          *              --> Disable headset detection
618          * 
619          * */
620         val     = 0x40;
621         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, val);    
622 }
623
624 /*
625  * Checks whether the headset is detected.
626  * If headset is detected, the type is returned. Type can be
627  *      0x01    = stereo headset detected
628  *      0x02    = cellurar headset detected
629  *      0x03    = stereo + cellurar headset detected
630  * If headset is not detected 0 is returned.
631  */
632 u16 get_headset_detected(void)
633 {
634         u16     curDetected;
635         u16     curType;
636         u16     curVal;
637         
638         curType = 0;    /* not detected */
639         curVal  = omap_tsc2101_audio_read(TSC2101_AUDIO_CTRL_7);
640         curDetected     = curVal & AC7_HDDETFL;
641         if (curDetected) {
642                 printk("headset detected, checking type from %d \n", curVal);
643                 curType = ((curVal & 0x6000) >> 13);
644                 printk("headset type detected = %d \n", curType);
645         }
646         else {
647                 printk("headset not detected\n");
648         }
649         return curType;
650 }
651
652 void init_playback_targets(void)
653 {
654         u16     val;
655
656         set_loudspeaker_to_playback_target();
657         /* Left line input volume control
658          * = SET_LINE in the OSS driver
659          */
660         set_mixer_volume_as_headset_gain_control_volume(DEFAULT_INPUT_VOLUME);
661
662         /* Set headset to be controllable by handset mixer
663          * AGC enable for handset input
664          * Handset input not muted
665          */
666         val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
667         val     = val | HNGC_AGCEN_HND; 
668         val     = val & ~HNGC_ADMUT_HND;
669         omap_tsc2101_audio_write(TSC2101_HANDSET_GAIN_CTRL, val);       
670                         
671         /* mic input volume control
672          * SET_MIC in the OSS driver 
673          */
674         set_mixer_volume_as_handset_gain_control_volume(DEFAULT_INPUT_VOLUME);
675
676         /* Left/Right headphone channel volume control
677          * Zero-cross detect on
678          */
679         set_mixer_volume_as_dac_gain_control_volume(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);      
680         /* unmute */
681         dac_gain_control_unmute(1, 1);
682 }
683
684 /*
685  * Initializes tsc2101 recourd source (to line) and playback target (to loudspeaker)
686  */
687 void snd_omap_init_mixer(void)
688 {       
689         FN_IN;
690         
691         /* Headset/Hook switch detect enabled */
692         omap_tsc2101_audio_write(TSC2101_AUDIO_CTRL_7, AC7_DETECT);
693
694         /* Select headset to record source (MIC_INHED)*/
695         set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
696         /* Init loudspeaker as a default playback target*/
697         init_playback_targets();
698
699         FN_OUT(0);
700 }
701
702 static int __pcm_playback_target_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
703 {
704         static char *texts[PLAYBACK_TARGET_COUNT] = {
705                 "Loudspeaker", "Headphone", "Cellphone"
706         };
707
708         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
709         uinfo->count = 1;
710         uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
711         if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1) {
712                 uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
713         }
714         strcpy(uinfo->value.enumerated.name,
715         texts[uinfo->value.enumerated.item]);
716         return 0;
717 }
718
719 static int __pcm_playback_target_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
720 {
721         ucontrol->value.integer.value[0] = current_playback_target;
722         return 0;
723 }
724
725 static int __pcm_playback_target_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
726 {
727         int     retVal;
728         int     curVal;
729         
730         retVal  = 0;
731         curVal  = ucontrol->value.integer.value[0];
732         if ((curVal >= 0) &&
733             (curVal < PLAYBACK_TARGET_COUNT) &&
734             (curVal != current_playback_target)) {              
735                 if (curVal == PLAYBACK_TARGET_LOUDSPEAKER) {
736                         set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
737                         set_loudspeaker_to_playback_target();
738                 }
739                 else if (curVal == PLAYBACK_TARGET_HEADPHONE) {
740                         set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
741                         set_headphone_to_playback_target();
742                 }
743                 else if (curVal == PLAYBACK_TARGET_CELLPHONE) {
744                         set_telephone_to_record_source();
745                         set_telephone_to_playback_target();
746                 }
747                 retVal  = 1;
748         }
749         return retVal;
750 }       
751
752 static int __pcm_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
753 {
754         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
755         uinfo->count                    = 2;
756         uinfo->value.integer.min        = 0;
757         uinfo->value.integer.max        = 100;
758         return 0;
759 }
760
761 /*
762  * Alsa mixer interface function for getting the volume read from the DGC in a 
763  * 0 -100 alsa mixer format.
764  */
765 static int __pcm_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
766 {
767         u16 volL;
768         u16 volR;       
769         u16 val;
770         
771         val     = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
772         M_DPRINTK("registry value = %d!\n", val);
773         volL    = DGC_DALVL_EXTRACT(val);
774         volR    = DGC_DARVL_EXTRACT(val);
775         /* make sure that other bits are not on */
776         volL    = volL & ~DGC_DALMU;
777         volR    = volR & ~DGC_DARMU;
778
779         volL    = get_dac_gain_control_volume_as_mixer_volume(volL);
780         volR    = get_dac_gain_control_volume_as_mixer_volume(volR);
781         
782         ucontrol->value.integer.value[0]        = volL; /* L */
783         ucontrol->value.integer.value[1]        = volR; /* R */
784         
785         M_DPRINTK("mixer volume left = %ld, right = %ld\n", ucontrol->value.integer.value[0], ucontrol->value.integer.value[1]);
786         return 0;
787 }
788
789 static int __pcm_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
790 {
791         return set_mixer_volume_as_dac_gain_control_volume(ucontrol->value.integer.value[0], 
792                                                         ucontrol->value.integer.value[1]);
793 }
794
795 static int __pcm_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
796 {
797         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
798         uinfo->count                    = 2;
799         uinfo->value.integer.min        = 0;
800         uinfo->value.integer.max        = 1;
801         return 0;
802 }
803
804 /* 
805  * When DGC_DALMU (bit 15) is 1, the left channel is muted.
806  * When DGC_DALMU is 0, left channel is not muted.
807  * Same logic apply also for the right channel.
808  */
809 static int __pcm_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
810 {
811         u16 val = omap_tsc2101_audio_read(TSC2101_DAC_GAIN_CTRL);
812         
813         ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);  // left
814         ucontrol->value.integer.value[1]        = IS_UNMUTED(7, val);   // right
815         return 0;
816 }
817
818 static int __pcm_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
819 {
820         return dac_gain_control_unmute(ucontrol->value.integer.value[0], 
821                                         ucontrol->value.integer.value[1]);
822 }
823
824 static int __headset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
825 {
826         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
827         uinfo->count                    = 1;
828         uinfo->value.integer.min        = 0;
829         uinfo->value.integer.max        = 100;
830         return 0;
831 }
832
833 static int __headset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
834 {
835         u16 val;
836         u16 vol;
837         
838         val     = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
839         M_DPRINTK("registry value = %d\n", val);
840         vol     = HGC_ADPGA_HED_EXTRACT(val);
841         vol     = vol & ~HGC_ADMUT_HED;
842
843         vol     = get_headset_gain_control_volume_as_mixer_volume(vol);
844         ucontrol->value.integer.value[0]        = vol;
845         
846         M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
847         return 0;
848 }
849
850 static int __headset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
851 {
852         return set_mixer_volume_as_headset_gain_control_volume(ucontrol->value.integer.value[0]);       
853 }
854
855 static int __headset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
856 {
857         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
858         uinfo->count                    = 1;
859         uinfo->value.integer.min        = 0;
860         uinfo->value.integer.max        = 1;
861         return 0;
862 }
863
864 /* When HGC_ADMUT_HED (bit 15) is 1, the headset is muted.
865  * When HGC_ADMUT_HED is 0, headset is not muted.
866  */
867 static int __headset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
868 {
869         u16 val = omap_tsc2101_audio_read(TSC2101_HEADSET_GAIN_CTRL);
870         ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
871         return 0;
872 }
873
874 static int __headset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
875 {
876         // mute/unmute headset
877         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
878                                 TSC2101_HEADSET_GAIN_CTRL,
879                                 15);
880 }
881
882 static int __handset_playback_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
883 {
884         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
885         uinfo->count                    = 1;
886         uinfo->value.integer.min        = 0;
887         uinfo->value.integer.max        = 100;
888         return 0;
889 }
890
891 static int __handset_playback_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
892 {
893         u16 val;
894         u16 vol;
895         
896         val     = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
897         M_DPRINTK("registry value = %d\n", val);
898         vol     = HNGC_ADPGA_HND_EXTRACT(val);
899         vol     = vol & ~HNGC_ADMUT_HND;
900         vol     = get_handset_gain_control_volume_as_mixer_volume(vol);
901         ucontrol->value.integer.value[0]        = vol;
902         
903         M_DPRINTK("mixer volume returned = %ld\n", ucontrol->value.integer.value[0]);
904         return 0;
905 }
906
907 static int __handset_playback_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
908 {
909         return set_mixer_volume_as_handset_gain_control_volume(ucontrol->value.integer.value[0]);       
910 }
911
912 static int __handset_playback_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
913 {
914         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
915         uinfo->count                    = 1;
916         uinfo->value.integer.min        = 0;
917         uinfo->value.integer.max        = 1;
918         return 0;
919 }
920
921 /* When HNGC_ADMUT_HND (bit 15) is 1, the handset is muted.
922  * When HNGC_ADMUT_HND is 0, handset is not muted.
923  */
924 static int __handset_playback_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
925 {
926         u16 val = omap_tsc2101_audio_read(TSC2101_HANDSET_GAIN_CTRL);
927         ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
928         return 0;
929 }
930
931 static int __handset_playback_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
932 {
933         // handset mute/unmute
934         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
935                                 TSC2101_HANDSET_GAIN_CTRL,
936                                 15);
937 }
938
939 static int __cellphone_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
940 {
941         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
942         uinfo->count                    = 1;
943         uinfo->value.integer.min        = 0;
944         uinfo->value.integer.max        = 1;
945         return 0;
946 }
947
948 /* When BGC_MUT_CP (bit 15) = 1, power down cellphone input pga.
949  * When BGC_MUT_CP = 0, power up cellphone input pga.
950  */
951 static int __cellphone_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
952 {
953         u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
954         ucontrol->value.integer.value[0]        = IS_UNMUTED(15, val);
955         return 0;
956 }
957
958 static int __cellphone_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
959 {
960         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
961                                 TSC2101_BUZZER_GAIN_CTRL,
962                                 15);    
963 }
964
965 static int __buzzer_input_switch_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) 
966 {
967         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
968         uinfo->count                    = 1;
969         uinfo->value.integer.min        = 0;
970         uinfo->value.integer.max        = 1;
971         return 0;
972 }
973
974 /* When BGC_MUT_BU (bit 6) = 1, power down cellphone input pga.
975  * When BGC_MUT_BU = 0, power up cellphone input pga.
976  */
977 static int __buzzer_input_switch_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
978 {
979         u16 val = omap_tsc2101_audio_read(TSC2101_BUZZER_GAIN_CTRL);
980         ucontrol->value.integer.value[0]        = IS_UNMUTED(6, val);
981         return 0;
982 }
983
984 static int __buzzer_input_switch_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) 
985 {
986         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
987                                 TSC2101_BUZZER_GAIN_CTRL,
988                                 6);     
989 }
990
991 static snd_kcontrol_new_t tsc2101_control[] __devinitdata = {
992         {
993                 .name  = "Target Playback Route",
994                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
995                 .index = 0,
996                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
997                 .info  = __pcm_playback_target_info,
998                 .get   = __pcm_playback_target_get,
999                 .put   = __pcm_playback_target_put,
1000         }, {
1001                 .name  = "Master Playback Volume",
1002                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1003                 .index = 0,
1004                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1005                 .info  = __pcm_playback_volume_info,
1006                 .get   = __pcm_playback_volume_get,
1007                 .put   = __pcm_playback_volume_put,
1008         }, {
1009                 .name  = "Master Playback Switch",
1010                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1011                 .index = 0,
1012                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1013                 .info  = __pcm_playback_switch_info,
1014                 .get   = __pcm_playback_switch_get,
1015                 .put   = __pcm_playback_switch_put,
1016         }, {
1017                 .name  = "Headset Playback Volume",
1018                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1019                 .index = 0,
1020                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1021                 .info  = __headset_playback_volume_info,
1022                 .get   = __headset_playback_volume_get,
1023                 .put   = __headset_playback_volume_put,
1024         }, {
1025                 .name  = "Headset Playback Switch",
1026                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1027                 .index = 0,
1028                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1029                 .info  = __headset_playback_switch_info,
1030                 .get   = __headset_playback_switch_get,
1031                 .put   = __headset_playback_switch_put,
1032         }, {
1033                 .name  = "Handset Playback Volume",
1034                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1035                 .index = 0,
1036                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1037                 .info  = __handset_playback_volume_info,
1038                 .get   = __handset_playback_volume_get,
1039                 .put   = __handset_playback_volume_put,
1040         }, {
1041                 .name  = "Handset Playback Switch",
1042                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1043                 .index = 0,
1044                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1045                 .info  = __handset_playback_switch_info,
1046                 .get   = __handset_playback_switch_get,
1047                 .put   = __handset_playback_switch_put,
1048         }, {
1049                 .name  = "Cellphone Input Switch",
1050                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1051                 .index = 0,
1052                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1053                 .info  = __cellphone_input_switch_info,
1054                 .get   = __cellphone_input_switch_get,
1055                 .put   = __cellphone_input_switch_put,
1056         }, {
1057                 .name  = "Buzzer Input Switch",
1058                 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1059                 .index = 0,
1060                 .access= SNDRV_CTL_ELEM_ACCESS_READWRITE,
1061                 .info  = __buzzer_input_switch_info,
1062                 .get   = __buzzer_input_switch_get,
1063                 .put   = __buzzer_input_switch_put,
1064         }
1065 };
1066
1067 #ifdef CONFIG_PM
1068
1069 void snd_omap_suspend_mixer(void)
1070 {
1071 }
1072
1073 void snd_omap_resume_mixer(void)
1074 {
1075         snd_omap_init_mixer();
1076 }
1077 #endif
1078
1079 int snd_omap_mixer(struct snd_card_omap_codec *tsc2101) 
1080 {
1081         int i=0;
1082         int err=0;
1083
1084         if (!tsc2101) {
1085                 return -EINVAL;
1086         }
1087         for (i=0; i < ARRAY_SIZE(tsc2101_control); i++) {
1088                 if ((err = snd_ctl_add(tsc2101->card, 
1089                                 snd_ctl_new1(&tsc2101_control[i], 
1090                                 tsc2101->card))) < 0) {
1091                         return err;
1092                 }
1093         }
1094         return 0;
1095 }