aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/au1x/Kconfig28
-rw-r--r--sound/soc/au1x/Makefile10
-rw-r--r--sound/soc/au1x/ac97c.c365
-rw-r--r--sound/soc/au1x/db1000.c75
-rw-r--r--sound/soc/au1x/db1200.c64
-rw-r--r--sound/soc/au1x/dbdma2.c91
-rw-r--r--sound/soc/au1x/dma.c377
-rw-r--r--sound/soc/au1x/i2sc.c347
-rw-r--r--sound/soc/au1x/psc-ac97.c48
-rw-r--r--sound/soc/au1x/psc-i2s.c42
-rw-r--r--sound/soc/au1x/psc.h16
-rw-r--r--sound/soc/codecs/sgtl5000.c136
-rw-r--r--sound/soc/codecs/wm1250-ev1.c20
-rw-r--r--sound/soc/codecs/wm8523.c2
-rw-r--r--sound/soc/codecs/wm8580.c2
-rw-r--r--sound/soc/codecs/wm8731.c10
-rw-r--r--sound/soc/codecs/wm8993.c3
-rw-r--r--sound/soc/codecs/wm8994.c6
-rw-r--r--sound/soc/codecs/wm_hubs.c35
-rw-r--r--sound/soc/codecs/wm_hubs.h3
-rw-r--r--sound/soc/mxs/Kconfig20
-rw-r--r--sound/soc/mxs/Makefile10
-rw-r--r--sound/soc/mxs/mxs-pcm.c359
-rw-r--r--sound/soc/mxs/mxs-pcm.h43
-rw-r--r--sound/soc/mxs/mxs-saif.c677
-rw-r--r--sound/soc/mxs/mxs-saif.h130
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c165
-rw-r--r--sound/soc/soc-core.c4
-rw-r--r--sound/soc/soc-dapm.c6
31 files changed, 2841 insertions, 255 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index f9054f7c1d52..1381db853ef0 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -53,6 +53,7 @@ source "sound/soc/nuc900/Kconfig"
53source "sound/soc/omap/Kconfig" 53source "sound/soc/omap/Kconfig"
54source "sound/soc/kirkwood/Kconfig" 54source "sound/soc/kirkwood/Kconfig"
55source "sound/soc/mid-x86/Kconfig" 55source "sound/soc/mid-x86/Kconfig"
56source "sound/soc/mxs/Kconfig"
56source "sound/soc/pxa/Kconfig" 57source "sound/soc/pxa/Kconfig"
57source "sound/soc/samsung/Kconfig" 58source "sound/soc/samsung/Kconfig"
58source "sound/soc/s6000/Kconfig" 59source "sound/soc/s6000/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 4f913876f332..9ea8ac827adc 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SND_SOC) += fsl/
12obj-$(CONFIG_SND_SOC) += imx/ 12obj-$(CONFIG_SND_SOC) += imx/
13obj-$(CONFIG_SND_SOC) += jz4740/ 13obj-$(CONFIG_SND_SOC) += jz4740/
14obj-$(CONFIG_SND_SOC) += mid-x86/ 14obj-$(CONFIG_SND_SOC) += mid-x86/
15obj-$(CONFIG_SND_SOC) += mxs/
15obj-$(CONFIG_SND_SOC) += nuc900/ 16obj-$(CONFIG_SND_SOC) += nuc900/
16obj-$(CONFIG_SND_SOC) += omap/ 17obj-$(CONFIG_SND_SOC) += omap/
17obj-$(CONFIG_SND_SOC) += kirkwood/ 18obj-$(CONFIG_SND_SOC) += kirkwood/
diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig
index 4b67140fdec3..6d592546e8fc 100644
--- a/sound/soc/au1x/Kconfig
+++ b/sound/soc/au1x/Kconfig
@@ -18,10 +18,38 @@ config SND_SOC_AU1XPSC_AC97
18 select SND_AC97_CODEC 18 select SND_AC97_CODEC
19 select SND_SOC_AC97_BUS 19 select SND_SOC_AC97_BUS
20 20
21##
22## Au1000/1500/1100 DMA + AC97C/I2SC
23##
24config SND_SOC_AU1XAUDIO
25 tristate "SoC Audio for Au1000/Au1500/Au1100"
26 depends on MIPS_ALCHEMY
27 help
28 This is a driver set for the AC97 unit and the
29 old DMA controller as found on the Au1000/Au1500/Au1100 chips.
30
31config SND_SOC_AU1XAC97C
32 tristate
33 select AC97_BUS
34 select SND_AC97_CODEC
35 select SND_SOC_AC97_BUS
36
37config SND_SOC_AU1XI2SC
38 tristate
39
21 40
22## 41##
23## Boards 42## Boards
24## 43##
44config SND_SOC_DB1000
45 tristate "DB1000 Audio support"
46 depends on SND_SOC_AU1XAUDIO
47 select SND_SOC_AU1XAC97C
48 select SND_SOC_AC97_CODEC
49 help
50 Select this option to enable AC97 audio on the early DB1x00 series
51 of boards (DB1000/DB1500/DB1100).
52
25config SND_SOC_DB1200 53config SND_SOC_DB1200
26 tristate "DB1200 AC97+I2S audio support" 54 tristate "DB1200 AC97+I2S audio support"
27 depends on SND_SOC_AU1XPSC 55 depends on SND_SOC_AU1XPSC
diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile
index 16873076e8c4..920710514ea0 100644
--- a/sound/soc/au1x/Makefile
+++ b/sound/soc/au1x/Makefile
@@ -3,11 +3,21 @@ snd-soc-au1xpsc-dbdma-objs := dbdma2.o
3snd-soc-au1xpsc-i2s-objs := psc-i2s.o 3snd-soc-au1xpsc-i2s-objs := psc-i2s.o
4snd-soc-au1xpsc-ac97-objs := psc-ac97.o 4snd-soc-au1xpsc-ac97-objs := psc-ac97.o
5 5
6# Au1000/1500/1100 Audio units
7snd-soc-au1x-dma-objs := dma.o
8snd-soc-au1x-ac97c-objs := ac97c.o
9snd-soc-au1x-i2sc-objs := i2sc.o
10
6obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o 11obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o
7obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o 12obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o
8obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o 13obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o
14obj-$(CONFIG_SND_SOC_AU1XAUDIO) += snd-soc-au1x-dma.o
15obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o
16obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o
9 17
10# Boards 18# Boards
19snd-soc-db1000-objs := db1000.o
11snd-soc-db1200-objs := db1200.o 20snd-soc-db1200-objs := db1200.o
12 21
22obj-$(CONFIG_SND_SOC_DB1000) += snd-soc-db1000.o
13obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o 23obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
new file mode 100644
index 000000000000..9c05f381d95e
--- /dev/null
+++ b/sound/soc/au1x/ac97c.c
@@ -0,0 +1,365 @@
1/*
2 * Au1000/Au1500/Au1100 AC97C controller driver for ASoC
3 *
4 * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
5 *
6 * based on the old ALSA driver originally written by
7 * Charles Eidsness <charles@cooper-street.com>
8 */
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/slab.h>
13#include <linux/device.h>
14#include <linux/delay.h>
15#include <linux/mutex.h>
16#include <linux/platform_device.h>
17#include <linux/suspend.h>
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/initval.h>
21#include <sound/soc.h>
22#include <asm/mach-au1x00/au1000.h>
23
24#include "psc.h"
25
26/* register offsets and bits */
27#define AC97_CONFIG 0x00
28#define AC97_STATUS 0x04
29#define AC97_DATA 0x08
30#define AC97_CMDRESP 0x0c
31#define AC97_ENABLE 0x10
32
33#define CFG_RC(x) (((x) & 0x3ff) << 13) /* valid rx slots mask */
34#define CFG_XS(x) (((x) & 0x3ff) << 3) /* valid tx slots mask */
35#define CFG_SG (1 << 2) /* sync gate */
36#define CFG_SN (1 << 1) /* sync control */
37#define CFG_RS (1 << 0) /* acrst# control */
38#define STAT_XU (1 << 11) /* tx underflow */
39#define STAT_XO (1 << 10) /* tx overflow */
40#define STAT_RU (1 << 9) /* rx underflow */
41#define STAT_RO (1 << 8) /* rx overflow */
42#define STAT_RD (1 << 7) /* codec ready */
43#define STAT_CP (1 << 6) /* command pending */
44#define STAT_TE (1 << 4) /* tx fifo empty */
45#define STAT_TF (1 << 3) /* tx fifo full */
46#define STAT_RE (1 << 1) /* rx fifo empty */
47#define STAT_RF (1 << 0) /* rx fifo full */
48#define CMD_SET_DATA(x) (((x) & 0xffff) << 16)
49#define CMD_GET_DATA(x) ((x) & 0xffff)
50#define CMD_READ (1 << 7)
51#define CMD_WRITE (0 << 7)
52#define CMD_IDX(x) ((x) & 0x7f)
53#define EN_D (1 << 1) /* DISable bit */
54#define EN_CE (1 << 0) /* clock enable bit */
55
56/* how often to retry failed codec register reads/writes */
57#define AC97_RW_RETRIES 5
58
59#define AC97_RATES \
60 SNDRV_PCM_RATE_CONTINUOUS
61
62#define AC97_FMTS \
63 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE)
64
65/* instance data. There can be only one, MacLeod!!!!, fortunately there IS only
66 * once AC97C on early Alchemy chips. The newer ones aren't so lucky.
67 */
68static struct au1xpsc_audio_data *ac97c_workdata;
69#define ac97_to_ctx(x) ac97c_workdata
70
71static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
72{
73 return __raw_readl(ctx->mmio + reg);
74}
75
76static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
77{
78 __raw_writel(v, ctx->mmio + reg);
79 wmb();
80}
81
82static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
83 unsigned short r)
84{
85 struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
86 unsigned int tmo, retry;
87 unsigned long data;
88
89 data = ~0;
90 retry = AC97_RW_RETRIES;
91 do {
92 mutex_lock(&ctx->lock);
93
94 tmo = 5;
95 while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
96 udelay(21); /* wait an ac97 frame time */
97 if (!tmo) {
98 pr_debug("ac97rd timeout #1\n");
99 goto next;
100 }
101
102 WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ);
103
104 /* stupid errata: data is only valid for 21us, so
105 * poll, Forrest, poll...
106 */
107 tmo = 0x10000;
108 while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
109 asm volatile ("nop");
110 data = RD(ctx, AC97_CMDRESP);
111
112 if (!tmo)
113 pr_debug("ac97rd timeout #2\n");
114
115next:
116 mutex_unlock(&ctx->lock);
117 } while (--retry && !tmo);
118
119 pr_debug("AC97RD %04x %04lx %d\n", r, data, retry);
120
121 return retry ? data & 0xffff : 0xffff;
122}
123
124static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r,
125 unsigned short v)
126{
127 struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
128 unsigned int tmo, retry;
129
130 retry = AC97_RW_RETRIES;
131 do {
132 mutex_lock(&ctx->lock);
133
134 for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
135 udelay(21);
136 if (!tmo) {
137 pr_debug("ac97wr timeout #1\n");
138 goto next;
139 }
140
141 WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v));
142
143 for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
144 udelay(21);
145 if (!tmo)
146 pr_debug("ac97wr timeout #2\n");
147next:
148 mutex_unlock(&ctx->lock);
149 } while (--retry && !tmo);
150
151 pr_debug("AC97WR %04x %04x %d\n", r, v, retry);
152}
153
154static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97)
155{
156 struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
157
158 WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN);
159 msleep(20);
160 WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG);
161 WR(ctx, AC97_CONFIG, ctx->cfg);
162}
163
164static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
165{
166 struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
167 int i;
168
169 WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS);
170 msleep(500);
171 WR(ctx, AC97_CONFIG, ctx->cfg);
172
173 /* wait for codec ready */
174 i = 50;
175 while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i)
176 msleep(20);
177 if (!i)
178 printk(KERN_ERR "ac97c: codec not ready after cold reset\n");
179}
180
181/* AC97 controller operations */
182struct snd_ac97_bus_ops soc_ac97_ops = {
183 .read = au1xac97c_ac97_read,
184 .write = au1xac97c_ac97_write,
185 .reset = au1xac97c_ac97_cold_reset,
186 .warm_reset = au1xac97c_ac97_warm_reset,
187};
188EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */
189
190static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
191 struct snd_soc_dai *dai)
192{
193 struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
194 snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
195 return 0;
196}
197
198static struct snd_soc_dai_ops alchemy_ac97c_ops = {
199 .startup = alchemy_ac97c_startup,
200};
201
202static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
203{
204 return ac97c_workdata ? 0 : -ENODEV;
205}
206
207static struct snd_soc_dai_driver au1xac97c_dai_driver = {
208 .name = "alchemy-ac97c",
209 .ac97_control = 1,
210 .probe = au1xac97c_dai_probe,
211 .playback = {
212 .rates = AC97_RATES,
213 .formats = AC97_FMTS,
214 .channels_min = 2,
215 .channels_max = 2,
216 },
217 .capture = {
218 .rates = AC97_RATES,
219 .formats = AC97_FMTS,
220 .channels_min = 2,
221 .channels_max = 2,
222 },
223 .ops = &alchemy_ac97c_ops,
224};
225
226static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
227{
228 int ret;
229 struct resource *r;
230 struct au1xpsc_audio_data *ctx;
231
232 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
233 if (!ctx)
234 return -ENOMEM;
235
236 mutex_init(&ctx->lock);
237
238 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
239 if (!r) {
240 ret = -ENODEV;
241 goto out0;
242 }
243
244 ret = -EBUSY;
245 if (!request_mem_region(r->start, resource_size(r), pdev->name))
246 goto out0;
247
248 ctx->mmio = ioremap_nocache(r->start, resource_size(r));
249 if (!ctx->mmio)
250 goto out1;
251
252 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
253 if (!r)
254 goto out1;
255 ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
256
257 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
258 if (!r)
259 goto out1;
260 ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
261
262 /* switch it on */
263 WR(ctx, AC97_ENABLE, EN_D | EN_CE);
264 WR(ctx, AC97_ENABLE, EN_CE);
265
266 ctx->cfg = CFG_RC(3) | CFG_XS(3);
267 WR(ctx, AC97_CONFIG, ctx->cfg);
268
269 platform_set_drvdata(pdev, ctx);
270
271 ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
272 if (ret)
273 goto out1;
274
275 ac97c_workdata = ctx;
276 return 0;
277
278
279 snd_soc_unregister_dai(&pdev->dev);
280out1:
281 release_mem_region(r->start, resource_size(r));
282out0:
283 kfree(ctx);
284 return ret;
285}
286
287static int __devexit au1xac97c_drvremove(struct platform_device *pdev)
288{
289 struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
290 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
291
292 snd_soc_unregister_dai(&pdev->dev);
293
294 WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
295
296 iounmap(ctx->mmio);
297 release_mem_region(r->start, resource_size(r));
298 kfree(ctx);
299
300 ac97c_workdata = NULL; /* MDEV */
301
302 return 0;
303}
304
305#ifdef CONFIG_PM
306static int au1xac97c_drvsuspend(struct device *dev)
307{
308 struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
309
310 WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
311
312 return 0;
313}
314
315static int au1xac97c_drvresume(struct device *dev)
316{
317 struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
318
319 WR(ctx, AC97_ENABLE, EN_D | EN_CE);
320 WR(ctx, AC97_ENABLE, EN_CE);
321 WR(ctx, AC97_CONFIG, ctx->cfg);
322
323 return 0;
324}
325
326static const struct dev_pm_ops au1xpscac97_pmops = {
327 .suspend = au1xac97c_drvsuspend,
328 .resume = au1xac97c_drvresume,
329};
330
331#define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops)
332
333#else
334
335#define AU1XPSCAC97_PMOPS NULL
336
337#endif
338
339static struct platform_driver au1xac97c_driver = {
340 .driver = {
341 .name = "alchemy-ac97c",
342 .owner = THIS_MODULE,
343 .pm = AU1XPSCAC97_PMOPS,
344 },
345 .probe = au1xac97c_drvprobe,
346 .remove = __devexit_p(au1xac97c_drvremove),
347};
348
349static int __init au1xac97c_load(void)
350{
351 ac97c_workdata = NULL;
352 return platform_driver_register(&au1xac97c_driver);
353}
354
355static void __exit au1xac97c_unload(void)
356{
357 platform_driver_unregister(&au1xac97c_driver);
358}
359
360module_init(au1xac97c_load);
361module_exit(au1xac97c_unload);
362
363MODULE_LICENSE("GPL");
364MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
365MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c
new file mode 100644
index 000000000000..127477a5e0c7
--- /dev/null
+++ b/sound/soc/au1x/db1000.c
@@ -0,0 +1,75 @@
1/*
2 * DB1000/DB1500/DB1100 ASoC audio fabric support code.
3 *
4 * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
5 *
6 */
7
8#include <linux/module.h>
9#include <linux/moduleparam.h>
10#include <linux/timer.h>
11#include <linux/interrupt.h>
12#include <linux/platform_device.h>
13#include <sound/core.h>
14#include <sound/pcm.h>
15#include <sound/soc.h>
16#include <asm/mach-au1x00/au1000.h>
17#include <asm/mach-db1x00/bcsr.h>
18
19#include "psc.h"
20
21static struct snd_soc_dai_link db1000_ac97_dai = {
22 .name = "AC97",
23 .stream_name = "AC97 HiFi",
24 .codec_dai_name = "ac97-hifi",
25 .cpu_dai_name = "alchemy-ac97c",
26 .platform_name = "alchemy-pcm-dma.0",
27 .codec_name = "ac97-codec",
28};
29
30static struct snd_soc_card db1000_ac97 = {
31 .name = "DB1000_AC97",
32 .dai_link = &db1000_ac97_dai,
33 .num_links = 1,
34};
35
36static int __devinit db1000_audio_probe(struct platform_device *pdev)
37{
38 struct snd_soc_card *card = &db1000_ac97;
39 card->dev = &pdev->dev;
40 return snd_soc_register_card(card);
41}
42
43static int __devexit db1000_audio_remove(struct platform_device *pdev)
44{
45 struct snd_soc_card *card = platform_get_drvdata(pdev);
46 snd_soc_unregister_card(card);
47 return 0;
48}
49
50static struct platform_driver db1000_audio_driver = {
51 .driver = {
52 .name = "db1000-audio",
53 .owner = THIS_MODULE,
54 .pm = &snd_soc_pm_ops,
55 },
56 .probe = db1000_audio_probe,
57 .remove = __devexit_p(db1000_audio_remove),
58};
59
60static int __init db1000_audio_load(void)
61{
62 return platform_driver_register(&db1000_audio_driver);
63}
64
65static void __exit db1000_audio_unload(void)
66{
67 platform_driver_unregister(&db1000_audio_driver);
68}
69
70module_init(db1000_audio_load);
71module_exit(db1000_audio_unload);
72
73MODULE_LICENSE("GPL");
74MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio");
75MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 1d3e258c9ea8..289312c14b99 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * DB1200 ASoC audio fabric support code. 2 * DB1200 ASoC audio fabric support code.
3 * 3 *
4 * (c) 2008-9 Manuel Lauss <manuel.lauss@gmail.com> 4 * (c) 2008-2011 Manuel Lauss <manuel.lauss@googlemail.com>
5 * 5 *
6 */ 6 */
7 7
@@ -21,6 +21,17 @@
21#include "../codecs/wm8731.h" 21#include "../codecs/wm8731.h"
22#include "psc.h" 22#include "psc.h"
23 23
24static struct platform_device_id db1200_pids[] = {
25 {
26 .name = "db1200-ac97",
27 .driver_data = 0,
28 }, {
29 .name = "db1200-i2s",
30 .driver_data = 1,
31 },
32 {},
33};
34
24/*------------------------- AC97 PART ---------------------------*/ 35/*------------------------- AC97 PART ---------------------------*/
25 36
26static struct snd_soc_dai_link db1200_ac97_dai = { 37static struct snd_soc_dai_link db1200_ac97_dai = {
@@ -89,36 +100,47 @@ static struct snd_soc_card db1200_i2s_machine = {
89 100
90/*------------------------- COMMON PART ---------------------------*/ 101/*------------------------- COMMON PART ---------------------------*/
91 102
92static struct platform_device *db1200_asoc_dev; 103static struct snd_soc_card *db1200_cards[] __devinitdata = {
104 &db1200_ac97_machine,
105 &db1200_i2s_machine,
106};
93 107
94static int __init db1200_audio_load(void) 108static int __devinit db1200_audio_probe(struct platform_device *pdev)
95{ 109{
96 int ret; 110 const struct platform_device_id *pid = platform_get_device_id(pdev);
111 struct snd_soc_card *card;
97 112
98 ret = -ENOMEM; 113 card = db1200_cards[pid->driver_data];
99 db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */ 114 card->dev = &pdev->dev;
100 if (!db1200_asoc_dev) 115 return snd_soc_register_card(card);
101 goto out; 116}
102 117
103 /* DB1200 board setup set PSC1MUX to preferred audio device */ 118static int __devexit db1200_audio_remove(struct platform_device *pdev)
104 if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX) 119{
105 platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine); 120 struct snd_soc_card *card = platform_get_drvdata(pdev);
106 else 121 snd_soc_unregister_card(card);
107 platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine); 122 return 0;
123}
108 124
109 ret = platform_device_add(db1200_asoc_dev); 125static struct platform_driver db1200_audio_driver = {
126 .driver = {
127 .name = "db1200-ac97",
128 .owner = THIS_MODULE,
129 .pm = &snd_soc_pm_ops,
130 },
131 .id_table = db1200_pids,
132 .probe = db1200_audio_probe,
133 .remove = __devexit_p(db1200_audio_remove),
134};
110 135
111 if (ret) { 136static int __init db1200_audio_load(void)
112 platform_device_put(db1200_asoc_dev); 137{
113 db1200_asoc_dev = NULL; 138 return platform_driver_register(&db1200_audio_driver);
114 }
115out:
116 return ret;
117} 139}
118 140
119static void __exit db1200_audio_unload(void) 141static void __exit db1200_audio_unload(void)
120{ 142{
121 platform_device_unregister(db1200_asoc_dev); 143 platform_driver_unregister(&db1200_audio_driver);
122} 144}
123 145
124module_init(db1200_audio_load); 146module_init(db1200_audio_load);
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c
index 20bb53a837b1..d7d04e26eee5 100644
--- a/sound/soc/au1x/dbdma2.c
+++ b/sound/soc/au1x/dbdma2.c
@@ -169,7 +169,7 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
169 169
170 au1x_pcm_dbdma_free(pcd); 170 au1x_pcm_dbdma_free(pcd);
171 171
172 if (stype == PCM_RX) 172 if (stype == SNDRV_PCM_STREAM_CAPTURE)
173 pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id, 173 pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
174 DSCR_CMD0_ALWAYS, 174 DSCR_CMD0_ALWAYS,
175 au1x_pcm_dmarx_cb, (void *)pcd); 175 au1x_pcm_dmarx_cb, (void *)pcd);
@@ -198,7 +198,7 @@ static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream
198 struct snd_soc_pcm_runtime *rtd = ss->private_data; 198 struct snd_soc_pcm_runtime *rtd = ss->private_data;
199 struct au1xpsc_audio_dmadata *pcd = 199 struct au1xpsc_audio_dmadata *pcd =
200 snd_soc_platform_get_drvdata(rtd->platform); 200 snd_soc_platform_get_drvdata(rtd->platform);
201 return &pcd[SUBSTREAM_TYPE(ss)]; 201 return &pcd[ss->stream];
202} 202}
203 203
204static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, 204static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -212,7 +212,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
212 if (ret < 0) 212 if (ret < 0)
213 goto out; 213 goto out;
214 214
215 stype = SUBSTREAM_TYPE(substream); 215 stype = substream->stream;
216 pcd = to_dmadata(substream); 216 pcd = to_dmadata(substream);
217 217
218 DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " 218 DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
@@ -255,7 +255,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
255 255
256 au1xxx_dbdma_reset(pcd->ddma_chan); 256 au1xxx_dbdma_reset(pcd->ddma_chan);
257 257
258 if (SUBSTREAM_TYPE(substream) == PCM_RX) { 258 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
259 au1x_pcm_queue_rx(pcd); 259 au1x_pcm_queue_rx(pcd);
260 au1x_pcm_queue_rx(pcd); 260 au1x_pcm_queue_rx(pcd);
261 } else { 261 } else {
@@ -293,6 +293,16 @@ au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
293 293
294static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) 294static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
295{ 295{
296 struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
297 struct snd_soc_pcm_runtime *rtd = substream->private_data;
298 int stype = substream->stream, *dmaids;
299
300 dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
301 if (!dmaids)
302 return -ENODEV; /* whoa, has ordering changed? */
303
304 pcd->ddma_id = dmaids[stype];
305
296 snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware); 306 snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
297 return 0; 307 return 0;
298} 308}
@@ -340,36 +350,18 @@ struct snd_soc_platform_driver au1xpsc_soc_platform = {
340static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) 350static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
341{ 351{
342 struct au1xpsc_audio_dmadata *dmadata; 352 struct au1xpsc_audio_dmadata *dmadata;
343 struct resource *r;
344 int ret; 353 int ret;
345 354
346 dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); 355 dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
347 if (!dmadata) 356 if (!dmadata)
348 return -ENOMEM; 357 return -ENOMEM;
349 358
350 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
351 if (!r) {
352 ret = -ENODEV;
353 goto out1;
354 }
355 dmadata[PCM_TX].ddma_id = r->start;
356
357 /* RX DMA */
358 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
359 if (!r) {
360 ret = -ENODEV;
361 goto out1;
362 }
363 dmadata[PCM_RX].ddma_id = r->start;
364
365 platform_set_drvdata(pdev, dmadata); 359 platform_set_drvdata(pdev, dmadata);
366 360
367 ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform); 361 ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
368 if (!ret) 362 if (ret)
369 return ret; 363 kfree(dmadata);
370 364
371out1:
372 kfree(dmadata);
373 return ret; 365 return ret;
374} 366}
375 367
@@ -405,57 +397,6 @@ static void __exit au1xpsc_audio_dbdma_unload(void)
405module_init(au1xpsc_audio_dbdma_load); 397module_init(au1xpsc_audio_dbdma_load);
406module_exit(au1xpsc_audio_dbdma_unload); 398module_exit(au1xpsc_audio_dbdma_unload);
407 399
408
409struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
410{
411 struct resource *res, *r;
412 struct platform_device *pd;
413 int id[2];
414 int ret;
415
416 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
417 if (!r)
418 return NULL;
419 id[0] = r->start;
420
421 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
422 if (!r)
423 return NULL;
424 id[1] = r->start;
425
426 res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
427 if (!res)
428 return NULL;
429
430 res[0].start = res[0].end = id[0];
431 res[1].start = res[1].end = id[1];
432 res[0].flags = res[1].flags = IORESOURCE_DMA;
433
434 pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
435 if (!pd)
436 goto out;
437
438 pd->resource = res;
439 pd->num_resources = 2;
440
441 ret = platform_device_add(pd);
442 if (!ret)
443 return pd;
444
445 platform_device_put(pd);
446out:
447 kfree(res);
448 return NULL;
449}
450EXPORT_SYMBOL_GPL(au1xpsc_pcm_add);
451
452void au1xpsc_pcm_destroy(struct platform_device *dmapd)
453{
454 if (dmapd)
455 platform_device_unregister(dmapd);
456}
457EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy);
458
459MODULE_LICENSE("GPL"); 400MODULE_LICENSE("GPL");
460MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); 401MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
461MODULE_AUTHOR("Manuel Lauss"); 402MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c
new file mode 100644
index 000000000000..7aa5b7606777
--- /dev/null
+++ b/sound/soc/au1x/dma.c
@@ -0,0 +1,377 @@
1/*
2 * Au1000/Au1500/Au1100 Audio DMA support.
3 *
4 * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
5 *
6 * copied almost verbatim from the old ALSA driver, written by
7 * Charles Eidsness <charles@cooper-street.com>
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/platform_device.h>
13#include <linux/slab.h>
14#include <linux/dma-mapping.h>
15#include <sound/core.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include <asm/mach-au1x00/au1000.h>
20#include <asm/mach-au1x00/au1000_dma.h>
21
22#include "psc.h"
23
24#define ALCHEMY_PCM_FMTS \
25 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
26 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
27 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
28 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
29 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
30 0)
31
32struct pcm_period {
33 u32 start;
34 u32 relative_end; /* relative to start of buffer */
35 struct pcm_period *next;
36};
37
38struct audio_stream {
39 struct snd_pcm_substream *substream;
40 int dma;
41 struct pcm_period *buffer;
42 unsigned int period_size;
43 unsigned int periods;
44};
45
46struct alchemy_pcm_ctx {
47 struct audio_stream stream[2]; /* playback & capture */
48};
49
50static void au1000_release_dma_link(struct audio_stream *stream)
51{
52 struct pcm_period *pointer;
53 struct pcm_period *pointer_next;
54
55 stream->period_size = 0;
56 stream->periods = 0;
57 pointer = stream->buffer;
58 if (!pointer)
59 return;
60 do {
61 pointer_next = pointer->next;
62 kfree(pointer);
63 pointer = pointer_next;
64 } while (pointer != stream->buffer);
65 stream->buffer = NULL;
66}
67
68static int au1000_setup_dma_link(struct audio_stream *stream,
69 unsigned int period_bytes,
70 unsigned int periods)
71{
72 struct snd_pcm_substream *substream = stream->substream;
73 struct snd_pcm_runtime *runtime = substream->runtime;
74 struct pcm_period *pointer;
75 unsigned long dma_start;
76 int i;
77
78 dma_start = virt_to_phys(runtime->dma_area);
79
80 if (stream->period_size == period_bytes &&
81 stream->periods == periods)
82 return 0; /* not changed */
83
84 au1000_release_dma_link(stream);
85
86 stream->period_size = period_bytes;
87 stream->periods = periods;
88
89 stream->buffer = kmalloc(sizeof(struct pcm_period), GFP_KERNEL);
90 if (!stream->buffer)
91 return -ENOMEM;
92 pointer = stream->buffer;
93 for (i = 0; i < periods; i++) {
94 pointer->start = (u32)(dma_start + (i * period_bytes));
95 pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
96 if (i < periods - 1) {
97 pointer->next = kmalloc(sizeof(struct pcm_period),
98 GFP_KERNEL);
99 if (!pointer->next) {
100 au1000_release_dma_link(stream);
101 return -ENOMEM;
102 }
103 pointer = pointer->next;
104 }
105 }
106 pointer->next = stream->buffer;
107 return 0;
108}
109
110static void au1000_dma_stop(struct audio_stream *stream)
111{
112 if (stream->buffer)
113 disable_dma(stream->dma);
114}
115
116static void au1000_dma_start(struct audio_stream *stream)
117{
118 if (!stream->buffer)
119 return;
120
121 init_dma(stream->dma);
122 if (get_dma_active_buffer(stream->dma) == 0) {
123 clear_dma_done0(stream->dma);
124 set_dma_addr0(stream->dma, stream->buffer->start);
125 set_dma_count0(stream->dma, stream->period_size >> 1);
126 set_dma_addr1(stream->dma, stream->buffer->next->start);
127 set_dma_count1(stream->dma, stream->period_size >> 1);
128 } else {
129 clear_dma_done1(stream->dma);
130 set_dma_addr1(stream->dma, stream->buffer->start);
131 set_dma_count1(stream->dma, stream->period_size >> 1);
132 set_dma_addr0(stream->dma, stream->buffer->next->start);
133 set_dma_count0(stream->dma, stream->period_size >> 1);
134 }
135 enable_dma_buffers(stream->dma);
136 start_dma(stream->dma);
137}
138
139static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
140{
141 struct audio_stream *stream = (struct audio_stream *)ptr;
142 struct snd_pcm_substream *substream = stream->substream;
143
144 switch (get_dma_buffer_done(stream->dma)) {
145 case DMA_D0:
146 stream->buffer = stream->buffer->next;
147 clear_dma_done0(stream->dma);
148 set_dma_addr0(stream->dma, stream->buffer->next->start);
149 set_dma_count0(stream->dma, stream->period_size >> 1);
150 enable_dma_buffer0(stream->dma);
151 break;
152 case DMA_D1:
153 stream->buffer = stream->buffer->next;
154 clear_dma_done1(stream->dma);
155 set_dma_addr1(stream->dma, stream->buffer->next->start);
156 set_dma_count1(stream->dma, stream->period_size >> 1);
157 enable_dma_buffer1(stream->dma);
158 break;
159 case (DMA_D0 | DMA_D1):
160 pr_debug("DMA %d missed interrupt.\n", stream->dma);
161 au1000_dma_stop(stream);
162 au1000_dma_start(stream);
163 break;
164 case (~DMA_D0 & ~DMA_D1):
165 pr_debug("DMA %d empty irq.\n", stream->dma);
166 }
167 snd_pcm_period_elapsed(substream);
168 return IRQ_HANDLED;
169}
170
171static const struct snd_pcm_hardware alchemy_pcm_hardware = {
172 .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
173 SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
174 .formats = ALCHEMY_PCM_FMTS,
175 .rates = SNDRV_PCM_RATE_8000_192000,
176 .rate_min = SNDRV_PCM_RATE_8000,
177 .rate_max = SNDRV_PCM_RATE_192000,
178 .channels_min = 2,
179 .channels_max = 2,
180 .period_bytes_min = 1024,
181 .period_bytes_max = 16 * 1024 - 1,
182 .periods_min = 4,
183 .periods_max = 255,
184 .buffer_bytes_max = 128 * 1024,
185 .fifo_size = 16,
186};
187
188static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
189{
190 struct snd_soc_pcm_runtime *rtd = ss->private_data;
191 return snd_soc_platform_get_drvdata(rtd->platform);
192}
193
194static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
195{
196 struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss);
197 return &(ctx->stream[ss->stream]);
198}
199
200static int alchemy_pcm_open(struct snd_pcm_substream *substream)
201{
202 struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
203 struct snd_soc_pcm_runtime *rtd = substream->private_data;
204 int *dmaids, s = substream->stream;
205 char *name;
206
207 dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
208 if (!dmaids)
209 return -ENODEV; /* whoa, has ordering changed? */
210
211 /* DMA setup */
212 name = (s == SNDRV_PCM_STREAM_PLAYBACK) ? "audio-tx" : "audio-rx";
213 ctx->stream[s].dma = request_au1000_dma(dmaids[s], name,
214 au1000_dma_interrupt, IRQF_DISABLED,
215 &ctx->stream[s]);
216 set_dma_mode(ctx->stream[s].dma,
217 get_dma_mode(ctx->stream[s].dma) & ~DMA_NC);
218
219 ctx->stream[s].substream = substream;
220 ctx->stream[s].buffer = NULL;
221 snd_soc_set_runtime_hwparams(substream, &alchemy_pcm_hardware);
222
223 return 0;
224}
225
226static int alchemy_pcm_close(struct snd_pcm_substream *substream)
227{
228 struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
229 int stype = substream->stream;
230
231 ctx->stream[stype].substream = NULL;
232 free_au1000_dma(ctx->stream[stype].dma);
233
234 return 0;
235}
236
237static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream,
238 struct snd_pcm_hw_params *hw_params)
239{
240 struct audio_stream *stream = ss_to_as(substream);
241 int err;
242
243 err = snd_pcm_lib_malloc_pages(substream,
244 params_buffer_bytes(hw_params));
245 if (err < 0)
246 return err;
247 err = au1000_setup_dma_link(stream,
248 params_period_bytes(hw_params),
249 params_periods(hw_params));
250 if (err)
251 snd_pcm_lib_free_pages(substream);
252
253 return err;
254}
255
256static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream)
257{
258 struct audio_stream *stream = ss_to_as(substream);
259 au1000_release_dma_link(stream);
260 return snd_pcm_lib_free_pages(substream);
261}
262
263static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
264{
265 struct audio_stream *stream = ss_to_as(substream);
266 int err = 0;
267
268 switch (cmd) {
269 case SNDRV_PCM_TRIGGER_START:
270 au1000_dma_start(stream);
271 break;
272 case SNDRV_PCM_TRIGGER_STOP:
273 au1000_dma_stop(stream);
274 break;
275 default:
276 err = -EINVAL;
277 break;
278 }
279 return err;
280}
281
282static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
283{
284 struct audio_stream *stream = ss_to_as(ss);
285 long location;
286
287 location = get_dma_residue(stream->dma);
288 location = stream->buffer->relative_end - location;
289 if (location == -1)
290 location = 0;
291 return bytes_to_frames(ss->runtime, location);
292}
293
294static struct snd_pcm_ops alchemy_pcm_ops = {
295 .open = alchemy_pcm_open,
296 .close = alchemy_pcm_close,
297 .ioctl = snd_pcm_lib_ioctl,
298 .hw_params = alchemy_pcm_hw_params,
299 .hw_free = alchemy_pcm_hw_free,
300 .trigger = alchemy_pcm_trigger,
301 .pointer = alchemy_pcm_pointer,
302};
303
304static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
305{
306 snd_pcm_lib_preallocate_free_for_all(pcm);
307}
308
309static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
310{
311 struct snd_pcm *pcm = rtd->pcm;
312
313 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
314 snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1);
315
316 return 0;
317}
318
319struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
320 .ops = &alchemy_pcm_ops,
321 .pcm_new = alchemy_pcm_new,
322 .pcm_free = alchemy_pcm_free_dma_buffers,
323};
324
325static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev)
326{
327 struct alchemy_pcm_ctx *ctx;
328 int ret;
329
330 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
331 if (!ctx)
332 return -ENOMEM;
333
334 platform_set_drvdata(pdev, ctx);
335
336 ret = snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
337 if (ret)
338 kfree(ctx);
339
340 return ret;
341}
342
343static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev)
344{
345 struct alchemy_pcm_ctx *ctx = platform_get_drvdata(pdev);
346
347 snd_soc_unregister_platform(&pdev->dev);
348 kfree(ctx);
349
350 return 0;
351}
352
353static struct platform_driver alchemy_pcmdma_driver = {
354 .driver = {
355 .name = "alchemy-pcm-dma",
356 .owner = THIS_MODULE,
357 },
358 .probe = alchemy_pcm_drvprobe,
359 .remove = __devexit_p(alchemy_pcm_drvremove),
360};
361
362static int __init alchemy_pcmdma_load(void)
363{
364 return platform_driver_register(&alchemy_pcmdma_driver);
365}
366
367static void __exit alchemy_pcmdma_unload(void)
368{
369 platform_driver_unregister(&alchemy_pcmdma_driver);
370}
371
372module_init(alchemy_pcmdma_load);
373module_exit(alchemy_pcmdma_unload);
374
375MODULE_LICENSE("GPL");
376MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver");
377MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c
new file mode 100644
index 000000000000..b4172fdd2c48
--- /dev/null
+++ b/sound/soc/au1x/i2sc.c
@@ -0,0 +1,347 @@
1/*
2 * Au1000/Au1500/Au1100 I2S controller driver for ASoC
3 *
4 * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
5 *
6 * Note: clock supplied to the I2S controller must be 256x samplerate.
7 */
8
9#include <linux/init.h>
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/suspend.h>
13#include <sound/core.h>
14#include <sound/pcm.h>
15#include <sound/initval.h>
16#include <sound/soc.h>
17#include <asm/mach-au1x00/au1000.h>
18
19#include "psc.h"
20
21#define I2S_RXTX 0x00
22#define I2S_CFG 0x04
23#define I2S_ENABLE 0x08
24
25#define CFG_XU (1 << 25) /* tx underflow */
26#define CFG_XO (1 << 24)
27#define CFG_RU (1 << 23)
28#define CFG_RO (1 << 22)
29#define CFG_TR (1 << 21)
30#define CFG_TE (1 << 20)
31#define CFG_TF (1 << 19)
32#define CFG_RR (1 << 18)
33#define CFG_RF (1 << 17)
34#define CFG_ICK (1 << 12) /* clock invert */
35#define CFG_PD (1 << 11) /* set to make I2SDIO INPUT */
36#define CFG_LB (1 << 10) /* loopback */
37#define CFG_IC (1 << 9) /* word select invert */
38#define CFG_FM_I2S (0 << 7) /* I2S format */
39#define CFG_FM_LJ (1 << 7) /* left-justified */
40#define CFG_FM_RJ (2 << 7) /* right-justified */
41#define CFG_FM_MASK (3 << 7)
42#define CFG_TN (1 << 6) /* tx fifo en */
43#define CFG_RN (1 << 5) /* rx fifo en */
44#define CFG_SZ_8 (0x08)
45#define CFG_SZ_16 (0x10)
46#define CFG_SZ_18 (0x12)
47#define CFG_SZ_20 (0x14)
48#define CFG_SZ_24 (0x18)
49#define CFG_SZ_MASK (0x1f)
50#define EN_D (1 << 1) /* DISable */
51#define EN_CE (1 << 0) /* clock enable */
52
53/* only limited by clock generator and board design */
54#define AU1XI2SC_RATES \
55 SNDRV_PCM_RATE_CONTINUOUS
56
57#define AU1XI2SC_FMTS \
58 (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
59 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
60 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
61 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
62 SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_U18_3BE | \
63 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
64 SNDRV_PCM_FMTBIT_S20_3BE | SNDRV_PCM_FMTBIT_U20_3BE | \
65 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
66 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \
67 0)
68
69static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
70{
71 return __raw_readl(ctx->mmio + reg);
72}
73
74static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
75{
76 __raw_writel(v, ctx->mmio + reg);
77 wmb();
78}
79
80static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
81{
82 struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(cpu_dai);
83 unsigned long c;
84 int ret;
85
86 ret = -EINVAL;
87 c = ctx->cfg;
88
89 c &= ~CFG_FM_MASK;
90 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
91 case SND_SOC_DAIFMT_I2S:
92 c |= CFG_FM_I2S;
93 break;
94 case SND_SOC_DAIFMT_MSB:
95 c |= CFG_FM_RJ;
96 break;
97 case SND_SOC_DAIFMT_LSB:
98 c |= CFG_FM_LJ;
99 break;
100 default:
101 goto out;
102 }
103
104 c &= ~(CFG_IC | CFG_ICK); /* IB-IF */
105 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
106 case SND_SOC_DAIFMT_NB_NF:
107 c |= CFG_IC | CFG_ICK;
108 break;
109 case SND_SOC_DAIFMT_NB_IF:
110 c |= CFG_IC;
111 break;
112 case SND_SOC_DAIFMT_IB_NF:
113 c |= CFG_ICK;
114 break;
115 case SND_SOC_DAIFMT_IB_IF:
116 break;
117 default:
118 goto out;
119 }
120
121 /* I2S controller only supports master */
122 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
123 case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */
124 break;
125 default:
126 goto out;
127 }
128
129 ret = 0;
130 ctx->cfg = c;
131out:
132 return ret;
133}
134
135static int au1xi2s_trigger(struct snd_pcm_substream *substream,
136 int cmd, struct snd_soc_dai *dai)
137{
138 struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
139 int stype = SUBSTREAM_TYPE(substream);
140
141 switch (cmd) {
142 case SNDRV_PCM_TRIGGER_START:
143 case SNDRV_PCM_TRIGGER_RESUME:
144 /* power up */
145 WR(ctx, I2S_ENABLE, EN_D | EN_CE);
146 WR(ctx, I2S_ENABLE, EN_CE);
147 ctx->cfg |= (stype == PCM_TX) ? CFG_TN : CFG_RN;
148 WR(ctx, I2S_CFG, ctx->cfg);
149 break;
150 case SNDRV_PCM_TRIGGER_STOP:
151 case SNDRV_PCM_TRIGGER_SUSPEND:
152 ctx->cfg &= ~((stype == PCM_TX) ? CFG_TN : CFG_RN);
153 WR(ctx, I2S_CFG, ctx->cfg);
154 WR(ctx, I2S_ENABLE, EN_D); /* power off */
155 break;
156 default:
157 return -EINVAL;
158 }
159
160 return 0;
161}
162
163static unsigned long msbits_to_reg(int msbits)
164{
165 switch (msbits) {
166 case 8:
167 return CFG_SZ_8;
168 case 16:
169 return CFG_SZ_16;
170 case 18:
171 return CFG_SZ_18;
172 case 20:
173 return CFG_SZ_20;
174 case 24:
175 return CFG_SZ_24;
176 }
177 return 0;
178}
179
180static int au1xi2s_hw_params(struct snd_pcm_substream *substream,
181 struct snd_pcm_hw_params *params,
182 struct snd_soc_dai *dai)
183{
184 struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
185 unsigned long v;
186
187 v = msbits_to_reg(params->msbits);
188 if (!v)
189 return -EINVAL;
190
191 ctx->cfg &= ~CFG_SZ_MASK;
192 ctx->cfg |= v;
193 return 0;
194}
195
196static int au1xi2s_startup(struct snd_pcm_substream *substream,
197 struct snd_soc_dai *dai)
198{
199 struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
200 snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
201 return 0;
202}
203
204static const struct snd_soc_dai_ops au1xi2s_dai_ops = {
205 .startup = au1xi2s_startup,
206 .trigger = au1xi2s_trigger,
207 .hw_params = au1xi2s_hw_params,
208 .set_fmt = au1xi2s_set_fmt,
209};
210
211static struct snd_soc_dai_driver au1xi2s_dai_driver = {
212 .symmetric_rates = 1,
213 .playback = {
214 .rates = AU1XI2SC_RATES,
215 .formats = AU1XI2SC_FMTS,
216 .channels_min = 2,
217 .channels_max = 2,
218 },
219 .capture = {
220 .rates = AU1XI2SC_RATES,
221 .formats = AU1XI2SC_FMTS,
222 .channels_min = 2,
223 .channels_max = 2,
224 },
225 .ops = &au1xi2s_dai_ops,
226};
227
228static int __devinit au1xi2s_drvprobe(struct platform_device *pdev)
229{
230 int ret;
231 struct resource *r;
232 struct au1xpsc_audio_data *ctx;
233
234 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
235 if (!ctx)
236 return -ENOMEM;
237
238 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
239 if (!r) {
240 ret = -ENODEV;
241 goto out0;
242 }
243
244 ret = -EBUSY;
245 if (!request_mem_region(r->start, resource_size(r), pdev->name))
246 goto out0;
247
248 ctx->mmio = ioremap_nocache(r->start, resource_size(r));
249 if (!ctx->mmio)
250 goto out1;
251
252 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
253 if (!r)
254 goto out1;
255 ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
256
257 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
258 if (!r)
259 goto out1;
260 ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
261
262 platform_set_drvdata(pdev, ctx);
263
264 ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
265 if (ret)
266 goto out1;
267
268 return 0;
269
270 snd_soc_unregister_dai(&pdev->dev);
271out1:
272 release_mem_region(r->start, resource_size(r));
273out0:
274 kfree(ctx);
275 return ret;
276}
277
278static int __devexit au1xi2s_drvremove(struct platform_device *pdev)
279{
280 struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
281 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
282
283 snd_soc_unregister_dai(&pdev->dev);
284
285 WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
286
287 iounmap(ctx->mmio);
288 release_mem_region(r->start, resource_size(r));
289 kfree(ctx);
290
291 return 0;
292}
293
294#ifdef CONFIG_PM
295static int au1xi2s_drvsuspend(struct device *dev)
296{
297 struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
298
299 WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
300
301 return 0;
302}
303
304static int au1xi2s_drvresume(struct device *dev)
305{
306 return 0;
307}
308
309static const struct dev_pm_ops au1xi2sc_pmops = {
310 .suspend = au1xi2s_drvsuspend,
311 .resume = au1xi2s_drvresume,
312};
313
314#define AU1XI2SC_PMOPS (&au1xi2sc_pmops)
315
316#else
317
318#define AU1XI2SC_PMOPS NULL
319
320#endif
321
322static struct platform_driver au1xi2s_driver = {
323 .driver = {
324 .name = "alchemy-i2sc",
325 .owner = THIS_MODULE,
326 .pm = AU1XI2SC_PMOPS,
327 },
328 .probe = au1xi2s_drvprobe,
329 .remove = __devexit_p(au1xi2s_drvremove),
330};
331
332static int __init au1xi2s_load(void)
333{
334 return platform_driver_register(&au1xi2s_driver);
335}
336
337static void __exit au1xi2s_unload(void)
338{
339 platform_driver_unregister(&au1xi2s_driver);
340}
341
342module_init(au1xi2s_load);
343module_exit(au1xi2s_unload);
344
345MODULE_LICENSE("GPL");
346MODULE_DESCRIPTION("Au1000/1500/1100 I2S ASoC driver");
347MODULE_AUTHOR("Manuel Lauss");
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index d0db66f24a00..172eefd38b2d 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -41,14 +41,14 @@
41 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE) 41 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE)
42 42
43#define AC97PCR_START(stype) \ 43#define AC97PCR_START(stype) \
44 ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) 44 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
45#define AC97PCR_STOP(stype) \ 45#define AC97PCR_STOP(stype) \
46 ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) 46 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
47#define AC97PCR_CLRFIFO(stype) \ 47#define AC97PCR_CLRFIFO(stype) \
48 ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) 48 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
49 49
50#define AC97STAT_BUSY(stype) \ 50#define AC97STAT_BUSY(stype) \
51 ((stype) == PCM_TX ? PSC_AC97STAT_TB : PSC_AC97STAT_RB) 51 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97STAT_TB : PSC_AC97STAT_RB)
52 52
53/* instance data. There can be only one, MacLeod!!!! */ 53/* instance data. There can be only one, MacLeod!!!! */
54static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; 54static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
@@ -215,7 +215,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
215{ 215{
216 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); 216 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
217 unsigned long r, ro, stat; 217 unsigned long r, ro, stat;
218 int chans, t, stype = SUBSTREAM_TYPE(substream); 218 int chans, t, stype = substream->stream;
219 219
220 chans = params_channels(params); 220 chans = params_channels(params);
221 221
@@ -235,7 +235,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
235 r |= PSC_AC97CFG_SET_LEN(params->msbits); 235 r |= PSC_AC97CFG_SET_LEN(params->msbits);
236 236
237 /* channels: enable slots for front L/R channel */ 237 /* channels: enable slots for front L/R channel */
238 if (stype == PCM_TX) { 238 if (stype == SNDRV_PCM_STREAM_PLAYBACK) {
239 r &= ~PSC_AC97CFG_TXSLOT_MASK; 239 r &= ~PSC_AC97CFG_TXSLOT_MASK;
240 r |= PSC_AC97CFG_TXSLOT_ENA(3); 240 r |= PSC_AC97CFG_TXSLOT_ENA(3);
241 r |= PSC_AC97CFG_TXSLOT_ENA(4); 241 r |= PSC_AC97CFG_TXSLOT_ENA(4);
@@ -294,7 +294,7 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
294 int cmd, struct snd_soc_dai *dai) 294 int cmd, struct snd_soc_dai *dai)
295{ 295{
296 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); 296 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
297 int ret, stype = SUBSTREAM_TYPE(substream); 297 int ret, stype = substream->stream;
298 298
299 ret = 0; 299 ret = 0;
300 300
@@ -324,12 +324,21 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
324 return ret; 324 return ret;
325} 325}
326 326
327static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream,
328 struct snd_soc_dai *dai)
329{
330 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
331 snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
332 return 0;
333}
334
327static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) 335static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
328{ 336{
329 return au1xpsc_ac97_workdata ? 0 : -ENODEV; 337 return au1xpsc_ac97_workdata ? 0 : -ENODEV;
330} 338}
331 339
332static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { 340static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
341 .startup = au1xpsc_ac97_startup,
333 .trigger = au1xpsc_ac97_trigger, 342 .trigger = au1xpsc_ac97_trigger,
334 .hw_params = au1xpsc_ac97_hw_params, 343 .hw_params = au1xpsc_ac97_hw_params,
335}; 344};
@@ -379,6 +388,16 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
379 if (!wd->mmio) 388 if (!wd->mmio)
380 goto out1; 389 goto out1;
381 390
391 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
392 if (!r)
393 goto out2;
394 wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
395
396 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
397 if (!r)
398 goto out2;
399 wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
400
382 /* configuration: max dma trigger threshold, enable ac97 */ 401 /* configuration: max dma trigger threshold, enable ac97 */
383 wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 | 402 wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
384 PSC_AC97CFG_DE_ENABLE; 403 PSC_AC97CFG_DE_ENABLE;
@@ -401,15 +420,13 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
401 420
402 ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv); 421 ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
403 if (ret) 422 if (ret)
404 goto out1; 423 goto out2;
405 424
406 wd->dmapd = au1xpsc_pcm_add(pdev); 425 au1xpsc_ac97_workdata = wd;
407 if (wd->dmapd) { 426 return 0;
408 au1xpsc_ac97_workdata = wd;
409 return 0;
410 }
411 427
412 snd_soc_unregister_dai(&pdev->dev); 428out2:
429 iounmap(wd->mmio);
413out1: 430out1:
414 release_mem_region(r->start, resource_size(r)); 431 release_mem_region(r->start, resource_size(r));
415out0: 432out0:
@@ -422,9 +439,6 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
422 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); 439 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
423 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 440 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
424 441
425 if (wd->dmapd)
426 au1xpsc_pcm_destroy(wd->dmapd);
427
428 snd_soc_unregister_dai(&pdev->dev); 442 snd_soc_unregister_dai(&pdev->dev);
429 443
430 /* disable PSC completely */ 444 /* disable PSC completely */
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index fca091276320..7c5ae920544f 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -42,13 +42,13 @@
42 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) 42 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
43 43
44#define I2SSTAT_BUSY(stype) \ 44#define I2SSTAT_BUSY(stype) \
45 ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB) 45 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB)
46#define I2SPCR_START(stype) \ 46#define I2SPCR_START(stype) \
47 ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS) 47 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TS : PSC_I2SPCR_RS)
48#define I2SPCR_STOP(stype) \ 48#define I2SPCR_STOP(stype) \
49 ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP) 49 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TP : PSC_I2SPCR_RP)
50#define I2SPCR_CLRFIFO(stype) \ 50#define I2SPCR_CLRFIFO(stype) \
51 ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC) 51 ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
52 52
53 53
54static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, 54static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
@@ -240,7 +240,7 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
240 struct snd_soc_dai *dai) 240 struct snd_soc_dai *dai)
241{ 241{
242 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); 242 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
243 int ret, stype = SUBSTREAM_TYPE(substream); 243 int ret, stype = substream->stream;
244 244
245 switch (cmd) { 245 switch (cmd) {
246 case SNDRV_PCM_TRIGGER_START: 246 case SNDRV_PCM_TRIGGER_START:
@@ -257,7 +257,16 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
257 return ret; 257 return ret;
258} 258}
259 259
260static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream,
261 struct snd_soc_dai *dai)
262{
263 struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
264 snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
265 return 0;
266}
267
260static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { 268static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
269 .startup = au1xpsc_i2s_startup,
261 .trigger = au1xpsc_i2s_trigger, 270 .trigger = au1xpsc_i2s_trigger,
262 .hw_params = au1xpsc_i2s_hw_params, 271 .hw_params = au1xpsc_i2s_hw_params,
263 .set_fmt = au1xpsc_i2s_set_fmt, 272 .set_fmt = au1xpsc_i2s_set_fmt,
@@ -304,6 +313,16 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
304 if (!wd->mmio) 313 if (!wd->mmio)
305 goto out1; 314 goto out1;
306 315
316 r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
317 if (!r)
318 goto out2;
319 wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
320
321 r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
322 if (!r)
323 goto out2;
324 wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
325
307 /* preserve PSC clock source set up by platform (dev.platform_data 326 /* preserve PSC clock source set up by platform (dev.platform_data
308 * is already occupied by soc layer) 327 * is already occupied by soc layer)
309 */ 328 */
@@ -330,15 +349,11 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
330 platform_set_drvdata(pdev, wd); 349 platform_set_drvdata(pdev, wd);
331 350
332 ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv); 351 ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
333 if (ret) 352 if (!ret)
334 goto out1;
335
336 /* finally add the DMA device for this PSC */
337 wd->dmapd = au1xpsc_pcm_add(pdev);
338 if (wd->dmapd)
339 return 0; 353 return 0;
340 354
341 snd_soc_unregister_dai(&pdev->dev); 355out2:
356 iounmap(wd->mmio);
342out1: 357out1:
343 release_mem_region(r->start, resource_size(r)); 358 release_mem_region(r->start, resource_size(r));
344out0: 359out0:
@@ -351,9 +366,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
351 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); 366 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
352 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 367 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
353 368
354 if (wd->dmapd)
355 au1xpsc_pcm_destroy(wd->dmapd);
356
357 snd_soc_unregister_dai(&pdev->dev); 369 snd_soc_unregister_dai(&pdev->dev);
358 370
359 au_writel(0, I2S_CFG(wd)); 371 au_writel(0, I2S_CFG(wd));
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index b30eadd422a7..b16b2e02e0c9 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * Au12x0/Au1550 PSC ALSA ASoC audio support. 2 * Alchemy ALSA ASoC audio support.
3 * 3 *
4 * (c) 2007-2008 MSC Vertriebsges.m.b.H., 4 * (c) 2007-2011 MSC Vertriebsges.m.b.H.,
5 * Manuel Lauss <manuel.lauss@gmail.com> 5 * Manuel Lauss <manuel.lauss@gmail.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -13,10 +13,6 @@
13#ifndef _AU1X_PCM_H 13#ifndef _AU1X_PCM_H
14#define _AU1X_PCM_H 14#define _AU1X_PCM_H
15 15
16/* DBDMA helpers */
17extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
18extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
19
20struct au1xpsc_audio_data { 16struct au1xpsc_audio_data {
21 void __iomem *mmio; 17 void __iomem *mmio;
22 18
@@ -27,15 +23,9 @@ struct au1xpsc_audio_data {
27 23
28 unsigned long pm[2]; 24 unsigned long pm[2];
29 struct mutex lock; 25 struct mutex lock;
30 struct platform_device *dmapd; 26 int dmaids[2];
31}; 27};
32 28
33#define PCM_TX 0
34#define PCM_RX 1
35
36#define SUBSTREAM_TYPE(substream) \
37 ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
38
39/* easy access macros */ 29/* easy access macros */
40#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) 30#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET)
41#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) 31#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET)
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index 76258f2a2ffb..666fae6e148d 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -20,6 +20,7 @@
20#include <linux/regulator/driver.h> 20#include <linux/regulator/driver.h>
21#include <linux/regulator/machine.h> 21#include <linux/regulator/machine.h>
22#include <linux/regulator/consumer.h> 22#include <linux/regulator/consumer.h>
23#include <linux/of_device.h>
23#include <sound/core.h> 24#include <sound/core.h>
24#include <sound/tlv.h> 25#include <sound/tlv.h>
25#include <sound/pcm.h> 26#include <sound/pcm.h>
@@ -33,73 +34,31 @@
33#define SGTL5000_DAP_REG_OFFSET 0x0100 34#define SGTL5000_DAP_REG_OFFSET 0x0100
34#define SGTL5000_MAX_REG_OFFSET 0x013A 35#define SGTL5000_MAX_REG_OFFSET 0x013A
35 36
36/* default value of sgtl5000 registers except DAP */ 37/* default value of sgtl5000 registers */
37static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] = { 38static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET] = {
38 0xa011, /* 0x0000, CHIP_ID. 11 stand for revison 17 */ 39 [SGTL5000_CHIP_CLK_CTRL] = 0x0008,
39 0x0000, /* 0x0002, CHIP_DIG_POWER. */ 40 [SGTL5000_CHIP_I2S_CTRL] = 0x0010,
40 0x0008, /* 0x0004, CHIP_CKL_CTRL */ 41 [SGTL5000_CHIP_SSS_CTRL] = 0x0008,
41 0x0010, /* 0x0006, CHIP_I2S_CTRL */ 42 [SGTL5000_CHIP_DAC_VOL] = 0x3c3c,
42 0x0000, /* 0x0008, reserved */ 43 [SGTL5000_CHIP_PAD_STRENGTH] = 0x015f,
43 0x0008, /* 0x000A, CHIP_SSS_CTRL */ 44 [SGTL5000_CHIP_ANA_HP_CTRL] = 0x1818,
44 0x0000, /* 0x000C, reserved */ 45 [SGTL5000_CHIP_ANA_CTRL] = 0x0111,
45 0x020c, /* 0x000E, CHIP_ADCDAC_CTRL */ 46 [SGTL5000_CHIP_LINE_OUT_VOL] = 0x0404,
46 0x3c3c, /* 0x0010, CHIP_DAC_VOL */ 47 [SGTL5000_CHIP_ANA_POWER] = 0x7060,
47 0x0000, /* 0x0012, reserved */ 48 [SGTL5000_CHIP_PLL_CTRL] = 0x5000,
48 0x015f, /* 0x0014, CHIP_PAD_STRENGTH */ 49 [SGTL5000_DAP_BASS_ENHANCE] = 0x0040,
49 0x0000, /* 0x0016, reserved */ 50 [SGTL5000_DAP_BASS_ENHANCE_CTRL] = 0x051f,
50 0x0000, /* 0x0018, reserved */ 51 [SGTL5000_DAP_SURROUND] = 0x0040,
51 0x0000, /* 0x001A, reserved */ 52 [SGTL5000_DAP_EQ_BASS_BAND0] = 0x002f,
52 0x0000, /* 0x001E, reserved */ 53 [SGTL5000_DAP_EQ_BASS_BAND1] = 0x002f,
53 0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */ 54 [SGTL5000_DAP_EQ_BASS_BAND2] = 0x002f,
54 0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */ 55 [SGTL5000_DAP_EQ_BASS_BAND3] = 0x002f,
55 0x0111, /* 0x0024, CHIP_ANN_CTRL */ 56 [SGTL5000_DAP_EQ_BASS_BAND4] = 0x002f,
56 0x0000, /* 0x0026, CHIP_LINREG_CTRL */ 57 [SGTL5000_DAP_MAIN_CHAN] = 0x8000,
57 0x0000, /* 0x0028, CHIP_REF_CTRL */ 58 [SGTL5000_DAP_AVC_CTRL] = 0x0510,
58 0x0000, /* 0x002A, CHIP_MIC_CTRL */ 59 [SGTL5000_DAP_AVC_THRESHOLD] = 0x1473,
59 0x0000, /* 0x002C, CHIP_LINE_OUT_CTRL */ 60 [SGTL5000_DAP_AVC_ATTACK] = 0x0028,
60 0x0404, /* 0x002E, CHIP_LINE_OUT_VOL */ 61 [SGTL5000_DAP_AVC_DECAY] = 0x0050,
61 0x7060, /* 0x0030, CHIP_ANA_POWER */
62 0x5000, /* 0x0032, CHIP_PLL_CTRL */
63 0x0000, /* 0x0034, CHIP_CLK_TOP_CTRL */
64 0x0000, /* 0x0036, CHIP_ANA_STATUS */
65 0x0000, /* 0x0038, reserved */
66 0x0000, /* 0x003A, CHIP_ANA_TEST2 */
67 0x0000, /* 0x003C, CHIP_SHORT_CTRL */
68 0x0000, /* reserved */
69};
70
71/* default value of dap registers */
72static const u16 sgtl5000_dap_regs[] = {
73 0x0000, /* 0x0100, DAP_CONTROL */
74 0x0000, /* 0x0102, DAP_PEQ */
75 0x0040, /* 0x0104, DAP_BASS_ENHANCE */
76 0x051f, /* 0x0106, DAP_BASS_ENHANCE_CTRL */
77 0x0000, /* 0x0108, DAP_AUDIO_EQ */
78 0x0040, /* 0x010A, DAP_SGTL_SURROUND */
79 0x0000, /* 0x010C, DAP_FILTER_COEF_ACCESS */
80 0x0000, /* 0x010E, DAP_COEF_WR_B0_MSB */
81 0x0000, /* 0x0110, DAP_COEF_WR_B0_LSB */
82 0x0000, /* 0x0112, reserved */
83 0x0000, /* 0x0114, reserved */
84 0x002f, /* 0x0116, DAP_AUDIO_EQ_BASS_BAND0 */
85 0x002f, /* 0x0118, DAP_AUDIO_EQ_BAND0 */
86 0x002f, /* 0x011A, DAP_AUDIO_EQ_BAND2 */
87 0x002f, /* 0x011C, DAP_AUDIO_EQ_BAND3 */
88 0x002f, /* 0x011E, DAP_AUDIO_EQ_TREBLE_BAND4 */
89 0x8000, /* 0x0120, DAP_MAIN_CHAN */
90 0x0000, /* 0x0122, DAP_MIX_CHAN */
91 0x0510, /* 0x0124, DAP_AVC_CTRL */
92 0x1473, /* 0x0126, DAP_AVC_THRESHOLD */
93 0x0028, /* 0x0128, DAP_AVC_ATTACK */
94 0x0050, /* 0x012A, DAP_AVC_DECAY */
95 0x0000, /* 0x012C, DAP_COEF_WR_B1_MSB */
96 0x0000, /* 0x012E, DAP_COEF_WR_B1_LSB */
97 0x0000, /* 0x0130, DAP_COEF_WR_B2_MSB */
98 0x0000, /* 0x0132, DAP_COEF_WR_B2_LSB */
99 0x0000, /* 0x0134, DAP_COEF_WR_A1_MSB */
100 0x0000, /* 0x0136, DAP_COEF_WR_A1_LSB */
101 0x0000, /* 0x0138, DAP_COEF_WR_A2_MSB */
102 0x0000, /* 0x013A, DAP_COEF_WR_A2_LSB */
103}; 62};
104 63
105/* regulator supplies for sgtl5000, VDDD is an optional external supply */ 64/* regulator supplies for sgtl5000, VDDD is an optional external supply */
@@ -1023,12 +982,10 @@ static int sgtl5000_suspend(struct snd_soc_codec *codec, pm_message_t state)
1023static int sgtl5000_restore_regs(struct snd_soc_codec *codec) 982static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
1024{ 983{
1025 u16 *cache = codec->reg_cache; 984 u16 *cache = codec->reg_cache;
1026 int i; 985 u16 reg;
1027 int regular_regs = SGTL5000_CHIP_SHORT_CTRL >> 1;
1028 986
1029 /* restore regular registers */ 987 /* restore regular registers */
1030 for (i = 0; i < regular_regs; i++) { 988 for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
1031 int reg = i << 1;
1032 989
1033 /* this regs depends on the others */ 990 /* this regs depends on the others */
1034 if (reg == SGTL5000_CHIP_ANA_POWER || 991 if (reg == SGTL5000_CHIP_ANA_POWER ||
@@ -1038,35 +995,31 @@ static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
1038 reg == SGTL5000_CHIP_CLK_CTRL) 995 reg == SGTL5000_CHIP_CLK_CTRL)
1039 continue; 996 continue;
1040 997
1041 snd_soc_write(codec, reg, cache[i]); 998 snd_soc_write(codec, reg, cache[reg]);
1042 } 999 }
1043 1000
1044 /* restore dap registers */ 1001 /* restore dap registers */
1045 for (i = SGTL5000_DAP_REG_OFFSET >> 1; 1002 for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2)
1046 i < SGTL5000_MAX_REG_OFFSET >> 1; i++) { 1003 snd_soc_write(codec, reg, cache[reg]);
1047 int reg = i << 1;
1048
1049 snd_soc_write(codec, reg, cache[i]);
1050 }
1051 1004
1052 /* 1005 /*
1053 * restore power and other regs according 1006 * restore power and other regs according
1054 * to set_power() and set_clock() 1007 * to set_power() and set_clock()
1055 */ 1008 */
1056 snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, 1009 snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
1057 cache[SGTL5000_CHIP_LINREG_CTRL >> 1]); 1010 cache[SGTL5000_CHIP_LINREG_CTRL]);
1058 1011
1059 snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, 1012 snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
1060 cache[SGTL5000_CHIP_ANA_POWER >> 1]); 1013 cache[SGTL5000_CHIP_ANA_POWER]);
1061 1014
1062 snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, 1015 snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
1063 cache[SGTL5000_CHIP_CLK_CTRL >> 1]); 1016 cache[SGTL5000_CHIP_CLK_CTRL]);
1064 1017
1065 snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL, 1018 snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
1066 cache[SGTL5000_CHIP_REF_CTRL >> 1]); 1019 cache[SGTL5000_CHIP_REF_CTRL]);
1067 1020
1068 snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL, 1021 snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
1069 cache[SGTL5000_CHIP_LINE_OUT_CTRL >> 1]); 1022 cache[SGTL5000_CHIP_LINE_OUT_CTRL]);
1070 return 0; 1023 return 0;
1071} 1024}
1072 1025
@@ -1454,16 +1407,6 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
1454 if (!sgtl5000) 1407 if (!sgtl5000)
1455 return -ENOMEM; 1408 return -ENOMEM;
1456 1409
1457 /*
1458 * copy DAP default values to default value array.
1459 * sgtl5000 register space has a big hole, merge it
1460 * at init phase makes life easy.
1461 * FIXME: should we drop 'const' of sgtl5000_regs?
1462 */
1463 memcpy((void *)(&sgtl5000_regs[0] + (SGTL5000_DAP_REG_OFFSET >> 1)),
1464 sgtl5000_dap_regs,
1465 SGTL5000_MAX_REG_OFFSET - SGTL5000_DAP_REG_OFFSET);
1466
1467 i2c_set_clientdata(client, sgtl5000); 1410 i2c_set_clientdata(client, sgtl5000);
1468 1411
1469 ret = snd_soc_register_codec(&client->dev, 1412 ret = snd_soc_register_codec(&client->dev,
@@ -1494,10 +1437,17 @@ static const struct i2c_device_id sgtl5000_id[] = {
1494 1437
1495MODULE_DEVICE_TABLE(i2c, sgtl5000_id); 1438MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
1496 1439
1440static const struct of_device_id sgtl5000_dt_ids[] = {
1441 { .compatible = "fsl,sgtl5000", },
1442 { /* sentinel */ }
1443};
1444MODULE_DEVICE_TABLE(i2c, sgtl5000_dt_ids);
1445
1497static struct i2c_driver sgtl5000_i2c_driver = { 1446static struct i2c_driver sgtl5000_i2c_driver = {
1498 .driver = { 1447 .driver = {
1499 .name = "sgtl5000", 1448 .name = "sgtl5000",
1500 .owner = THIS_MODULE, 1449 .owner = THIS_MODULE,
1450 .of_match_table = sgtl5000_dt_ids,
1501 }, 1451 },
1502 .probe = sgtl5000_i2c_probe, 1452 .probe = sgtl5000_i2c_probe,
1503 .remove = __devexit_p(sgtl5000_i2c_remove), 1453 .remove = __devexit_p(sgtl5000_i2c_remove),
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index bcc208967917..bbcf9ec34759 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -56,8 +56,26 @@ static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
56}; 56};
57 57
58static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, 58static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
59 const struct i2c_device_id *id) 59 const struct i2c_device_id *i2c_id)
60{ 60{
61 int ret, id, board, rev;
62
63 board = i2c_smbus_read_byte_data(i2c, 0);
64 if (board < 0) {
65 dev_err(&i2c->dev, "Failed to read ID: %d\n", ret);
66 return ret;
67 }
68
69 id = (board & 0xfe) >> 2;
70 rev = board & 0x3;
71
72 if (id != 1) {
73 dev_err(&i2c->dev, "Unknown board ID %d\n", id);
74 return -ENODEV;
75 }
76
77 dev_info(&i2c->dev, "revision %d\n", rev);
78
61 return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1, 79 return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
62 &wm1250_ev1_dai, 1); 80 &wm1250_ev1_dai, 1);
63} 81}
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 4fd4d8dca0fc..131200917c56 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -551,7 +551,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
551 551
552static struct i2c_driver wm8523_i2c_driver = { 552static struct i2c_driver wm8523_i2c_driver = {
553 .driver = { 553 .driver = {
554 .name = "wm8523-codec", 554 .name = "wm8523",
555 .owner = THIS_MODULE, 555 .owner = THIS_MODULE,
556 }, 556 },
557 .probe = wm8523_i2c_probe, 557 .probe = wm8523_i2c_probe,
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 4bbc0a79f01e..95ac6651094f 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -943,7 +943,7 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
943 943
944static struct i2c_driver wm8580_i2c_driver = { 944static struct i2c_driver wm8580_i2c_driver = {
945 .driver = { 945 .driver = {
946 .name = "wm8580-codec", 946 .name = "wm8580",
947 .owner = THIS_MODULE, 947 .owner = THIS_MODULE,
948 }, 948 },
949 .probe = wm8580_i2c_probe, 949 .probe = wm8580_i2c_probe,
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 76b4361e9b80..f76b6fc6766a 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -22,6 +22,7 @@
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/regulator/consumer.h> 23#include <linux/regulator/consumer.h>
24#include <linux/spi/spi.h> 24#include <linux/spi/spi.h>
25#include <linux/of_device.h>
25#include <sound/core.h> 26#include <sound/core.h>
26#include <sound/pcm.h> 27#include <sound/pcm.h>
27#include <sound/pcm_params.h> 28#include <sound/pcm_params.h>
@@ -607,6 +608,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
607 .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), 608 .num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
608}; 609};
609 610
611static const struct of_device_id wm8731_of_match[] = {
612 { .compatible = "wlf,wm8731", },
613 { }
614};
615
616MODULE_DEVICE_TABLE(of, wm8731_of_match);
617
610#if defined(CONFIG_SPI_MASTER) 618#if defined(CONFIG_SPI_MASTER)
611static int __devinit wm8731_spi_probe(struct spi_device *spi) 619static int __devinit wm8731_spi_probe(struct spi_device *spi)
612{ 620{
@@ -638,6 +646,7 @@ static struct spi_driver wm8731_spi_driver = {
638 .driver = { 646 .driver = {
639 .name = "wm8731", 647 .name = "wm8731",
640 .owner = THIS_MODULE, 648 .owner = THIS_MODULE,
649 .of_match_table = wm8731_of_match,
641 }, 650 },
642 .probe = wm8731_spi_probe, 651 .probe = wm8731_spi_probe,
643 .remove = __devexit_p(wm8731_spi_remove), 652 .remove = __devexit_p(wm8731_spi_remove),
@@ -682,6 +691,7 @@ static struct i2c_driver wm8731_i2c_driver = {
682 .driver = { 691 .driver = {
683 .name = "wm8731", 692 .name = "wm8731",
684 .owner = THIS_MODULE, 693 .owner = THIS_MODULE,
694 .of_match_table = wm8731_of_match,
685 }, 695 },
686 .probe = wm8731_i2c_probe, 696 .probe = wm8731_i2c_probe,
687 .remove = __devexit_p(wm8731_i2c_remove), 697 .remove = __devexit_p(wm8731_i2c_remove),
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 6e85b8869af7..f014e5676d20 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1433,7 +1433,8 @@ static int wm8993_probe(struct snd_soc_codec *codec)
1433 int ret, i, val; 1433 int ret, i, val;
1434 1434
1435 wm8993->hubs_data.hp_startup_mode = 1; 1435 wm8993->hubs_data.hp_startup_mode = 1;
1436 wm8993->hubs_data.dcs_codes = -2; 1436 wm8993->hubs_data.dcs_codes_l = -2;
1437 wm8993->hubs_data.dcs_codes_r = -2;
1437 wm8993->hubs_data.series_startup = 1; 1438 wm8993->hubs_data.series_startup = 1;
1438 1439
1439 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); 1440 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 09e680ae88b2..fb5c96163610 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -107,6 +107,7 @@ static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg)
107 case WM8994_LDO_2: 107 case WM8994_LDO_2:
108 case WM8958_DSP2_EXECCONTROL: 108 case WM8958_DSP2_EXECCONTROL:
109 case WM8958_MIC_DETECT_3: 109 case WM8958_MIC_DETECT_3:
110 case WM8994_DC_SERVO_4E:
110 return 1; 111 return 1;
111 default: 112 default:
112 return 0; 113 return 0;
@@ -2972,13 +2973,14 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2972 switch (wm8994->revision) { 2973 switch (wm8994->revision) {
2973 case 2: 2974 case 2:
2974 case 3: 2975 case 3:
2975 wm8994->hubs.dcs_codes = -5; 2976 wm8994->hubs.dcs_codes_l = -5;
2977 wm8994->hubs.dcs_codes_r = -5;
2976 wm8994->hubs.hp_startup_mode = 1; 2978 wm8994->hubs.hp_startup_mode = 1;
2977 wm8994->hubs.dcs_readback_mode = 1; 2979 wm8994->hubs.dcs_readback_mode = 1;
2978 wm8994->hubs.series_startup = 1; 2980 wm8994->hubs.series_startup = 1;
2979 break; 2981 break;
2980 default: 2982 default:
2981 wm8994->hubs.dcs_readback_mode = 1; 2983 wm8994->hubs.dcs_readback_mode = 2;
2982 break; 2984 break;
2983 } 2985 }
2984 2986
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 4cc2d567f22f..017522e7cef9 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -18,6 +18,7 @@
18#include <linux/pm.h> 18#include <linux/pm.h>
19#include <linux/i2c.h> 19#include <linux/i2c.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/mfd/wm8994/registers.h>
21#include <sound/core.h> 22#include <sound/core.h>
22#include <sound/pcm.h> 23#include <sound/pcm.h>
23#include <sound/pcm_params.h> 24#include <sound/pcm_params.h>
@@ -116,14 +117,23 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
116{ 117{
117 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); 118 struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
118 s8 offset; 119 s8 offset;
119 u16 reg, reg_l, reg_r, dcs_cfg; 120 u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
121
122 switch (hubs->dcs_readback_mode) {
123 case 2:
124 dcs_reg = WM8994_DC_SERVO_4E;
125 break;
126 default:
127 dcs_reg = WM8993_DC_SERVO_3;
128 break;
129 }
120 130
121 /* If we're using a digital only path and have a previously 131 /* If we're using a digital only path and have a previously
122 * callibrated DC servo offset stored then use that. */ 132 * callibrated DC servo offset stored then use that. */
123 if (hubs->class_w && hubs->class_w_dcs) { 133 if (hubs->class_w && hubs->class_w_dcs) {
124 dev_dbg(codec->dev, "Using cached DC servo offset %x\n", 134 dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
125 hubs->class_w_dcs); 135 hubs->class_w_dcs);
126 snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs); 136 snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
127 wait_for_dc_servo(codec, 137 wait_for_dc_servo(codec,
128 WM8993_DCS_TRIG_DAC_WR_0 | 138 WM8993_DCS_TRIG_DAC_WR_0 |
129 WM8993_DCS_TRIG_DAC_WR_1); 139 WM8993_DCS_TRIG_DAC_WR_1);
@@ -154,8 +164,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
154 reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) 164 reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
155 & WM8993_DCS_INTEG_CHAN_1_MASK; 165 & WM8993_DCS_INTEG_CHAN_1_MASK;
156 break; 166 break;
167 case 2:
157 case 1: 168 case 1:
158 reg = snd_soc_read(codec, WM8993_DC_SERVO_3); 169 reg = snd_soc_read(codec, dcs_reg);
159 reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) 170 reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
160 >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; 171 >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
161 reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; 172 reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
@@ -168,24 +179,25 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
168 dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); 179 dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
169 180
170 /* Apply correction to DC servo result */ 181 /* Apply correction to DC servo result */
171 if (hubs->dcs_codes) { 182 if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
172 dev_dbg(codec->dev, "Applying %d code DC servo correction\n", 183 dev_dbg(codec->dev,
173 hubs->dcs_codes); 184 "Applying %d/%d code DC servo correction\n",
185 hubs->dcs_codes_l, hubs->dcs_codes_r);
174 186
175 /* HPOUT1R */ 187 /* HPOUT1R */
176 offset = reg_r; 188 offset = reg_r;
177 offset += hubs->dcs_codes; 189 offset += hubs->dcs_codes_r;
178 dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT; 190 dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
179 191
180 /* HPOUT1L */ 192 /* HPOUT1L */
181 offset = reg_l; 193 offset = reg_l;
182 offset += hubs->dcs_codes; 194 offset += hubs->dcs_codes_l;
183 dcs_cfg |= (u8)offset; 195 dcs_cfg |= (u8)offset;
184 196
185 dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg); 197 dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
186 198
187 /* Do it */ 199 /* Do it */
188 snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg); 200 snd_soc_write(codec, dcs_reg, dcs_cfg);
189 wait_for_dc_servo(codec, 201 wait_for_dc_servo(codec,
190 WM8993_DCS_TRIG_DAC_WR_0 | 202 WM8993_DCS_TRIG_DAC_WR_0 |
191 WM8993_DCS_TRIG_DAC_WR_1); 203 WM8993_DCS_TRIG_DAC_WR_1);
@@ -217,7 +229,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
217 229
218 /* If we're applying an offset correction then updating the 230 /* If we're applying an offset correction then updating the
219 * callibration would be likely to introduce further offsets. */ 231 * callibration would be likely to introduce further offsets. */
220 if (hubs->dcs_codes || hubs->no_series_update) 232 if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
221 return ret; 233 return ret;
222 234
223 /* Only need to do this if the outputs are active */ 235 /* Only need to do this if the outputs are active */
@@ -440,9 +452,8 @@ static int hp_event(struct snd_soc_dapm_widget *w,
440 reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY; 452 reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
441 snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); 453 snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
442 454
443 /* Smallest supported update interval */
444 snd_soc_update_bits(codec, WM8993_DC_SERVO_1, 455 snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
445 WM8993_DCS_TIMER_PERIOD_01_MASK, 1); 456 WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
446 457
447 calibrate_dc_servo(codec); 458 calibrate_dc_servo(codec);
448 459
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 676b1252ab91..c674c7a502a6 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -23,7 +23,8 @@ extern const unsigned int wm_hubs_spkmix_tlv[];
23 23
24/* This *must* be the first element of the codec->private_data struct */ 24/* This *must* be the first element of the codec->private_data struct */
25struct wm_hubs_data { 25struct wm_hubs_data {
26 int dcs_codes; 26 int dcs_codes_l;
27 int dcs_codes_r;
27 int dcs_readback_mode; 28 int dcs_readback_mode;
28 int hp_startup_mode; 29 int hp_startup_mode;
29 int series_startup; 30 int series_startup;
diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig
new file mode 100644
index 000000000000..e4ba8d5f25fa
--- /dev/null
+++ b/sound/soc/mxs/Kconfig
@@ -0,0 +1,20 @@
1menuconfig SND_MXS_SOC
2 tristate "SoC Audio for Freescale MXS CPUs"
3 depends on ARCH_MXS
4 select SND_PCM
5 help
6 Say Y or M if you want to add support for codecs attached to
7 the MXS SAIF interface.
8
9
10if SND_MXS_SOC
11
12config SND_SOC_MXS_SGTL5000
13 tristate "SoC Audio support for i.MX boards with sgtl5000"
14 depends on I2C
15 select SND_SOC_SGTL5000
16 help
17 Say Y if you want to add support for SoC audio on an MXS board with
18 a sgtl5000 codec.
19
20endif # SND_MXS_SOC
diff --git a/sound/soc/mxs/Makefile b/sound/soc/mxs/Makefile
new file mode 100644
index 000000000000..565b5b51e8b7
--- /dev/null
+++ b/sound/soc/mxs/Makefile
@@ -0,0 +1,10 @@
1# MXS Platform Support
2snd-soc-mxs-objs := mxs-saif.o
3snd-soc-mxs-pcm-objs := mxs-pcm.o
4
5obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs.o snd-soc-mxs-pcm.o
6
7# i.MX Machine Support
8snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o
9
10obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
new file mode 100644
index 000000000000..dea5aa4aa647
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -0,0 +1,359 @@
1/*
2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
3 *
4 * Based on sound/soc/imx/imx-pcm-dma-mx2.c
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/clk.h>
22#include <linux/delay.h>
23#include <linux/device.h>
24#include <linux/dma-mapping.h>
25#include <linux/init.h>
26#include <linux/interrupt.h>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/slab.h>
30#include <linux/dmaengine.h>
31
32#include <sound/core.h>
33#include <sound/initval.h>
34#include <sound/pcm.h>
35#include <sound/pcm_params.h>
36#include <sound/soc.h>
37
38#include <mach/dma.h>
39#include "mxs-pcm.h"
40
41static struct snd_pcm_hardware snd_mxs_hardware = {
42 .info = SNDRV_PCM_INFO_MMAP |
43 SNDRV_PCM_INFO_MMAP_VALID |
44 SNDRV_PCM_INFO_PAUSE |
45 SNDRV_PCM_INFO_RESUME |
46 SNDRV_PCM_INFO_INTERLEAVED,
47 .formats = SNDRV_PCM_FMTBIT_S16_LE |
48 SNDRV_PCM_FMTBIT_S20_3LE |
49 SNDRV_PCM_FMTBIT_S24_LE,
50 .channels_min = 2,
51 .channels_max = 2,
52 .period_bytes_min = 32,
53 .period_bytes_max = 8192,
54 .periods_min = 1,
55 .periods_max = 52,
56 .buffer_bytes_max = 64 * 1024,
57 .fifo_size = 32,
58
59};
60
61static void audio_dma_irq(void *data)
62{
63 struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
64 struct snd_pcm_runtime *runtime = substream->runtime;
65 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
66
67 iprtd->offset += iprtd->period_bytes;
68 iprtd->offset %= iprtd->period_bytes * iprtd->periods;
69 snd_pcm_period_elapsed(substream);
70}
71
72static bool filter(struct dma_chan *chan, void *param)
73{
74 struct mxs_pcm_runtime_data *iprtd = param;
75 struct mxs_pcm_dma_params *dma_params = iprtd->dma_params;
76
77 if (!mxs_dma_is_apbx(chan))
78 return false;
79
80 if (chan->chan_id != dma_params->chan_num)
81 return false;
82
83 chan->private = &iprtd->dma_data;
84
85 return true;
86}
87
88static int mxs_dma_alloc(struct snd_pcm_substream *substream,
89 struct snd_pcm_hw_params *params)
90{
91 struct snd_soc_pcm_runtime *rtd = substream->private_data;
92 struct snd_pcm_runtime *runtime = substream->runtime;
93 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
94 dma_cap_mask_t mask;
95
96 iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
97
98 dma_cap_zero(mask);
99 dma_cap_set(DMA_SLAVE, mask);
100 iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq;
101 iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
102 if (!iprtd->dma_chan)
103 return -EINVAL;
104
105 return 0;
106}
107
108static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
109 struct snd_pcm_hw_params *params)
110{
111 struct snd_pcm_runtime *runtime = substream->runtime;
112 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
113 unsigned long dma_addr;
114 struct dma_chan *chan;
115 int ret;
116
117 ret = mxs_dma_alloc(substream, params);
118 if (ret)
119 return ret;
120 chan = iprtd->dma_chan;
121
122 iprtd->size = params_buffer_bytes(params);
123 iprtd->periods = params_periods(params);
124 iprtd->period_bytes = params_period_bytes(params);
125 iprtd->offset = 0;
126 iprtd->period_time = HZ / (params_rate(params) /
127 params_period_size(params));
128
129 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
130
131 dma_addr = runtime->dma_addr;
132
133 iprtd->buf = substream->dma_buffer.area;
134
135 iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
136 iprtd->period_bytes * iprtd->periods,
137 iprtd->period_bytes,
138 substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
139 DMA_TO_DEVICE : DMA_FROM_DEVICE);
140 if (!iprtd->desc) {
141 dev_err(&chan->dev->device, "cannot prepare slave dma\n");
142 return -EINVAL;
143 }
144
145 iprtd->desc->callback = audio_dma_irq;
146 iprtd->desc->callback_param = substream;
147
148 return 0;
149}
150
151static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream)
152{
153 struct snd_pcm_runtime *runtime = substream->runtime;
154 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
155
156 if (iprtd->dma_chan) {
157 dma_release_channel(iprtd->dma_chan);
158 iprtd->dma_chan = NULL;
159 }
160
161 return 0;
162}
163
164static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
165{
166 struct snd_pcm_runtime *runtime = substream->runtime;
167 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
168
169 switch (cmd) {
170 case SNDRV_PCM_TRIGGER_START:
171 case SNDRV_PCM_TRIGGER_RESUME:
172 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
173 dmaengine_submit(iprtd->desc);
174
175 break;
176 case SNDRV_PCM_TRIGGER_STOP:
177 case SNDRV_PCM_TRIGGER_SUSPEND:
178 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
179 dmaengine_terminate_all(iprtd->dma_chan);
180
181 break;
182 default:
183 return -EINVAL;
184 }
185
186 return 0;
187}
188
189static snd_pcm_uframes_t snd_mxs_pcm_pointer(
190 struct snd_pcm_substream *substream)
191{
192 struct snd_pcm_runtime *runtime = substream->runtime;
193 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
194
195 return bytes_to_frames(substream->runtime, iprtd->offset);
196}
197
198static int snd_mxs_open(struct snd_pcm_substream *substream)
199{
200 struct snd_pcm_runtime *runtime = substream->runtime;
201 struct mxs_pcm_runtime_data *iprtd;
202 int ret;
203
204 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
205 if (iprtd == NULL)
206 return -ENOMEM;
207 runtime->private_data = iprtd;
208
209 ret = snd_pcm_hw_constraint_integer(substream->runtime,
210 SNDRV_PCM_HW_PARAM_PERIODS);
211 if (ret < 0) {
212 kfree(iprtd);
213 return ret;
214 }
215
216 snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
217
218 return 0;
219}
220
221static int snd_mxs_close(struct snd_pcm_substream *substream)
222{
223 struct snd_pcm_runtime *runtime = substream->runtime;
224 struct mxs_pcm_runtime_data *iprtd = runtime->private_data;
225
226 kfree(iprtd);
227
228 return 0;
229}
230
231static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
232 struct vm_area_struct *vma)
233{
234 struct snd_pcm_runtime *runtime = substream->runtime;
235
236 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
237 runtime->dma_area,
238 runtime->dma_addr,
239 runtime->dma_bytes);
240}
241
242static struct snd_pcm_ops mxs_pcm_ops = {
243 .open = snd_mxs_open,
244 .close = snd_mxs_close,
245 .ioctl = snd_pcm_lib_ioctl,
246 .hw_params = snd_mxs_pcm_hw_params,
247 .hw_free = snd_mxs_pcm_hw_free,
248 .trigger = snd_mxs_pcm_trigger,
249 .pointer = snd_mxs_pcm_pointer,
250 .mmap = snd_mxs_pcm_mmap,
251};
252
253static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
254{
255 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
256 struct snd_dma_buffer *buf = &substream->dma_buffer;
257 size_t size = snd_mxs_hardware.buffer_bytes_max;
258
259 buf->dev.type = SNDRV_DMA_TYPE_DEV;
260 buf->dev.dev = pcm->card->dev;
261 buf->private_data = NULL;
262 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
263 &buf->addr, GFP_KERNEL);
264 if (!buf->area)
265 return -ENOMEM;
266 buf->bytes = size;
267
268 return 0;
269}
270
271static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32);
272static int mxs_pcm_new(struct snd_soc_pcm_runtime *rtd)
273{
274 struct snd_card *card = rtd->card->snd_card;
275 struct snd_pcm *pcm = rtd->pcm;
276 int ret = 0;
277
278 if (!card->dev->dma_mask)
279 card->dev->dma_mask = &mxs_pcm_dmamask;
280 if (!card->dev->coherent_dma_mask)
281 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
282
283 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
284 ret = mxs_pcm_preallocate_dma_buffer(pcm,
285 SNDRV_PCM_STREAM_PLAYBACK);
286 if (ret)
287 goto out;
288 }
289
290 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
291 ret = mxs_pcm_preallocate_dma_buffer(pcm,
292 SNDRV_PCM_STREAM_CAPTURE);
293 if (ret)
294 goto out;
295 }
296
297out:
298 return ret;
299}
300
301static void mxs_pcm_free(struct snd_pcm *pcm)
302{
303 struct snd_pcm_substream *substream;
304 struct snd_dma_buffer *buf;
305 int stream;
306
307 for (stream = 0; stream < 2; stream++) {
308 substream = pcm->streams[stream].substream;
309 if (!substream)
310 continue;
311
312 buf = &substream->dma_buffer;
313 if (!buf->area)
314 continue;
315
316 dma_free_writecombine(pcm->card->dev, buf->bytes,
317 buf->area, buf->addr);
318 buf->area = NULL;
319 }
320}
321
322static struct snd_soc_platform_driver mxs_soc_platform = {
323 .ops = &mxs_pcm_ops,
324 .pcm_new = mxs_pcm_new,
325 .pcm_free = mxs_pcm_free,
326};
327
328static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
329{
330 return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
331}
332
333static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
334{
335 snd_soc_unregister_platform(&pdev->dev);
336
337 return 0;
338}
339
340static struct platform_driver mxs_pcm_driver = {
341 .driver = {
342 .name = "mxs-pcm-audio",
343 .owner = THIS_MODULE,
344 },
345 .probe = mxs_soc_platform_probe,
346 .remove = __devexit_p(mxs_soc_platform_remove),
347};
348
349static int __init snd_mxs_pcm_init(void)
350{
351 return platform_driver_register(&mxs_pcm_driver);
352}
353module_init(snd_mxs_pcm_init);
354
355static void __exit snd_mxs_pcm_exit(void)
356{
357 platform_driver_unregister(&mxs_pcm_driver);
358}
359module_exit(snd_mxs_pcm_exit);
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
new file mode 100644
index 000000000000..f55ac4f7a76a
--- /dev/null
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -0,0 +1,43 @@
1/*
2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#ifndef _MXS_PCM_H
20#define _MXS_PCM_H
21
22#include <mach/dma.h>
23
24struct mxs_pcm_dma_params {
25 int chan_irq;
26 int chan_num;
27};
28
29struct mxs_pcm_runtime_data {
30 int period_bytes;
31 int periods;
32 int dma;
33 unsigned long offset;
34 unsigned long size;
35 void *buf;
36 int period_time;
37 struct dma_async_tx_descriptor *desc;
38 struct dma_chan *dma_chan;
39 struct mxs_dma_data dma_data;
40 struct mxs_pcm_dma_params *dma_params;
41};
42
43#endif
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
new file mode 100644
index 000000000000..0b3adaec9f4c
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.c
@@ -0,0 +1,677 @@
1/*
2 * Copyright 2011 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/dma-mapping.h>
24#include <linux/clk.h>
25#include <linux/delay.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include <sound/soc.h>
30#include <mach/dma.h>
31#include <asm/mach-types.h>
32#include <mach/hardware.h>
33#include <mach/mxs.h>
34
35#include "mxs-saif.h"
36
37static struct mxs_saif *mxs_saif[2];
38
39static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
40 int clk_id, unsigned int freq, int dir)
41{
42 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
43
44 switch (clk_id) {
45 case MXS_SAIF_MCLK:
46 saif->mclk = freq;
47 break;
48 default:
49 return -EINVAL;
50 }
51 return 0;
52}
53
54/*
55 * Set SAIF clock and MCLK
56 */
57static int mxs_saif_set_clk(struct mxs_saif *saif,
58 unsigned int mclk,
59 unsigned int rate)
60{
61 u32 scr;
62 int ret;
63
64 scr = __raw_readl(saif->base + SAIF_CTRL);
65 scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE;
66 scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
67
68 /*
69 * Set SAIF clock
70 *
71 * The SAIF clock should be either 384*fs or 512*fs.
72 * If MCLK is used, the SAIF clk ratio need to match mclk ratio.
73 * For 32x mclk, set saif clk as 512*fs.
74 * For 48x mclk, set saif clk as 384*fs.
75 *
76 * If MCLK is not used, we just set saif clk to 512*fs.
77 */
78 if (saif->mclk_in_use) {
79 if (mclk % 32 == 0) {
80 scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
81 ret = clk_set_rate(saif->clk, 512 * rate);
82 } else if (mclk % 48 == 0) {
83 scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE;
84 ret = clk_set_rate(saif->clk, 384 * rate);
85 } else {
86 /* SAIF MCLK should be either 32x or 48x */
87 return -EINVAL;
88 }
89 } else {
90 ret = clk_set_rate(saif->clk, 512 * rate);
91 scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE;
92 }
93
94 if (ret)
95 return ret;
96
97 if (!saif->mclk_in_use) {
98 __raw_writel(scr, saif->base + SAIF_CTRL);
99 return 0;
100 }
101
102 /*
103 * Program the over-sample rate for MCLK output
104 *
105 * The available MCLK range is 32x, 48x... 512x. The rate
106 * could be from 8kHz to 192kH.
107 */
108 switch (mclk / rate) {
109 case 32:
110 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4);
111 break;
112 case 64:
113 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
114 break;
115 case 128:
116 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
117 break;
118 case 256:
119 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
120 break;
121 case 512:
122 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
123 break;
124 case 48:
125 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3);
126 break;
127 case 96:
128 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2);
129 break;
130 case 192:
131 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1);
132 break;
133 case 384:
134 scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0);
135 break;
136 default:
137 return -EINVAL;
138 }
139
140 __raw_writel(scr, saif->base + SAIF_CTRL);
141
142 return 0;
143}
144
145/*
146 * Put and disable MCLK.
147 */
148int mxs_saif_put_mclk(unsigned int saif_id)
149{
150 struct mxs_saif *saif = mxs_saif[saif_id];
151 u32 stat;
152
153 if (!saif)
154 return -EINVAL;
155
156 stat = __raw_readl(saif->base + SAIF_STAT);
157 if (stat & BM_SAIF_STAT_BUSY) {
158 dev_err(saif->dev, "error: busy\n");
159 return -EBUSY;
160 }
161
162 clk_disable(saif->clk);
163
164 /* disable MCLK output */
165 __raw_writel(BM_SAIF_CTRL_CLKGATE,
166 saif->base + SAIF_CTRL + MXS_SET_ADDR);
167 __raw_writel(BM_SAIF_CTRL_RUN,
168 saif->base + SAIF_CTRL + MXS_CLR_ADDR);
169
170 saif->mclk_in_use = 0;
171 return 0;
172}
173
174/*
175 * Get MCLK and set clock rate, then enable it
176 *
177 * This interface is used for codecs who are using MCLK provided
178 * by saif.
179 */
180int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
181 unsigned int rate)
182{
183 struct mxs_saif *saif = mxs_saif[saif_id];
184 u32 stat;
185 int ret;
186
187 if (!saif)
188 return -EINVAL;
189
190 stat = __raw_readl(saif->base + SAIF_STAT);
191 if (stat & BM_SAIF_STAT_BUSY) {
192 dev_err(saif->dev, "error: busy\n");
193 return -EBUSY;
194 }
195
196 /* Clear Reset */
197 __raw_writel(BM_SAIF_CTRL_SFTRST,
198 saif->base + SAIF_CTRL + MXS_CLR_ADDR);
199
200 saif->mclk_in_use = 1;
201 ret = mxs_saif_set_clk(saif, mclk, rate);
202 if (ret)
203 return ret;
204
205 ret = clk_enable(saif->clk);
206 if (ret)
207 return ret;
208
209 /* enable MCLK output */
210 __raw_writel(BM_SAIF_CTRL_CLKGATE,
211 saif->base + SAIF_CTRL + MXS_CLR_ADDR);
212 __raw_writel(BM_SAIF_CTRL_RUN,
213 saif->base + SAIF_CTRL + MXS_SET_ADDR);
214
215 return 0;
216}
217
218/*
219 * SAIF DAI format configuration.
220 * Should only be called when port is inactive.
221 */
222static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
223{
224 u32 scr, stat;
225 u32 scr0;
226 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
227
228 stat = __raw_readl(saif->base + SAIF_STAT);
229 if (stat & BM_SAIF_STAT_BUSY) {
230 dev_err(cpu_dai->dev, "error: busy\n");
231 return -EBUSY;
232 }
233
234 scr0 = __raw_readl(saif->base + SAIF_CTRL);
235 scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \
236 & ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY;
237 scr = 0;
238
239 /* DAI mode */
240 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
241 case SND_SOC_DAIFMT_I2S:
242 /* data frame low 1clk before data */
243 scr |= BM_SAIF_CTRL_DELAY;
244 scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
245 break;
246 case SND_SOC_DAIFMT_LEFT_J:
247 /* data frame high with data */
248 scr &= ~BM_SAIF_CTRL_DELAY;
249 scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
250 scr &= ~BM_SAIF_CTRL_JUSTIFY;
251 break;
252 default:
253 return -EINVAL;
254 }
255
256 /* DAI clock inversion */
257 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
258 case SND_SOC_DAIFMT_IB_IF:
259 scr |= BM_SAIF_CTRL_BITCLK_EDGE;
260 scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
261 break;
262 case SND_SOC_DAIFMT_IB_NF:
263 scr |= BM_SAIF_CTRL_BITCLK_EDGE;
264 scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
265 break;
266 case SND_SOC_DAIFMT_NB_IF:
267 scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
268 scr |= BM_SAIF_CTRL_LRCLK_POLARITY;
269 break;
270 case SND_SOC_DAIFMT_NB_NF:
271 scr &= ~BM_SAIF_CTRL_BITCLK_EDGE;
272 scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY;
273 break;
274 }
275
276 /*
277 * Note: We simply just support master mode since SAIF TX can only
278 * work as master.
279 */
280 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
281 case SND_SOC_DAIFMT_CBS_CFS:
282 scr &= ~BM_SAIF_CTRL_SLAVE_MODE;
283 __raw_writel(scr | scr0, saif->base + SAIF_CTRL);
284 break;
285 default:
286 return -EINVAL;
287 }
288
289 return 0;
290}
291
292static int mxs_saif_startup(struct snd_pcm_substream *substream,
293 struct snd_soc_dai *cpu_dai)
294{
295 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
296 snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param);
297
298 /* clear error status to 0 for each re-open */
299 saif->fifo_underrun = 0;
300 saif->fifo_overrun = 0;
301
302 /* Clear Reset for normal operations */
303 __raw_writel(BM_SAIF_CTRL_SFTRST,
304 saif->base + SAIF_CTRL + MXS_CLR_ADDR);
305
306 return 0;
307}
308
309/*
310 * Should only be called when port is inactive.
311 * although can be called multiple times by upper layers.
312 */
313static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
314 struct snd_pcm_hw_params *params,
315 struct snd_soc_dai *cpu_dai)
316{
317 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
318 u32 scr, stat;
319 int ret;
320
321 /* mclk should already be set */
322 if (!saif->mclk && saif->mclk_in_use) {
323 dev_err(cpu_dai->dev, "set mclk first\n");
324 return -EINVAL;
325 }
326
327 stat = __raw_readl(saif->base + SAIF_STAT);
328 if (stat & BM_SAIF_STAT_BUSY) {
329 dev_err(cpu_dai->dev, "error: busy\n");
330 return -EBUSY;
331 }
332
333 /*
334 * Set saif clk based on sample rate.
335 * If mclk is used, we also set mclk, if not, saif->mclk is
336 * default 0, means not used.
337 */
338 ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params));
339 if (ret) {
340 dev_err(cpu_dai->dev, "unable to get proper clk\n");
341 return ret;
342 }
343
344 scr = __raw_readl(saif->base + SAIF_CTRL);
345
346 scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
347 scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
348 switch (params_format(params)) {
349 case SNDRV_PCM_FORMAT_S16_LE:
350 scr |= BF_SAIF_CTRL_WORD_LENGTH(0);
351 break;
352 case SNDRV_PCM_FORMAT_S20_3LE:
353 scr |= BF_SAIF_CTRL_WORD_LENGTH(4);
354 scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
355 break;
356 case SNDRV_PCM_FORMAT_S24_LE:
357 scr |= BF_SAIF_CTRL_WORD_LENGTH(8);
358 scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE;
359 break;
360 default:
361 return -EINVAL;
362 }
363
364 /* Tx/Rx config */
365 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
366 /* enable TX mode */
367 scr &= ~BM_SAIF_CTRL_READ_MODE;
368 } else {
369 /* enable RX mode */
370 scr |= BM_SAIF_CTRL_READ_MODE;
371 }
372
373 __raw_writel(scr, saif->base + SAIF_CTRL);
374 return 0;
375}
376
377static int mxs_saif_prepare(struct snd_pcm_substream *substream,
378 struct snd_soc_dai *cpu_dai)
379{
380 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
381
382 /* clear clock gate */
383 __raw_writel(BM_SAIF_CTRL_CLKGATE,
384 saif->base + SAIF_CTRL + MXS_CLR_ADDR);
385
386 /* enable FIFO error irqs */
387 __raw_writel(BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN,
388 saif->base + SAIF_CTRL + MXS_SET_ADDR);
389
390 return 0;
391}
392
393static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
394 struct snd_soc_dai *cpu_dai)
395{
396 struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
397
398 switch (cmd) {
399 case SNDRV_PCM_TRIGGER_START:
400 case SNDRV_PCM_TRIGGER_RESUME:
401 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
402 dev_dbg(cpu_dai->dev, "start\n");
403
404 clk_enable(saif->clk);
405 if (!saif->mclk_in_use)
406 __raw_writel(BM_SAIF_CTRL_RUN,
407 saif->base + SAIF_CTRL + MXS_SET_ADDR);
408
409 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
410 /*
411 * write a data to saif data register to trigger
412 * the transfer
413 */
414 __raw_writel(0, saif->base + SAIF_DATA);
415 } else {
416 /*
417 * read a data from saif data register to trigger
418 * the receive
419 */
420 __raw_readl(saif->base + SAIF_DATA);
421 }
422
423 dev_dbg(cpu_dai->dev, "CTRL 0x%x STAT 0x%x\n",
424 __raw_readl(saif->base + SAIF_CTRL),
425 __raw_readl(saif->base + SAIF_STAT));
426
427 break;
428 case SNDRV_PCM_TRIGGER_SUSPEND:
429 case SNDRV_PCM_TRIGGER_STOP:
430 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
431 dev_dbg(cpu_dai->dev, "stop\n");
432
433 clk_disable(saif->clk);
434 if (!saif->mclk_in_use)
435 __raw_writel(BM_SAIF_CTRL_RUN,
436 saif->base + SAIF_CTRL + MXS_CLR_ADDR);
437
438 break;
439 default:
440 return -EINVAL;
441 }
442
443 return 0;
444}
445
446#define MXS_SAIF_RATES SNDRV_PCM_RATE_8000_192000
447#define MXS_SAIF_FORMATS \
448 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
449 SNDRV_PCM_FMTBIT_S24_LE)
450
451static struct snd_soc_dai_ops mxs_saif_dai_ops = {
452 .startup = mxs_saif_startup,
453 .trigger = mxs_saif_trigger,
454 .prepare = mxs_saif_prepare,
455 .hw_params = mxs_saif_hw_params,
456 .set_sysclk = mxs_saif_set_dai_sysclk,
457 .set_fmt = mxs_saif_set_dai_fmt,
458};
459
460static int mxs_saif_dai_probe(struct snd_soc_dai *dai)
461{
462 struct mxs_saif *saif = dev_get_drvdata(dai->dev);
463
464 snd_soc_dai_set_drvdata(dai, saif);
465
466 return 0;
467}
468
469static struct snd_soc_dai_driver mxs_saif_dai = {
470 .name = "mxs-saif",
471 .probe = mxs_saif_dai_probe,
472 .playback = {
473 .channels_min = 2,
474 .channels_max = 2,
475 .rates = MXS_SAIF_RATES,
476 .formats = MXS_SAIF_FORMATS,
477 },
478 .capture = {
479 .channels_min = 2,
480 .channels_max = 2,
481 .rates = MXS_SAIF_RATES,
482 .formats = MXS_SAIF_FORMATS,
483 },
484 .ops = &mxs_saif_dai_ops,
485};
486
487static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
488{
489 struct mxs_saif *saif = dev_id;
490 unsigned int stat;
491
492 stat = __raw_readl(saif->base + SAIF_STAT);
493 if (!(stat & (BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ |
494 BM_SAIF_STAT_FIFO_OVERFLOW_IRQ)))
495 return IRQ_NONE;
496
497 if (stat & BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ) {
498 dev_dbg(saif->dev, "underrun!!! %d\n", ++saif->fifo_underrun);
499 __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ,
500 saif->base + SAIF_STAT + MXS_CLR_ADDR);
501 }
502
503 if (stat & BM_SAIF_STAT_FIFO_OVERFLOW_IRQ) {
504 dev_dbg(saif->dev, "overrun!!! %d\n", ++saif->fifo_overrun);
505 __raw_writel(BM_SAIF_STAT_FIFO_OVERFLOW_IRQ,
506 saif->base + SAIF_STAT + MXS_CLR_ADDR);
507 }
508
509 dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n",
510 __raw_readl(saif->base + SAIF_CTRL),
511 __raw_readl(saif->base + SAIF_STAT));
512
513 return IRQ_HANDLED;
514}
515
516static int mxs_saif_probe(struct platform_device *pdev)
517{
518 struct resource *res;
519 struct mxs_saif *saif;
520 int ret = 0;
521
522 saif = kzalloc(sizeof(*saif), GFP_KERNEL);
523 if (!saif)
524 return -ENOMEM;
525
526 if (pdev->id >= ARRAY_SIZE(mxs_saif))
527 return -EINVAL;
528 mxs_saif[pdev->id] = saif;
529
530 saif->clk = clk_get(&pdev->dev, NULL);
531 if (IS_ERR(saif->clk)) {
532 ret = PTR_ERR(saif->clk);
533 dev_err(&pdev->dev, "Cannot get the clock: %d\n",
534 ret);
535 goto failed_clk;
536 }
537
538 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
539 if (!res) {
540 ret = -ENODEV;
541 dev_err(&pdev->dev, "failed to get io resource: %d\n",
542 ret);
543 goto failed_get_resource;
544 }
545
546 if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) {
547 dev_err(&pdev->dev, "request_mem_region failed\n");
548 ret = -EBUSY;
549 goto failed_get_resource;
550 }
551
552 saif->base = ioremap(res->start, resource_size(res));
553 if (!saif->base) {
554 dev_err(&pdev->dev, "ioremap failed\n");
555 ret = -ENODEV;
556 goto failed_ioremap;
557 }
558
559 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
560 if (!res) {
561 ret = -ENODEV;
562 dev_err(&pdev->dev, "failed to get dma resource: %d\n",
563 ret);
564 goto failed_ioremap;
565 }
566 saif->dma_param.chan_num = res->start;
567
568 saif->irq = platform_get_irq(pdev, 0);
569 if (saif->irq < 0) {
570 ret = saif->irq;
571 dev_err(&pdev->dev, "failed to get irq resource: %d\n",
572 ret);
573 goto failed_get_irq1;
574 }
575
576 saif->dev = &pdev->dev;
577 ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif);
578 if (ret) {
579 dev_err(&pdev->dev, "failed to request irq\n");
580 goto failed_get_irq1;
581 }
582
583 saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
584 if (saif->dma_param.chan_irq < 0) {
585 ret = saif->dma_param.chan_irq;
586 dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
587 ret);
588 goto failed_get_irq2;
589 }
590
591 platform_set_drvdata(pdev, saif);
592
593 ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
594 if (ret) {
595 dev_err(&pdev->dev, "register DAI failed\n");
596 goto failed_register;
597 }
598
599 saif->soc_platform_pdev = platform_device_alloc(
600 "mxs-pcm-audio", pdev->id);
601 if (!saif->soc_platform_pdev) {
602 ret = -ENOMEM;
603 goto failed_pdev_alloc;
604 }
605
606 platform_set_drvdata(saif->soc_platform_pdev, saif);
607 ret = platform_device_add(saif->soc_platform_pdev);
608 if (ret) {
609 dev_err(&pdev->dev, "failed to add soc platform device\n");
610 goto failed_pdev_add;
611 }
612
613 return 0;
614
615failed_pdev_add:
616 platform_device_put(saif->soc_platform_pdev);
617failed_pdev_alloc:
618 snd_soc_unregister_dai(&pdev->dev);
619failed_register:
620failed_get_irq2:
621 free_irq(saif->irq, saif);
622failed_get_irq1:
623 iounmap(saif->base);
624failed_ioremap:
625 release_mem_region(res->start, resource_size(res));
626failed_get_resource:
627 clk_put(saif->clk);
628failed_clk:
629 kfree(saif);
630
631 return ret;
632}
633
634static int __devexit mxs_saif_remove(struct platform_device *pdev)
635{
636 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
637 struct mxs_saif *saif = platform_get_drvdata(pdev);
638
639 platform_device_unregister(saif->soc_platform_pdev);
640
641 snd_soc_unregister_dai(&pdev->dev);
642
643 iounmap(saif->base);
644 release_mem_region(res->start, resource_size(res));
645 free_irq(saif->irq, saif);
646
647 clk_put(saif->clk);
648 kfree(saif);
649
650 return 0;
651}
652
653static struct platform_driver mxs_saif_driver = {
654 .probe = mxs_saif_probe,
655 .remove = __devexit_p(mxs_saif_remove),
656
657 .driver = {
658 .name = "mxs-saif",
659 .owner = THIS_MODULE,
660 },
661};
662
663static int __init mxs_saif_init(void)
664{
665 return platform_driver_register(&mxs_saif_driver);
666}
667
668static void __exit mxs_saif_exit(void)
669{
670 platform_driver_unregister(&mxs_saif_driver);
671}
672
673module_init(mxs_saif_init);
674module_exit(mxs_saif_exit);
675MODULE_AUTHOR("Freescale Semiconductor, Inc.");
676MODULE_DESCRIPTION("MXS ASoC SAIF driver");
677MODULE_LICENSE("GPL");
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
new file mode 100644
index 000000000000..0e2ff8cdbfee
--- /dev/null
+++ b/sound/soc/mxs/mxs-saif.h
@@ -0,0 +1,130 @@
1/*
2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19
20#ifndef _MXS_SAIF_H
21#define _MXS_SAIF_H
22
23#define SAIF_CTRL 0x0
24#define SAIF_STAT 0x10
25#define SAIF_DATA 0x20
26#define SAIF_VERSION 0X30
27
28/* SAIF_CTRL */
29#define BM_SAIF_CTRL_SFTRST 0x80000000
30#define BM_SAIF_CTRL_CLKGATE 0x40000000
31#define BP_SAIF_CTRL_BITCLK_MULT_RATE 27
32#define BM_SAIF_CTRL_BITCLK_MULT_RATE 0x38000000
33#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \
34 (((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE)
35#define BM_SAIF_CTRL_BITCLK_BASE_RATE 0x04000000
36#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN 0x02000000
37#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN 0x01000000
38#define BP_SAIF_CTRL_RSRVD2 21
39#define BM_SAIF_CTRL_RSRVD2 0x00E00000
40
41#define BP_SAIF_CTRL_DMAWAIT_COUNT 16
42#define BM_SAIF_CTRL_DMAWAIT_COUNT 0x001F0000
43#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \
44 (((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT)
45#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14
46#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000
47#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \
48 (((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT)
49#define BM_SAIF_CTRL_LRCLK_PULSE 0x00002000
50#define BM_SAIF_CTRL_BIT_ORDER 0x00001000
51#define BM_SAIF_CTRL_DELAY 0x00000800
52#define BM_SAIF_CTRL_JUSTIFY 0x00000400
53#define BM_SAIF_CTRL_LRCLK_POLARITY 0x00000200
54#define BM_SAIF_CTRL_BITCLK_EDGE 0x00000100
55#define BP_SAIF_CTRL_WORD_LENGTH 4
56#define BM_SAIF_CTRL_WORD_LENGTH 0x000000F0
57#define BF_SAIF_CTRL_WORD_LENGTH(v) \
58 (((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH)
59#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE 0x00000008
60#define BM_SAIF_CTRL_SLAVE_MODE 0x00000004
61#define BM_SAIF_CTRL_READ_MODE 0x00000002
62#define BM_SAIF_CTRL_RUN 0x00000001
63
64/* SAIF_STAT */
65#define BM_SAIF_STAT_PRESENT 0x80000000
66#define BP_SAIF_STAT_RSRVD2 17
67#define BM_SAIF_STAT_RSRVD2 0x7FFE0000
68#define BF_SAIF_STAT_RSRVD2(v) \
69 (((v) << 17) & BM_SAIF_STAT_RSRVD2)
70#define BM_SAIF_STAT_DMA_PREQ 0x00010000
71#define BP_SAIF_STAT_RSRVD1 7
72#define BM_SAIF_STAT_RSRVD1 0x0000FF80
73#define BF_SAIF_STAT_RSRVD1(v) \
74 (((v) << 7) & BM_SAIF_STAT_RSRVD1)
75
76#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040
77#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ 0x00000020
78#define BM_SAIF_STAT_FIFO_SERVICE_IRQ 0x00000010
79#define BP_SAIF_STAT_RSRVD0 1
80#define BM_SAIF_STAT_RSRVD0 0x0000000E
81#define BF_SAIF_STAT_RSRVD0(v) \
82 (((v) << 1) & BM_SAIF_STAT_RSRVD0)
83#define BM_SAIF_STAT_BUSY 0x00000001
84
85/* SAFI_DATA */
86#define BP_SAIF_DATA_PCM_RIGHT 16
87#define BM_SAIF_DATA_PCM_RIGHT 0xFFFF0000
88#define BF_SAIF_DATA_PCM_RIGHT(v) \
89 (((v) << 16) & BM_SAIF_DATA_PCM_RIGHT)
90#define BP_SAIF_DATA_PCM_LEFT 0
91#define BM_SAIF_DATA_PCM_LEFT 0x0000FFFF
92#define BF_SAIF_DATA_PCM_LEFT(v) \
93 (((v) << 0) & BM_SAIF_DATA_PCM_LEFT)
94
95/* SAIF_VERSION */
96#define BP_SAIF_VERSION_MAJOR 24
97#define BM_SAIF_VERSION_MAJOR 0xFF000000
98#define BF_SAIF_VERSION_MAJOR(v) \
99 (((v) << 24) & BM_SAIF_VERSION_MAJOR)
100#define BP_SAIF_VERSION_MINOR 16
101#define BM_SAIF_VERSION_MINOR 0x00FF0000
102#define BF_SAIF_VERSION_MINOR(v) \
103 (((v) << 16) & BM_SAIF_VERSION_MINOR)
104#define BP_SAIF_VERSION_STEP 0
105#define BM_SAIF_VERSION_STEP 0x0000FFFF
106#define BF_SAIF_VERSION_STEP(v) \
107 (((v) << 0) & BM_SAIF_VERSION_STEP)
108
109#define MXS_SAIF_MCLK 0
110
111#include "mxs-pcm.h"
112
113struct mxs_saif {
114 struct device *dev;
115 struct clk *clk;
116 unsigned int mclk;
117 unsigned int mclk_in_use;
118 void __iomem *base;
119 int irq;
120 struct mxs_pcm_dma_params dma_param;
121
122 struct platform_device *soc_platform_pdev;
123 u32 fifo_underrun;
124 u32 fifo_overrun;
125};
126
127extern int mxs_saif_put_mclk(unsigned int saif_id);
128extern int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk,
129 unsigned int rate);
130#endif
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
new file mode 100644
index 000000000000..a0d89c93df0f
--- /dev/null
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -0,0 +1,165 @@
1/*
2 * Copyright 2011 Freescale Semiconductor, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include <linux/module.h>
20#include <linux/device.h>
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/soc.h>
24#include <sound/jack.h>
25#include <sound/soc-dapm.h>
26#include <asm/mach-types.h>
27
28#include "../codecs/sgtl5000.h"
29#include "mxs-saif.h"
30
31static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
32 struct snd_pcm_hw_params *params)
33{
34 struct snd_soc_pcm_runtime *rtd = substream->private_data;
35 struct snd_soc_dai *codec_dai = rtd->codec_dai;
36 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
37 unsigned int rate = params_rate(params);
38 u32 dai_format, mclk;
39 int ret;
40
41 /* sgtl5000 does not support 512*rate when in 96000 fs */
42 switch (rate) {
43 case 96000:
44 mclk = 256 * rate;
45 break;
46 default:
47 mclk = 512 * rate;
48 break;
49 }
50
51 /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */
52 if (mclk < 8000000 || mclk > 27000000)
53 return -EINVAL;
54
55 /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */
56 ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0);
57 if (ret)
58 return ret;
59
60 /* The SAIF MCLK should be the same as SGTL5000_SYSCLK */
61 ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0);
62 if (ret)
63 return ret;
64
65 /* set codec to slave mode */
66 dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
67 SND_SOC_DAIFMT_CBS_CFS;
68
69 /* set codec DAI configuration */
70 ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
71 if (ret)
72 return ret;
73
74 /* set cpu DAI configuration */
75 ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
76 if (ret)
77 return ret;
78
79 return 0;
80}
81
82static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
83 .hw_params = mxs_sgtl5000_hw_params,
84};
85
86static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
87 {
88 .name = "HiFi",
89 .stream_name = "HiFi Playback",
90 .codec_dai_name = "sgtl5000",
91 .codec_name = "sgtl5000.0-000a",
92 .cpu_dai_name = "mxs-saif.0",
93 .platform_name = "mxs-pcm-audio.0",
94 .ops = &mxs_sgtl5000_hifi_ops,
95 },
96};
97
98static struct snd_soc_card mxs_sgtl5000 = {
99 .name = "mxs_sgtl5000",
100 .dai_link = mxs_sgtl5000_dai,
101 .num_links = ARRAY_SIZE(mxs_sgtl5000_dai),
102};
103
104static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
105{
106 struct snd_soc_card *card = &mxs_sgtl5000;
107 int ret;
108
109 /*
110 * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
111 * The Sgtl5000 sysclk is derived from saif0 mclk and it's range
112 * should be >= 8MHz and <= 27M.
113 */
114 ret = mxs_saif_get_mclk(0, 44100 * 256, 44100);
115 if (ret)
116 return ret;
117
118 card->dev = &pdev->dev;
119 platform_set_drvdata(pdev, card);
120
121 ret = snd_soc_register_card(card);
122 if (ret) {
123 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
124 ret);
125 return ret;
126 }
127
128 return 0;
129}
130
131static int __devexit mxs_sgtl5000_remove(struct platform_device *pdev)
132{
133 struct snd_soc_card *card = platform_get_drvdata(pdev);
134
135 mxs_saif_put_mclk(0);
136
137 snd_soc_unregister_card(card);
138
139 return 0;
140}
141
142static struct platform_driver mxs_sgtl5000_audio_driver = {
143 .driver = {
144 .name = "mxs-sgtl5000",
145 .owner = THIS_MODULE,
146 },
147 .probe = mxs_sgtl5000_probe,
148 .remove = __devexit_p(mxs_sgtl5000_remove),
149};
150
151static int __init mxs_sgtl5000_init(void)
152{
153 return platform_driver_register(&mxs_sgtl5000_audio_driver);
154}
155module_init(mxs_sgtl5000_init);
156
157static void __exit mxs_sgtl5000_exit(void)
158{
159 platform_driver_unregister(&mxs_sgtl5000_audio_driver);
160}
161module_exit(mxs_sgtl5000_exit);
162
163MODULE_AUTHOR("Freescale Semiconductor, Inc.");
164MODULE_DESCRIPTION("MXS ALSA SoC Machine driver");
165MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 83ad8ca27490..ae93aa81244c 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -105,7 +105,7 @@ static int format_register_str(struct snd_soc_codec *codec,
105 if (wordsize + regsize + 2 + 1 != len) 105 if (wordsize + regsize + 2 + 1 != len)
106 return -EINVAL; 106 return -EINVAL;
107 107
108 ret = snd_soc_read(codec , reg); 108 ret = snd_soc_read(codec, reg);
109 if (ret < 0) { 109 if (ret < 0) {
110 memset(regbuf, 'X', regsize); 110 memset(regbuf, 'X', regsize);
111 regbuf[regsize] = '\0'; 111 regbuf[regsize] = '\0';
@@ -3141,6 +3141,7 @@ int snd_soc_register_platform(struct device *dev,
3141 platform->driver = platform_drv; 3141 platform->driver = platform_drv;
3142 platform->dapm.dev = dev; 3142 platform->dapm.dev = dev;
3143 platform->dapm.platform = platform; 3143 platform->dapm.platform = platform;
3144 platform->dapm.stream_event = platform_drv->stream_event;
3144 3145
3145 mutex_lock(&client_mutex); 3146 mutex_lock(&client_mutex);
3146 list_add(&platform->list, &platform_list); 3147 list_add(&platform->list, &platform_list);
@@ -3253,6 +3254,7 @@ int snd_soc_register_codec(struct device *dev,
3253 codec->dapm.dev = dev; 3254 codec->dapm.dev = dev;
3254 codec->dapm.codec = codec; 3255 codec->dapm.codec = codec;
3255 codec->dapm.seq_notifier = codec_drv->seq_notifier; 3256 codec->dapm.seq_notifier = codec_drv->seq_notifier;
3257 codec->dapm.stream_event = codec_drv->stream_event;
3256 codec->dev = dev; 3258 codec->dev = dev;
3257 codec->driver = codec_drv; 3259 codec->driver = codec_drv;
3258 codec->num_dai = num_dai; 3260 codec->num_dai = num_dai;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7e15914b3633..c26531132c66 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2584,7 +2584,7 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
2584 { 2584 {
2585 if (!w->sname || w->dapm != dapm) 2585 if (!w->sname || w->dapm != dapm)
2586 continue; 2586 continue;
2587 dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", 2587 dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
2588 w->name, w->sname, stream, event); 2588 w->name, w->sname, stream, event);
2589 if (strstr(w->sname, stream)) { 2589 if (strstr(w->sname, stream)) {
2590 switch(event) { 2590 switch(event) {
@@ -2604,6 +2604,10 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
2604 } 2604 }
2605 2605
2606 dapm_power_widgets(dapm, event); 2606 dapm_power_widgets(dapm, event);
2607
2608 /* do we need to notify any clients that DAPM stream is complete */
2609 if (dapm->stream_event)
2610 dapm->stream_event(dapm, event);
2607} 2611}
2608 2612
2609/** 2613/**