• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/sound/soc/omap/
1/*
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/jack.h>
31#include <sound/pcm.h>
32#include <sound/soc.h>
33#include <sound/soc-dapm.h>
34
35#include <asm/mach-types.h>
36
37#include "omap-mcbsp.h"
38#include "omap-pcm.h"
39#include "../codecs/tlv320aic3x.h"
40
41#define RX51_TVOUT_SEL_GPIO		40
42#define RX51_JACK_DETECT_GPIO		177
43/*
44 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
45 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
46 */
47#define RX51_SPEAKER_AMP_TWL_GPIO	(192 + 7)
48
49enum {
50	RX51_JACK_DISABLED,
51	RX51_JACK_TVOUT,		/* tv-out */
52};
53
54static int rx51_spk_func;
55static int rx51_dmic_func;
56static int rx51_jack_func;
57
58static void rx51_ext_control(struct snd_soc_codec *codec)
59{
60	if (rx51_spk_func)
61		snd_soc_dapm_enable_pin(codec, "Ext Spk");
62	else
63		snd_soc_dapm_disable_pin(codec, "Ext Spk");
64	if (rx51_dmic_func)
65		snd_soc_dapm_enable_pin(codec, "DMic");
66	else
67		snd_soc_dapm_disable_pin(codec, "DMic");
68
69	gpio_set_value(RX51_TVOUT_SEL_GPIO,
70		       rx51_jack_func == RX51_JACK_TVOUT);
71
72	snd_soc_dapm_sync(codec);
73}
74
75static int rx51_startup(struct snd_pcm_substream *substream)
76{
77	struct snd_pcm_runtime *runtime = substream->runtime;
78	struct snd_soc_pcm_runtime *rtd = substream->private_data;
79	struct snd_soc_codec *codec = rtd->socdev->card->codec;
80
81	snd_pcm_hw_constraint_minmax(runtime,
82				     SNDRV_PCM_HW_PARAM_CHANNELS, 2, 2);
83	rx51_ext_control(codec);
84
85	return 0;
86}
87
88static int rx51_hw_params(struct snd_pcm_substream *substream,
89	struct snd_pcm_hw_params *params)
90{
91	struct snd_soc_pcm_runtime *rtd = substream->private_data;
92	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
93	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
94	int err;
95
96	/* Set codec DAI configuration */
97	err = snd_soc_dai_set_fmt(codec_dai,
98				  SND_SOC_DAIFMT_DSP_A |
99				  SND_SOC_DAIFMT_IB_NF |
100				  SND_SOC_DAIFMT_CBM_CFM);
101	if (err < 0)
102		return err;
103
104	/* Set cpu DAI configuration */
105	err = snd_soc_dai_set_fmt(cpu_dai,
106				  SND_SOC_DAIFMT_DSP_A |
107				  SND_SOC_DAIFMT_IB_NF |
108				  SND_SOC_DAIFMT_CBM_CFM);
109	if (err < 0)
110		return err;
111
112	/* Set the codec system clock for DAC and ADC */
113	return snd_soc_dai_set_sysclk(codec_dai, 0, 19200000,
114				      SND_SOC_CLOCK_IN);
115}
116
117static struct snd_soc_ops rx51_ops = {
118	.startup = rx51_startup,
119	.hw_params = rx51_hw_params,
120};
121
122static int rx51_get_spk(struct snd_kcontrol *kcontrol,
123			struct snd_ctl_elem_value *ucontrol)
124{
125	ucontrol->value.integer.value[0] = rx51_spk_func;
126
127	return 0;
128}
129
130static int rx51_set_spk(struct snd_kcontrol *kcontrol,
131			struct snd_ctl_elem_value *ucontrol)
132{
133	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
134
135	if (rx51_spk_func == ucontrol->value.integer.value[0])
136		return 0;
137
138	rx51_spk_func = ucontrol->value.integer.value[0];
139	rx51_ext_control(codec);
140
141	return 1;
142}
143
144static int rx51_spk_event(struct snd_soc_dapm_widget *w,
145			  struct snd_kcontrol *k, int event)
146{
147	if (SND_SOC_DAPM_EVENT_ON(event))
148		gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 1);
149	else
150		gpio_set_value(RX51_SPEAKER_AMP_TWL_GPIO, 0);
151
152	return 0;
153}
154
155static int rx51_get_input(struct snd_kcontrol *kcontrol,
156			  struct snd_ctl_elem_value *ucontrol)
157{
158	ucontrol->value.integer.value[0] = rx51_dmic_func;
159
160	return 0;
161}
162
163static int rx51_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 (rx51_dmic_func == ucontrol->value.integer.value[0])
169		return 0;
170
171	rx51_dmic_func = ucontrol->value.integer.value[0];
172	rx51_ext_control(codec);
173
174	return 1;
175}
176
177static int rx51_get_jack(struct snd_kcontrol *kcontrol,
178			 struct snd_ctl_elem_value *ucontrol)
179{
180	ucontrol->value.integer.value[0] = rx51_jack_func;
181
182	return 0;
183}
184
185static int rx51_set_jack(struct snd_kcontrol *kcontrol,
186			 struct snd_ctl_elem_value *ucontrol)
187{
188	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
189
190	if (rx51_jack_func == ucontrol->value.integer.value[0])
191		return 0;
192
193	rx51_jack_func = ucontrol->value.integer.value[0];
194	rx51_ext_control(codec);
195
196	return 1;
197}
198
199static struct snd_soc_jack rx51_av_jack;
200
201static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
202	{
203		.gpio = RX51_JACK_DETECT_GPIO,
204		.name = "avdet-gpio",
205		.report = SND_JACK_VIDEOOUT,
206		.invert = 1,
207		.debounce_time = 200,
208	},
209};
210
211static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
212	SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
213	SND_SOC_DAPM_MIC("DMic", NULL),
214};
215
216static const struct snd_soc_dapm_route audio_map[] = {
217	{"Ext Spk", NULL, "HPLOUT"},
218	{"Ext Spk", NULL, "HPROUT"},
219
220	{"DMic Rate 64", NULL, "Mic Bias 2V"},
221	{"Mic Bias 2V", NULL, "DMic"},
222};
223
224static const char *spk_function[] = {"Off", "On"};
225static const char *input_function[] = {"ADC", "Digital Mic"};
226static const char *jack_function[] = {"Off", "TV-OUT"};
227
228static const struct soc_enum rx51_enum[] = {
229	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
230	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
231	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
232};
233
234static const struct snd_kcontrol_new aic34_rx51_controls[] = {
235	SOC_ENUM_EXT("Speaker Function", rx51_enum[0],
236		     rx51_get_spk, rx51_set_spk),
237	SOC_ENUM_EXT("Input Select",  rx51_enum[1],
238		     rx51_get_input, rx51_set_input),
239	SOC_ENUM_EXT("Jack Function", rx51_enum[2],
240		     rx51_get_jack, rx51_set_jack),
241};
242
243static int rx51_aic34_init(struct snd_soc_codec *codec)
244{
245	struct snd_soc_card *card = codec->socdev->card;
246	int err;
247
248	/* Set up NC codec pins */
249	snd_soc_dapm_nc_pin(codec, "MIC3L");
250	snd_soc_dapm_nc_pin(codec, "MIC3R");
251	snd_soc_dapm_nc_pin(codec, "LINE1R");
252
253	/* Add RX-51 specific controls */
254	err = snd_soc_add_controls(codec, aic34_rx51_controls,
255				   ARRAY_SIZE(aic34_rx51_controls));
256	if (err < 0)
257		return err;
258
259	/* Add RX-51 specific widgets */
260	snd_soc_dapm_new_controls(codec, aic34_dapm_widgets,
261				  ARRAY_SIZE(aic34_dapm_widgets));
262
263	/* Set up RX-51 specific audio path audio_map */
264	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
265
266	snd_soc_dapm_sync(codec);
267
268	/* AV jack detection */
269	err = snd_soc_jack_new(card, "AV Jack",
270			       SND_JACK_VIDEOOUT, &rx51_av_jack);
271	if (err)
272		return err;
273	err = snd_soc_jack_add_gpios(&rx51_av_jack,
274				     ARRAY_SIZE(rx51_av_jack_gpios),
275				     rx51_av_jack_gpios);
276
277	return err;
278}
279
280/* Digital audio interface glue - connects codec <--> CPU */
281static struct snd_soc_dai_link rx51_dai[] = {
282	{
283		.name = "TLV320AIC34",
284		.stream_name = "AIC34",
285		.cpu_dai = &omap_mcbsp_dai[0],
286		.codec_dai = &aic3x_dai,
287		.init = rx51_aic34_init,
288		.ops = &rx51_ops,
289	},
290};
291
292/* Audio private data */
293static struct aic3x_setup_data rx51_aic34_setup = {
294	.gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
295	.gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
296};
297
298/* Audio card */
299static struct snd_soc_card rx51_sound_card = {
300	.name = "RX-51",
301	.dai_link = rx51_dai,
302	.num_links = ARRAY_SIZE(rx51_dai),
303	.platform = &omap_soc_platform,
304};
305
306/* Audio subsystem */
307static struct snd_soc_device rx51_snd_devdata = {
308	.card = &rx51_sound_card,
309	.codec_dev = &soc_codec_dev_aic3x,
310	.codec_data = &rx51_aic34_setup,
311};
312
313static struct platform_device *rx51_snd_device;
314
315static int __init rx51_soc_init(void)
316{
317	int err;
318
319	if (!machine_is_nokia_rx51())
320		return -ENODEV;
321
322	err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel");
323	if (err)
324		goto err_gpio_tvout_sel;
325	gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0);
326
327	rx51_snd_device = platform_device_alloc("soc-audio", -1);
328	if (!rx51_snd_device) {
329		err = -ENOMEM;
330		goto err1;
331	}
332
333	platform_set_drvdata(rx51_snd_device, &rx51_snd_devdata);
334	rx51_snd_devdata.dev = &rx51_snd_device->dev;
335	*(unsigned int *)rx51_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
336
337	err = platform_device_add(rx51_snd_device);
338	if (err)
339		goto err2;
340
341	return 0;
342err2:
343	platform_device_put(rx51_snd_device);
344err1:
345	gpio_free(RX51_TVOUT_SEL_GPIO);
346err_gpio_tvout_sel:
347
348	return err;
349}
350
351static void __exit rx51_soc_exit(void)
352{
353	snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
354				rx51_av_jack_gpios);
355
356	platform_device_unregister(rx51_snd_device);
357	gpio_free(RX51_TVOUT_SEL_GPIO);
358}
359
360module_init(rx51_soc_init);
361module_exit(rx51_soc_exit);
362
363MODULE_AUTHOR("Nokia Corporation");
364MODULE_DESCRIPTION("ALSA SoC Nokia RX-51");
365MODULE_LICENSE("GPL");
366