aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/samsung
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-03-07 02:04:58 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-03-07 07:19:50 -0500
commitf5c4ffbd65892829f7ec503a89ea24eb0fc952dc (patch)
tree321eb2c61af4a7adc27d86f1ccd3c6323110fe67 /sound/soc/samsung
parentb7874e4490aa201be2f904ffd8bb88a7b9970c6a (diff)
ASoC: Samsung: Merge neo1937_wm8753 and neo1973_gta02_wm8753 sound board driver
The neo1973(GTA01) and neo1973_gta02(GTA02) have a very similar audio hardware setup. They both use the same codec with the same routing to the gsm modem and bluetooth chip. But they do use different AMPs though and there are some minor differences in the speaker setup. As a result most of the code of those two drivers is identical. So from a maintenance point of view it makes sense to merge them into a single driver. It also reduces the size of kernel images supporting both the GTA01 and GTA02. As a side-effect of this merge the GTA01 for example gains support for routing audio to and from the bluetooth DAI. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/samsung')
-rw-r--r--sound/soc/samsung/Kconfig19
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/neo1973_gta02_wm8753.c435
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c262
4 files changed, 196 insertions, 522 deletions
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index ba78e26e20f..c3014e82157 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -35,24 +35,15 @@ config SND_SAMSUNG_I2S
35 tristate 35 tristate
36 36
37config SND_SOC_SAMSUNG_NEO1973_WM8753 37config SND_SOC_SAMSUNG_NEO1973_WM8753
38 tristate "SoC I2S Audio support for NEO1973 - WM8753" 38 tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)"
39 depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01 39 depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02)
40 select SND_S3C24XX_I2S 40 select SND_S3C24XX_I2S
41 select SND_SOC_WM8753 41 select SND_SOC_WM8753
42 select SND_SOC_LM4857 42 select SND_SOC_LM4857 if MACH_NEO1973_GTA01
43 help 43 help
44 Say Y if you want to add support for SoC audio on smdk2440 44 Say Y here to enable audio support for the Openmoko Neo1973
45 with the WM8753. 45 Smartphones.
46 46
47config SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753
48 tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)"
49 depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
50 select SND_S3C24XX_I2S
51 select SND_SOC_WM8753
52 help
53 This driver provides audio support for the Openmoko Neo FreeRunner
54 smartphone.
55
56config SND_SOC_SAMSUNG_JIVE_WM8750 47config SND_SOC_SAMSUNG_JIVE_WM8750
57 tristate "SoC I2S Audio support for Jive" 48 tristate "SoC I2S Audio support for Jive"
58 depends on SND_SOC_SAMSUNG && MACH_JIVE 49 depends on SND_SOC_SAMSUNG && MACH_JIVE
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 705d4e8a672..294dec05c26 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -20,7 +20,6 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
20# S3C24XX Machine Support 20# S3C24XX Machine Support
21snd-soc-jive-wm8750-objs := jive_wm8750.o 21snd-soc-jive-wm8750-objs := jive_wm8750.o
22snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o 22snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
23snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o
24snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o 23snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
25snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o 24snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o
26snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o 25snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
@@ -38,7 +37,6 @@ snd-soc-smdk-spdif-objs := smdk_spdif.o
38 37
39obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o 38obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
40obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 39obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
41obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o
42obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o 40obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
43obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o 41obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o
44obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o 42obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c
deleted file mode 100644
index 28d8448e959..00000000000
--- a/sound/soc/samsung/neo1973_gta02_wm8753.c
+++ /dev/null
@@ -1,435 +0,0 @@
1/*
2 * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02)
3 *
4 * Copyright 2007 Openmoko Inc
5 * Author: Graeme Gregory <graeme@openmoko.org>
6 * Copyright 2007 Wolfson Microelectronics PLC.
7 * Author: Graeme Gregory <linux@wolfsonmicro.com>
8 * Copyright 2009 Wolfson Microelectronics
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#include <linux/gpio.h>
17
18#include <sound/soc.h>
19
20#include <asm/mach-types.h>
21#include <plat/regs-iis.h>
22#include <mach/gta02.h>
23
24#include "../codecs/wm8753.h"
25#include "s3c24xx-i2s.h"
26
27static struct snd_soc_card neo1973_gta02;
28
29static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
30 struct snd_pcm_hw_params *params)
31{
32 struct snd_soc_pcm_runtime *rtd = substream->private_data;
33 struct snd_soc_dai *codec_dai = rtd->codec_dai;
34 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
35 unsigned int pll_out = 0, bclk = 0;
36 int ret = 0;
37 unsigned long iis_clkrate;
38
39 iis_clkrate = s3c24xx_i2s_get_clockrate();
40
41 switch (params_rate(params)) {
42 case 8000:
43 case 16000:
44 pll_out = 12288000;
45 break;
46 case 48000:
47 bclk = WM8753_BCLK_DIV_4;
48 pll_out = 12288000;
49 break;
50 case 96000:
51 bclk = WM8753_BCLK_DIV_2;
52 pll_out = 12288000;
53 break;
54 case 11025:
55 bclk = WM8753_BCLK_DIV_16;
56 pll_out = 11289600;
57 break;
58 case 22050:
59 bclk = WM8753_BCLK_DIV_8;
60 pll_out = 11289600;
61 break;
62 case 44100:
63 bclk = WM8753_BCLK_DIV_4;
64 pll_out = 11289600;
65 break;
66 case 88200:
67 bclk = WM8753_BCLK_DIV_2;
68 pll_out = 11289600;
69 break;
70 }
71
72 /* set codec DAI configuration */
73 ret = snd_soc_dai_set_fmt(codec_dai,
74 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
75 SND_SOC_DAIFMT_CBM_CFM);
76 if (ret < 0)
77 return ret;
78
79 /* set cpu DAI configuration */
80 ret = snd_soc_dai_set_fmt(cpu_dai,
81 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
82 SND_SOC_DAIFMT_CBM_CFM);
83 if (ret < 0)
84 return ret;
85
86 /* set the codec system clock for DAC and ADC */
87 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
88 SND_SOC_CLOCK_IN);
89 if (ret < 0)
90 return ret;
91
92 /* set MCLK division for sample rate */
93 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
94 S3C2410_IISMOD_32FS);
95 if (ret < 0)
96 return ret;
97
98 /* set codec BCLK division for sample rate */
99 ret = snd_soc_dai_set_clkdiv(codec_dai,
100 WM8753_BCLKDIV, bclk);
101 if (ret < 0)
102 return ret;
103
104 /* set prescaler division for sample rate */
105 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
106 S3C24XX_PRESCALE(4, 4));
107 if (ret < 0)
108 return ret;
109
110 /* codec PLL input is PCLK/4 */
111 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
112 iis_clkrate / 4, pll_out);
113 if (ret < 0)
114 return ret;
115
116 return 0;
117}
118
119static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
120{
121 struct snd_soc_pcm_runtime *rtd = substream->private_data;
122 struct snd_soc_dai *codec_dai = rtd->codec_dai;
123
124 /* disable the PLL */
125 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
126}
127
128/*
129 * Neo1973 WM8753 HiFi DAI opserations.
130 */
131static struct snd_soc_ops neo1973_gta02_hifi_ops = {
132 .hw_params = neo1973_gta02_hifi_hw_params,
133 .hw_free = neo1973_gta02_hifi_hw_free,
134};
135
136static int neo1973_gta02_voice_hw_params(
137 struct snd_pcm_substream *substream,
138 struct snd_pcm_hw_params *params)
139{
140 struct snd_soc_pcm_runtime *rtd = substream->private_data;
141 struct snd_soc_dai *codec_dai = rtd->codec_dai;
142 unsigned int pcmdiv = 0;
143 int ret = 0;
144 unsigned long iis_clkrate;
145
146 iis_clkrate = s3c24xx_i2s_get_clockrate();
147
148 if (params_rate(params) != 8000)
149 return -EINVAL;
150 if (params_channels(params) != 1)
151 return -EINVAL;
152
153 pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
154
155 /* todo: gg check mode (DSP_B) against CSR datasheet */
156 /* set codec DAI configuration */
157 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
158 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
159 if (ret < 0)
160 return ret;
161
162 /* set the codec system clock for DAC and ADC */
163 ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK,
164 12288000, SND_SOC_CLOCK_IN);
165 if (ret < 0)
166 return ret;
167
168 /* set codec PCM division for sample rate */
169 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV,
170 pcmdiv);
171 if (ret < 0)
172 return ret;
173
174 /* configure and enable PLL for 12.288MHz output */
175 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
176 iis_clkrate / 4, 12288000);
177 if (ret < 0)
178 return ret;
179
180 return 0;
181}
182
183static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
184{
185 struct snd_soc_pcm_runtime *rtd = substream->private_data;
186 struct snd_soc_dai *codec_dai = rtd->codec_dai;
187
188 /* disable the PLL */
189 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
190}
191
192static struct snd_soc_ops neo1973_gta02_voice_ops = {
193 .hw_params = neo1973_gta02_voice_hw_params,
194 .hw_free = neo1973_gta02_voice_hw_free,
195};
196
197static int gta02_speaker_enabled;
198
199static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
200 struct snd_ctl_elem_value *ucontrol)
201{
202 gta02_speaker_enabled = ucontrol->value.integer.value[0];
203
204 gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled);
205
206 return 0;
207}
208
209static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
210 struct snd_ctl_elem_value *ucontrol)
211{
212 ucontrol->value.integer.value[0] = gta02_speaker_enabled;
213 return 0;
214}
215
216static int lm4853_event(struct snd_soc_dapm_widget *w,
217 struct snd_kcontrol *k, int event)
218{
219 gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
220
221 return 0;
222}
223
224static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
225 SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
226 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
227 SND_SOC_DAPM_LINE("GSM Line In", NULL),
228 SND_SOC_DAPM_MIC("Headset Mic", NULL),
229 SND_SOC_DAPM_MIC("Handset Mic", NULL),
230 SND_SOC_DAPM_SPK("Handset Spk", NULL),
231};
232
233
234/* example machine audio_mapnections */
235static const struct snd_soc_dapm_route audio_map[] = {
236
237 /* Connections to the lm4853 amp */
238 {"Stereo Out", NULL, "LOUT1"},
239 {"Stereo Out", NULL, "ROUT1"},
240
241 /* Connections to the GSM Module */
242 {"GSM Line Out", NULL, "MONO1"},
243 {"GSM Line Out", NULL, "MONO2"},
244 {"RXP", NULL, "GSM Line In"},
245 {"RXN", NULL, "GSM Line In"},
246
247 /* Connections to Headset */
248 {"MIC1", NULL, "Mic Bias"},
249 {"Mic Bias", NULL, "Headset Mic"},
250
251 /* Call Mic */
252 {"MIC2", NULL, "Mic Bias"},
253 {"MIC2N", NULL, "Mic Bias"},
254 {"Mic Bias", NULL, "Handset Mic"},
255
256 /* Call Speaker */
257 {"Handset Spk", NULL, "LOUT2"},
258 {"Handset Spk", NULL, "ROUT2"},
259
260 /* Connect the ALC pins */
261 {"ACIN", NULL, "ACOP"},
262};
263
264static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = {
265 SOC_DAPM_PIN_SWITCH("Stereo Out"),
266 SOC_DAPM_PIN_SWITCH("GSM Line Out"),
267 SOC_DAPM_PIN_SWITCH("GSM Line In"),
268 SOC_DAPM_PIN_SWITCH("Headset Mic"),
269 SOC_DAPM_PIN_SWITCH("Handset Mic"),
270 SOC_DAPM_PIN_SWITCH("Handset Spk"),
271
272 SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
273 lm4853_get_spk,
274 lm4853_set_spk),
275};
276
277/*
278 * This is an example machine initialisation for a wm8753 connected to a
279 * neo1973 GTA02.
280 */
281static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd)
282{
283 struct snd_soc_codec *codec = rtd->codec;
284 struct snd_soc_dapm_context *dapm = &codec->dapm;
285 int err;
286
287 /* set up NC codec pins */
288 snd_soc_dapm_nc_pin(dapm, "OUT3");
289 snd_soc_dapm_nc_pin(dapm, "OUT4");
290 snd_soc_dapm_nc_pin(dapm, "LINE1");
291 snd_soc_dapm_nc_pin(dapm, "LINE2");
292
293 /* Add neo1973 gta02 specific widgets */
294 snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
295 ARRAY_SIZE(wm8753_dapm_widgets));
296
297 /* add neo1973 gta02 specific controls */
298 err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls,
299 ARRAY_SIZE(wm8753_neo1973_gta02_controls));
300
301 if (err < 0)
302 return err;
303
304 /* set up neo1973 gta02 specific audio path audio_map */
305 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
306
307 /* set endpoints to default off mode */
308 snd_soc_dapm_disable_pin(dapm, "Stereo Out");
309 snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
310 snd_soc_dapm_disable_pin(dapm, "GSM Line In");
311 snd_soc_dapm_disable_pin(dapm, "Headset Mic");
312 snd_soc_dapm_disable_pin(dapm, "Handset Mic");
313 snd_soc_dapm_disable_pin(dapm, "Handset Spk");
314
315 /* allow audio paths from the GSM modem to run during suspend */
316 snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
317 snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
318 snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
319 snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
320 snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
321 snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
322
323 snd_soc_dapm_sync(dapm);
324
325 return 0;
326}
327
328/*
329 * BT Codec DAI
330 */
331static struct snd_soc_dai_driver bt_dai = {
332 .name = "bluetooth-dai",
333 .playback = {
334 .channels_min = 1,
335 .channels_max = 1,
336 .rates = SNDRV_PCM_RATE_8000,
337 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
338 .capture = {
339 .channels_min = 1,
340 .channels_max = 1,
341 .rates = SNDRV_PCM_RATE_8000,
342 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
343};
344
345static struct snd_soc_dai_link neo1973_gta02_dai[] = {
346{ /* Hifi Playback - for similatious use with voice below */
347 .name = "WM8753",
348 .stream_name = "WM8753 HiFi",
349 .cpu_dai_name = "s3c24xx-iis",
350 .codec_dai_name = "wm8753-hifi",
351 .init = neo1973_gta02_wm8753_init,
352 .platform_name = "samsung-audio",
353 .codec_name = "wm8753-codec.0-001a",
354 .ops = &neo1973_gta02_hifi_ops,
355},
356{ /* Voice via BT */
357 .name = "Bluetooth",
358 .stream_name = "Voice",
359 .cpu_dai_name = "bluetooth-dai",
360 .codec_dai_name = "wm8753-voice",
361 .ops = &neo1973_gta02_voice_ops,
362 .codec_name = "wm8753-codec.0-001a",
363 .platform_name = "samsung-audio",
364},
365};
366
367static struct snd_soc_card neo1973_gta02 = {
368 .name = "neo1973-gta02",
369 .dai_link = neo1973_gta02_dai,
370 .num_links = ARRAY_SIZE(neo1973_gta02_dai),
371};
372
373static const struct gpio neo1973_gta02_gpios[] = {
374 { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
375 { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
376};
377
378static struct platform_device *neo1973_gta02_snd_device;
379
380static int __init neo1973_gta02_init(void)
381{
382 int ret;
383
384 if (!machine_is_neo1973_gta02()) {
385 printk(KERN_INFO
386 "Only GTA02 is supported by this ASoC driver\n");
387 return -ENODEV;
388 }
389
390 ret = gpio_request_array(neo1973_gta02_gpios,
391 ARRAY_SIZE(neo1973_gta02_gpios));
392 if (ret)
393 return ret;
394
395 neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1);
396 if (!neo1973_gta02_snd_device) {
397 ret = -ENOMEM;
398 goto err_gpio_free;
399 }
400
401 /* register bluetooth DAI here */
402 ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, &bt_dai);
403 if (ret)
404 goto err_put_device;
405
406 platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02);
407 ret = platform_device_add(neo1973_gta02_snd_device);
408
409 if (ret)
410 goto err_unregister_dai;
411
412 return 0;
413
414err_unregister_dai:
415 snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev);
416err_put_device:
417 platform_device_put(neo1973_gta02_snd_device);
418err_gpio_free:
419 gpio_free_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios));
420 return ret;
421}
422module_init(neo1973_gta02_init);
423
424static void __exit neo1973_gta02_exit(void)
425{
426 snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev);
427 platform_device_unregister(neo1973_gta02_snd_device);
428 gpio_free_array(neo1973_gta02_gpios, ARRAY_SIZE(neo1973_gta02_gpios));
429}
430module_exit(neo1973_gta02_exit);
431
432/* Module information */
433MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org");
434MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02");
435MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 7761827314b..37cfbb8ca39 100644
--- a/sound/soc/samsung/neo1973_wm8753.c
+++ b/sound/soc/samsung/neo1973_wm8753.c
@@ -1,41 +1,32 @@
1/* 1/*
2 * neo1973_wm8753.c -- SoC audio for Neo1973 2 * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices
3 * 3 *
4 * Copyright 2007 Openmoko Inc
5 * Author: Graeme Gregory <graeme@openmoko.org>
4 * Copyright 2007 Wolfson Microelectronics PLC. 6 * Copyright 2007 Wolfson Microelectronics PLC.
5 * Author: Graeme Gregory 7 * Author: Graeme Gregory
6 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 8 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
9 * Copyright 2009 Wolfson Microelectronics
7 * 10 *
8 * This program is free software; you can redistribute it and/or modify it 11 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the 12 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your 13 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. 14 * option) any later version.
12 *
13 */ 15 */
14 16
15#include <linux/module.h> 17#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/timer.h>
18#include <linux/interrupt.h>
19#include <linux/platform_device.h> 18#include <linux/platform_device.h>
20#include <sound/core.h> 19#include <linux/gpio.h>
21#include <sound/pcm.h> 20
22#include <sound/soc.h> 21#include <sound/soc.h>
23 22
24#include <asm/mach-types.h> 23#include <asm/mach-types.h>
25#include <mach/regs-clock.h>
26#include <mach/regs-gpio.h>
27#include <mach/hardware.h>
28#include <linux/io.h>
29#include <mach/spi-gpio.h>
30
31#include <plat/regs-iis.h> 24#include <plat/regs-iis.h>
25#include <mach/gta02.h>
32 26
33#include "../codecs/wm8753.h" 27#include "../codecs/wm8753.h"
34#include "dma.h"
35#include "s3c24xx-i2s.h" 28#include "s3c24xx-i2s.h"
36 29
37static struct snd_soc_card neo1973;
38
39static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, 30static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
40 struct snd_pcm_hw_params *params) 31 struct snd_pcm_hw_params *params)
41{ 32{
@@ -46,8 +37,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
46 int ret = 0; 37 int ret = 0;
47 unsigned long iis_clkrate; 38 unsigned long iis_clkrate;
48 39
49 pr_debug("Entered %s\n", __func__);
50
51 iis_clkrate = s3c24xx_i2s_get_clockrate(); 40 iis_clkrate = s3c24xx_i2s_get_clockrate();
52 41
53 switch (params_rate(params)) { 42 switch (params_rate(params)) {
@@ -132,8 +121,6 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
132 struct snd_soc_pcm_runtime *rtd = substream->private_data; 121 struct snd_soc_pcm_runtime *rtd = substream->private_data;
133 struct snd_soc_dai *codec_dai = rtd->codec_dai; 122 struct snd_soc_dai *codec_dai = rtd->codec_dai;
134 123
135 pr_debug("Entered %s\n", __func__);
136
137 /* disable the PLL */ 124 /* disable the PLL */
138 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); 125 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
139} 126}
@@ -155,8 +142,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
155 int ret = 0; 142 int ret = 0;
156 unsigned long iis_clkrate; 143 unsigned long iis_clkrate;
157 144
158 pr_debug("Entered %s\n", __func__);
159
160 iis_clkrate = s3c24xx_i2s_get_clockrate(); 145 iis_clkrate = s3c24xx_i2s_get_clockrate();
161 146
162 if (params_rate(params) != 8000) 147 if (params_rate(params) != 8000)
@@ -198,8 +183,6 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
198 struct snd_soc_pcm_runtime *rtd = substream->private_data; 183 struct snd_soc_pcm_runtime *rtd = substream->private_data;
199 struct snd_soc_dai *codec_dai = rtd->codec_dai; 184 struct snd_soc_dai *codec_dai = rtd->codec_dai;
200 185
201 pr_debug("Entered %s\n", __func__);
202
203 /* disable the PLL */ 186 /* disable the PLL */
204 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); 187 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
205} 188}
@@ -209,14 +192,15 @@ static struct snd_soc_ops neo1973_voice_ops = {
209 .hw_free = neo1973_voice_hw_free, 192 .hw_free = neo1973_voice_hw_free,
210}; 193};
211 194
212static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { 195/* Shared routes and controls */
196
197static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = {
213 SND_SOC_DAPM_LINE("GSM Line Out", NULL), 198 SND_SOC_DAPM_LINE("GSM Line Out", NULL),
214 SND_SOC_DAPM_LINE("GSM Line In", NULL), 199 SND_SOC_DAPM_LINE("GSM Line In", NULL),
215 SND_SOC_DAPM_MIC("Headset Mic", NULL), 200 SND_SOC_DAPM_MIC("Headset Mic", NULL),
216 SND_SOC_DAPM_MIC("Call Mic", NULL), 201 SND_SOC_DAPM_MIC("Handset Mic", NULL),
217}; 202};
218 203
219
220static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { 204static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
221 /* Connections to the GSM Module */ 205 /* Connections to the GSM Module */
222 {"GSM Line Out", NULL, "MONO1"}, 206 {"GSM Line Out", NULL, "MONO1"},
@@ -231,7 +215,7 @@ static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = {
231 /* Call Mic */ 215 /* Call Mic */
232 {"MIC2", NULL, "Mic Bias"}, 216 {"MIC2", NULL, "Mic Bias"},
233 {"MIC2N", NULL, "Mic Bias"}, 217 {"MIC2N", NULL, "Mic Bias"},
234 {"Mic Bias", NULL, "Call Mic"}, 218 {"Mic Bias", NULL, "Handset Mic"},
235 219
236 /* Connect the ALC pins */ 220 /* Connect the ALC pins */
237 {"ACIN", NULL, "ACOP"}, 221 {"ACIN", NULL, "ACOP"},
@@ -241,55 +225,157 @@ static const struct snd_kcontrol_new neo1973_wm8753_controls[] = {
241 SOC_DAPM_PIN_SWITCH("GSM Line Out"), 225 SOC_DAPM_PIN_SWITCH("GSM Line Out"),
242 SOC_DAPM_PIN_SWITCH("GSM Line In"), 226 SOC_DAPM_PIN_SWITCH("GSM Line In"),
243 SOC_DAPM_PIN_SWITCH("Headset Mic"), 227 SOC_DAPM_PIN_SWITCH("Headset Mic"),
244 SOC_DAPM_PIN_SWITCH("Call Mic"), 228 SOC_DAPM_PIN_SWITCH("Handset Mic"),
245}; 229};
246 230
231/* GTA02 specific routes and controlls */
232
233#ifdef CONFIG_MACH_NEO1973_GTA02
234
235static int gta02_speaker_enabled;
236
237static int lm4853_set_spk(struct snd_kcontrol *kcontrol,
238 struct snd_ctl_elem_value *ucontrol)
239{
240 gta02_speaker_enabled = ucontrol->value.integer.value[0];
241
242 gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled);
243
244 return 0;
245}
246
247static int lm4853_get_spk(struct snd_kcontrol *kcontrol,
248 struct snd_ctl_elem_value *ucontrol)
249{
250 ucontrol->value.integer.value[0] = gta02_speaker_enabled;
251 return 0;
252}
253
254static int lm4853_event(struct snd_soc_dapm_widget *w,
255 struct snd_kcontrol *k, int event)
256{
257 gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event));
258
259 return 0;
260}
261
262static const struct snd_soc_dapm_route neo1973_gta02_routes[] = {
263 /* Connections to the amp */
264 {"Stereo Out", NULL, "LOUT1"},
265 {"Stereo Out", NULL, "ROUT1"},
266
267 /* Call Speaker */
268 {"Handset Spk", NULL, "LOUT2"},
269 {"Handset Spk", NULL, "ROUT2"},
270};
271
272static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = {
273 SOC_DAPM_PIN_SWITCH("Handset Spk"),
274 SOC_DAPM_PIN_SWITCH("Stereo Out"),
275
276 SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0,
277 lm4853_get_spk,
278 lm4853_set_spk),
279};
280
281static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = {
282 SND_SOC_DAPM_SPK("Handset Spk", NULL),
283 SND_SOC_DAPM_SPK("Stereo Out", lm4853_event),
284};
285
286static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec)
287{
288 struct snd_soc_dapm_context *dapm = &codec->dapm;
289 int ret;
290
291 ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets,
292 ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets));
293 if (ret)
294 return ret;
295
296 ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes,
297 ARRAY_SIZE(neo1973_gta02_routes));
298 if (ret)
299 return ret;
300
301 ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls,
302 ARRAY_SIZE(neo1973_gta02_wm8753_controls));
303 if (ret)
304 return ret;
305
306 snd_soc_dapm_disable_pin(dapm, "Stereo Out");
307 snd_soc_dapm_disable_pin(dapm, "Handset Spk");
308 snd_soc_dapm_ignore_suspend(dapm, "Stereo Out");
309 snd_soc_dapm_ignore_suspend(dapm, "Handset Spk");
310
311 return 0;
312}
313
314#else
315static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; }
316#endif
247 317
248/*
249 * This is an example machine initialisation for a wm8753 connected to a
250 * neo1973 II. It is missing logic to detect hp/mic insertions and logic
251 * to re-route the audio in such an event.
252 */
253static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) 318static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd)
254{ 319{
255 struct snd_soc_codec *codec = rtd->codec; 320 struct snd_soc_codec *codec = rtd->codec;
256 struct snd_soc_dapm_context *dapm = &codec->dapm; 321 struct snd_soc_dapm_context *dapm = &codec->dapm;
257 int err; 322 int ret;
258
259 pr_debug("Entered %s\n", __func__);
260 323
261 /* set up NC codec pins */ 324 /* set up NC codec pins */
262 snd_soc_dapm_nc_pin(dapm, "LOUT2"); 325 if (machine_is_neo1973_gta01()) {
263 snd_soc_dapm_nc_pin(dapm, "ROUT2"); 326 snd_soc_dapm_nc_pin(dapm, "LOUT2");
327 snd_soc_dapm_nc_pin(dapm, "ROUT2");
328 }
264 snd_soc_dapm_nc_pin(dapm, "OUT3"); 329 snd_soc_dapm_nc_pin(dapm, "OUT3");
265 snd_soc_dapm_nc_pin(dapm, "OUT4"); 330 snd_soc_dapm_nc_pin(dapm, "OUT4");
266 snd_soc_dapm_nc_pin(dapm, "LINE1"); 331 snd_soc_dapm_nc_pin(dapm, "LINE1");
267 snd_soc_dapm_nc_pin(dapm, "LINE2"); 332 snd_soc_dapm_nc_pin(dapm, "LINE2");
268 333
269 /* Add neo1973 specific widgets */ 334 /* Add neo1973 specific widgets */
270 snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, 335 ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets,
271 ARRAY_SIZE(wm8753_dapm_widgets)); 336 ARRAY_SIZE(neo1973_wm8753_dapm_widgets));
272 337 if (ret)
273 /* set endpoints to default mode */ 338 return ret;
274 snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
275 snd_soc_dapm_disable_pin(dapm, "GSM Line In");
276 snd_soc_dapm_disable_pin(dapm, "Headset Mic");
277 snd_soc_dapm_disable_pin(dapm, "Call Mic");
278 339
279 /* add neo1973 specific controls */ 340 /* add neo1973 specific controls */
280 err = snd_soc_add_controls(codec, neo1973_wm8753_controls, 341 ret = snd_soc_add_controls(codec, neo1973_wm8753_controls,
281 ARRAY_SIZE(neo1973_wm8753_controls)); 342 ARRAY_SIZE(neo1973_wm8753_controls));
282 if (err < 0) 343 if (ret)
283 return err; 344 return ret;
284 345
285 /* set up neo1973 specific audio routes */ 346 /* set up neo1973 specific audio routes */
286 err = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, 347 ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes,
287 ARRAY_SIZE(neo1973_wm8753_routes)); 348 ARRAY_SIZE(neo1973_wm8753_routes));
349 if (ret)
350 return ret;
351
352 /* set endpoints to default off mode */
353 snd_soc_dapm_disable_pin(dapm, "GSM Line Out");
354 snd_soc_dapm_disable_pin(dapm, "GSM Line In");
355 snd_soc_dapm_disable_pin(dapm, "Headset Mic");
356 snd_soc_dapm_disable_pin(dapm, "Handset Mic");
357
358 /* allow audio paths from the GSM modem to run during suspend */
359 snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out");
360 snd_soc_dapm_ignore_suspend(dapm, "GSM Line In");
361 snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
362 snd_soc_dapm_ignore_suspend(dapm, "Handset Mic");
363
364 if (machine_is_neo1973_gta02()) {
365 ret = neo1973_gta02_wm8753_init(codec);
366 if (ret)
367 return ret;
368 }
288 369
289 snd_soc_dapm_sync(dapm); 370 snd_soc_dapm_sync(dapm);
371
290 return 0; 372 return 0;
291} 373}
292 374
375/* GTA01 specific controlls */
376
377#ifdef CONFIG_MACH_NEO1973_GTA01
378
293static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { 379static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = {
294 {"Amp IN", NULL, "ROUT1"}, 380 {"Amp IN", NULL, "ROUT1"},
295 {"Amp IN", NULL, "LOUT1"}, 381 {"Amp IN", NULL, "LOUT1"},
@@ -328,10 +414,14 @@ static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm)
328 return 0; 414 return 0;
329} 415}
330 416
417#else
418static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; };
419#endif
420
331/* 421/*
332 * BT Codec DAI 422 * BT Codec DAI
333 */ 423 */
334static struct snd_soc_dai bt_dai = { 424static struct snd_soc_dai_driver bt_dai = {
335 .name = "bluetooth-dai", 425 .name = "bluetooth-dai",
336 .playback = { 426 .playback = {
337 .channels_min = 1, 427 .channels_min = 1,
@@ -382,6 +472,15 @@ static struct snd_soc_codec_conf neo1973_codec_conf[] = {
382 }, 472 },
383}; 473};
384 474
475#ifdef CONFIG_MACH_NEO1973_GTA02
476static const struct gpio neo1973_gta02_gpios[] = {
477 { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" },
478 { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" },
479};
480#else
481static const struct gpio neo1973_gta02_gpios[] = {};
482#endif
483
385static struct snd_soc_card neo1973 = { 484static struct snd_soc_card neo1973 = {
386 .name = "neo1973", 485 .name = "neo1973",
387 .dai_link = neo1973_dai, 486 .dai_link = neo1973_dai,
@@ -398,43 +497,64 @@ static int __init neo1973_init(void)
398{ 497{
399 int ret; 498 int ret;
400 499
401 pr_debug("Entered %s\n", __func__); 500 if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02())
402
403 if (!machine_is_neo1973_gta01()) {
404 printk(KERN_INFO
405 "Only GTA01 hardware supported by ASoC driver\n");
406 return -ENODEV; 501 return -ENODEV;
502
503 if (machine_is_neo1973_gta02()) {
504 neo1973.name = "neo1973gta02";
505 neo1973.num_aux_devs = 0;
506
507 ret = gpio_request_array(neo1973_gta02_gpios,
508 ARRAY_SIZE(neo1973_gta02_gpios));
509 if (ret)
510 return ret;
407 } 511 }
408 512
409 neo1973_snd_device = platform_device_alloc("soc-audio", -1); 513 neo1973_snd_device = platform_device_alloc("soc-audio", -1);
410 if (!neo1973_snd_device) 514 if (!neo1973_snd_device) {
411 return -ENOMEM; 515 ret = -ENOMEM;
516 goto err_gpio_free;
517 }
518
519 /* register bluetooth DAI here */
520 ret = snd_soc_register_dai(&neo1973_snd_device->dev, &bt_dai);
521 if (ret)
522 goto err_put_device;
412 523
413 platform_set_drvdata(neo1973_snd_device, &neo1973); 524 platform_set_drvdata(neo1973_snd_device, &neo1973);
414 ret = platform_device_add(neo1973_snd_device); 525 ret = platform_device_add(neo1973_snd_device);
415 526
416 if (ret) { 527 if (ret)
417 platform_device_put(neo1973_snd_device); 528 goto err_unregister_dai;
418 return ret;
419 }
420 529
421 if (ret != 0) 530 return 0;
422 platform_device_unregister(neo1973_snd_device);
423 531
532err_unregister_dai:
533 snd_soc_unregister_dai(&neo1973_snd_device->dev);
534err_put_device:
535 platform_device_put(neo1973_snd_device);
536err_gpio_free:
537 if (machine_is_neo1973_gta02()) {
538 gpio_free_array(neo1973_gta02_gpios,
539 ARRAY_SIZE(neo1973_gta02_gpios));
540 }
424 return ret; 541 return ret;
425} 542}
543module_init(neo1973_init);
426 544
427static void __exit neo1973_exit(void) 545static void __exit neo1973_exit(void)
428{ 546{
429 pr_debug("Entered %s\n", __func__); 547 snd_soc_unregister_dai(&neo1973_snd_device->dev);
430
431 platform_device_unregister(neo1973_snd_device); 548 platform_device_unregister(neo1973_snd_device);
432}
433 549
434module_init(neo1973_init); 550 if (machine_is_neo1973_gta02()) {
551 gpio_free_array(neo1973_gta02_gpios,
552 ARRAY_SIZE(neo1973_gta02_gpios));
553 }
554}
435module_exit(neo1973_exit); 555module_exit(neo1973_exit);
436 556
437/* Module information */ 557/* Module information */
438MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); 558MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
439MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973"); 559MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner");
440MODULE_LICENSE("GPL"); 560MODULE_LICENSE("GPL");