blob: 1a2de34eecf5d20557dd0d62b29ac557ed59ca46 [file] [log] [blame]
Jarkko Nikula49100c92010-05-05 11:14:22 +03001/*
2 * rx51.c -- SoC audio for Nokia RX-51
3 *
4 * Copyright (C) 2008 - 2009 Nokia Corporation
5 *
6 * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com>
7 * Eduardo Valentin <eduardo.valentin@nokia.com>
8 * Jarkko Nikula <jhnikula@gmail.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26#include <linux/delay.h>
27#include <linux/gpio.h>
28#include <linux/platform_device.h>
29#include <sound/core.h>
30#include <sound/pcm.h>
31#include <sound/soc.h>
32#include <sound/soc-dapm.h>
33
34#include <asm/mach-types.h>
35
36#include "omap-mcbsp.h"
37#include "omap-pcm.h"
38#include "../codecs/tlv320aic3x.h"
39
Jarkko Nikula4eb54702010-06-21 14:14:59 +030040#define RX51_TVOUT_SEL_GPIO 40
Jarkko Nikula49100c92010-05-05 11:14:22 +030041/*
42 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
43 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
44 */
45#define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7)
46
Jarkko Nikula4eb54702010-06-21 14:14:59 +030047enum {
48 RX51_JACK_DISABLED,
49 RX51_JACK_TVOUT, /* tv-out */
50};
51
Jarkko Nikula49100c92010-05-05 11:14:22 +030052static int rx51_spk_func;
53static int rx51_dmic_func;
Jarkko Nikula4eb54702010-06-21 14:14:59 +030054static int rx51_jack_func;
Jarkko Nikula49100c92010-05-05 11:14:22 +030055
56static void rx51_ext_control(struct snd_soc_codec *codec)
57{
58 if (rx51_spk_func)
59 snd_soc_dapm_enable_pin(codec, "Ext Spk");
60 else
61 snd_soc_dapm_disable_pin(codec, "Ext Spk");
62 if (rx51_dmic_func)
63 snd_soc_dapm_enable_pin(codec, "DMic");
64 else
65 snd_soc_dapm_disable_pin(codec, "DMic");
66
Jarkko Nikula4eb54702010-06-21 14:14:59 +030067 gpio_set_value(RX51_TVOUT_SEL_GPIO,
68 rx51_jack_func == RX51_JACK_TVOUT);
69
Jarkko Nikula49100c92010-05-05 11:14:22 +030070 snd_soc_dapm_sync(codec);
71}
72
73static int rx51_startup(struct snd_pcm_substream *substream)
74{
75 struct snd_pcm_runtime *runtime = substream->runtime;
76 struct snd_soc_pcm_runtime *rtd = substream->private_data;
77 struct snd_soc_codec *codec = rtd->socdev->card->codec;
78
79 snd_pcm_hw_constraint_minmax(runtime,
80 SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
81 rx51_ext_control(codec);
82
83 return 0;
84}
85
86static int rx51_hw_params(struct snd_pcm_substream *substream,
87 struct snd_pcm_hw_params *params)
88{
89 struct snd_soc_pcm_runtime *rtd = substream->private_data;
90 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
91 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
92 int err;
93
94 /* Set codec DAI configuration */
95 err = snd_soc_dai_set_fmt(codec_dai,
96 SND_SOC_DAIFMT_DSP_A |
97 SND_SOC_DAIFMT_IB_NF |
98 SND_SOC_DAIFMT_CBM_CFM);
99 if (err < 0)
100 return err;
101
102 /* Set cpu DAI configuration */
103 err = snd_soc_dai_set_fmt(cpu_dai,
104 SND_SOC_DAIFMT_DSP_A |
105 SND_SOC_DAIFMT_IB_NF |
106 SND_SOC_DAIFMT_CBM_CFM);
107 if (err < 0)
108 return err;
109
110 /* Set the codec system clock for DAC and ADC */
111 return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
112 SND_SOC_CLOCK_IN);
113}
114
115static struct snd_soc_ops rx51_ops = {
116 .startup = rx51_startup,
117 .hw_params = rx51_hw_params,
118};
119
120static int rx51_get_spk(struct snd_kcontrol *kcontrol,
121 struct snd_ctl_elem_value *ucontrol)
122{
123 ucontrol->value.integer.value[0] = rx51_spk_func;
124
125 return 0;
126}
127
128static int rx51_set_spk(struct snd_kcontrol *kcontrol,
129 struct snd_ctl_elem_value *ucontrol)
130{
131 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
132
133 if (rx51_spk_func == ucontrol->value.integer.value[0])
134 return 0;
135
136 rx51_spk_func = ucontrol->value.integer.value[0];
137 rx51_ext_control(codec);
138
139 return 1;
140}
141
142static int rx51_spk_event(struct snd_soc_dapm_widget *w,
143 struct snd_kcontrol *k, int event)
144{
145 if (SND_SOC_DAPM_EVENT_ON(event))
146 gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1);
147 else
148 gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0);
149
150 return 0;
151}
152
153static int rx51_get_input(struct snd_kcontrol *kcontrol,
154 struct snd_ctl_elem_value *ucontrol)
155{
156 ucontrol->value.integer.value[0] = rx51_dmic_func;
157
158 return 0;
159}
160
161static int rx51_set_input(struct snd_kcontrol *kcontrol,
162 struct snd_ctl_elem_value *ucontrol)
163{
164 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
165
166 if (rx51_dmic_func == ucontrol->value.integer.value[0])
167 return 0;
168
169 rx51_dmic_func = ucontrol->value.integer.value[0];
170 rx51_ext_control(codec);
171
172 return 1;
173}
174
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300175static int rx51_get_jack(struct snd_kcontrol *kcontrol,
176 struct snd_ctl_elem_value *ucontrol)
177{
178 ucontrol->value.integer.value[0] = rx51_jack_func;
179
180 return 0;
181}
182
183static int rx51_set_jack(struct snd_kcontrol *kcontrol,
184 struct snd_ctl_elem_value *ucontrol)
185{
186 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
187
188 if (rx51_jack_func == ucontrol->value.integer.value[0])
189 return 0;
190
191 rx51_jack_func = ucontrol->value.integer.value[0];
192 rx51_ext_control(codec);
193
194 return 1;
195}
196
Jarkko Nikula49100c92010-05-05 11:14:22 +0300197static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
198 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
199 SND_SOC_DAPM_MIC("DMic", NULL),
200};
201
202static const struct snd_soc_dapm_route audio_map[] = {
203 {"Ext Spk", NULL, "HPLOUT"},
204 {"Ext Spk", NULL, "HPROUT"},
205
206 {"DMic Rate 64", NULL, "Mic Bias 2V"},
207 {"Mic Bias 2V", NULL, "DMic"},
208};
209
210static const char *spk_function[] = {"Off", "On"};
211static const char *input_function[] = {"ADC", "Digital Mic"};
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300212static const char *jack_function[] = {"Off", "TV-OUT"};
Jarkko Nikula49100c92010-05-05 11:14:22 +0300213
214static const struct soc_enum rx51_enum[] = {
215 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
216 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300217 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
Jarkko Nikula49100c92010-05-05 11:14:22 +0300218};
219
220static const struct snd_kcontrol_new aic34_rx51_controls[] = {
221 SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
222 rx51_get_spk, rx51_set_spk),
223 SOC_ENUM_EXT("Input Select", rx51_enum[1],
224 rx51_get_input, rx51_set_input),
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300225 SOC_ENUM_EXT("Jack Function", rx51_enum[2],
226 rx51_get_jack, rx51_set_jack),
Jarkko Nikula49100c92010-05-05 11:14:22 +0300227};
228
229static int rx51_aic34_init(struct snd_soc_codec *codec)
230{
231 int err;
232
233 /* Set up NC codec pins */
234 snd_soc_dapm_nc_pin(codec, "MIC3L");
235 snd_soc_dapm_nc_pin(codec, "MIC3R");
236 snd_soc_dapm_nc_pin(codec, "LINE1R");
237
238 /* Add RX-51 specific controls */
239 err = snd_soc_add_controls(codec, aic34_rx51_controls,
240 ARRAY_SIZE(aic34_rx51_controls));
241 if (err < 0)
242 return err;
243
244 /* Add RX-51 specific widgets */
245 snd_soc_dapm_new_controls(codec, aic34_dapm_widgets,
246 ARRAY_SIZE(aic34_dapm_widgets));
247
248 /* Set up RX-51 specific audio path audio_map */
249 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
250
251 snd_soc_dapm_sync(codec);
252
253 return 0;
254}
255
256/* Digital audio interface glue - connects codec <--> CPU */
257static struct snd_soc_dai_link rx51_dai[] = {
258 {
259 .name = "TLV320AIC34",
260 .stream_name = "AIC34",
261 .cpu_dai = &omap_mcbsp_dai[0],
262 .codec_dai = &aic3x_dai,
263 .init = rx51_aic34_init,
264 .ops = &rx51_ops,
265 },
266};
267
268/* Audio private data */
269static struct aic3x_setup_data rx51_aic34_setup = {
270 .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
271 .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
272};
273
274/* Audio card */
275static struct snd_soc_card rx51_sound_card = {
276 .name = "RX-51",
277 .dai_link = rx51_dai,
278 .num_links = ARRAY_SIZE(rx51_dai),
279 .platform = &omap_soc_platform,
280};
281
282/* Audio subsystem */
283static struct snd_soc_device rx51_snd_devdata = {
284 .card = &rx51_sound_card,
285 .codec_dev = &soc_codec_dev_aic3x,
286 .codec_data = &rx51_aic34_setup,
287};
288
289static struct platform_device *rx51_snd_device;
290
291static int __init rx51_soc_init(void)
292{
293 int err;
294
295 if (!machine_is_nokia_rx51())
296 return -ENODEV;
297
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300298 err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel");
299 if (err)
300 goto err_gpio_tvout_sel;
301 gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0);
302
Jarkko Nikula49100c92010-05-05 11:14:22 +0300303 rx51_snd_device = platform_device_alloc("soc-audio", -1);
304 if (!rx51_snd_device) {
305 err = -ENOMEM;
306 goto err1;
307 }
308
309 platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata);
310 rx51_snd_devdata.dev = &rx51_snd_device->dev;
311 *(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
312
313 err = platform_device_add(rx51_snd_device);
314 if (err)
315 goto err2;
316
317 return 0;
318err2:
319 platform_device_put(rx51_snd_device);
320err1:
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300321 gpio_free(RX51_TVOUT_SEL_GPIO);
322err_gpio_tvout_sel:
Jarkko Nikula49100c92010-05-05 11:14:22 +0300323
324 return err;
325}
326
327static void __exit rx51_soc_exit(void)
328{
329 platform_device_unregister(rx51_snd_device);
Jarkko Nikula4eb54702010-06-21 14:14:59 +0300330 gpio_free(RX51_TVOUT_SEL_GPIO);
Jarkko Nikula49100c92010-05-05 11:14:22 +0300331}
332
333module_init(rx51_soc_init);
334module_exit(rx51_soc_exit);
335
336MODULE_AUTHOR("Nokia Corporation");
337MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
338MODULE_LICENSE("GPL");