summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:14:24 +0100
committerRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:29:45 +0100
commit29d6678fd546377459ef75cf54abeef5b969b5cf (patch)
tree8edd65790e37a00d01c3f203f773fe4b5012db18 /meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch
parentda49de6885ee1bc424e70bc02f21f6ab920efb55 (diff)
downloadpoky-29d6678fd546377459ef75cf54abeef5b969b5cf.tar.gz
Major layout change to the packages directory
Having one monolithic packages directory makes it hard to find things and is generally overwhelming. This commit splits it into several logical sections roughly based on function, recipes.txt gives more information about the classifications used. The opportunity is also used to switch from "packages" to "recipes" as used in OpenEmbedded as the term "packages" can be confusing to people and has many different meanings. Not all recipes have been classified yet, this is just a first pass at separating things out. Some packages are moved to meta-extras as they're no longer actively used or maintained. Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch1154
1 files changed, 1154 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch b/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch
new file mode 100644
index 0000000000..f4cce21ca7
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/soc.patch
@@ -0,0 +1,1154 @@
1diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
2index 3903ab7..468536d 100644
3--- a/sound/soc/codecs/Kconfig
4+++ b/sound/soc/codecs/Kconfig
5@@ -44,3 +44,7 @@ config SND_SOC_CS4270_VD33_ERRATA
6 config SND_SOC_TLV320AIC3X
7 tristate
8 depends on SND_SOC && I2C
9+
10+config SND_SOC_TWL4030
11+ tristate
12+ depends on SND_SOC && I2C
13diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
14index 4e1314c..d2c0b12 100644
15--- a/sound/soc/codecs/Makefile
16+++ b/sound/soc/codecs/Makefile
17@@ -6,6 +6,7 @@ snd-soc-wm9712-objs := wm9712.o
18 snd-soc-wm9713-objs := wm9713.o
19 snd-soc-cs4270-objs := cs4270.o
20 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
21+snd-soc-twl4030-objs := twl4030.o
22
23 obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
24 obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
25@@ -15,3 +16,4 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
26 obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
27 obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
28 obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
29+obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
30diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
31new file mode 100644
32index 0000000..eb8370c
33--- /dev/null
34+++ b/sound/soc/codecs/twl4030.c
35@@ -0,0 +1,625 @@
36+/*
37+ * ALSA SoC TWL4030 codec driver
38+ *
39+ * Author: Steve Sakoman, <steve@sakoman.com>
40+ *
41+ * This program is free software; you can redistribute it and/or modify
42+ * it under the terms of the GNU General Public License version 2 as
43+ * published by the Free Software Foundation.
44+ */
45+
46+#include <linux/module.h>
47+#include <linux/moduleparam.h>
48+#include <linux/init.h>
49+#include <linux/delay.h>
50+#include <linux/pm.h>
51+#include <linux/i2c.h>
52+#include <linux/platform_device.h>
53+#include <linux/i2c/twl4030.h>
54+#include <sound/core.h>
55+#include <sound/pcm.h>
56+#include <sound/pcm_params.h>
57+#include <sound/soc.h>
58+#include <sound/soc-dapm.h>
59+#include <sound/initval.h>
60+
61+#include "twl4030.h"
62+
63+/*
64+ * twl4030 register cache & default register settings
65+ */
66+static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
67+ 0x00, // this register not used
68+ 0x93, // REG_CODEC_MODE (0x1)
69+ 0xc3, // REG_OPTION (0x2)
70+ 0x00, // REG_UNKNOWN (0x3)
71+ 0x00, // REG_MICBIAS_CTL (0x4)
72+ 0x34, // REG_ANAMICL (0x5)
73+ 0x14, // REG_ANAMICR (0x6)
74+ 0x0a, // REG_AVADC_CTL (0x7)
75+ 0x00, // REG_ADCMICSEL (0x8)
76+ 0x00, // REG_DIGMIXING (0x9)
77+ 0x0c, // REG_ATXL1PGA (0xA)
78+ 0x0c, // REG_ATXR1PGA (0xB)
79+ 0x00, // REG_AVTXL2PGA (0xC)
80+ 0x00, // REG_AVTXR2PGA (0xD)
81+ 0x01, // REG_AUDIO_IF (0xE)
82+ 0x00, // REG_VOICE_IF (0xF)
83+ 0x00, // REG_ARXR1PGA (0x10)
84+ 0x00, // REG_ARXL1PGA (0x11)
85+ 0x6c, // REG_ARXR2PGA (0x12)
86+ 0x6c, // REG_ARXL2PGA (0x13)
87+ 0x00, // REG_VRXPGA (0x14)
88+ 0x00, // REG_VSTPGA (0x15)
89+ 0x00, // REG_VRX2ARXPGA (0x16)
90+ 0x0c, // REG_AVDAC_CTL (0x17)
91+ 0x00, // REG_ARX2VTXPGA (0x18)
92+ 0x00, // REG_ARXL1_APGA_CTL (0x19)
93+ 0x00, // REG_ARXR1_APGA_CTL (0x1A)
94+ 0x4b, // REG_ARXL2_APGA_CTL (0x1B)
95+ 0x4b, // REG_ARXR2_APGA_CTL (0x1C)
96+ 0x00, // REG_ATX2ARXPGA (0x1D)
97+ 0x00, // REG_BT_IF (0x1E)
98+ 0x00, // REG_BTPGA (0x1F)
99+ 0x00, // REG_BTSTPGA (0x20)
100+ 0x00, // REG_EAR_CTL (0x21)
101+ 0x24, // REG_HS_SEL (0x22)
102+ 0x0a, // REG_HS_GAIN_SET (0x23)
103+ 0x00, // REG_HS_POPN_SET (0x24)
104+ 0x00, // REG_PREDL_CTL (0x25)
105+ 0x00, // REG_PREDR_CTL (0x26)
106+ 0x00, // REG_PRECKL_CTL (0x27)
107+ 0x00, // REG_PRECKR_CTL (0x28)
108+ 0x00, // REG_HFL_CTL (0x29)
109+ 0x00, // REG_HFR_CTL (0x2A)
110+ 0x00, // REG_ALC_CTL (0x2B)
111+ 0x00, // REG_ALC_SET1 (0x2C)
112+ 0x00, // REG_ALC_SET2 (0x2D)
113+ 0x00, // REG_BOOST_CTL (0x2E)
114+ 0x01, // REG_SOFTVOL_CTL (0x2F)
115+ 0x00, // REG_DTMF_FREQSEL (0x30)
116+ 0x00, // REG_DTMF_TONEXT1H (0x31)
117+ 0x00, // REG_DTMF_TONEXT1L (0x32)
118+ 0x00, // REG_DTMF_TONEXT2H (0x33)
119+ 0x00, // REG_DTMF_TONEXT2L (0x34)
120+ 0x00, // REG_DTMF_TONOFF (0x35)
121+ 0x00, // REG_DTMF_WANONOFF (0x36)
122+ 0x00, // REG_I2S_RX_SCRAMBLE_H (0x37)
123+ 0x00, // REG_I2S_RX_SCRAMBLE_M (0x38)
124+ 0x00, // REG_I2S_RX_SCRAMBLE_L (0x39)
125+ 0x16, // REG_APLL_CTL (0x3A)
126+ 0x00, // REG_DTMF_CTL (0x3B)
127+ 0x00, // REG_DTMF_PGA_CTL2 (0x3C)
128+ 0x00, // REG_DTMF_PGA_CTL1 (0x3D)
129+ 0x00, // REG_MISC_SET_1 (0x3E)
130+ 0x00, // REG_PCMBTMUX (0x3F)
131+ 0x00, // REG_RX_PATH_SEL (0x43)
132+ 0x00, // REG_VDL_APGA_CTL (0x44)
133+ 0x00, // REG_VIBRA_CTL (0x45)
134+ 0x00, // REG_VIBRA_SET (0x46)
135+ 0x00, // REG_VIBRA_PWM_SET (0x47)
136+ 0x00, // REG_ANAMIC_GAIN (0x48)
137+ 0x00, // REG_MISC_SET_2 (0x49)
138+};
139+
140+static void twl4030_dump_registers(void)
141+{
142+ int i = 0;
143+ u8 data;
144+
145+ printk(KERN_INFO "TWL 4030 Register dump for Audio Module\n");
146+
147+ for (i = REG_CODEC_MODE; i <= REG_MISC_SET_2; i++) {
148+ twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &data, i);
149+ printk(KERN_INFO "Register[0x%02x]=0x%02x\n", i, data);
150+ }
151+}
152+
153+struct twl4030_priv {
154+ unsigned int dummy;
155+};
156+
157+/*
158+ * read twl4030 register cache
159+ */
160+static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
161+ unsigned int reg)
162+{
163+ u8 *cache = codec->reg_cache;
164+
165+ return cache[reg];
166+}
167+
168+/*
169+ * write twl4030 register cache
170+ */
171+static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
172+ u8 reg, u8 value)
173+{
174+ u8 *cache = codec->reg_cache;
175+
176+ if (reg >= TWL4030_CACHEREGNUM)
177+ return;
178+ cache[reg] = value;
179+}
180+
181+/*
182+ * write to the twl4030 register space
183+ */
184+static int twl4030_write(struct snd_soc_codec *codec,
185+ unsigned int reg, unsigned int value)
186+{
187+ twl4030_write_reg_cache(codec, reg, value);
188+ return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
189+}
190+
191+static void twl4030_init_chip(void)
192+{
193+ unsigned char byte;
194+ int i;
195+
196+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
197+ twl4030_reg[REG_CODEC_MODE] & 0xfd, REG_CODEC_MODE);
198+
199+ udelay(10); /* delay for power settling */
200+
201+ for (i = REG_OPTION; i <= REG_MISC_SET_2; i++) {
202+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, twl4030_reg[i], i);
203+ }
204+
205+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
206+ twl4030_reg[REG_CODEC_MODE], REG_CODEC_MODE);
207+
208+ udelay(10); /* delay for power settling */
209+
210+ /* initiate offset cancellation */
211+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
212+ twl4030_reg[REG_ANAMICL] | 0x80, REG_ANAMICL);
213+
214+ /* wait for offset cancellation to complete */
215+ twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, REG_ANAMICL);
216+ while ((byte & 0x80) == 0x80)
217+ twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, REG_ANAMICL);
218+
219+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
220+ twl4030_reg[REG_MISC_SET_1] | 0x02, REG_MISC_SET_1);
221+
222+}
223+
224+static const struct snd_kcontrol_new twl4030_snd_controls[] = {
225+ SOC_DOUBLE_R("Master Playback Volume",
226+ REG_ARXL2PGA, REG_ARXR2PGA,
227+ 0, 127, 0),
228+ SOC_DOUBLE_R("Capture Volume",
229+ REG_ATXL1PGA, REG_ATXR1PGA,
230+ 0, 127, 0),
231+};
232+
233+/* add non dapm controls */
234+static int twl4030_add_controls(struct snd_soc_codec *codec)
235+{
236+ int err, i;
237+
238+ for (i = 0; i < ARRAY_SIZE(twl4030_snd_controls); i++) {
239+ err = snd_ctl_add(codec->card,
240+ snd_soc_cnew(&twl4030_snd_controls[i],
241+ codec, NULL));
242+ if (err < 0)
243+ return err;
244+ }
245+
246+ return 0;
247+}
248+
249+static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
250+ SND_SOC_DAPM_INPUT("INL"),
251+ SND_SOC_DAPM_INPUT("INR"),
252+
253+ SND_SOC_DAPM_OUTPUT("OUTL"),
254+ SND_SOC_DAPM_OUTPUT("OUTR"),
255+
256+ SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0),
257+ SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0),
258+
259+ SND_SOC_DAPM_ADC("ADCL", "Left Capture", SND_SOC_NOPM, 0, 0),
260+ SND_SOC_DAPM_ADC("ADCR", "Right Capture", SND_SOC_NOPM, 0, 0),
261+};
262+
263+static const char *intercon[][3] = {
264+ /* outputs */
265+ {"OUTL", NULL, "DACL"},
266+ {"OUTR", NULL, "DACR"},
267+
268+ /* inputs */
269+ {"ADCL", NULL, "INL"},
270+ {"ADCR", NULL, "INR"},
271+
272+ /* terminator */
273+ {NULL, NULL, NULL},
274+};
275+
276+static int twl4030_add_widgets(struct snd_soc_codec *codec)
277+{
278+ int i;
279+
280+ for (i = 0; i < ARRAY_SIZE(twl4030_dapm_widgets); i++)
281+ snd_soc_dapm_new_control(codec, &twl4030_dapm_widgets[i]);
282+
283+ /* set up audio path interconnects */
284+ for (i = 0; intercon[i][0] != NULL; i++)
285+ snd_soc_dapm_connect_input(codec, intercon[i][0],
286+ intercon[i][1], intercon[i][2]);
287+
288+ snd_soc_dapm_new_widgets(codec);
289+ return 0;
290+}
291+
292+static int twl4030_dapm_event(struct snd_soc_codec *codec, int event)
293+{
294+
295+ printk(KERN_INFO "TWL4030 Audio Codec dapm event\n");
296+ switch (event) {
297+ case SNDRV_CTL_POWER_D0: /* full On */
298+ break;
299+ case SNDRV_CTL_POWER_D1: /* partial On */
300+ case SNDRV_CTL_POWER_D2: /* partial On */
301+ break;
302+ case SNDRV_CTL_POWER_D3hot: /* off, with power */
303+ break;
304+ case SNDRV_CTL_POWER_D3cold: /* off, without power */
305+ break;
306+ }
307+ codec->dapm_state = event;
308+
309+ return 0;
310+}
311+
312+static void twl4030_power_up (struct snd_soc_codec *codec, u8 mode)
313+{
314+ u8 popn, hsgain;
315+
316+ twl4030_write(codec, REG_CODEC_MODE, mode & ~CODECPDZ);
317+ twl4030_write(codec, REG_CODEC_MODE, mode | CODECPDZ);
318+ udelay(10);
319+
320+ popn = twl4030_read_reg_cache(codec, REG_HS_POPN_SET);
321+ popn &= RAMP_DELAY;
322+ popn |= VMID_EN | RAMP_DELAY_161MS;
323+ twl4030_write(codec, REG_HS_POPN_SET, popn);
324+
325+ hsgain = HSR_GAIN_0DB| HSL_GAIN_0DB;
326+ twl4030_write(codec, REG_HS_GAIN_SET, hsgain);
327+
328+ popn |= RAMP_EN;
329+ twl4030_write(codec, REG_HS_POPN_SET, popn);
330+}
331+
332+static void twl4030_power_down (struct snd_soc_codec *codec)
333+{
334+ u8 popn, hsgain, mode;
335+
336+ popn = twl4030_read_reg_cache(codec, REG_HS_POPN_SET);
337+ popn &= ~RAMP_EN;
338+ twl4030_write(codec, REG_HS_POPN_SET, popn);
339+
340+ hsgain = HSR_GAIN_PWR_DOWN | HSL_GAIN_PWR_DOWN;
341+ twl4030_write(codec, REG_HS_GAIN_SET, hsgain);
342+
343+ popn &= ~VMID_EN;
344+ twl4030_write(codec, REG_HS_POPN_SET, popn);
345+
346+ mode = twl4030_read_reg_cache(codec, REG_CODEC_MODE);
347+ mode &= ~CODECPDZ;
348+ twl4030_write(codec, REG_CODEC_MODE, mode);
349+ udelay(10);
350+}
351+
352+
353+static int twl4030_hw_params(struct snd_pcm_substream *substream,
354+ struct snd_pcm_hw_params *params)
355+{
356+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
357+ struct snd_soc_device *socdev = rtd->socdev;
358+ struct snd_soc_codec *codec = socdev->codec;
359+ struct twl4030_priv *twl4030 = codec->private_data;
360+ u8 mode, old_mode, format, old_format;
361+
362+
363+ /* bit rate */
364+ old_mode = twl4030_read_reg_cache(codec, REG_CODEC_MODE) & ~CODECPDZ;
365+ mode = old_mode;
366+ mode &= ~APLL_RATE;
367+ switch (params_rate(params)) {
368+ case 44100:
369+ mode |= APLL_RATE_44100;
370+ break;
371+ case 48000:
372+ mode |= APLL_RATE_48000;
373+ break;
374+ default:
375+ printk(KERN_INFO "TWL4030 hw params: unknown rate %d\n", params_rate(params));
376+ return -EINVAL;
377+ }
378+
379+ if (mode != old_mode) {
380+ /* change rate and turn codec back on */
381+ twl4030_write(codec, REG_CODEC_MODE, mode);
382+ mode |= CODECPDZ;
383+ twl4030_write(codec, REG_CODEC_MODE, mode);
384+ }
385+
386+ /* sample size */
387+ old_format = twl4030_read_reg_cache(codec, REG_AUDIO_IF);
388+ format = old_format;
389+ format &= ~DATA_WIDTH;
390+ switch (params_format(params)) {
391+ case SNDRV_PCM_FORMAT_S16_LE:
392+ format |= DATA_WIDTH_16S_16W;
393+ break;
394+ case SNDRV_PCM_FORMAT_S24_LE:
395+ format |= DATA_WIDTH_32S_24W;
396+ break;
397+ default:
398+ printk(KERN_INFO "TWL4030 hw params: unknown format %d\n", params_format(params));
399+ return -EINVAL;
400+ }
401+
402+ if (format != old_format) {
403+
404+ /* turn off codec before changing format */
405+ mode = twl4030_read_reg_cache(codec, REG_CODEC_MODE);
406+ mode &= ~CODECPDZ;
407+ twl4030_write(codec, REG_CODEC_MODE, mode);
408+
409+ /* change format */
410+ twl4030_write(codec, REG_AUDIO_IF, format);
411+
412+ /* turn on codec */
413+ mode |= CODECPDZ;
414+ twl4030_write(codec, REG_CODEC_MODE, mode);
415+ }
416+ return 0;
417+}
418+
419+static int twl4030_mute(struct snd_soc_codec_dai *dai, int mute)
420+{
421+ struct snd_soc_codec *codec = dai->codec;
422+
423+ u8 ldac_reg = twl4030_read_reg_cache(codec, REG_ARXL2PGA);
424+ u8 rdac_reg = twl4030_read_reg_cache(codec, REG_ARXR2PGA);
425+
426+ if (mute) {
427+ /* printk(KERN_INFO "TWL4030 Audio Codec mute\n"); */
428+ twl4030_write(codec, REG_ARXL2PGA, 0x00);
429+ twl4030_write(codec, REG_ARXR2PGA, 0x00);
430+ twl4030_write_reg_cache(codec, REG_ARXL2PGA, ldac_reg);
431+ twl4030_write_reg_cache(codec, REG_ARXR2PGA, rdac_reg);
432+ }
433+ else {
434+ /* printk(KERN_INFO "TWL4030 Audio Codec unmute: %02x/%02x\n", ldac_reg, rdac_reg); */
435+ twl4030_write(codec, REG_ARXL2PGA, ldac_reg);
436+ twl4030_write(codec, REG_ARXR2PGA, rdac_reg);
437+ }
438+
439+ return 0;
440+}
441+
442+static int twl4030_set_dai_fmt(struct snd_soc_codec_dai *codec_dai,
443+ unsigned int fmt)
444+{
445+ struct snd_soc_codec *codec = codec_dai->codec;
446+ struct twl4030_priv *twl4030 = codec->private_data;
447+ u8 mode, old_format, format;
448+
449+ /* get format */
450+ old_format = twl4030_read_reg_cache(codec, REG_AUDIO_IF);
451+ format = old_format;
452+
453+ /* set master/slave audio interface */
454+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
455+ case SND_SOC_DAIFMT_CBM_CFM:
456+ /* printk(KERN_INFO "TWL4030 set dai fmt: master\n"); */
457+ format &= ~(AIF_SLAVE_EN);
458+ format |= CLK256FS_EN;
459+ break;
460+ case SND_SOC_DAIFMT_CBS_CFS:
461+ /* printk(KERN_INFO "TWL4030 set dai fmt: slave\n"); */
462+ format &= ~(CLK256FS_EN);
463+ format |= AIF_SLAVE_EN;
464+ break;
465+ default:
466+ return -EINVAL;
467+ }
468+
469+ /* interface format */
470+ format &= ~AIF_FORMAT;
471+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
472+ case SND_SOC_DAIFMT_I2S:
473+ /* printk(KERN_INFO "TWL4030 set dai fmt: i2s\n"); */
474+ format |= AIF_FORMAT_CODEC;
475+ break;
476+ default:
477+ return -EINVAL;
478+ }
479+
480+ if (format != old_format) {
481+
482+ /* turn off codec before changing format */
483+ mode = twl4030_read_reg_cache(codec, REG_CODEC_MODE);
484+ mode &= ~CODECPDZ;
485+ twl4030_write(codec, REG_CODEC_MODE, mode);
486+
487+ /* change format */
488+ twl4030_write(codec, REG_AUDIO_IF, format);
489+
490+ mode |= CODECPDZ;
491+ twl4030_write(codec, REG_CODEC_MODE, mode);
492+ }
493+
494+ return 0;
495+}
496+
497+#define TWL4030_RATES SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000
498+#define TWL4030_FORMATS SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE
499+
500+struct snd_soc_codec_dai twl4030_dai = {
501+ .name = "twl4030",
502+ .playback = {
503+ .stream_name = "Playback",
504+ .channels_min = 2,
505+ .channels_max = 2,
506+ .rates = TWL4030_RATES,
507+ .formats = TWL4030_FORMATS,},
508+ .capture = {
509+ .stream_name = "Capture",
510+ .channels_min = 2,
511+ .channels_max = 2,
512+ .rates = TWL4030_RATES,
513+ .formats = TWL4030_FORMATS,},
514+ .ops = {
515+ .hw_params = twl4030_hw_params,
516+ },
517+ .dai_ops = {
518+ .digital_mute = twl4030_mute,
519+ .set_fmt = twl4030_set_dai_fmt,
520+ }
521+};
522+
523+EXPORT_SYMBOL_GPL(twl4030_dai);
524+
525+static int twl4030_suspend(struct platform_device *pdev, pm_message_t state)
526+{
527+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
528+ struct snd_soc_codec *codec = socdev->codec;
529+
530+ printk(KERN_INFO "TWL4030 Audio Codec suspend\n");
531+ twl4030_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
532+
533+ return 0;
534+}
535+
536+static int twl4030_resume(struct platform_device *pdev)
537+{
538+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
539+ struct snd_soc_codec *codec = socdev->codec;
540+ int i;
541+ u16 *cache = codec->reg_cache;
542+
543+ printk(KERN_INFO "TWL4030 Audio Codec resume\n");
544+ /* Sync reg_cache with the hardware */
545+ for (i = REG_CODEC_MODE; i <= REG_MISC_SET_2; i++) {
546+ twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, cache[i], i);
547+ }
548+ twl4030_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
549+ twl4030_dapm_event(codec, codec->suspend_dapm_state);
550+ return 0;
551+}
552+
553+/*
554+ * initialize the driver
555+ * register the mixer and dsp interfaces with the kernel
556+ */
557+
558+static int twl4030_init(struct snd_soc_device *socdev)
559+{
560+ struct snd_soc_codec *codec = socdev->codec;
561+ int ret = 0;
562+
563+ printk(KERN_INFO "TWL4030 Audio Codec init \n");
564+
565+ codec->name = "twl4030";
566+ codec->owner = THIS_MODULE;
567+ codec->read = twl4030_read_reg_cache;
568+ codec->write = twl4030_write;
569+ codec->dapm_event = twl4030_dapm_event;
570+ codec->dai = &twl4030_dai;
571+ codec->num_dai = 1;
572+ codec->reg_cache_size = sizeof(twl4030_reg);
573+ codec->reg_cache = kmemdup(twl4030_reg, sizeof(twl4030_reg), GFP_KERNEL);
574+ if (codec->reg_cache == NULL)
575+ return -ENOMEM;
576+
577+ /* register pcms */
578+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
579+ if (ret < 0) {
580+ printk(KERN_ERR "twl4030: failed to create pcms\n");
581+ goto pcm_err;
582+ }
583+
584+ twl4030_add_controls(codec);
585+ twl4030_add_widgets(codec);
586+
587+ ret = snd_soc_register_card(socdev);
588+ if (ret < 0) {
589+ printk(KERN_ERR "twl4030: failed to register card\n");
590+ goto card_err;
591+ }
592+
593+ twl4030_init_chip();
594+ twl4030_power_up(codec, APLL_RATE_44100 | OPT_MODE);
595+
596+ return ret;
597+
598+card_err:
599+ printk(KERN_INFO "TWL4030 Audio Codec init card error\n");
600+ snd_soc_free_pcms(socdev);
601+ snd_soc_dapm_free(socdev);
602+pcm_err:
603+ printk(KERN_INFO "TWL4030 Audio Codec init pcm error\n");
604+ kfree(codec->reg_cache);
605+ return ret;
606+}
607+
608+static struct snd_soc_device *twl4030_socdev;
609+
610+static int twl4030_probe(struct platform_device *pdev)
611+{
612+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
613+ struct snd_soc_codec *codec;
614+ struct twl4030_priv *twl4030;
615+
616+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
617+ if (codec == NULL)
618+ return -ENOMEM;
619+
620+ twl4030 = kzalloc(sizeof(struct twl4030_priv), GFP_KERNEL);
621+ if (twl4030 == NULL) {
622+ kfree(codec);
623+ return -ENOMEM;
624+ }
625+
626+ codec->private_data = twl4030;
627+ socdev->codec = codec;
628+ mutex_init(&codec->mutex);
629+ INIT_LIST_HEAD(&codec->dapm_widgets);
630+ INIT_LIST_HEAD(&codec->dapm_paths);
631+
632+ twl4030_socdev = socdev;
633+ twl4030_init(socdev);
634+
635+ return 0;
636+}
637+
638+static int twl4030_remove(struct platform_device *pdev)
639+{
640+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
641+ struct snd_soc_codec *codec = socdev->codec;
642+
643+ printk(KERN_INFO "TWL4030 Audio Codec remove\n");
644+ kfree(codec->private_data);
645+ kfree(codec);
646+
647+ return 0;
648+}
649+
650+struct snd_soc_codec_device soc_codec_dev_twl4030 = {
651+ .probe = twl4030_probe,
652+ .remove = twl4030_remove,
653+ .suspend = twl4030_suspend,
654+ .resume = twl4030_resume,
655+};
656+EXPORT_SYMBOL_GPL(soc_codec_dev_twl4030);
657+
658+MODULE_DESCRIPTION("ASoC TWL4030 codec driver");
659+MODULE_AUTHOR("Steve Sakoman");
660+MODULE_LICENSE("GPL");
661diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
662new file mode 100644
663index 0000000..e126f96
664--- /dev/null
665+++ b/sound/soc/codecs/twl4030.h
666@@ -0,0 +1,152 @@
667+/*
668+ * ALSA SoC TWL4030 codec driver
669+ *
670+ * Author: Steve Sakoman, <steve@sakoman.com>
671+ *
672+ * This program is free software; you can redistribute it and/or modify
673+ * it under the terms of the GNU General Public License version 2 as
674+ * published by the Free Software Foundation.
675+ */
676+
677+#ifndef __TWL4030_AUDIO_H__
678+#define __TWL4030_AUDIO_H__
679+
680+#define REG_CODEC_MODE 0x1
681+#define REG_OPTION 0x2
682+#define REG_UNKNOWN 0x3
683+#define REG_MICBIAS_CTL 0x4
684+#define REG_ANAMICL 0x5
685+#define REG_ANAMICR 0x6
686+#define REG_AVADC_CTL 0x7
687+#define REG_ADCMICSEL 0x8
688+#define REG_DIGMIXING 0x9
689+#define REG_ATXL1PGA 0xA
690+#define REG_ATXR1PGA 0xB
691+#define REG_AVTXL2PGA 0xC
692+#define REG_AVTXR2PGA 0xD
693+#define REG_AUDIO_IF 0xE
694+#define REG_VOICE_IF 0xF
695+#define REG_ARXR1PGA 0x10
696+#define REG_ARXL1PGA 0x11
697+#define REG_ARXR2PGA 0x12
698+#define REG_ARXL2PGA 0x13
699+#define REG_VRXPGA 0x14
700+#define REG_VSTPGA 0x15
701+#define REG_VRX2ARXPGA 0x16
702+#define REG_AVDAC_CTL 0x17
703+#define REG_ARX2VTXPGA 0x18
704+#define REG_ARXL1_APGA_CTL 0x19
705+#define REG_ARXR1_APGA_CTL 0x1A
706+#define REG_ARXL2_APGA_CTL 0x1B
707+#define REG_ARXR2_APGA_CTL 0x1C
708+#define REG_ATX2ARXPGA 0x1D
709+#define REG_BT_IF 0x1E
710+#define REG_BTPGA 0x1F
711+#define REG_BTSTPGA 0x20
712+#define REG_EAR_CTL 0x21
713+#define REG_HS_SEL 0x22
714+#define REG_HS_GAIN_SET 0x23
715+#define REG_HS_POPN_SET 0x24
716+#define REG_PREDL_CTL 0x25
717+#define REG_PREDR_CTL 0x26
718+#define REG_PRECKL_CTL 0x27
719+#define REG_PRECKR_CTL 0x28
720+#define REG_HFL_CTL 0x29
721+#define REG_HFR_CTL 0x2A
722+#define REG_ALC_CTL 0x2B
723+#define REG_ALC_SET1 0x2C
724+#define REG_ALC_SET2 0x2D
725+#define REG_BOOST_CTL 0x2E
726+#define REG_SOFTVOL_CTL 0x2F
727+#define REG_DTMF_FREQSEL 0x30
728+#define REG_DTMF_TONEXT1H 0x31
729+#define REG_DTMF_TONEXT1L 0x32
730+#define REG_DTMF_TONEXT2H 0x33
731+#define REG_DTMF_TONEXT2L 0x34
732+#define REG_DTMF_TONOFF 0x35
733+#define REG_DTMF_WANONOFF 0x36
734+#define REG_I2S_RX_SCRAMBLE_H 0x37
735+#define REG_I2S_RX_SCRAMBLE_M 0x38
736+#define REG_I2S_RX_SCRAMBLE_L 0x39
737+#define REG_APLL_CTL 0x3A
738+#define REG_DTMF_CTL 0x3B
739+#define REG_DTMF_PGA_CTL2 0x3C
740+#define REG_DTMF_PGA_CTL1 0x3D
741+#define REG_MISC_SET_1 0x3E
742+#define REG_PCMBTMUX 0x3F
743+#define REG_RX_PATH_SEL 0x43
744+#define REG_VDL_APGA_CTL 0x44
745+#define REG_VIBRA_CTL 0x45
746+#define REG_VIBRA_SET 0x46
747+#define REG_VIBRA_PWM_SET 0x47
748+#define REG_ANAMIC_GAIN 0x48
749+#define REG_MISC_SET_2 0x49
750+
751+#define TWL4030_CACHEREGNUM REG_MISC_SET_2 + 1
752+
753+/* Bitfield Definitions */
754+
755+/* CODEC_MODE (0x01) Fields */
756+
757+#define APLL_RATE 0xF0
758+#define APLL_RATE_8000 0x00
759+#define APLL_RATE_11025 0x10
760+#define APLL_RATE_12000 0x20
761+#define APLL_RATE_16000 0x40
762+#define APLL_RATE_22050 0x50
763+#define APLL_RATE_24000 0x60
764+#define APLL_RATE_32000 0x80
765+#define APLL_RATE_44100 0x90
766+#define APLL_RATE_48000 0xa0
767+#define SEL_16K 0x04
768+#define CODECPDZ 0x02
769+#define OPT_MODE 0x01
770+
771+/* AUDIO_IF (0x0E) Fields */
772+
773+#define AIF_SLAVE_EN 0x80
774+#define DATA_WIDTH 0x60
775+#define DATA_WIDTH_16S_16W 0x00
776+#define DATA_WIDTH_32S_16W 0x40
777+#define DATA_WIDTH_32S_24W 0x60
778+#define AIF_FORMAT 0x18
779+#define AIF_FORMAT_CODEC 0x00
780+#define AIF_FORMAT_LEFT 0x08
781+#define AIF_FORMAT_RIGHT 0x10
782+#define AIF_FORMAT_TDM 0x18
783+#define AIF_TRI_EN 0x04
784+#define CLK256FS_EN 0x02
785+#define AIF_EN 0x01
786+
787+/* HS_GAIN_SET (0x23) Fields */
788+
789+#define HSR_GAIN 0x0c
790+#define HSR_GAIN_PWR_DOWN 0x00
791+#define HSR_GAIN_PLUS_6DB 0x04
792+#define HSR_GAIN_0DB 0x08
793+#define HSR_GAIN_MINUS_6DB 0x0c
794+#define HSL_GAIN 0x0c
795+#define HSL_GAIN_PWR_DOWN 0x00
796+#define HSL_GAIN_PLUS_6DB 0x01
797+#define HSL_GAIN_0DB 0x02
798+#define HSL_GAIN_MINUS_6DB 0x03
799+
800+/* HS_POPN_SET (0x24) Fields */
801+
802+#define VMID_EN 0x40
803+#define EXTMUTE 0x20
804+#define RAMP_DELAY 0x1C
805+#define RAMP_DELAY_20MS 0x00
806+#define RAMP_DELAY_40MS 0x04
807+#define RAMP_DELAY_81MS 0x08
808+#define RAMP_DELAY_161MS 0x0c
809+#define RAMP_DELAY_323MS 0x10
810+#define RAMP_DELAY_645MS 0x14
811+#define RAMP_DELAY_1291MS 0x18
812+#define RAMP_DELAY_2581MS 0x1c
813+#define RAMP_EN 0x02
814+
815+extern struct snd_soc_codec_dai twl4030_dai;
816+extern struct snd_soc_codec_device soc_codec_dev_twl4030;
817+
818+#endif /* End of __TWL4030_AUDIO_H__ */
819diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
820index 0230d83..8703cea 100644
821--- a/sound/soc/omap/Kconfig
822+++ b/sound/soc/omap/Kconfig
823@@ -16,4 +16,20 @@ config SND_OMAP_SOC_N810
824 help
825 Say Y if you want to add support for SoC audio on Nokia N810.
826
827+config SND_OMAP_SOC_OMAP3EVM
828+ tristate "SoC Audio support for OMAP3 EVM"
829+ depends on SND_OMAP_SOC && MACH_OMAP3EVM
830+ select SND_OMAP_SOC_MCBSP
831+ select SND_SOC_TWL4030
832+ help
833+ Say Y if you want to add support for SoC audio on the OMAP3 EVM.
834+
835+config SND_OMAP_SOC_OMAP3BEAGLE
836+ tristate "SoC Audio support for OMAP3 Beagle"
837+ depends on SND_OMAP_SOC && MACH_OMAP3_BEAGLE
838+ select SND_OMAP_SOC_MCBSP
839+ select SND_SOC_TWL4030
840+ help
841+ Say Y if you want to add support for SoC audio on the OMAP3 Beagle.
842+
843 endmenu
844diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
845index d8d8d58..638a240 100644
846--- a/sound/soc/omap/Makefile
847+++ b/sound/soc/omap/Makefile
848@@ -7,5 +7,10 @@ obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
849
850 # OMAP Machine Support
851 snd-soc-n810-objs := n810.o
852+snd-soc-omap3evm-objs := omap3evm.o
853+snd-soc-omap3beagle-objs := omap3beagle.o
854
855 obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
856+obj-$(CONFIG_SND_OMAP_SOC_OMAP3EVM) += snd-soc-omap3evm.o
857+obj-$(CONFIG_SND_OMAP_SOC_OMAP3BEAGLE) += snd-soc-omap3beagle.o
858+
859diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c
860new file mode 100644
861index 0000000..878f894
862--- /dev/null
863+++ b/sound/soc/omap/omap3beagle.c
864@@ -0,0 +1,142 @@
865+/*
866+ * omap3beagle.c -- SoC audio for OMAP3 Beagle
867+ *
868+ * Author: Steve Sakoman <steve@sakoman.com>
869+ *
870+ * This program is free software; you can redistribute it and/or
871+ * modify it under the terms of the GNU General Public License
872+ * version 2 as published by the Free Software Foundation.
873+ *
874+ * This program is distributed in the hope that it will be useful, but
875+ * WITHOUT ANY WARRANTY; without even the implied warranty of
876+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
877+ * General Public License for more details.
878+ *
879+ * You should have received a copy of the GNU General Public License
880+ * along with this program; if not, write to the Free Software
881+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
882+ * 02110-1301 USA
883+ *
884+ */
885+
886+#include <linux/clk.h>
887+#include <linux/platform_device.h>
888+#include <sound/core.h>
889+#include <sound/pcm.h>
890+#include <sound/soc.h>
891+#include <sound/soc-dapm.h>
892+
893+#include <asm/mach-types.h>
894+#include <asm/arch/hardware.h>
895+#include <asm/arch/gpio.h>
896+#include <asm/arch/mcbsp.h>
897+
898+#include "omap-mcbsp.h"
899+#include "omap-pcm.h"
900+#include "../codecs/twl4030.h"
901+
902+static int omap3beagle_hw_params(struct snd_pcm_substream *substream,
903+ struct snd_pcm_hw_params *params)
904+{
905+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
906+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
907+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
908+ int ret;
909+
910+ /* Set codec DAI configuration */
911+ ret = codec_dai->dai_ops.set_fmt(codec_dai,
912+ SND_SOC_DAIFMT_I2S |
913+ SND_SOC_DAIFMT_NB_NF |
914+ SND_SOC_DAIFMT_CBM_CFM);
915+ if (ret < 0) {
916+ printk(KERN_INFO "can't set codec DAI configuration\n");
917+ return ret;
918+ }
919+
920+ /* Set cpu DAI configuration */
921+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
922+ SND_SOC_DAIFMT_I2S |
923+ SND_SOC_DAIFMT_NB_NF |
924+ SND_SOC_DAIFMT_CBM_CFM);
925+ if (ret < 0) {
926+ printk(KERN_INFO "can't set cpu DAI configuration\n");
927+ return ret;
928+ }
929+
930+ return 0;
931+}
932+
933+static struct snd_soc_ops omap3beagle_ops = {
934+ .hw_params = omap3beagle_hw_params,
935+};
936+
937+/* Digital audio interface glue - connects codec <--> CPU */
938+static struct snd_soc_dai_link omap3beagle_dai = {
939+ .name = "TWL4030",
940+ .stream_name = "TWL4030",
941+ .cpu_dai = &omap_mcbsp_dai[0],
942+ .codec_dai = &twl4030_dai,
943+ .ops = &omap3beagle_ops,
944+};
945+
946+/* Audio machine driver */
947+static struct snd_soc_machine snd_soc_machine_omap3beagle = {
948+ .name = "omap3beagle",
949+ .dai_link = &omap3beagle_dai,
950+ .num_links = 1,
951+};
952+
953+/* Audio subsystem */
954+static struct snd_soc_device omap3beagle_snd_devdata = {
955+ .machine = &snd_soc_machine_omap3beagle,
956+ .platform = &omap_soc_platform,
957+ .codec_dev = &soc_codec_dev_twl4030,
958+};
959+
960+static struct platform_device *omap3beagle_snd_device;
961+
962+static int __init omap3beagle_soc_init(void)
963+{
964+ int ret;
965+
966+ printk(KERN_INFO "OMAP3 Beagle SoC init\n");
967+ if (!machine_is_omap3_beagle()) {
968+ printk(KERN_INFO "Not OMAP3 Beagle!\n");
969+ return -ENODEV;
970+ }
971+
972+ omap3beagle_snd_device = platform_device_alloc("soc-audio", -1);
973+ if (!omap3beagle_snd_device) {
974+ printk(KERN_INFO "Platform device allocation failed\n");
975+ return -ENOMEM;
976+ }
977+
978+ platform_set_drvdata(omap3beagle_snd_device, &omap3beagle_snd_devdata);
979+ omap3beagle_snd_devdata.dev = &omap3beagle_snd_device->dev;
980+ *(unsigned int *)omap3beagle_dai.cpu_dai->private_data = 1; /* McBSP2 */
981+
982+ ret = platform_device_add(omap3beagle_snd_device);
983+ if (ret)
984+ goto err1;
985+
986+ return 0;
987+
988+err1:
989+ printk(KERN_INFO "Unable to add platform device\n");
990+ platform_device_put(omap3beagle_snd_device);
991+
992+ return ret;
993+}
994+
995+static void __exit omap3beagle_soc_exit(void)
996+{
997+ printk(KERN_INFO "OMAP3 Beagle SoC exit\n");
998+ platform_device_unregister(omap3beagle_snd_device);
999+}
1000+
1001+module_init(omap3beagle_soc_init);
1002+module_exit(omap3beagle_soc_exit);
1003+
1004+MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
1005+MODULE_DESCRIPTION("ALSA SoC OMAP3 Beagle");
1006+MODULE_LICENSE("GPL");
1007diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c
1008new file mode 100644
1009index 0000000..a64c788
1010--- /dev/null
1011+++ b/sound/soc/omap/omap3evm.c
1012@@ -0,0 +1,142 @@
1013+/*
1014+ * omap3evm.c -- SoC audio for OMAP3 EVM
1015+ *
1016+ * Author: Steve Sakoman <steve@sakoman.com>
1017+ *
1018+ * This program is free software; you can redistribute it and/or
1019+ * modify it under the terms of the GNU General Public License
1020+ * version 2 as published by the Free Software Foundation.
1021+ *
1022+ * This program is distributed in the hope that it will be useful, but
1023+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1024+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1025+ * General Public License for more details.
1026+ *
1027+ * You should have received a copy of the GNU General Public License
1028+ * along with this program; if not, write to the Free Software
1029+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
1030+ * 02110-1301 USA
1031+ *
1032+ */
1033+
1034+#include <linux/clk.h>
1035+#include <linux/platform_device.h>
1036+#include <sound/core.h>
1037+#include <sound/pcm.h>
1038+#include <sound/soc.h>
1039+#include <sound/soc-dapm.h>
1040+
1041+#include <asm/mach-types.h>
1042+#include <asm/arch/hardware.h>
1043+#include <asm/arch/gpio.h>
1044+#include <asm/arch/mcbsp.h>
1045+
1046+#include "omap-mcbsp.h"
1047+#include "omap-pcm.h"
1048+#include "../codecs/twl4030.h"
1049+
1050+static int omap3evm_hw_params(struct snd_pcm_substream *substream,
1051+ struct snd_pcm_hw_params *params)
1052+{
1053+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
1054+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
1055+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
1056+ int ret;
1057+
1058+ /* Set codec DAI configuration */
1059+ ret = codec_dai->dai_ops.set_fmt(codec_dai,
1060+ SND_SOC_DAIFMT_I2S |
1061+ SND_SOC_DAIFMT_NB_NF |
1062+ SND_SOC_DAIFMT_CBM_CFM);
1063+ if (ret < 0) {
1064+ printk(KERN_INFO "can't set codec DAI configuration\n");
1065+ return ret;
1066+ }
1067+
1068+ /* Set cpu DAI configuration */
1069+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
1070+ SND_SOC_DAIFMT_I2S |
1071+ SND_SOC_DAIFMT_NB_NF |
1072+ SND_SOC_DAIFMT_CBM_CFM);
1073+ if (ret < 0) {
1074+ printk(KERN_INFO "can't set cpu DAI configuration\n");
1075+ return ret;
1076+ }
1077+
1078+ return 0;
1079+}
1080+
1081+static struct snd_soc_ops omap3evm_ops = {
1082+ .hw_params = omap3evm_hw_params,
1083+};
1084+
1085+/* Digital audio interface glue - connects codec <--> CPU */
1086+static struct snd_soc_dai_link omap3evm_dai = {
1087+ .name = "TWL4030",
1088+ .stream_name = "TWL4030",
1089+ .cpu_dai = &omap_mcbsp_dai[0],
1090+ .codec_dai = &twl4030_dai,
1091+ .ops = &omap3evm_ops,
1092+};
1093+
1094+/* Audio machine driver */
1095+static struct snd_soc_machine snd_soc_machine_omap3evm = {
1096+ .name = "omap3evm",
1097+ .dai_link = &omap3evm_dai,
1098+ .num_links = 1,
1099+};
1100+
1101+/* Audio subsystem */
1102+static struct snd_soc_device omap3evm_snd_devdata = {
1103+ .machine = &snd_soc_machine_omap3evm,
1104+ .platform = &omap_soc_platform,
1105+ .codec_dev = &soc_codec_dev_twl4030,
1106+};
1107+
1108+static struct platform_device *omap3evm_snd_device;
1109+
1110+static int __init omap3evm_soc_init(void)
1111+{
1112+ int ret;
1113+
1114+ printk(KERN_INFO "OMAP3 EVM SoC init\n");
1115+ if (!machine_is_omap3evm()) {
1116+ printk(KERN_INFO "Not OMAP3 EVM!\n");
1117+ return -ENODEV;
1118+ }
1119+
1120+ omap3evm_snd_device = platform_device_alloc("soc-audio", -1);
1121+ if (!omap3evm_snd_device) {
1122+ printk(KERN_INFO "Platform device allocation failed\n");
1123+ return -ENOMEM;
1124+ }
1125+
1126+ platform_set_drvdata(omap3evm_snd_device, &omap3evm_snd_devdata);
1127+ omap3evm_snd_devdata.dev = &omap3evm_snd_device->dev;
1128+ *(unsigned int *)omap3evm_dai.cpu_dai->private_data = 1; /* McBSP2 */
1129+
1130+ ret = platform_device_add(omap3evm_snd_device);
1131+ if (ret)
1132+ goto err1;
1133+
1134+ return 0;
1135+
1136+err1:
1137+ printk(KERN_INFO "Unable to add platform device\n");
1138+ platform_device_put(omap3evm_snd_device);
1139+
1140+ return ret;
1141+}
1142+
1143+static void __exit omap3evm_soc_exit(void)
1144+{
1145+ printk(KERN_INFO "OMAP3 EVM SoC exit\n");
1146+ platform_device_unregister(omap3evm_snd_device);
1147+}
1148+
1149+module_init(omap3evm_soc_init);
1150+module_exit(omap3evm_soc_exit);
1151+
1152+MODULE_AUTHOR("Steve Sakoman <steve@sakoman.com>");
1153+MODULE_DESCRIPTION("ALSA SoC OMAP3 EVM");
1154+MODULE_LICENSE("GPL");