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>
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
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
31 + Say Y if you want to add support for SoC audio on smdk2440
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
50 index 0000000..382d6c4
52 +++ b/sound/soc/s3c24xx/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 */
65 +#define LM4857_WAKEUP 5
66 +#define LM4857_EPGAIN 4
69 diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
71 index 0000000..46a70e3
73 +++ b/sound/soc/s3c24xx/neo1973_wm8753.c
76 + * neo1973_wm8753.c -- SoC audio for Neo1973
78 + * Copyright 2007 Wolfson Microelectronics PLC.
79 + * Author: Graeme Gregory
80 + * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
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.
88 + * 20th Jan 2007 Initial version.
89 + * 05th Feb 2007 Rename all to Neo1973
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>
113 +#include <asm/arch/spi-gpio.h>
114 +#include "../codecs/wm8753.h"
116 +#include "s3c24xx-pcm.h"
117 +#include "s3c24xx-i2s.h"
119 +#define NEO1973_DEBUG 0
121 +#define DBG(x...) printk(KERN_DEBUG x)
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;
148 + unsigned long iis_clkrate;
150 + iis_clkrate = s3c24xx_i2s_get_clockrate();
152 + switch (params_rate(params)) {
155 + pll_out = 12288000;
158 + bclk = WM8753_BCLK_DIV_4;
159 + pll_out = 12288000;
162 + bclk = WM8753_BCLK_DIV_2;
163 + pll_out = 12288000;
166 + bclk = WM8753_BCLK_DIV_16;
167 + pll_out = 11289600;
170 + bclk = WM8753_BCLK_DIV_8;
171 + pll_out = 11289600;
174 + bclk = WM8753_BCLK_DIV_4;
175 + pll_out = 11289600;
178 + bclk = WM8753_BCLK_DIV_2;
179 + pll_out = 11289600;
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);
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);
195 + /* set the codec system clock for DAC and ADC */
196 + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
201 + /* set MCLK division for sample rate */
202 + ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
203 + S3C2410_IISMOD_32FS );
207 + /* set codec BCLK division for sample rate */
208 + ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
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));
218 + /* codec PLL input is PCLK/4 */
219 + ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, iis_clkrate/4,
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.
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;
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)
258 + if(params_channels(params) != 1)
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);
270 + /* set the codec system clock for DAC and ADC */
271 + ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
276 + /* set codec PCM division for sample rate */
277 + ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
281 + /* configue and enable PLL for 12.288MHz output */
282 + ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, iis_clkrate/4,
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;
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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])
400 + neo1973_scenario = ucontrol->value.integer.value[0];
402 + set_scenario_endpoints(codec, neo1973_scenario);
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;
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])
438 + lm4857_regs[reg] &= ~ (mask << shift);
439 + lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
441 + lm4857_write_regs();
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;
453 + ucontrol->value.integer.value[0] = value;
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];
465 + if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
468 + lm4857_regs[LM4857_CTRL] &= 0xF0;
469 + lm4857_regs[LM4857_CTRL] |= value;
471 + lm4857_write_regs();
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"},
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[] = {
516 + "Stereo Speakers + Headphones",
520 +static const struct soc_enum lm4857_mode_enum[] = {
521 + SOC_ENUM_SINGLE_EXT(5, lm4857_mode),
524 +static const char *neo_scenarios[] = {
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.
566 +static int neo1973_wm8753_init(struct snd_soc_codec *codec)
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)
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],
599 + snd_soc_dapm_sync_endpoints(codec);
606 +static struct snd_soc_cpu_dai bt_dai =
607 +{ .name = "Bluetooth",
609 + .type = SND_SOC_DAI_PCM,
613 + .rates = SNDRV_PCM_RATE_8000,
614 + .formats = SNDRV_PCM_FMTBIT_S16_LE,},
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 */
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 = {
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 */
664 +static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
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);
677 + memcpy(i2c, &client_template, sizeof(struct i2c_client));
679 + ret = i2c_attach_client(i2c);
681 + DBG("failed to attach codec at addr %x\n", addr);
685 + lm4857_write_regs();
694 +static int lm4857_i2c_detach(struct i2c_client *client)
696 + i2c_detach_client(client);
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 = {
711 + .name = "LM4857 I2C Amp",
712 + .owner = THIS_MODULE,
714 + .id = I2C_DRIVERID_LM4857,
715 + .attach_adapter = lm4857_i2c_attach,
716 + .detach_client = lm4857_i2c_detach,
720 +static struct i2c_client client_template = {
722 + .driver = &lm4857_i2c_driver,
725 +static struct platform_device *neo1973_snd_device;
727 +static int __init neo1973_init(void)
731 + neo1973_snd_device = platform_device_alloc("soc-audio", -1);
732 + if (!neo1973_snd_device)
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);
740 + platform_device_put(neo1973_snd_device);
742 + ret = i2c_add_driver(&lm4857_i2c_driver);
744 + printk(KERN_ERR "can't add i2c driver");
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");