ALSA: ASoC: Add digital mic configuration to N810 machine driver
[linux-2.6.git] / sound / soc / omap / n810.c
1 /*
2  * n810.c  --  SoC audio for Nokia N810
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  *
6  * Contact: Jarkko Nikula <jarkko.nikula@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 #include <linux/clk.h>
25 #include <linux/platform_device.h>
26 #include <sound/core.h>
27 #include <sound/pcm.h>
28 #include <sound/soc.h>
29 #include <sound/soc-dapm.h>
30
31 #include <asm/mach-types.h>
32 #include <asm/arch/hardware.h>
33 #include <linux/gpio.h>
34 #include <asm/arch/mcbsp.h>
35
36 #include "omap-mcbsp.h"
37 #include "omap-pcm.h"
38 #include "../codecs/tlv320aic3x.h"
39
40 #define N810_HEADSET_AMP_GPIO   10
41 #define N810_SPEAKER_AMP_GPIO   101
42
43 static struct clk *sys_clkout2;
44 static struct clk *sys_clkout2_src;
45 static struct clk *func96m_clk;
46
47 static int n810_spk_func;
48 static int n810_jack_func;
49 static int n810_dmic_func;
50
51 static void n810_ext_control(struct snd_soc_codec *codec)
52 {
53         snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func);
54         snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func);
55         snd_soc_dapm_set_endpoint(codec, "DMic", n810_dmic_func);
56
57         snd_soc_dapm_sync_endpoints(codec);
58 }
59
60 static int n810_startup(struct snd_pcm_substream *substream)
61 {
62         struct snd_soc_pcm_runtime *rtd = substream->private_data;
63         struct snd_soc_codec *codec = rtd->socdev->codec;
64
65         n810_ext_control(codec);
66         return clk_enable(sys_clkout2);
67 }
68
69 static void n810_shutdown(struct snd_pcm_substream *substream)
70 {
71         clk_disable(sys_clkout2);
72 }
73
74 static int n810_hw_params(struct snd_pcm_substream *substream,
75         struct snd_pcm_hw_params *params)
76 {
77         struct snd_soc_pcm_runtime *rtd = substream->private_data;
78         struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
79         struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
80         int err;
81
82         /* Set codec DAI configuration */
83         err = codec_dai->dai_ops.set_fmt(codec_dai,
84                                          SND_SOC_DAIFMT_I2S |
85                                          SND_SOC_DAIFMT_NB_NF |
86                                          SND_SOC_DAIFMT_CBM_CFM);
87         if (err < 0)
88                 return err;
89
90         /* Set cpu DAI configuration */
91         err = cpu_dai->dai_ops.set_fmt(cpu_dai,
92                                        SND_SOC_DAIFMT_I2S |
93                                        SND_SOC_DAIFMT_NB_NF |
94                                        SND_SOC_DAIFMT_CBM_CFM);
95         if (err < 0)
96                 return err;
97
98         /* Set the codec system clock for DAC and ADC */
99         err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000,
100                                             SND_SOC_CLOCK_IN);
101
102         return err;
103 }
104
105 static struct snd_soc_ops n810_ops = {
106         .startup = n810_startup,
107         .hw_params = n810_hw_params,
108         .shutdown = n810_shutdown,
109 };
110
111 static int n810_get_spk(struct snd_kcontrol *kcontrol,
112                         struct snd_ctl_elem_value *ucontrol)
113 {
114         ucontrol->value.integer.value[0] = n810_spk_func;
115
116         return 0;
117 }
118
119 static int n810_set_spk(struct snd_kcontrol *kcontrol,
120                         struct snd_ctl_elem_value *ucontrol)
121 {
122         struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
123
124         if (n810_spk_func == ucontrol->value.integer.value[0])
125                 return 0;
126
127         n810_spk_func = ucontrol->value.integer.value[0];
128         n810_ext_control(codec);
129
130         return 1;
131 }
132
133 static int n810_get_jack(struct snd_kcontrol *kcontrol,
134                          struct snd_ctl_elem_value *ucontrol)
135 {
136         ucontrol->value.integer.value[0] = n810_jack_func;
137
138         return 0;
139 }
140
141 static int n810_set_jack(struct snd_kcontrol *kcontrol,
142                          struct snd_ctl_elem_value *ucontrol)
143 {
144         struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
145
146         if (n810_jack_func == ucontrol->value.integer.value[0])
147                 return 0;
148
149         n810_jack_func = ucontrol->value.integer.value[0];
150         n810_ext_control(codec);
151
152         return 1;
153 }
154
155 static int n810_get_input(struct snd_kcontrol *kcontrol,
156                           struct snd_ctl_elem_value *ucontrol)
157 {
158         ucontrol->value.integer.value[0] = n810_dmic_func;
159
160         return 0;
161 }
162
163 static int n810_set_input(struct snd_kcontrol *kcontrol,
164                           struct snd_ctl_elem_value *ucontrol)
165 {
166         struct snd_soc_codec *codec =  snd_kcontrol_chip(kcontrol);
167
168         if (n810_dmic_func == ucontrol->value.integer.value[0])
169                 return 0;
170
171         n810_dmic_func = ucontrol->value.integer.value[0];
172         n810_ext_control(codec);
173
174         return 1;
175 }
176
177 static int n810_spk_event(struct snd_soc_dapm_widget *w,
178                           struct snd_kcontrol *k, int event)
179 {
180         if (SND_SOC_DAPM_EVENT_ON(event))
181                 gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
182         else
183                 gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
184
185         return 0;
186 }
187
188 static int n810_jack_event(struct snd_soc_dapm_widget *w,
189                            struct snd_kcontrol *k, int event)
190 {
191         if (SND_SOC_DAPM_EVENT_ON(event))
192                 gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
193         else
194                 gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
195
196         return 0;
197 }
198
199 static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
200         SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
201         SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
202         SND_SOC_DAPM_MIC("DMic", NULL),
203 };
204
205 static const struct snd_soc_dapm_route audio_map[] = {
206         {"Headphone Jack", NULL, "HPLOUT"},
207         {"Headphone Jack", NULL, "HPROUT"},
208
209         {"Ext Spk", NULL, "LLOUT"},
210         {"Ext Spk", NULL, "RLOUT"},
211
212         {"DMic Rate 64", NULL, "Mic Bias 2V"},
213         {"Mic Bias 2V", NULL, "DMic"},
214 };
215
216 static const char *spk_function[] = {"Off", "On"};
217 static const char *jack_function[] = {"Off", "Headphone"};
218 static const char *input_function[] = {"ADC", "Digital Mic"};
219 static const struct soc_enum n810_enum[] = {
220         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
221         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
222         SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
223 };
224
225 static const struct snd_kcontrol_new aic33_n810_controls[] = {
226         SOC_ENUM_EXT("Speaker Function", n810_enum[0],
227                      n810_get_spk, n810_set_spk),
228         SOC_ENUM_EXT("Jack Function", n810_enum[1],
229                      n810_get_jack, n810_set_jack),
230         SOC_ENUM_EXT("Input Select",  n810_enum[2],
231                      n810_get_input, n810_set_input),
232 };
233
234 static int n810_aic33_init(struct snd_soc_codec *codec)
235 {
236         int i, err;
237
238         /* Not connected */
239         snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0);
240         snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0);
241         snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0);
242
243         /* Add N810 specific controls */
244         for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
245                 err = snd_ctl_add(codec->card,
246                         snd_soc_cnew(&aic33_n810_controls[i], codec, NULL));
247                 if (err < 0)
248                         return err;
249         }
250
251         /* Add N810 specific widgets */
252         snd_soc_dapm_new_controls(codec, aic33_dapm_widgets,
253                                   ARRAY_SIZE(aic33_dapm_widgets));
254
255         /* Set up N810 specific audio path audio_map */
256         snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
257
258         snd_soc_dapm_sync_endpoints(codec);
259
260         return 0;
261 }
262
263 /* Digital audio interface glue - connects codec <--> CPU */
264 static struct snd_soc_dai_link n810_dai = {
265         .name = "TLV320AIC33",
266         .stream_name = "AIC33",
267         .cpu_dai = &omap_mcbsp_dai[0],
268         .codec_dai = &aic3x_dai,
269         .init = n810_aic33_init,
270         .ops = &n810_ops,
271 };
272
273 /* Audio machine driver */
274 static struct snd_soc_machine snd_soc_machine_n810 = {
275         .name = "N810",
276         .dai_link = &n810_dai,
277         .num_links = 1,
278 };
279
280 /* Audio private data */
281 static struct aic3x_setup_data n810_aic33_setup = {
282         .i2c_address = 0x18,
283         .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
284         .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
285 };
286
287 /* Audio subsystem */
288 static struct snd_soc_device n810_snd_devdata = {
289         .machine = &snd_soc_machine_n810,
290         .platform = &omap_soc_platform,
291         .codec_dev = &soc_codec_dev_aic3x,
292         .codec_data = &n810_aic33_setup,
293 };
294
295 static struct platform_device *n810_snd_device;
296
297 static int __init n810_soc_init(void)
298 {
299         int err;
300         struct device *dev;
301
302         if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
303                 return -ENODEV;
304
305         n810_snd_device = platform_device_alloc("soc-audio", -1);
306         if (!n810_snd_device)
307                 return -ENOMEM;
308
309         platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
310         n810_snd_devdata.dev = &n810_snd_device->dev;
311         *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
312         err = platform_device_add(n810_snd_device);
313         if (err)
314                 goto err1;
315
316         dev = &n810_snd_device->dev;
317
318         sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
319         if (IS_ERR(sys_clkout2_src)) {
320                 dev_err(dev, "Could not get sys_clkout2_src clock\n");
321                 return -ENODEV;
322         }
323         sys_clkout2 = clk_get(dev, "sys_clkout2");
324         if (IS_ERR(sys_clkout2)) {
325                 dev_err(dev, "Could not get sys_clkout2\n");
326                 goto err1;
327         }
328         /*
329          * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
330          * 96 MHz as its parent in order to get 12 MHz
331          */
332         func96m_clk = clk_get(dev, "func_96m_ck");
333         if (IS_ERR(func96m_clk)) {
334                 dev_err(dev, "Could not get func 96M clock\n");
335                 goto err2;
336         }
337         clk_set_parent(sys_clkout2_src, func96m_clk);
338         clk_set_rate(sys_clkout2, 12000000);
339
340         if (gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0)
341                 BUG();
342         if (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0)
343                 BUG();
344         gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
345         gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
346
347         return 0;
348 err2:
349         clk_put(sys_clkout2);
350         platform_device_del(n810_snd_device);
351 err1:
352         platform_device_put(n810_snd_device);
353
354         return err;
355
356 }
357
358 static void __exit n810_soc_exit(void)
359 {
360         gpio_free(N810_SPEAKER_AMP_GPIO);
361         gpio_free(N810_HEADSET_AMP_GPIO);
362
363         platform_device_unregister(n810_snd_device);
364 }
365
366 module_init(n810_soc_init);
367 module_exit(n810_soc_exit);
368
369 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
370 MODULE_DESCRIPTION("ALSA SoC Nokia N810");
371 MODULE_LICENSE("GPL");