• 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/pxa/
1/*
2 * SoC audio for HTC Magician
3 *
4 * Copyright (c) 2006 Philipp Zabel <philipp.zabel@gmail.com>
5 *
6 * based on spitz.c,
7 * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
8 *          Richard Purdie <richard@openedhand.com>
9 *
10 *  This program is free software; you can redistribute  it and/or modify it
11 *  under  the terms of  the GNU General  Public License as published by the
12 *  Free Software Foundation;  either version 2 of the  License, or (at your
13 *  option) any later version.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/timer.h>
19#include <linux/interrupt.h>
20#include <linux/platform_device.h>
21#include <linux/delay.h>
22#include <linux/gpio.h>
23#include <linux/i2c.h>
24
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/uda1380.h>
31
32#include <mach/magician.h>
33#include <asm/mach-types.h>
34#include "../codecs/uda1380.h"
35#include "pxa2xx-pcm.h"
36#include "pxa2xx-i2s.h"
37#include "pxa-ssp.h"
38
39#define MAGICIAN_MIC       0
40#define MAGICIAN_MIC_EXT   1
41
42static int magician_hp_switch;
43static int magician_spk_switch = 1;
44static int magician_in_sel = MAGICIAN_MIC;
45
46static void magician_ext_control(struct snd_soc_codec *codec)
47{
48	if (magician_spk_switch)
49		snd_soc_dapm_enable_pin(codec, "Speaker");
50	else
51		snd_soc_dapm_disable_pin(codec, "Speaker");
52	if (magician_hp_switch)
53		snd_soc_dapm_enable_pin(codec, "Headphone Jack");
54	else
55		snd_soc_dapm_disable_pin(codec, "Headphone Jack");
56
57	switch (magician_in_sel) {
58	case MAGICIAN_MIC:
59		snd_soc_dapm_disable_pin(codec, "Headset Mic");
60		snd_soc_dapm_enable_pin(codec, "Call Mic");
61		break;
62	case MAGICIAN_MIC_EXT:
63		snd_soc_dapm_disable_pin(codec, "Call Mic");
64		snd_soc_dapm_enable_pin(codec, "Headset Mic");
65		break;
66	}
67
68	snd_soc_dapm_sync(codec);
69}
70
71static int magician_startup(struct snd_pcm_substream *substream)
72{
73	struct snd_soc_pcm_runtime *rtd = substream->private_data;
74	struct snd_soc_codec *codec = rtd->socdev->card->codec;
75
76	/* check the jack status at stream startup */
77	magician_ext_control(codec);
78
79	return 0;
80}
81
82/*
83 * Magician uses SSP port for playback.
84 */
85static int magician_playback_hw_params(struct snd_pcm_substream *substream,
86				       struct snd_pcm_hw_params *params)
87{
88	struct snd_soc_pcm_runtime *rtd = substream->private_data;
89	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
90	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
91	unsigned int acps, acds, width, rate;
92	unsigned int div4 = PXA_SSP_CLK_SCDB_4;
93	int ret = 0;
94
95	rate = params_rate(params);
96	width = snd_pcm_format_physical_width(params_format(params));
97
98	/*
99	 * rate = SSPSCLK / (2 * width(16 or 32))
100	 * SSPSCLK = (ACPS / ACDS) / SSPSCLKDIV(div4 or div1)
101	 */
102	switch (params_rate(params)) {
103	case 8000:
104		/* off by a factor of 2: bug in the PXA27x audio clock? */
105		acps = 32842000;
106		switch (width) {
107		case 16:
108			/* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */
109			acds = PXA_SSP_CLK_AUDIO_DIV_16;
110			break;
111		default: /* 32 */
112			/* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */
113			acds = PXA_SSP_CLK_AUDIO_DIV_8;
114		}
115		break;
116	case 11025:
117		acps = 5622000;
118		switch (width) {
119		case 16:
120			/* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */
121			acds = PXA_SSP_CLK_AUDIO_DIV_4;
122			break;
123		default: /* 32 */
124			/* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */
125			acds = PXA_SSP_CLK_AUDIO_DIV_2;
126		}
127		break;
128	case 22050:
129		acps = 5622000;
130		switch (width) {
131		case 16:
132			/* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */
133			acds = PXA_SSP_CLK_AUDIO_DIV_2;
134			break;
135		default: /* 32 */
136			/* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */
137			acds = PXA_SSP_CLK_AUDIO_DIV_1;
138		}
139		break;
140	case 44100:
141		acps = 5622000;
142		switch (width) {
143		case 16:
144			/* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */
145			acds = PXA_SSP_CLK_AUDIO_DIV_2;
146			break;
147		default: /* 32 */
148			/* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */
149			acds = PXA_SSP_CLK_AUDIO_DIV_1;
150		}
151		break;
152	case 48000:
153		acps = 12235000;
154		switch (width) {
155		case 16:
156			/* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */
157			acds = PXA_SSP_CLK_AUDIO_DIV_2;
158			break;
159		default: /* 32 */
160			/* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */
161			acds = PXA_SSP_CLK_AUDIO_DIV_1;
162		}
163		break;
164	case 96000:
165	default:
166		acps = 12235000;
167		switch (width) {
168		case 16:
169			/* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */
170			acds = PXA_SSP_CLK_AUDIO_DIV_1;
171			break;
172		default: /* 32 */
173			/* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */
174			acds = PXA_SSP_CLK_AUDIO_DIV_2;
175			div4 = PXA_SSP_CLK_SCDB_1;
176			break;
177		}
178		break;
179	}
180
181	/* set codec DAI configuration */
182	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
183			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
184	if (ret < 0)
185		return ret;
186
187	/* set cpu DAI configuration */
188	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
189			SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
190	if (ret < 0)
191		return ret;
192
193	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width);
194	if (ret < 0)
195		return ret;
196
197	/* set audio clock as clock source */
198	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0,
199			SND_SOC_CLOCK_OUT);
200	if (ret < 0)
201		return ret;
202
203	/* set the SSP audio system clock ACDS divider */
204	ret = snd_soc_dai_set_clkdiv(cpu_dai,
205			PXA_SSP_AUDIO_DIV_ACDS, acds);
206	if (ret < 0)
207		return ret;
208
209	/* set the SSP audio system clock SCDB divider4 */
210	ret = snd_soc_dai_set_clkdiv(cpu_dai,
211			PXA_SSP_AUDIO_DIV_SCDB, div4);
212	if (ret < 0)
213		return ret;
214
215	/* set SSP audio pll clock */
216	ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps);
217	if (ret < 0)
218		return ret;
219
220	return 0;
221}
222
223/*
224 * Magician uses I2S for capture.
225 */
226static int magician_capture_hw_params(struct snd_pcm_substream *substream,
227				      struct snd_pcm_hw_params *params)
228{
229	struct snd_soc_pcm_runtime *rtd = substream->private_data;
230	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
231	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
232	int ret = 0;
233
234	/* set codec DAI configuration */
235	ret = snd_soc_dai_set_fmt(codec_dai,
236			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
237			SND_SOC_DAIFMT_CBS_CFS);
238	if (ret < 0)
239		return ret;
240
241	/* set cpu DAI configuration */
242	ret = snd_soc_dai_set_fmt(cpu_dai,
243			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
244			SND_SOC_DAIFMT_CBS_CFS);
245	if (ret < 0)
246		return ret;
247
248	/* set the I2S system clock as output */
249	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
250			SND_SOC_CLOCK_OUT);
251	if (ret < 0)
252		return ret;
253
254	return 0;
255}
256
257static struct snd_soc_ops magician_capture_ops = {
258	.startup = magician_startup,
259	.hw_params = magician_capture_hw_params,
260};
261
262static struct snd_soc_ops magician_playback_ops = {
263	.startup = magician_startup,
264	.hw_params = magician_playback_hw_params,
265};
266
267static int magician_get_hp(struct snd_kcontrol *kcontrol,
268			     struct snd_ctl_elem_value *ucontrol)
269{
270	ucontrol->value.integer.value[0] = magician_hp_switch;
271	return 0;
272}
273
274static int magician_set_hp(struct snd_kcontrol *kcontrol,
275			     struct snd_ctl_elem_value *ucontrol)
276{
277	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
278
279	if (magician_hp_switch == ucontrol->value.integer.value[0])
280		return 0;
281
282	magician_hp_switch = ucontrol->value.integer.value[0];
283	magician_ext_control(codec);
284	return 1;
285}
286
287static int magician_get_spk(struct snd_kcontrol *kcontrol,
288			    struct snd_ctl_elem_value *ucontrol)
289{
290	ucontrol->value.integer.value[0] = magician_spk_switch;
291	return 0;
292}
293
294static int magician_set_spk(struct snd_kcontrol *kcontrol,
295			    struct snd_ctl_elem_value *ucontrol)
296{
297	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
298
299	if (magician_spk_switch == ucontrol->value.integer.value[0])
300		return 0;
301
302	magician_spk_switch = ucontrol->value.integer.value[0];
303	magician_ext_control(codec);
304	return 1;
305}
306
307static int magician_get_input(struct snd_kcontrol *kcontrol,
308			      struct snd_ctl_elem_value *ucontrol)
309{
310	ucontrol->value.integer.value[0] = magician_in_sel;
311	return 0;
312}
313
314static int magician_set_input(struct snd_kcontrol *kcontrol,
315			      struct snd_ctl_elem_value *ucontrol)
316{
317	if (magician_in_sel == ucontrol->value.integer.value[0])
318		return 0;
319
320	magician_in_sel = ucontrol->value.integer.value[0];
321
322	switch (magician_in_sel) {
323	case MAGICIAN_MIC:
324		gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 1);
325		break;
326	case MAGICIAN_MIC_EXT:
327		gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 0);
328	}
329
330	return 1;
331}
332
333static int magician_spk_power(struct snd_soc_dapm_widget *w,
334				struct snd_kcontrol *k, int event)
335{
336	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, SND_SOC_DAPM_EVENT_ON(event));
337	return 0;
338}
339
340static int magician_hp_power(struct snd_soc_dapm_widget *w,
341				struct snd_kcontrol *k, int event)
342{
343	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, SND_SOC_DAPM_EVENT_ON(event));
344	return 0;
345}
346
347static int magician_mic_bias(struct snd_soc_dapm_widget *w,
348				struct snd_kcontrol *k, int event)
349{
350	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, SND_SOC_DAPM_EVENT_ON(event));
351	return 0;
352}
353
354/* magician machine dapm widgets */
355static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
356	SND_SOC_DAPM_HP("Headphone Jack", magician_hp_power),
357	SND_SOC_DAPM_SPK("Speaker", magician_spk_power),
358	SND_SOC_DAPM_MIC("Call Mic", magician_mic_bias),
359	SND_SOC_DAPM_MIC("Headset Mic", magician_mic_bias),
360};
361
362/* magician machine audio_map */
363static const struct snd_soc_dapm_route audio_map[] = {
364
365	/* Headphone connected to VOUTL, VOUTR */
366	{"Headphone Jack", NULL, "VOUTL"},
367	{"Headphone Jack", NULL, "VOUTR"},
368
369	/* Speaker connected to VOUTL, VOUTR */
370	{"Speaker", NULL, "VOUTL"},
371	{"Speaker", NULL, "VOUTR"},
372
373	/* Mics are connected to VINM */
374	{"VINM", NULL, "Headset Mic"},
375	{"VINM", NULL, "Call Mic"},
376};
377
378static const char *input_select[] = {"Call Mic", "Headset Mic"};
379static const struct soc_enum magician_in_sel_enum =
380	SOC_ENUM_SINGLE_EXT(2, input_select);
381
382static const struct snd_kcontrol_new uda1380_magician_controls[] = {
383	SOC_SINGLE_BOOL_EXT("Headphone Switch",
384			(unsigned long)&magician_hp_switch,
385			magician_get_hp, magician_set_hp),
386	SOC_SINGLE_BOOL_EXT("Speaker Switch",
387			(unsigned long)&magician_spk_switch,
388			magician_get_spk, magician_set_spk),
389	SOC_ENUM_EXT("Input Select", magician_in_sel_enum,
390			magician_get_input, magician_set_input),
391};
392
393/*
394 * Logic for a uda1380 as connected on a HTC Magician
395 */
396static int magician_uda1380_init(struct snd_soc_codec *codec)
397{
398	int err;
399
400	/* NC codec pins */
401	snd_soc_dapm_nc_pin(codec, "VOUTLHP");
402	snd_soc_dapm_nc_pin(codec, "VOUTRHP");
403
404	snd_soc_dapm_nc_pin(codec, "VINL");
405	snd_soc_dapm_nc_pin(codec, "VINR");
406
407	/* Add magician specific controls */
408	err = snd_soc_add_controls(codec, uda1380_magician_controls,
409				ARRAY_SIZE(uda1380_magician_controls));
410	if (err < 0)
411		return err;
412
413	/* Add magician specific widgets */
414	snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
415				  ARRAY_SIZE(uda1380_dapm_widgets));
416
417	/* Set up magician specific audio path interconnects */
418	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
419
420	snd_soc_dapm_sync(codec);
421	return 0;
422}
423
424/* magician digital audio interface glue - connects codec <--> CPU */
425static struct snd_soc_dai_link magician_dai[] = {
426{
427	.name = "uda1380",
428	.stream_name = "UDA1380 Playback",
429	.cpu_dai = &pxa_ssp_dai[PXA_DAI_SSP1],
430	.codec_dai = &uda1380_dai[UDA1380_DAI_PLAYBACK],
431	.init = magician_uda1380_init,
432	.ops = &magician_playback_ops,
433},
434{
435	.name = "uda1380",
436	.stream_name = "UDA1380 Capture",
437	.cpu_dai = &pxa_i2s_dai,
438	.codec_dai = &uda1380_dai[UDA1380_DAI_CAPTURE],
439	.ops = &magician_capture_ops,
440}
441};
442
443/* magician audio machine driver */
444static struct snd_soc_card snd_soc_card_magician = {
445	.name = "Magician",
446	.dai_link = magician_dai,
447	.num_links = ARRAY_SIZE(magician_dai),
448	.platform = &pxa2xx_soc_platform,
449};
450
451/* magician audio subsystem */
452static struct snd_soc_device magician_snd_devdata = {
453	.card = &snd_soc_card_magician,
454	.codec_dev = &soc_codec_dev_uda1380,
455};
456
457static struct platform_device *magician_snd_device;
458
459static struct uda1380_platform_data uda1380_info = {
460	.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
461	.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
462	.dac_clk    = UDA1380_DAC_CLK_WSPLL,
463};
464
465static struct i2c_board_info i2c_board_info[] = {
466	{
467		I2C_BOARD_INFO("uda1380", 0x18),
468		.platform_data = &uda1380_info,
469	},
470};
471
472static int __init magician_init(void)
473{
474	int ret;
475	struct i2c_adapter *adapter;
476	struct i2c_client *client;
477
478	if (!machine_is_magician())
479		return -ENODEV;
480
481	adapter = i2c_get_adapter(0);
482	if (!adapter)
483		return -ENODEV;
484	client = i2c_new_device(adapter, i2c_board_info);
485	i2c_put_adapter(adapter);
486	if (!client)
487		return -ENODEV;
488
489	ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
490	if (ret)
491		goto err_request_spk;
492	ret = gpio_request(EGPIO_MAGICIAN_EP_POWER, "EP_POWER");
493	if (ret)
494		goto err_request_ep;
495	ret = gpio_request(EGPIO_MAGICIAN_MIC_POWER, "MIC_POWER");
496	if (ret)
497		goto err_request_mic;
498	ret = gpio_request(EGPIO_MAGICIAN_IN_SEL0, "IN_SEL0");
499	if (ret)
500		goto err_request_in_sel0;
501	ret = gpio_request(EGPIO_MAGICIAN_IN_SEL1, "IN_SEL1");
502	if (ret)
503		goto err_request_in_sel1;
504
505	gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
506
507	magician_snd_device = platform_device_alloc("soc-audio", -1);
508	if (!magician_snd_device) {
509		ret = -ENOMEM;
510		goto err_pdev;
511	}
512
513	platform_set_drvdata(magician_snd_device, &magician_snd_devdata);
514	magician_snd_devdata.dev = &magician_snd_device->dev;
515	ret = platform_device_add(magician_snd_device);
516	if (ret) {
517		platform_device_put(magician_snd_device);
518		goto err_pdev;
519	}
520
521	return 0;
522
523err_pdev:
524	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
525err_request_in_sel1:
526	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
527err_request_in_sel0:
528	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
529err_request_mic:
530	gpio_free(EGPIO_MAGICIAN_EP_POWER);
531err_request_ep:
532	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
533err_request_spk:
534	return ret;
535}
536
537static void __exit magician_exit(void)
538{
539	platform_device_unregister(magician_snd_device);
540
541	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
542	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
543	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
544
545	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
546	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
547	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
548	gpio_free(EGPIO_MAGICIAN_EP_POWER);
549	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
550}
551
552module_init(magician_init);
553module_exit(magician_exit);
554
555MODULE_AUTHOR("Philipp Zabel");
556MODULE_DESCRIPTION("ALSA SoC Magician");
557MODULE_LICENSE("GPL");
558