• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/sound/soc/omap/
1/*
2 * omap3pandora.c  --  SoC audio for Pandora Handheld Console
3 *
4 * Author: Gra��vydas Ignotas <notasas@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include <linux/clk.h>
23#include <linux/platform_device.h>
24#include <linux/gpio.h>
25#include <linux/delay.h>
26#include <linux/regulator/consumer.h>
27
28#include <sound/core.h>
29#include <sound/pcm.h>
30#include <sound/soc.h>
31#include <sound/soc-dapm.h>
32
33#include <asm/mach-types.h>
34
35#include "omap-mcbsp.h"
36#include "omap-pcm.h"
37#include "../codecs/twl4030.h"
38
39#define OMAP3_PANDORA_DAC_POWER_GPIO	118
40#define OMAP3_PANDORA_AMP_POWER_GPIO	14
41
42#define PREFIX "ASoC omap3pandora: "
43
44static struct regulator *omap3pandora_dac_reg;
45
46static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
47	struct snd_pcm_hw_params *params)
48{
49	struct snd_soc_pcm_runtime *rtd = substream->private_data;
50	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
51	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
52	int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
53		  SND_SOC_DAIFMT_CBS_CFS;
54	int ret;
55
56	/* Set codec DAI configuration */
57	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
58	if (ret < 0) {
59		pr_err(PREFIX "can't set codec DAI configuration\n");
60		return ret;
61	}
62
63	/* Set cpu DAI configuration */
64	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
65	if (ret < 0) {
66		pr_err(PREFIX "can't set cpu DAI configuration\n");
67		return ret;
68	}
69
70	/* Set the codec system clock for DAC and ADC */
71	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
72					    SND_SOC_CLOCK_IN);
73	if (ret < 0) {
74		pr_err(PREFIX "can't set codec system clock\n");
75		return ret;
76	}
77
78	/* Set McBSP clock to external */
79	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
80				     256 * params_rate(params),
81				     SND_SOC_CLOCK_IN);
82	if (ret < 0) {
83		pr_err(PREFIX "can't set cpu system clock\n");
84		return ret;
85	}
86
87	ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_MCBSP_CLKGDV, 8);
88	if (ret < 0) {
89		pr_err(PREFIX "can't set SRG clock divider\n");
90		return ret;
91	}
92
93	return 0;
94}
95
96static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
97	struct snd_kcontrol *k, int event)
98{
99	/*
100	 * The PCM1773 DAC datasheet requires 1ms delay between switching
101	 * VCC power on/off and /PD pin high/low
102	 */
103	if (SND_SOC_DAPM_EVENT_ON(event)) {
104		regulator_enable(omap3pandora_dac_reg);
105		mdelay(1);
106		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
107	} else {
108		gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
109		mdelay(1);
110		regulator_disable(omap3pandora_dac_reg);
111	}
112
113	return 0;
114}
115
116static int omap3pandora_hp_event(struct snd_soc_dapm_widget *w,
117	struct snd_kcontrol *k, int event)
118{
119	if (SND_SOC_DAPM_EVENT_ON(event))
120		gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 1);
121	else
122		gpio_set_value(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
123
124	return 0;
125}
126
127/*
128 * Audio paths on Pandora board:
129 *
130 *  |O| ---> PCM DAC +-> AMP -> Headphone Jack
131 *  |M|         A    +--------> Line Out
132 *  |A| <~~clk~~+
133 *  |P| <--- TWL4030 <--------- Line In and MICs
134 */
135static const struct snd_soc_dapm_widget omap3pandora_out_dapm_widgets[] = {
136	SND_SOC_DAPM_DAC_E("PCM DAC", "HiFi Playback", SND_SOC_NOPM,
137			   0, 0, omap3pandora_dac_event,
138			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
139	SND_SOC_DAPM_PGA_E("Headphone Amplifier", SND_SOC_NOPM,
140			   0, 0, NULL, 0, omap3pandora_hp_event,
141			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
142	SND_SOC_DAPM_HP("Headphone Jack", NULL),
143	SND_SOC_DAPM_LINE("Line Out", NULL),
144};
145
146static const struct snd_soc_dapm_widget omap3pandora_in_dapm_widgets[] = {
147	SND_SOC_DAPM_MIC("Mic (internal)", NULL),
148	SND_SOC_DAPM_MIC("Mic (external)", NULL),
149	SND_SOC_DAPM_LINE("Line In", NULL),
150};
151
152static const struct snd_soc_dapm_route omap3pandora_out_map[] = {
153	{"PCM DAC", NULL, "APLL Enable"},
154	{"Headphone Amplifier", NULL, "PCM DAC"},
155	{"Line Out", NULL, "PCM DAC"},
156	{"Headphone Jack", NULL, "Headphone Amplifier"},
157};
158
159static const struct snd_soc_dapm_route omap3pandora_in_map[] = {
160	{"AUXL", NULL, "Line In"},
161	{"AUXR", NULL, "Line In"},
162
163	{"MAINMIC", NULL, "Mic Bias 1"},
164	{"Mic Bias 1", NULL, "Mic (internal)"},
165
166	{"SUBMIC", NULL, "Mic Bias 2"},
167	{"Mic Bias 2", NULL, "Mic (external)"},
168};
169
170static int omap3pandora_out_init(struct snd_soc_codec *codec)
171{
172	int ret;
173
174	/* All TWL4030 output pins are floating */
175	snd_soc_dapm_nc_pin(codec, "EARPIECE");
176	snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
177	snd_soc_dapm_nc_pin(codec, "PREDRIVER");
178	snd_soc_dapm_nc_pin(codec, "HSOL");
179	snd_soc_dapm_nc_pin(codec, "HSOR");
180	snd_soc_dapm_nc_pin(codec, "CARKITL");
181	snd_soc_dapm_nc_pin(codec, "CARKITR");
182	snd_soc_dapm_nc_pin(codec, "HFL");
183	snd_soc_dapm_nc_pin(codec, "HFR");
184	snd_soc_dapm_nc_pin(codec, "VIBRA");
185
186	ret = snd_soc_dapm_new_controls(codec, omap3pandora_out_dapm_widgets,
187				ARRAY_SIZE(omap3pandora_out_dapm_widgets));
188	if (ret < 0)
189		return ret;
190
191	snd_soc_dapm_add_routes(codec, omap3pandora_out_map,
192		ARRAY_SIZE(omap3pandora_out_map));
193
194	return snd_soc_dapm_sync(codec);
195}
196
197static int omap3pandora_in_init(struct snd_soc_codec *codec)
198{
199	int ret;
200
201	/* Not comnnected */
202	snd_soc_dapm_nc_pin(codec, "HSMIC");
203	snd_soc_dapm_nc_pin(codec, "CARKITMIC");
204	snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
205	snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
206
207	ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets,
208				ARRAY_SIZE(omap3pandora_in_dapm_widgets));
209	if (ret < 0)
210		return ret;
211
212	snd_soc_dapm_add_routes(codec, omap3pandora_in_map,
213		ARRAY_SIZE(omap3pandora_in_map));
214
215	return snd_soc_dapm_sync(codec);
216}
217
218static struct snd_soc_ops omap3pandora_ops = {
219	.hw_params = omap3pandora_hw_params,
220};
221
222/* Digital audio interface glue - connects codec <--> CPU */
223static struct snd_soc_dai_link omap3pandora_dai[] = {
224	{
225		.name = "PCM1773",
226		.stream_name = "HiFi Out",
227		.cpu_dai = &omap_mcbsp_dai[0],
228		.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
229		.ops = &omap3pandora_ops,
230		.init = omap3pandora_out_init,
231	}, {
232		.name = "TWL4030",
233		.stream_name = "Line/Mic In",
234		.cpu_dai = &omap_mcbsp_dai[1],
235		.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
236		.ops = &omap3pandora_ops,
237		.init = omap3pandora_in_init,
238	}
239};
240
241/* SoC card */
242static struct snd_soc_card snd_soc_card_omap3pandora = {
243	.name = "omap3pandora",
244	.platform = &omap_soc_platform,
245	.dai_link = omap3pandora_dai,
246	.num_links = ARRAY_SIZE(omap3pandora_dai),
247};
248
249/* Audio subsystem */
250static struct snd_soc_device omap3pandora_snd_data = {
251	.card = &snd_soc_card_omap3pandora,
252	.codec_dev = &soc_codec_dev_twl4030,
253};
254
255static struct platform_device *omap3pandora_snd_device;
256
257static int __init omap3pandora_soc_init(void)
258{
259	int ret;
260
261	if (!machine_is_omap3_pandora())
262		return -ENODEV;
263
264	pr_info("OMAP3 Pandora SoC init\n");
265
266	ret = gpio_request(OMAP3_PANDORA_DAC_POWER_GPIO, "dac_power");
267	if (ret) {
268		pr_err(PREFIX "Failed to get DAC power GPIO\n");
269		return ret;
270	}
271
272	ret = gpio_direction_output(OMAP3_PANDORA_DAC_POWER_GPIO, 0);
273	if (ret) {
274		pr_err(PREFIX "Failed to set DAC power GPIO direction\n");
275		goto fail0;
276	}
277
278	ret = gpio_request(OMAP3_PANDORA_AMP_POWER_GPIO, "amp_power");
279	if (ret) {
280		pr_err(PREFIX "Failed to get amp power GPIO\n");
281		goto fail0;
282	}
283
284	ret = gpio_direction_output(OMAP3_PANDORA_AMP_POWER_GPIO, 0);
285	if (ret) {
286		pr_err(PREFIX "Failed to set amp power GPIO direction\n");
287		goto fail1;
288	}
289
290	omap3pandora_snd_device = platform_device_alloc("soc-audio", -1);
291	if (omap3pandora_snd_device == NULL) {
292		pr_err(PREFIX "Platform device allocation failed\n");
293		ret = -ENOMEM;
294		goto fail1;
295	}
296
297	platform_set_drvdata(omap3pandora_snd_device, &omap3pandora_snd_data);
298	omap3pandora_snd_data.dev = &omap3pandora_snd_device->dev;
299	*(unsigned int *)omap_mcbsp_dai[0].private_data = 1; /* McBSP2 */
300	*(unsigned int *)omap_mcbsp_dai[1].private_data = 3; /* McBSP4 */
301
302	ret = platform_device_add(omap3pandora_snd_device);
303	if (ret) {
304		pr_err(PREFIX "Unable to add platform device\n");
305		goto fail2;
306	}
307
308	omap3pandora_dac_reg = regulator_get(&omap3pandora_snd_device->dev, "vcc");
309	if (IS_ERR(omap3pandora_dac_reg)) {
310		pr_err(PREFIX "Failed to get DAC regulator from %s: %ld\n",
311			dev_name(&omap3pandora_snd_device->dev),
312			PTR_ERR(omap3pandora_dac_reg));
313		goto fail3;
314	}
315
316	return 0;
317
318fail3:
319	platform_device_del(omap3pandora_snd_device);
320fail2:
321	platform_device_put(omap3pandora_snd_device);
322fail1:
323	gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
324fail0:
325	gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
326	return ret;
327}
328module_init(omap3pandora_soc_init);
329
330static void __exit omap3pandora_soc_exit(void)
331{
332	regulator_put(omap3pandora_dac_reg);
333	platform_device_unregister(omap3pandora_snd_device);
334	gpio_free(OMAP3_PANDORA_AMP_POWER_GPIO);
335	gpio_free(OMAP3_PANDORA_DAC_POWER_GPIO);
336}
337module_exit(omap3pandora_soc_exit);
338
339MODULE_AUTHOR("Grazvydas Ignotas <notasas@gmail.com>");
340MODULE_DESCRIPTION("ALSA SoC OMAP3 Pandora");
341MODULE_LICENSE("GPL");
342