]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa-tsc2102-mixer.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa-tsc2102-mixer.c
1 /*
2  * sound/arm/omap/omap-alsa-tsc2102-mixer.c
3  *
4  * Alsa mixer driver for TSC2102 chip for OMAP platforms.
5  *
6  * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
7  * Code based on the TSC2101 ALSA driver.
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  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
20  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * You should have received a copy of the  GNU General Public License along
26  * with this program; if not, write  to the Free Software Foundation, Inc.,
27  * 675 Mass Ave, Cambridge, MA 02139, USA.
28  */
29
30 #include <linux/types.h>
31 #include <linux/spi/tsc2102.h>
32
33 #include <asm/arch/omap-alsa.h>
34
35 #include <sound/driver.h>
36 #include <sound/initval.h>
37 #include <sound/control.h>
38
39 #include "omap-alsa-tsc2102.h"
40 #include "omap-alsa-dma.h"
41
42 static int vol[2], mute[2], filter[2];
43
44 /*
45  * Converts the Alsa mixer volume (0 - 100) to actual Digital
46  * Gain Control (DGC) value that can be written or read from the
47  * TSC2102 registers.
48  *
49  * Note that the number "OUTPUT_VOLUME_MAX" is smaller than
50  * OUTPUT_VOLUME_MIN because DGC works as a volume decreaser.  (The
51  * higher the value sent to DAC, the more the volume of controlled
52  * channel is decreased)
53  */
54 static void set_dac_gain_stereo(int left_ch, int right_ch)
55 {
56         int lch, rch;
57
58         if (left_ch > 100)
59                 vol[0] = 100;
60         else if (left_ch < 0)
61                 vol[0] = 0;
62         else
63                 vol[0] = left_ch;
64         lch = OUTPUT_VOLUME_MIN - vol[0] *
65                 (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
66
67         if (right_ch > 100)
68                 vol[1] = 100;
69         else if (right_ch < 0)
70                 vol[1] = 0;
71         else
72                 vol[1] = right_ch;
73         rch = OUTPUT_VOLUME_MIN - vol[1] *
74                 (OUTPUT_VOLUME_MIN - OUTPUT_VOLUME_MAX) / 100;
75
76         tsc2102_set_volume(lch, rch);
77 }
78
79 void init_playback_targets(void)
80 {
81         set_dac_gain_stereo(DEFAULT_OUTPUT_VOLUME, DEFAULT_OUTPUT_VOLUME);
82
83         /* Unmute */
84         tsc2102_set_mute(0, 0);
85
86         mute[0] = mute[1] = 0;
87         filter[0] = filter[1] = 0;
88 }
89
90 /*
91  * Initializes TSC 2102 and playback target.
92  */
93 void snd_omap_init_mixer(void)
94 {
95         FN_IN;
96
97         init_playback_targets();
98
99         FN_OUT(0);
100 }
101
102 static int __pcm_playback_volume_info(struct snd_kcontrol *kcontrol,
103                 struct snd_ctl_elem_info *uinfo)
104 {
105         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_INTEGER;
106         uinfo->count                    = 2;
107         uinfo->value.integer.min        = 0;
108         uinfo->value.integer.max        = 100;
109         return 0;
110 }
111
112 static int __pcm_playback_volume_get(struct snd_kcontrol *kcontrol,
113                 struct snd_ctl_elem_value *ucontrol)
114 {
115         ucontrol->value.integer.value[0] = vol[0];      /* L */
116         ucontrol->value.integer.value[1] = vol[1];      /* R */
117
118         return 0;
119 }
120
121 static int __pcm_playback_volume_put(struct snd_kcontrol *kcontrol,
122                 struct snd_ctl_elem_value *ucontrol)
123 {
124         set_dac_gain_stereo(
125                         ucontrol->value.integer.value[0],       /* L */
126                         ucontrol->value.integer.value[1]);      /* R */
127         return 1;
128 }
129
130 static int __pcm_playback_switch_info(struct snd_kcontrol *kcontrol,
131                 struct snd_ctl_elem_info *uinfo)
132 {
133         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
134         uinfo->count                    = 2;
135         uinfo->value.integer.min        = 0;
136         uinfo->value.integer.max        = 1;
137         return 0;
138 }
139
140 static int __pcm_playback_switch_get(struct snd_kcontrol *kcontrol,
141                 struct snd_ctl_elem_value *ucontrol)
142 {
143         ucontrol->value.integer.value[0] = !mute[0];            /* L */
144         ucontrol->value.integer.value[1] = !mute[1];            /* R */
145
146         return 0;
147 }
148
149 static int __pcm_playback_switch_put(struct snd_kcontrol *kcontrol,
150                 struct snd_ctl_elem_value *ucontrol) 
151 {
152         mute[0] = (ucontrol->value.integer.value[0] == 0);      /* L */
153         mute[1] = (ucontrol->value.integer.value[1] == 0);      /* R */
154
155         tsc2102_set_mute(mute[0], mute[1]);
156         return 1;
157 }
158
159 static int __pcm_playback_deemphasis_info(struct snd_kcontrol *kcontrol,
160                 struct snd_ctl_elem_info *uinfo)
161 {
162         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
163         uinfo->count                    = 1;
164         uinfo->value.integer.min        = 0;
165         uinfo->value.integer.max        = 1;
166         return 0;
167 }
168
169 static int __pcm_playback_deemphasis_get(struct snd_kcontrol *kcontrol,
170                 struct snd_ctl_elem_value *ucontrol)
171 {
172         ucontrol->value.integer.value[0] = filter[0];
173         return 0;
174 }
175
176 static int __pcm_playback_deemphasis_put(struct snd_kcontrol *kcontrol,
177                 struct snd_ctl_elem_value *ucontrol) 
178 {
179         filter[0] = (ucontrol->value.integer.value[0] > 0);
180
181         tsc2102_set_deemphasis(filter[0]);
182         return 1;
183 }
184
185 static int __pcm_playback_bassboost_info(struct snd_kcontrol *kcontrol,
186                 struct snd_ctl_elem_info *uinfo)
187 {
188         uinfo->type                     = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
189         uinfo->count                    = 1;
190         uinfo->value.integer.min        = 0;
191         uinfo->value.integer.max        = 1;
192         return 0;
193 }
194
195 static int __pcm_playback_bassboost_get(struct snd_kcontrol *kcontrol,
196                 struct snd_ctl_elem_value *ucontrol)
197 {
198         ucontrol->value.integer.value[0] = filter[1];
199         return 0;
200 }
201
202 static int __pcm_playback_bassboost_put(struct snd_kcontrol *kcontrol,
203                 struct snd_ctl_elem_value *ucontrol) 
204 {
205         filter[1] = (ucontrol->value.integer.value[0] > 0);
206
207         tsc2102_set_bassboost(filter[1]);
208         return 1;
209 }
210
211 static struct snd_kcontrol_new tsc2102_controls[] __devinitdata = {
212         {
213                 .name   = "Master Playback Volume",
214                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
215                 .index  = 0,
216                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
217                 .info   = __pcm_playback_volume_info,
218                 .get    = __pcm_playback_volume_get,
219                 .put    = __pcm_playback_volume_put,
220         },
221         {
222                 .name   = "Master Playback Switch",
223                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
224                 .index  = 0,
225                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
226                 .info   = __pcm_playback_switch_info,
227                 .get    = __pcm_playback_switch_get,
228                 .put    = __pcm_playback_switch_put,
229         },
230         {
231                 .name   = "De-emphasis Filter Switch",
232                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
233                 .index  = 0,
234                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
235                 .info   = __pcm_playback_deemphasis_info,
236                 .get    = __pcm_playback_deemphasis_get,
237                 .put    = __pcm_playback_deemphasis_put,
238         },
239         {
240                 .name   = "Bass-boost Filter Switch",
241                 .iface  = SNDRV_CTL_ELEM_IFACE_MIXER,
242                 .index  = 0,
243                 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
244                 .info   = __pcm_playback_bassboost_info,
245                 .get    = __pcm_playback_bassboost_get,
246                 .put    = __pcm_playback_bassboost_put,
247         },
248 };
249
250 #ifdef CONFIG_PM
251 void snd_omap_suspend_mixer(void)
252 {
253         /* Nothing to do */
254 }
255
256 void snd_omap_resume_mixer(void)
257 {
258         /* The chip was reset, restore the last used values */
259         set_dac_gain_stereo(vol[0], vol[1]);
260
261         tsc2102_set_mute(mute[0], mute[1]);
262         tsc2102_set_deemphasis(filter[0]);
263         tsc2102_set_bassboost(filter[1]);
264 }
265 #endif
266
267 int snd_omap_mixer(struct snd_card_omap_codec *tsc2102)
268 {
269         int i, err;
270
271         if (!tsc2102)
272                 return -EINVAL;
273
274         for (i = 0; i < ARRAY_SIZE(tsc2102_controls); i ++) {
275                 err = snd_ctl_add(tsc2102->card,
276                                 snd_ctl_new1(&tsc2102_controls[i],
277                                 tsc2102->card));
278
279                 if (err < 0)
280                         return err;
281         }
282         return 0;
283 }