initscripts-shr: remove devtmpfs initscript for palmpre machine
[openembedded.git] / recipes / linux / linux-smdk2443 / 0021-Add-Neo1973-ASoC-support.patch
blob4b518241b809d522263f9302f9829de17e944c97
1 From eb7cbe67158924a0de114664ce5251fcad418b12 Mon Sep 17 00:00:00 2001
2 From: Liam Girdwood <liam@localhost.localdomain>
3 Date: Sun, 4 Mar 2007 16:58:40 +0000
4 Subject: [PATCH] Add Neo1973 ASoC support.
6 Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
7 Signed-off-by: Liam Girdwood <lg@opensource.wolfsonmicro.com>
8 ---
9 sound/soc/s3c24xx/Kconfig | 9 +
10 sound/soc/s3c24xx/Makefile | 4 +
11 sound/soc/s3c24xx/lm4857.h | 15 +
12 sound/soc/s3c24xx/neo1973_wm8753.c | 686 ++++++++++++++++++++++++++++++++++++
13 4 files changed, 714 insertions(+), 0 deletions(-)
14 create mode 100644 sound/soc/s3c24xx/lm4857.h
15 create mode 100644 sound/soc/s3c24xx/neo1973_wm8753.c
17 diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
18 index 433da9f..c414886 100644
19 --- a/sound/soc/s3c24xx/Kconfig
20 +++ b/sound/soc/s3c24xx/Kconfig
21 @@ -12,5 +12,14 @@ config SND_S3C24XX_SOC
22 config SND_S3C24XX_SOC_I2S
23 tristate
25 +config SND_S3C24XX_SOC_NEO1973_WM8753
26 + tristate "SoC I2S Audio support for NEO1973 - WM8753"
27 + depends on SND_S3C24XX_SOC && MACH_GTA01
28 + select SND_S3C24XX_SOC_I2S
29 + select SND_SOC_WM8753
30 + help
31 + Say Y if you want to add support for SoC audio on smdk2440
32 + with the WM8753.
34 endmenu
36 diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
37 index 56200d7..7b5c6fe 100644
38 --- a/sound/soc/s3c24xx/Makefile
39 +++ b/sound/soc/s3c24xx/Makefile
40 @@ -5,3 +5,7 @@ snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
41 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
42 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
44 +# S3C24XX Machine Support
45 +snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
47 +obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
48 diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
49 new file mode 100644
50 index 0000000..382d6c4
51 --- /dev/null
52 +++ b/sound/soc/s3c24xx/lm4857.h
53 @@ -0,0 +1,15 @@
54 +#ifndef LM4857_H_
55 +#define LM4857_H_
57 +/* The register offsets in the cache array */
58 +#define LM4857_MVOL 0
59 +#define LM4857_LVOL 1
60 +#define LM4857_RVOL 2
61 +#define LM4857_CTRL 3
63 +/* the shifts required to set these bits */
64 +#define LM4857_3D 5
65 +#define LM4857_WAKEUP 5
66 +#define LM4857_EPGAIN 4
68 +#endif /*LM4857_H_*/
69 diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
70 new file mode 100644
71 index 0000000..46a70e3
72 --- /dev/null
73 +++ b/sound/soc/s3c24xx/neo1973_wm8753.c
74 @@ -0,0 +1,686 @@
75 +/*
76 + * neo1973_wm8753.c -- SoC audio for Neo1973
77 + *
78 + * Copyright 2007 Wolfson Microelectronics PLC.
79 + * Author: Graeme Gregory
80 + * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
81 + *
82 + * This program is free software; you can redistribute it and/or modify it
83 + * under the terms of the GNU General Public License as published by the
84 + * Free Software Foundation; either version 2 of the License, or (at your
85 + * option) any later version.
86 + *
87 + * Revision history
88 + * 20th Jan 2007 Initial version.
89 + * 05th Feb 2007 Rename all to Neo1973
90 + *
91 + */
93 +#include <linux/module.h>
94 +#include <linux/moduleparam.h>
95 +#include <linux/timer.h>
96 +#include <linux/interrupt.h>
97 +#include <linux/platform_device.h>
98 +#include <linux/i2c.h>
99 +#include <sound/driver.h>
100 +#include <sound/core.h>
101 +#include <sound/pcm.h>
102 +#include <sound/soc.h>
103 +#include <sound/soc-dapm.h>
105 +#include <asm/mach-types.h>
106 +#include <asm/hardware/scoop.h>
107 +#include <asm/arch/regs-iis.h>
108 +#include <asm/arch/regs-clock.h>
109 +#include <asm/arch/regs-gpio.h>
110 +#include <asm/arch/hardware.h>
111 +#include <asm/arch/audio.h>
112 +#include <asm/io.h>
113 +#include <asm/arch/spi-gpio.h>
114 +#include "../codecs/wm8753.h"
115 +#include "lm4857.h"
116 +#include "s3c24xx-pcm.h"
117 +#include "s3c24xx-i2s.h"
119 +#define NEO1973_DEBUG 0
120 +#if NEO1973_DEBUG
121 +#define DBG(x...) printk(KERN_DEBUG x)
122 +#else
123 +#define DBG(x...)
124 +#endif
126 +/* define the scenarios */
127 +#define NEO_AUDIO_OFF 0
128 +#define NEO_GSM_CALL_AUDIO_HANDSET 1
129 +#define NEO_GSM_CALL_AUDIO_HEADSET 2
130 +#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3
131 +#define NEO_STEREO_TO_SPEAKERS 4
132 +#define NEO_STEREO_TO_HEADPHONES 5
133 +#define NEO_CAPTURE_HANDSET 6
134 +#define NEO_CAPTURE_HEADSET 7
135 +#define NEO_CAPTURE_BLUETOOTH 8
137 +static struct snd_soc_machine neo1973;
138 +static struct i2c_client *i2c;
140 +static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
141 + struct snd_pcm_hw_params *params)
143 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
144 + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
145 + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
146 + unsigned int pll_out = 0, bclk = 0;
147 + int ret = 0;
148 + unsigned long iis_clkrate;
150 + iis_clkrate = s3c24xx_i2s_get_clockrate();
152 + switch (params_rate(params)) {
153 + case 8000:
154 + case 16000:
155 + pll_out = 12288000;
156 + break;
157 + case 48000:
158 + bclk = WM8753_BCLK_DIV_4;
159 + pll_out = 12288000;
160 + break;
161 + case 96000:
162 + bclk = WM8753_BCLK_DIV_2;
163 + pll_out = 12288000;
164 + break;
165 + case 11025:
166 + bclk = WM8753_BCLK_DIV_16;
167 + pll_out = 11289600;
168 + break;
169 + case 22050:
170 + bclk = WM8753_BCLK_DIV_8;
171 + pll_out = 11289600;
172 + break;
173 + case 44100:
174 + bclk = WM8753_BCLK_DIV_4;
175 + pll_out = 11289600;
176 + break;
177 + case 88200:
178 + bclk = WM8753_BCLK_DIV_2;
179 + pll_out = 11289600;
180 + break;
183 + /* set codec DAI configuration */
184 + ret = codec_dai->dai_ops.set_fmt(codec_dai,
185 + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
186 + if (ret < 0)
187 + return ret;
189 + /* set cpu DAI configuration */
190 + ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
191 + SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
192 + if (ret < 0)
193 + return ret;
195 + /* set the codec system clock for DAC and ADC */
196 + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
197 + SND_SOC_CLOCK_IN);
198 + if (ret < 0)
199 + return ret;
201 + /* set MCLK division for sample rate */
202 + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
203 + S3C2410_IISMOD_32FS );
204 + if (ret < 0)
205 + return ret;
207 + /* set codec BCLK division for sample rate */
208 + ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
209 + if (ret < 0)
210 + return ret;
212 + /* set prescaler division for sample rate */
213 + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
214 + S3C24XX_PRESCALE(4,4));
215 + if (ret < 0)
216 + return ret;
218 + /* codec PLL input is PCLK/4 */
219 + ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, iis_clkrate/4,
220 + pll_out);
221 + if (ret < 0)
222 + return ret;
224 + return 0;
227 +static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
229 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
230 + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
232 + /* disable the PLL */
233 + return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
237 + * Neo1973 WM8753 HiFi DAI opserations.
238 + */
239 +static struct snd_soc_ops neo1973_hifi_ops = {
240 + .hw_params = neo1973_hifi_hw_params,
241 + .hw_free = neo1973_hifi_hw_free,
244 +static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
245 + struct snd_pcm_hw_params *params)
247 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
248 + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
249 + unsigned int pcmdiv = 0;
250 + int ret = 0;
251 + unsigned long iis_clkrate;
253 + /* todo: gg where is sysclk coming from for voice ?? */
254 + iis_clkrate = s3c24xx_i2s_get_clockrate();
256 + if (params_rate(params) != 8000)
257 + return -EINVAL;
258 + if(params_channels(params) != 1)
259 + return -EINVAL;
261 + pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
263 + /* todo: gg check mode (DSP_B) against CSR datasheet */
264 + /* set codec DAI configuration */
265 + ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
266 + SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
267 + if (ret < 0)
268 + return ret;
270 + /* set the codec system clock for DAC and ADC */
271 + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
272 + SND_SOC_CLOCK_IN);
273 + if (ret < 0)
274 + return ret;
276 + /* set codec PCM division for sample rate */
277 + ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
278 + if (ret < 0)
279 + return ret;
281 + /* configue and enable PLL for 12.288MHz output */
282 + ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, iis_clkrate/4,
283 + 12288000);
284 + if (ret < 0)
285 + return ret;
287 + return 0;
290 +static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
292 + struct snd_soc_pcm_runtime *rtd = substream->private_data;
293 + struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
295 + /* disable the PLL */
296 + return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
299 +static struct snd_soc_ops neo1973_voice_ops = {
300 + .hw_params = neo1973_voice_hw_params,
301 + .hw_free = neo1973_voice_hw_free,
304 +static int neo1973_scenario = 0;
306 +static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
307 + struct snd_ctl_elem_value *ucontrol)
309 + ucontrol->value.integer.value[0] = neo1973_scenario;
310 + return 0;
313 +static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
315 + switch(neo1973_scenario) {
316 + case NEO_AUDIO_OFF:
317 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
318 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
319 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
320 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
321 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
322 + break;
323 + case NEO_GSM_CALL_AUDIO_HANDSET:
324 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
325 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
326 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
327 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
328 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 1);
329 + break;
330 + case NEO_GSM_CALL_AUDIO_HEADSET:
331 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
332 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
333 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
334 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1);
335 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
336 + break;
337 + case NEO_GSM_CALL_AUDIO_BLUETOOTH:
338 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
339 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
340 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
341 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
342 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
343 + break;
344 + case NEO_STEREO_TO_SPEAKERS:
345 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
346 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
347 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
348 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
349 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
350 + break;
351 + case NEO_STEREO_TO_HEADPHONES:
352 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
353 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
354 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
355 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
356 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
357 + break;
358 + case NEO_CAPTURE_HANDSET:
359 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
360 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
361 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
362 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
363 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 1);
364 + break;
365 + case NEO_CAPTURE_HEADSET:
366 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
367 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
368 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
369 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1);
370 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
371 + break;
372 + case NEO_CAPTURE_BLUETOOTH:
373 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
374 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
375 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
376 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
377 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
378 + break;
379 + default:
380 + snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
381 + snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
382 + snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
383 + snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
384 + snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
387 + snd_soc_dapm_sync_endpoints(codec);
389 + return 0;
392 +static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
393 + struct snd_ctl_elem_value *ucontrol)
395 + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
397 + if (neo1973_scenario == ucontrol->value.integer.value[0])
398 + return 0;
400 + neo1973_scenario = ucontrol->value.integer.value[0];
402 + set_scenario_endpoints(codec, neo1973_scenario);
404 + return 1;
407 +static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
409 +static void lm4857_write_regs( void )
411 + if( i2c_master_send(i2c, lm4857_regs, 4) != 4)
412 + printk(KERN_WARNING "lm4857: i2c write failed\n");
415 +static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
416 + struct snd_ctl_elem_value *ucontrol)
418 + int reg=kcontrol->private_value & 0xFF;
419 + int shift = (kcontrol->private_value >> 8) & 0x0F;
420 + int mask = (kcontrol->private_value >> 16) & 0xFF;
422 + ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
424 + return 0;
427 +static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
428 + struct snd_ctl_elem_value *ucontrol)
430 + int reg = kcontrol->private_value & 0xFF;
431 + int shift = (kcontrol->private_value >> 8) & 0x0F;
432 + int mask = (kcontrol->private_value >> 16) & 0xFF;
434 + if (((lm4857_regs[reg] >> shift ) & mask) ==
435 + ucontrol->value.integer.value[0])
436 + return 0;
438 + lm4857_regs[reg] &= ~ (mask << shift);
439 + lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
441 + lm4857_write_regs();
442 + return 1;
445 +static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
446 + struct snd_ctl_elem_value *ucontrol)
448 + u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
450 + if (value)
451 + value -= 5;
453 + ucontrol->value.integer.value[0] = value;
454 + return 0;
457 +static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
458 + struct snd_ctl_elem_value *ucontrol)
460 + u8 value = ucontrol->value.integer.value[0];
462 + if (value)
463 + value += 5;
465 + if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
466 + return 0;
468 + lm4857_regs[LM4857_CTRL] &= 0xF0;
469 + lm4857_regs[LM4857_CTRL] |= value;
471 + lm4857_write_regs();
472 + return 1;
475 +static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
476 + SND_SOC_DAPM_LINE("Audio Out", NULL),
477 + SND_SOC_DAPM_LINE("GSM Line Out", NULL),
478 + SND_SOC_DAPM_LINE("GSM Line In", NULL),
479 + SND_SOC_DAPM_MIC("Headset Mic", NULL),
480 + SND_SOC_DAPM_MIC("Call Mic", NULL),
484 +/* example machine audio_mapnections */
485 +static const char* audio_map[][3] = {
487 + /* Connections to the lm4857 amp */
488 + {"Audio Out", NULL, "LOUT1"},
489 + {"Audio Out", NULL, "ROUT1"},
491 + /* Connections to the GSM Module */
492 + {"GSM Line Out", NULL, "MONO1"},
493 + {"GSM Line Out", NULL, "MONO2"},
494 + {"RXP", NULL, "GSM Line In"},
495 + {"RXN", NULL, "GSM Line In"},
497 + /* Connections to Headset */
498 + {"MIC1", NULL, "Mic Bias"},
499 + {"Mic Bias", NULL, "Headset Mic"},
501 + /* Call Mic */
502 + {"MIC2", NULL, "Mic Bias"},
503 + {"MIC2N", NULL, "Mic Bias"},
504 + {"Mic Bias", NULL, "Call Mic"},
506 + /* Connect the ALC pins */
507 + {"ACIN", NULL, "ACOP"},
509 + {NULL, NULL, NULL},
512 +static const char *lm4857_mode[] = {
513 + "Off",
514 + "Call Speaker",
515 + "Stereo Speakers",
516 + "Stereo Speakers + Headphones",
517 + "Headphones"
520 +static const struct soc_enum lm4857_mode_enum[] = {
521 + SOC_ENUM_SINGLE_EXT(5, lm4857_mode),
524 +static const char *neo_scenarios[] = {
525 + "Off",
526 + "GSM Handset",
527 + "GSM Headset",
528 + "GSM Bluetooth",
529 + "Speakers",
530 + "Headphones",
531 + "Capture Handset",
532 + "Capture Headset",
533 + "Capture Bluetooth"
536 +static const struct soc_enum neo_scenario_enum[] = {
537 + SOC_ENUM_SINGLE_EXT(9,neo_scenarios),
540 +static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
541 + SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
542 + lm4857_get_reg, lm4857_set_reg),
543 + SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
544 + lm4857_get_reg, lm4857_set_reg),
545 + SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
546 + lm4857_get_reg, lm4857_set_reg),
547 + SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
548 + lm4857_get_mode, lm4857_set_mode),
549 + SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
550 + neo1973_get_scenario, neo1973_set_scenario),
551 + SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
552 + lm4857_get_reg, lm4857_set_reg),
553 + SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
554 + lm4857_get_reg, lm4857_set_reg),
555 + SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
556 + lm4857_get_reg, lm4857_set_reg),
557 + SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
558 + lm4857_get_reg, lm4857_set_reg),
562 + * This is an example machine initialisation for a wm8753 connected to a
563 + * neo1973 II. It is missing logic to detect hp/mic insertions and logic
564 + * to re-route the audio in such an event.
565 + */
566 +static int neo1973_wm8753_init(struct snd_soc_codec *codec)
568 + int i, err;
570 + /* set up NC codec pins */
571 + snd_soc_dapm_set_endpoint(codec, "LOUT2", 0);
572 + snd_soc_dapm_set_endpoint(codec, "ROUT2", 0);
573 + snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
574 + snd_soc_dapm_set_endpoint(codec, "OUT4", 0);
575 + snd_soc_dapm_set_endpoint(codec, "LINE1", 0);
576 + snd_soc_dapm_set_endpoint(codec, "LINE2", 0);
579 + /* set endpoints to default mode */
580 + set_scenario_endpoints(codec, NEO_AUDIO_OFF);
582 + /* Add neo1973 specific widgets */
583 + for(i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
584 + snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
586 + /* add neo1973 specific controls */
587 + for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
588 + if ((err = snd_ctl_add(codec->card,
589 + snd_soc_cnew(&wm8753_neo1973_controls[i],codec, NULL))) < 0)
590 + return err;
593 + /* set up neo1973 specific audio path audio_mapnects */
594 + for(i = 0; audio_map[i][0] != NULL; i++) {
595 + snd_soc_dapm_connect_input(codec, audio_map[i][0], audio_map[i][1],
596 + audio_map[i][2]);
599 + snd_soc_dapm_sync_endpoints(codec);
600 + return 0;
604 + * BT Codec DAI
605 + */
606 +static struct snd_soc_cpu_dai bt_dai =
607 +{ .name = "Bluetooth",
608 + .id = 0,
609 + .type = SND_SOC_DAI_PCM,
610 + .playback = {
611 + .channels_min = 1,
612 + .channels_max = 1,
613 + .rates = SNDRV_PCM_RATE_8000,
614 + .formats = SNDRV_PCM_FMTBIT_S16_LE,},
615 + .capture = {
616 + .channels_min = 1,
617 + .channels_max = 1,
618 + .rates = SNDRV_PCM_RATE_8000,
619 + .formats = SNDRV_PCM_FMTBIT_S16_LE,},
622 +static struct snd_soc_dai_link neo1973_dai[] = {
623 +{ /* Hifi Playback - for similatious use with voice below */
624 + .name = "WM8753",
625 + .stream_name = "WM8753 HiFi",
626 + .cpu_dai = &s3c24xx_i2s_dai,
627 + .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
628 + .init = neo1973_wm8753_init,
629 + .ops = &neo1973_hifi_ops,
631 +{ /* Voice via BT */
632 + .name = "Bluetooth",
633 + .stream_name = "Voice",
634 + .cpu_dai = &bt_dai,
635 + .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
636 + .ops = &neo1973_voice_ops,
640 +static struct snd_soc_machine neo1973 = {
641 + .name = "neo1973",
642 + .dai_link = neo1973_dai,
643 + .num_links = ARRAY_SIZE(neo1973_dai),
646 +static struct wm8753_setup_data neo1973_wm8753_setup = {
647 + .i2c_address = 0x1a,
650 +static struct snd_soc_device neo1973_snd_devdata = {
651 + .machine = &neo1973,
652 + .platform = &s3c24xx_soc_platform,
653 + .codec_dev = &soc_codec_dev_wm8753,
654 + .codec_data = &neo1973_wm8753_setup,
657 +static struct i2c_client client_template;
659 +static unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
661 +/* Magic definition of all other variables and things */
662 +I2C_CLIENT_INSMOD;
664 +static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
666 + int ret;
668 + client_template.adapter = adap;
669 + client_template.addr = addr;
671 + DBG("Entering %s\n", __FUNCTION__);
673 + i2c = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
674 + if (i2c == NULL){
675 + return -ENOMEM;
677 + memcpy(i2c, &client_template, sizeof(struct i2c_client));
679 + ret = i2c_attach_client(i2c);
680 + if (ret < 0) {
681 + DBG("failed to attach codec at addr %x\n", addr);
682 + goto exit_err;
685 + lm4857_write_regs();
687 + return ret;
689 +exit_err:
690 + kfree(i2c);
691 + return ret;
694 +static int lm4857_i2c_detach(struct i2c_client *client)
696 + i2c_detach_client(client);
697 + kfree(client);
698 + return 0;
701 +static int lm4857_i2c_attach(struct i2c_adapter *adap)
703 + return i2c_probe(adap, &addr_data, lm4857_amp_probe);
706 +#define I2C_DRIVERID_LM4857 0xA5A5 /* liam - need a proper id */
708 +/* corgi i2c codec control layer */
709 +static struct i2c_driver lm4857_i2c_driver = {
710 + .driver = {
711 + .name = "LM4857 I2C Amp",
712 + .owner = THIS_MODULE,
713 + },
714 + .id = I2C_DRIVERID_LM4857,
715 + .attach_adapter = lm4857_i2c_attach,
716 + .detach_client = lm4857_i2c_detach,
717 + .command = NULL,
720 +static struct i2c_client client_template = {
721 + .name = "LM4857",
722 + .driver = &lm4857_i2c_driver,
725 +static struct platform_device *neo1973_snd_device;
727 +static int __init neo1973_init(void)
729 + int ret;
731 + neo1973_snd_device = platform_device_alloc("soc-audio", -1);
732 + if (!neo1973_snd_device)
733 + return -ENOMEM;
735 + platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
736 + neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
737 + ret = platform_device_add(neo1973_snd_device);
739 + if (ret)
740 + platform_device_put(neo1973_snd_device);
742 + ret = i2c_add_driver(&lm4857_i2c_driver);
743 + if (ret != 0)
744 + printk(KERN_ERR "can't add i2c driver");
746 + return ret;
749 +static void __exit neo1973_exit(void)
751 + platform_device_unregister(neo1973_snd_device);
754 +module_init(neo1973_init);
755 +module_exit(neo1973_exit);
757 +/* Module information */
758 +MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
759 +MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
760 +MODULE_LICENSE("GPL");
762 1.5.0.3