aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/samsung/neo1973_wm8753.c
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/neo1973_wm8753.c
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/neo1973_wm8753.c')
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c262
1 files changed, 191 insertions, 71 deletions
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c
index 7761827314b2..37cfbb8ca39f 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");