]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-sx1-mixer.c
d0c3322378f6a343435634d0cec161d4740c83ef
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa-sx1-mixer.c
1 /*
2  * sound/arm/omap/omap-alsa-sx1-mixer.c
3  *
4  * Alsa codec Driver for Siemens SX1 board.
5  * based on omap-alsa-tsc2101-mixer.c
6  *
7  *  Copyright (C) 2006 Vladimir Ananiev (vovan888 at gmail com)
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  *
14  * You should have received a copy of the  GNU General Public License along
15  * with this program; if not, write  to the Free Software Foundation, Inc.,
16  * 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  */
19
20 #include "omap-alsa-sx1.h"
21 #include "omap-alsa-sx1-mixer.h"
22
23 #include <linux/types.h>
24 #include <sound/initval.h>
25 #include <sound/control.h>
26
27 static int current_playback_target      = PLAYBACK_TARGET_LOUDSPEAKER;
28 static int current_rec_src              = REC_SRC_SINGLE_ENDED_MICIN_HED;
29 static int current_volume;      /* current volume, we cant read it */
30 static int current_fm_volume;   /* current FM radio volume, we cant read it */
31
32 /*
33  * Select SX1 recording source.
34  */
35 static void set_record_source(int val)
36 {
37         /* TODO Recording is done on McBSP2 and Mic only */
38         current_rec_src = val;
39 }
40
41 static int set_mixer_volume(int mixer_vol)
42 {
43         int ret, i;
44         if ((mixer_vol < 0) || (mixer_vol > 9)) {
45                 printk(KERN_ERR "Trying a bad mixer volume (%d)!\n", mixer_vol);
46                 return -EPERM;
47         }
48         ret = (current_volume != mixer_vol);
49         current_volume = mixer_vol; /* set current volume, we cant read it */
50
51         i = cn_sx1snd_send(DAC_VOLUME_UPDATE, mixer_vol, 0);
52         if (i)
53                 return i;
54         return ret;
55 }
56
57 static void set_loudspeaker_to_playback_target(void)
58 {
59         /* TODO */
60         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_SPEAKER, 0);
61
62         current_playback_target = PLAYBACK_TARGET_LOUDSPEAKER;
63 }
64
65 static void set_headphone_to_playback_target(void)
66 {
67         /* TODO */
68         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_HEADPHONE, 0);
69
70         current_playback_target = PLAYBACK_TARGET_HEADPHONE;
71 }
72
73 static void set_telephone_to_playback_target(void)
74 {
75         /* TODO */
76         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
77
78         current_playback_target = PLAYBACK_TARGET_CELLPHONE;
79 }
80
81 static void set_telephone_to_record_source(void)
82 {
83         cn_sx1snd_send(DAC_SETAUDIODEVICE, SX1_DEVICE_PHONE, 0);
84 }
85
86 static void init_playback_targets(void)
87 {
88         set_loudspeaker_to_playback_target();
89         set_mixer_volume(DEFAULT_OUTPUT_VOLUME);
90 }
91
92 /*
93  * Initializes SX1 record source (to mic) and playback target (to loudspeaker)
94  */
95 void snd_omap_init_mixer(void)
96 {
97         /* Select headset to record source */
98         set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
99         /* Init loudspeaker as a default playback target*/
100         init_playback_targets();
101 }
102
103 /* ---------------------------------------------------------------------- */
104 static int pcm_playback_target_info(struct snd_kcontrol *kcontrol,
105                                         struct snd_ctl_elem_info *uinfo)
106 {
107         static char *texts[PLAYBACK_TARGET_COUNT] = {
108                 "Loudspeaker", "Headphone", "Cellphone"
109         };
110
111         uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
112         uinfo->count = 1;
113         uinfo->value.enumerated.items = PLAYBACK_TARGET_COUNT;
114         if (uinfo->value.enumerated.item > PLAYBACK_TARGET_COUNT - 1)
115                 uinfo->value.enumerated.item = PLAYBACK_TARGET_COUNT - 1;
116
117         strcpy(uinfo->value.enumerated.name,
118                         texts[uinfo->value.enumerated.item]);
119         return 0;
120 }
121
122 static int pcm_playback_target_get(struct snd_kcontrol *kcontrol,
123                                         struct snd_ctl_elem_value *ucontrol)
124 {
125         ucontrol->value.integer.value[0] = current_playback_target;
126         return 0;
127 }
128
129 static int pcm_playback_target_put(struct snd_kcontrol *kcontrol,
130                                         struct snd_ctl_elem_value *ucontrol)
131 {
132         int ret_val = 0;
133         int cur_val = ucontrol->value.integer.value[0];
134
135         if ((cur_val >= 0) &&
136                 (cur_val < PLAYBACK_TARGET_COUNT) &&
137                 (cur_val != current_playback_target)) {
138                 if (cur_val == PLAYBACK_TARGET_LOUDSPEAKER) {
139                         set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HED);
140                         set_loudspeaker_to_playback_target();
141                 } else if (cur_val == PLAYBACK_TARGET_HEADPHONE) {
142                         set_record_source(REC_SRC_SINGLE_ENDED_MICIN_HND);
143                         set_headphone_to_playback_target();
144                 } else if (cur_val == PLAYBACK_TARGET_CELLPHONE) {
145                         set_telephone_to_record_source();
146                         set_telephone_to_playback_target();
147                 }
148                 ret_val = 1;
149         }
150         return ret_val;
151 }
152
153 /*-----------------------------------------------------------*/
154 static int pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
155                                         struct snd_ctl_elem_info *uinfo)
156 {
157         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
158         uinfo->count                    = 1;
159         uinfo->value.integer.min        = 0;
160         uinfo->value.integer.max        = 9;
161         return 0;
162 }
163
164 static int pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
165                                         struct snd_ctl_elem_value *ucontrol)
166 {
167         ucontrol->value.integer.value[0] = current_volume;
168         return 0;
169 }
170
171 static int pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
172                                         struct snd_ctl_elem_value *ucontrol)
173 {
174         return set_mixer_volume(ucontrol->value.integer.value[0]);
175 }
176
177 static int pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
178                                         struct snd_ctl_elem_info *uinfo)
179 {
180         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
181         uinfo->count                    = 1;
182         uinfo->value.integer.min        = 0;
183         uinfo->value.integer.max        = 1;
184         return 0;
185 }
186
187 static int pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
188                                         struct snd_ctl_elem_value *ucontrol)
189 {
190         ucontrol->value.integer.value[0] = 1;
191         return 0;
192 }
193
194 static int pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
195                                         struct snd_ctl_elem_value *ucontrol)
196 {
197         return 0;
198 }
199
200 /* ----------------------------------------------------------- */
201
202 static int headset_playback_volume_info(struct snd_kcontrol *kcontrol,
203                                         struct snd_ctl_elem_info *uinfo)
204 {
205         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
206         uinfo->count                    = 1;
207         uinfo->value.integer.min        = 0;
208         uinfo->value.integer.max        = 9;
209         return 0;
210 }
211
212 static int headset_playback_volume_get(struct snd_kcontrol *kcontrol,
213                                         struct snd_ctl_elem_value *ucontrol)
214 {
215         ucontrol->value.integer.value[0]        = current_volume;
216         return 0;
217 }
218
219 static int headset_playback_volume_put(struct snd_kcontrol *kcontrol,
220                                         struct snd_ctl_elem_value *ucontrol)
221 {
222         return set_mixer_volume(ucontrol->value.integer.value[0]);
223 }
224
225 static int headset_playback_switch_info(struct snd_kcontrol *kcontrol,
226                                         struct snd_ctl_elem_info *uinfo)
227 {
228         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
229         uinfo->count                    = 1;
230         uinfo->value.integer.min        = 0;
231         uinfo->value.integer.max        = 1;
232         return 0;
233 }
234
235 static int headset_playback_switch_get(struct snd_kcontrol *kcontrol,
236                                         struct snd_ctl_elem_value *ucontrol)
237 {
238         ucontrol->value.integer.value[0] = 1;
239         return 0;
240 }
241
242 static int headset_playback_switch_put(struct snd_kcontrol *kcontrol,
243                                         struct snd_ctl_elem_value *ucontrol)
244 {
245         /* mute/unmute headset */
246 #if 0
247         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
248                                 TSC2101_HEADSET_GAIN_CTRL,
249                                 15);
250 #endif
251         return 0;
252 }
253 /* ----------------------------------------------------------- */
254 static int fmradio_playback_volume_info(struct snd_kcontrol *kcontrol,
255                                         struct snd_ctl_elem_info *uinfo)
256 {
257         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
258         uinfo->count                    = 1;
259         uinfo->value.integer.min        = 0;
260         uinfo->value.integer.max        = 9;
261         return 0;
262 }
263
264 static int fmradio_playback_volume_get(struct snd_kcontrol *kcontrol,
265                                         struct snd_ctl_elem_value *ucontrol)
266 {
267         ucontrol->value.integer.value[0] = current_fm_volume;
268         return 0;
269 }
270
271 static int fmradio_playback_volume_put(struct snd_kcontrol *kcontrol,
272                                         struct snd_ctl_elem_value *ucontrol)
273 {
274         int ret = current_fm_volume != ucontrol->value.integer.value[0];
275         int i;
276         current_fm_volume = ucontrol->value.integer.value[0];
277         i = cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
278         if (i)
279                 return i;
280         return ret;
281 }
282
283 static int fmradio_playback_switch_info(struct snd_kcontrol *kcontrol,
284                                         struct snd_ctl_elem_info *uinfo)
285 {
286         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
287         uinfo->count                    = 1;
288         uinfo->value.integer.min        = 0;
289         uinfo->value.integer.max        = 1;
290         return 0;
291 }
292
293 static int fmradio_playback_switch_get(struct snd_kcontrol *kcontrol,
294                                         struct snd_ctl_elem_value *ucontrol)
295 {
296         ucontrol->value.integer.value[0] = 1;
297         return 0;
298 }
299
300 static int fmradio_playback_switch_put(struct snd_kcontrol *kcontrol,
301                                         struct snd_ctl_elem_value *ucontrol)
302 {
303         /* mute/unmute FM radio */
304         if (ucontrol->value.integer.value[0])
305                 cn_sx1snd_send(DAC_FMRADIO_OPEN, current_fm_volume, 0);
306         else
307                 cn_sx1snd_send(DAC_FMRADIO_CLOSE, 0, 0);
308
309         return 0;
310 }
311 /* ----------------------------------------------------------- */
312 static int cellphone_input_switch_info(struct snd_kcontrol *kcontrol,
313                                                 struct snd_ctl_elem_info *uinfo)
314 {
315         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
316         uinfo->count                    = 1;
317         uinfo->value.integer.min        = 0;
318         uinfo->value.integer.max        = 1;
319         return 0;
320 }
321
322 static int cellphone_input_switch_get(struct snd_kcontrol *kcontrol,
323                                         struct snd_ctl_elem_value *ucontrol)
324 {
325         ucontrol->value.integer.value[0] = 1;
326         return 0;
327 }
328
329 static int cellphone_input_switch_put(struct snd_kcontrol *kcontrol,
330                                         struct snd_ctl_elem_value *ucontrol)
331 {
332 #if 0
333         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
334                                 TSC2101_BUZZER_GAIN_CTRL, 15);
335 #endif
336         return 0;
337 }
338 /* ----------------------------------------------------------- */
339
340 static int buzzer_input_switch_info(struct snd_kcontrol *kcontrol,
341                                         struct snd_ctl_elem_info *uinfo)
342 {
343         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
344         uinfo->count                    = 1;
345         uinfo->value.integer.min        = 0;
346         uinfo->value.integer.max        = 1;
347         return 0;
348 }
349
350 static int buzzer_input_switch_get(struct snd_kcontrol *kcontrol,
351                                         struct snd_ctl_elem_value *ucontrol)
352 {
353         ucontrol->value.integer.value[0] = 1;
354         return 0;
355 }
356
357 static int buzzer_input_switch_put(struct snd_kcontrol *kcontrol,
358                                         struct snd_ctl_elem_value *ucontrol)
359 {
360 #if 0
361         return adc_pga_unmute_control(ucontrol->value.integer.value[0],
362                                 TSC2101_BUZZER_GAIN_CTRL, 6);
363 #endif
364         return 0;
365 }
366 /*-----------------------------------------------------------*/
367
368 static struct snd_kcontrol_new egold_control[] __devinitdata = {
369         {
370                 .name   = "Playback Playback Route",
371                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
372                 .index  = 0,
373                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
374                 .info   = pcm_playback_target_info,
375                 .get    = pcm_playback_target_get,
376                 .put    = pcm_playback_target_put,
377         }, {
378                 .name   = "Master Playback Volume",
379                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
380                 .index  = 0,
381                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
382                 .info   = pcm_playback_volume_info,
383                 .get    = pcm_playback_volume_get,
384                 .put    = pcm_playback_volume_put,
385         }, {
386                 .name   = "Master Playback Switch",
387                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
388                 .index  = 0,
389                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
390                 .info   = pcm_playback_switch_info,
391                 .get    = pcm_playback_switch_get,
392                 .put    = pcm_playback_switch_put,
393         }, {
394                 .name   = "Headset Playback Volume",
395                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
396                 .index  = 1,
397                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
398                 .info   = headset_playback_volume_info,
399                 .get    = headset_playback_volume_get,
400                 .put    = headset_playback_volume_put,
401         }, {
402                 .name   = "Headset Playback Switch",
403                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
404                 .index  = 1,
405                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
406                 .info   = headset_playback_switch_info,
407                 .get    = headset_playback_switch_get,
408                 .put    = headset_playback_switch_put,
409         }, {
410                 .name   = "FM Playback Volume",
411                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
412                 .index  = 2,
413                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
414                 .info   = fmradio_playback_volume_info,
415                 .get    = fmradio_playback_volume_get,
416                 .put    = fmradio_playback_volume_put,
417         }, {
418                 .name   = "FM Playback Switch",
419                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
420                 .index  = 2,
421                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
422                 .info   = fmradio_playback_switch_info,
423                 .get    = fmradio_playback_switch_get,
424                 .put    = fmradio_playback_switch_put,
425         }, {
426                 .name   = "Cellphone Input Switch",
427                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
428                 .index  = 0,
429                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
430                 .info   = cellphone_input_switch_info,
431                 .get    = cellphone_input_switch_get,
432                 .put    = cellphone_input_switch_put,
433         }, {
434                 .name   = "Buzzer Input Switch",
435                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
436                 .index  = 0,
437                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
438                 .info   = buzzer_input_switch_info,
439                 .get    = buzzer_input_switch_get,
440                 .put    = buzzer_input_switch_put,
441         }
442 };
443
444 #ifdef CONFIG_PM
445 void snd_omap_suspend_mixer(void)
446 {
447 }
448
449 void snd_omap_resume_mixer(void)
450 {
451         snd_omap_init_mixer();
452 }
453 #endif
454
455 int snd_omap_mixer(struct snd_card_omap_codec *egold)
456 {
457         int i = 0;
458         int err = 0;
459
460         if (!egold)
461                 return -EINVAL;
462
463         for (i = 0; i < ARRAY_SIZE(egold_control); i++) {
464                 err = snd_ctl_add(egold->card,
465                                 snd_ctl_new1(&egold_control[i], egold->card));
466                 if (err < 0)
467                         return err;
468         }
469         return 0;
470 }