aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/cirrus
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/cirrus')
-rw-r--r--sound/soc/cirrus/Kconfig42
-rw-r--r--sound/soc/cirrus/Makefile17
-rw-r--r--sound/soc/cirrus/edb93xx.c128
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c435
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c451
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c242
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.h20
-rw-r--r--sound/soc/cirrus/simone.c90
-rw-r--r--sound/soc/cirrus/snappercl15.c146
9 files changed, 1571 insertions, 0 deletions
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
new file mode 100644
index 000000000000..88143db7e753
--- /dev/null
+++ b/sound/soc/cirrus/Kconfig
@@ -0,0 +1,42 @@
1config SND_EP93XX_SOC
2 tristate "SoC Audio support for the Cirrus Logic EP93xx series"
3 depends on ARCH_EP93XX && SND_SOC
4 select SND_SOC_DMAENGINE_PCM
5 help
6 Say Y or M if you want to add support for codecs attached to
7 the EP93xx I2S or AC97 interfaces.
8
9config SND_EP93XX_SOC_I2S
10 tristate
11
12config SND_EP93XX_SOC_AC97
13 tristate
14 select AC97_BUS
15 select SND_SOC_AC97_BUS
16
17config SND_EP93XX_SOC_SNAPPERCL15
18 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
19 depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
20 select SND_EP93XX_SOC_I2S
21 select SND_SOC_TLV320AIC23
22 help
23 Say Y or M here if you want to add support for I2S audio on the
24 Bluewater Systems Snapper CL15 module.
25
26config SND_EP93XX_SOC_SIMONE
27 tristate "SoC Audio support for Simplemachines Sim.One board"
28 depends on SND_EP93XX_SOC && MACH_SIM_ONE
29 select SND_EP93XX_SOC_AC97
30 select SND_SOC_AC97_CODEC
31 help
32 Say Y or M here if you want to add support for AC97 audio on the
33 Simplemachines Sim.One board.
34
35config SND_EP93XX_SOC_EDB93XX
36 tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
37 depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
38 select SND_EP93XX_SOC_I2S
39 select SND_SOC_CS4271
40 help
41 Say Y or M here if you want to add support for I2S audio on the
42 Cirrus Logic EDB93xx boards.
diff --git a/sound/soc/cirrus/Makefile b/sound/soc/cirrus/Makefile
new file mode 100644
index 000000000000..5514146cbdf0
--- /dev/null
+++ b/sound/soc/cirrus/Makefile
@@ -0,0 +1,17 @@
1# EP93xx Platform Support
2snd-soc-ep93xx-objs := ep93xx-pcm.o
3snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
4snd-soc-ep93xx-ac97-objs := ep93xx-ac97.o
5
6obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
7obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
8obj-$(CONFIG_SND_EP93XX_SOC_AC97) += snd-soc-ep93xx-ac97.o
9
10# EP93XX Machine Support
11snd-soc-snappercl15-objs := snappercl15.o
12snd-soc-simone-objs := simone.o
13snd-soc-edb93xx-objs := edb93xx.o
14
15obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o
16obj-$(CONFIG_SND_EP93XX_SOC_SIMONE) += snd-soc-simone.o
17obj-$(CONFIG_SND_EP93XX_SOC_EDB93XX) += snd-soc-edb93xx.o
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
new file mode 100644
index 000000000000..e01cb02abd3a
--- /dev/null
+++ b/sound/soc/cirrus/edb93xx.c
@@ -0,0 +1,128 @@
1/*
2 * SoC audio for EDB93xx
3 *
4 * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (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 * This driver support CS4271 codec being master or slave, working
17 * in control port mode, connected either via SPI or I2C.
18 * The data format accepted is I2S or left-justified.
19 * DAPM support not implemented.
20 */
21
22#include <linux/platform_device.h>
23#include <linux/gpio.h>
24#include <linux/module.h>
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/soc.h>
28#include <asm/mach-types.h>
29#include <mach/hardware.h>
30#include "ep93xx-pcm.h"
31
32static int edb93xx_hw_params(struct snd_pcm_substream *substream,
33 struct snd_pcm_hw_params *params)
34{
35 struct snd_soc_pcm_runtime *rtd = substream->private_data;
36 struct snd_soc_dai *codec_dai = rtd->codec_dai;
37 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
38 int err;
39 unsigned int mclk_rate;
40 unsigned int rate = params_rate(params);
41
42 /*
43 * According to CS4271 datasheet we use MCLK/LRCK=256 for
44 * rates below 50kHz and 128 for higher sample rates
45 */
46 if (rate < 50000)
47 mclk_rate = rate * 64 * 4;
48 else
49 mclk_rate = rate * 64 * 2;
50
51 err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
52 SND_SOC_CLOCK_IN);
53 if (err)
54 return err;
55
56 return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate,
57 SND_SOC_CLOCK_OUT);
58}
59
60static struct snd_soc_ops edb93xx_ops = {
61 .hw_params = edb93xx_hw_params,
62};
63
64static struct snd_soc_dai_link edb93xx_dai = {
65 .name = "CS4271",
66 .stream_name = "CS4271 HiFi",
67 .platform_name = "ep93xx-pcm-audio",
68 .cpu_dai_name = "ep93xx-i2s",
69 .codec_name = "spi0.0",
70 .codec_dai_name = "cs4271-hifi",
71 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
72 SND_SOC_DAIFMT_CBS_CFS,
73 .ops = &edb93xx_ops,
74};
75
76static struct snd_soc_card snd_soc_edb93xx = {
77 .name = "EDB93XX",
78 .owner = THIS_MODULE,
79 .dai_link = &edb93xx_dai,
80 .num_links = 1,
81};
82
83static int __devinit edb93xx_probe(struct platform_device *pdev)
84{
85 struct snd_soc_card *card = &snd_soc_edb93xx;
86 int ret;
87
88 ret = ep93xx_i2s_acquire();
89 if (ret)
90 return ret;
91
92 card->dev = &pdev->dev;
93
94 ret = snd_soc_register_card(card);
95 if (ret) {
96 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
97 ret);
98 ep93xx_i2s_release();
99 }
100
101 return ret;
102}
103
104static int __devexit edb93xx_remove(struct platform_device *pdev)
105{
106 struct snd_soc_card *card = platform_get_drvdata(pdev);
107
108 snd_soc_unregister_card(card);
109 ep93xx_i2s_release();
110
111 return 0;
112}
113
114static struct platform_driver edb93xx_driver = {
115 .driver = {
116 .name = "edb93xx-audio",
117 .owner = THIS_MODULE,
118 },
119 .probe = edb93xx_probe,
120 .remove = __devexit_p(edb93xx_remove),
121};
122
123module_platform_driver(edb93xx_driver);
124
125MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
126MODULE_DESCRIPTION("ALSA SoC EDB93xx");
127MODULE_LICENSE("GPL");
128MODULE_ALIAS("platform:edb93xx-audio");
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
new file mode 100644
index 000000000000..c3521653cfd3
--- /dev/null
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -0,0 +1,435 @@
1/*
2 * ASoC driver for Cirrus Logic EP93xx AC97 controller.
3 *
4 * Copyright (c) 2010 Mika Westerberg
5 *
6 * Based on s3c-ac97 ASoC driver by Jaswinder Singh.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/delay.h>
14#include <linux/io.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19
20#include <sound/core.h>
21#include <sound/ac97_codec.h>
22#include <sound/soc.h>
23
24#include <linux/platform_data/dma-ep93xx.h>
25#include "ep93xx-pcm.h"
26
27/*
28 * Per channel (1-4) registers.
29 */
30#define AC97CH(n) (((n) - 1) * 0x20)
31
32#define AC97DR(n) (AC97CH(n) + 0x0000)
33
34#define AC97RXCR(n) (AC97CH(n) + 0x0004)
35#define AC97RXCR_REN BIT(0)
36#define AC97RXCR_RX3 BIT(3)
37#define AC97RXCR_RX4 BIT(4)
38#define AC97RXCR_CM BIT(15)
39
40#define AC97TXCR(n) (AC97CH(n) + 0x0008)
41#define AC97TXCR_TEN BIT(0)
42#define AC97TXCR_TX3 BIT(3)
43#define AC97TXCR_TX4 BIT(4)
44#define AC97TXCR_CM BIT(15)
45
46#define AC97SR(n) (AC97CH(n) + 0x000c)
47#define AC97SR_TXFE BIT(1)
48#define AC97SR_TXUE BIT(6)
49
50#define AC97RISR(n) (AC97CH(n) + 0x0010)
51#define AC97ISR(n) (AC97CH(n) + 0x0014)
52#define AC97IE(n) (AC97CH(n) + 0x0018)
53
54/*
55 * Global AC97 controller registers.
56 */
57#define AC97S1DATA 0x0080
58#define AC97S2DATA 0x0084
59#define AC97S12DATA 0x0088
60
61#define AC97RGIS 0x008c
62#define AC97GIS 0x0090
63#define AC97IM 0x0094
64/*
65 * Common bits for RGIS, GIS and IM registers.
66 */
67#define AC97_SLOT2RXVALID BIT(1)
68#define AC97_CODECREADY BIT(5)
69#define AC97_SLOT2TXCOMPLETE BIT(6)
70
71#define AC97EOI 0x0098
72#define AC97EOI_WINT BIT(0)
73#define AC97EOI_CODECREADY BIT(1)
74
75#define AC97GCR 0x009c
76#define AC97GCR_AC97IFE BIT(0)
77
78#define AC97RESET 0x00a0
79#define AC97RESET_TIMEDRESET BIT(0)
80
81#define AC97SYNC 0x00a4
82#define AC97SYNC_TIMEDSYNC BIT(0)
83
84#define AC97_TIMEOUT msecs_to_jiffies(5)
85
86/**
87 * struct ep93xx_ac97_info - EP93xx AC97 controller info structure
88 * @lock: mutex serializing access to the bus (slot 1 & 2 ops)
89 * @dev: pointer to the platform device dev structure
90 * @regs: mapped AC97 controller registers
91 * @done: bus ops wait here for an interrupt
92 */
93struct ep93xx_ac97_info {
94 struct mutex lock;
95 struct device *dev;
96 void __iomem *regs;
97 struct completion done;
98};
99
100/* currently ALSA only supports a single AC97 device */
101static struct ep93xx_ac97_info *ep93xx_ac97_info;
102
103static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
104 .name = "ac97-pcm-out",
105 .dma_port = EP93XX_DMA_AAC1,
106};
107
108static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
109 .name = "ac97-pcm-in",
110 .dma_port = EP93XX_DMA_AAC1,
111};
112
113static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
114 unsigned reg)
115{
116 return __raw_readl(info->regs + reg);
117}
118
119static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info,
120 unsigned reg, unsigned val)
121{
122 __raw_writel(val, info->regs + reg);
123}
124
125static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97,
126 unsigned short reg)
127{
128 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
129 unsigned short val;
130
131 mutex_lock(&info->lock);
132
133 ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
134 ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID);
135 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) {
136 dev_warn(info->dev, "timeout reading register %x\n", reg);
137 mutex_unlock(&info->lock);
138 return -ETIMEDOUT;
139 }
140 val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA);
141
142 mutex_unlock(&info->lock);
143 return val;
144}
145
146static void ep93xx_ac97_write(struct snd_ac97 *ac97,
147 unsigned short reg,
148 unsigned short val)
149{
150 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
151
152 mutex_lock(&info->lock);
153
154 /*
155 * Writes to the codec need to be done so that slot 2 is filled in
156 * before slot 1.
157 */
158 ep93xx_ac97_write_reg(info, AC97S2DATA, val);
159 ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
160
161 ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE);
162 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
163 dev_warn(info->dev, "timeout writing register %x\n", reg);
164
165 mutex_unlock(&info->lock);
166}
167
168static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97)
169{
170 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
171
172 mutex_lock(&info->lock);
173
174 /*
175 * We are assuming that before this functions gets called, the codec
176 * BIT_CLK is stopped by forcing the codec into powerdown mode. We can
177 * control the SYNC signal directly via AC97SYNC register. Using
178 * TIMEDSYNC the controller will keep the SYNC high > 1us.
179 */
180 ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC);
181 ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
182 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
183 dev_warn(info->dev, "codec warm reset timeout\n");
184
185 mutex_unlock(&info->lock);
186}
187
188static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97)
189{
190 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
191
192 mutex_lock(&info->lock);
193
194 /*
195 * For doing cold reset, we disable the AC97 controller interface, clear
196 * WINT and CODECREADY bits, and finally enable the interface again.
197 */
198 ep93xx_ac97_write_reg(info, AC97GCR, 0);
199 ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT);
200 ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE);
201
202 /*
203 * Now, assert the reset and wait for the codec to become ready.
204 */
205 ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET);
206 ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
207 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
208 dev_warn(info->dev, "codec cold reset timeout\n");
209
210 /*
211 * Give the codec some time to come fully out from the reset. This way
212 * we ensure that the subsequent reads/writes will work.
213 */
214 usleep_range(15000, 20000);
215
216 mutex_unlock(&info->lock);
217}
218
219static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
220{
221 struct ep93xx_ac97_info *info = dev_id;
222 unsigned status, mask;
223
224 /*
225 * Just mask out the interrupt and wake up the waiting thread.
226 * Interrupts are cleared via reading/writing to slot 1 & 2 registers by
227 * the waiting thread.
228 */
229 status = ep93xx_ac97_read_reg(info, AC97GIS);
230 mask = ep93xx_ac97_read_reg(info, AC97IM);
231 mask &= ~status;
232 ep93xx_ac97_write_reg(info, AC97IM, mask);
233
234 complete(&info->done);
235 return IRQ_HANDLED;
236}
237
238struct snd_ac97_bus_ops soc_ac97_ops = {
239 .read = ep93xx_ac97_read,
240 .write = ep93xx_ac97_write,
241 .reset = ep93xx_ac97_cold_reset,
242 .warm_reset = ep93xx_ac97_warm_reset,
243};
244EXPORT_SYMBOL_GPL(soc_ac97_ops);
245
246static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
247 int cmd, struct snd_soc_dai *dai)
248{
249 struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
250 unsigned v = 0;
251
252 switch (cmd) {
253 case SNDRV_PCM_TRIGGER_START:
254 case SNDRV_PCM_TRIGGER_RESUME:
255 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
256 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
257 /*
258 * Enable compact mode, TX slots 3 & 4, and the TX FIFO
259 * itself.
260 */
261 v |= AC97TXCR_CM;
262 v |= AC97TXCR_TX3 | AC97TXCR_TX4;
263 v |= AC97TXCR_TEN;
264 ep93xx_ac97_write_reg(info, AC97TXCR(1), v);
265 } else {
266 /*
267 * Enable compact mode, RX slots 3 & 4, and the RX FIFO
268 * itself.
269 */
270 v |= AC97RXCR_CM;
271 v |= AC97RXCR_RX3 | AC97RXCR_RX4;
272 v |= AC97RXCR_REN;
273 ep93xx_ac97_write_reg(info, AC97RXCR(1), v);
274 }
275 break;
276
277 case SNDRV_PCM_TRIGGER_STOP:
278 case SNDRV_PCM_TRIGGER_SUSPEND:
279 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
280 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
281 /*
282 * As per Cirrus EP93xx errata described below:
283 *
284 * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf
285 *
286 * we will wait for the TX FIFO to be empty before
287 * clearing the TEN bit.
288 */
289 unsigned long timeout = jiffies + AC97_TIMEOUT;
290
291 do {
292 v = ep93xx_ac97_read_reg(info, AC97SR(1));
293 if (time_after(jiffies, timeout)) {
294 dev_warn(info->dev, "TX timeout\n");
295 break;
296 }
297 } while (!(v & (AC97SR_TXFE | AC97SR_TXUE)));
298
299 /* disable the TX FIFO */
300 ep93xx_ac97_write_reg(info, AC97TXCR(1), 0);
301 } else {
302 /* disable the RX FIFO */
303 ep93xx_ac97_write_reg(info, AC97RXCR(1), 0);
304 }
305 break;
306
307 default:
308 dev_warn(info->dev, "unknown command %d\n", cmd);
309 return -EINVAL;
310 }
311
312 return 0;
313}
314
315static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
316 struct snd_soc_dai *dai)
317{
318 struct ep93xx_pcm_dma_params *dma_data;
319
320 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
321 dma_data = &ep93xx_ac97_pcm_out;
322 else
323 dma_data = &ep93xx_ac97_pcm_in;
324
325 snd_soc_dai_set_dma_data(dai, substream, dma_data);
326 return 0;
327}
328
329static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
330 .startup = ep93xx_ac97_startup,
331 .trigger = ep93xx_ac97_trigger,
332};
333
334static struct snd_soc_dai_driver ep93xx_ac97_dai = {
335 .name = "ep93xx-ac97",
336 .id = 0,
337 .ac97_control = 1,
338 .playback = {
339 .stream_name = "AC97 Playback",
340 .channels_min = 2,
341 .channels_max = 2,
342 .rates = SNDRV_PCM_RATE_8000_48000,
343 .formats = SNDRV_PCM_FMTBIT_S16_LE,
344 },
345 .capture = {
346 .stream_name = "AC97 Capture",
347 .channels_min = 2,
348 .channels_max = 2,
349 .rates = SNDRV_PCM_RATE_8000_48000,
350 .formats = SNDRV_PCM_FMTBIT_S16_LE,
351 },
352 .ops = &ep93xx_ac97_dai_ops,
353};
354
355static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
356{
357 struct ep93xx_ac97_info *info;
358 struct resource *res;
359 unsigned int irq;
360 int ret;
361
362 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
363 if (!info)
364 return -ENOMEM;
365
366 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
367 if (!res)
368 return -ENODEV;
369
370 info->regs = devm_request_and_ioremap(&pdev->dev, res);
371 if (!info->regs)
372 return -ENXIO;
373
374 irq = platform_get_irq(pdev, 0);
375 if (!irq)
376 return -ENODEV;
377
378 ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
379 IRQF_TRIGGER_HIGH, pdev->name, info);
380 if (ret)
381 goto fail;
382
383 dev_set_drvdata(&pdev->dev, info);
384
385 mutex_init(&info->lock);
386 init_completion(&info->done);
387 info->dev = &pdev->dev;
388
389 ep93xx_ac97_info = info;
390 platform_set_drvdata(pdev, info);
391
392 ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
393 if (ret)
394 goto fail;
395
396 return 0;
397
398fail:
399 platform_set_drvdata(pdev, NULL);
400 ep93xx_ac97_info = NULL;
401 dev_set_drvdata(&pdev->dev, NULL);
402 return ret;
403}
404
405static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
406{
407 struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
408
409 snd_soc_unregister_dai(&pdev->dev);
410
411 /* disable the AC97 controller */
412 ep93xx_ac97_write_reg(info, AC97GCR, 0);
413
414 platform_set_drvdata(pdev, NULL);
415 ep93xx_ac97_info = NULL;
416 dev_set_drvdata(&pdev->dev, NULL);
417
418 return 0;
419}
420
421static struct platform_driver ep93xx_ac97_driver = {
422 .probe = ep93xx_ac97_probe,
423 .remove = __devexit_p(ep93xx_ac97_remove),
424 .driver = {
425 .name = "ep93xx-ac97",
426 .owner = THIS_MODULE,
427 },
428};
429
430module_platform_driver(ep93xx_ac97_driver);
431
432MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
433MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
434MODULE_LICENSE("GPL");
435MODULE_ALIAS("platform:ep93xx-ac97");
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
new file mode 100644
index 000000000000..ac4a7515e7be
--- /dev/null
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -0,0 +1,451 @@
1/*
2 * linux/sound/soc/ep93xx-i2s.c
3 * EP93xx I2S driver
4 *
5 * Copyright (C) 2010 Ryan Mallon
6 *
7 * Based on the original driver by:
8 * Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
9 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/clk.h>
21#include <linux/io.h>
22
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/initval.h>
27#include <sound/soc.h>
28
29#include <mach/hardware.h>
30#include <mach/ep93xx-regs.h>
31#include <linux/platform_data/dma-ep93xx.h>
32
33#include "ep93xx-pcm.h"
34
35#define EP93XX_I2S_TXCLKCFG 0x00
36#define EP93XX_I2S_RXCLKCFG 0x04
37#define EP93XX_I2S_GLCTRL 0x0C
38
39#define EP93XX_I2S_TXLINCTRLDATA 0x28
40#define EP93XX_I2S_TXCTRL 0x2C
41#define EP93XX_I2S_TXWRDLEN 0x30
42#define EP93XX_I2S_TX0EN 0x34
43
44#define EP93XX_I2S_RXLINCTRLDATA 0x58
45#define EP93XX_I2S_RXCTRL 0x5C
46#define EP93XX_I2S_RXWRDLEN 0x60
47#define EP93XX_I2S_RX0EN 0x64
48
49#define EP93XX_I2S_WRDLEN_16 (0 << 0)
50#define EP93XX_I2S_WRDLEN_24 (1 << 0)
51#define EP93XX_I2S_WRDLEN_32 (2 << 0)
52
53#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */
54
55#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */
56#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */
57#define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */
58#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */
59#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */
60
61struct ep93xx_i2s_info {
62 struct clk *mclk;
63 struct clk *sclk;
64 struct clk *lrclk;
65 struct ep93xx_pcm_dma_params *dma_params;
66 void __iomem *regs;
67};
68
69struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
70 [SNDRV_PCM_STREAM_PLAYBACK] = {
71 .name = "i2s-pcm-out",
72 .dma_port = EP93XX_DMA_I2S1,
73 },
74 [SNDRV_PCM_STREAM_CAPTURE] = {
75 .name = "i2s-pcm-in",
76 .dma_port = EP93XX_DMA_I2S1,
77 },
78};
79
80static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
81 unsigned reg, unsigned val)
82{
83 __raw_writel(val, info->regs + reg);
84}
85
86static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
87 unsigned reg)
88{
89 return __raw_readl(info->regs + reg);
90}
91
92static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
93{
94 unsigned base_reg;
95 int i;
96
97 if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
98 (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
99 /* Enable clocks */
100 clk_enable(info->mclk);
101 clk_enable(info->sclk);
102 clk_enable(info->lrclk);
103
104 /* Enable i2s */
105 ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
106 }
107
108 /* Enable fifos */
109 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
110 base_reg = EP93XX_I2S_TX0EN;
111 else
112 base_reg = EP93XX_I2S_RX0EN;
113 for (i = 0; i < 3; i++)
114 ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
115}
116
117static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
118{
119 unsigned base_reg;
120 int i;
121
122 /* Disable fifos */
123 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
124 base_reg = EP93XX_I2S_TX0EN;
125 else
126 base_reg = EP93XX_I2S_RX0EN;
127 for (i = 0; i < 3; i++)
128 ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
129
130 if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
131 (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
132 /* Disable i2s */
133 ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
134
135 /* Disable clocks */
136 clk_disable(info->lrclk);
137 clk_disable(info->sclk);
138 clk_disable(info->mclk);
139 }
140}
141
142static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
143 struct snd_soc_dai *dai)
144{
145 struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
147 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
148
149 snd_soc_dai_set_dma_data(cpu_dai, substream,
150 &info->dma_params[substream->stream]);
151 return 0;
152}
153
154static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
155 struct snd_soc_dai *dai)
156{
157 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
158
159 ep93xx_i2s_disable(info, substream->stream);
160}
161
162static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
163 unsigned int fmt)
164{
165 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
166 unsigned int clk_cfg, lin_ctrl;
167
168 clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
169 lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
170
171 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
172 case SND_SOC_DAIFMT_I2S:
173 clk_cfg |= EP93XX_I2S_CLKCFG_REL;
174 lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
175 break;
176
177 case SND_SOC_DAIFMT_LEFT_J:
178 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
179 lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
180 break;
181
182 case SND_SOC_DAIFMT_RIGHT_J:
183 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
184 lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
185 break;
186
187 default:
188 return -EINVAL;
189 }
190
191 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
192 case SND_SOC_DAIFMT_CBS_CFS:
193 /* CPU is master */
194 clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
195 break;
196
197 case SND_SOC_DAIFMT_CBM_CFM:
198 /* Codec is master */
199 clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
200 break;
201
202 default:
203 return -EINVAL;
204 }
205
206 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
207 case SND_SOC_DAIFMT_NB_NF:
208 /* Negative bit clock, lrclk low on left word */
209 clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
210 break;
211
212 case SND_SOC_DAIFMT_NB_IF:
213 /* Negative bit clock, lrclk low on right word */
214 clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
215 clk_cfg |= EP93XX_I2S_CLKCFG_REL;
216 break;
217
218 case SND_SOC_DAIFMT_IB_NF:
219 /* Positive bit clock, lrclk low on left word */
220 clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
221 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
222 break;
223
224 case SND_SOC_DAIFMT_IB_IF:
225 /* Positive bit clock, lrclk low on right word */
226 clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
227 break;
228 }
229
230 /* Write new register values */
231 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
232 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
233 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
234 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
235 return 0;
236}
237
238static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
239 struct snd_pcm_hw_params *params,
240 struct snd_soc_dai *dai)
241{
242 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
243 unsigned word_len, div, sdiv, lrdiv;
244 int err;
245
246 switch (params_format(params)) {
247 case SNDRV_PCM_FORMAT_S16_LE:
248 word_len = EP93XX_I2S_WRDLEN_16;
249 break;
250
251 case SNDRV_PCM_FORMAT_S24_LE:
252 word_len = EP93XX_I2S_WRDLEN_24;
253 break;
254
255 case SNDRV_PCM_FORMAT_S32_LE:
256 word_len = EP93XX_I2S_WRDLEN_32;
257 break;
258
259 default:
260 return -EINVAL;
261 }
262
263 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
264 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
265 else
266 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
267
268 /*
269 * EP93xx I2S module can be setup so SCLK / LRCLK value can be
270 * 32, 64, 128. MCLK / SCLK value can be 2 and 4.
271 * We set LRCLK equal to `rate' and minimum SCLK / LRCLK
272 * value is 64, because our sample size is 32 bit * 2 channels.
273 * I2S standard permits us to transmit more bits than
274 * the codec uses.
275 */
276 div = clk_get_rate(info->mclk) / params_rate(params);
277 sdiv = 4;
278 if (div > (256 + 512) / 2) {
279 lrdiv = 128;
280 } else {
281 lrdiv = 64;
282 if (div < (128 + 256) / 2)
283 sdiv = 2;
284 }
285
286 err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
287 if (err)
288 return err;
289
290 err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
291 if (err)
292 return err;
293
294 ep93xx_i2s_enable(info, substream->stream);
295 return 0;
296}
297
298static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
299 unsigned int freq, int dir)
300{
301 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
302
303 if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
304 return -EINVAL;
305
306 return clk_set_rate(info->mclk, freq);
307}
308
309#ifdef CONFIG_PM
310static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
311{
312 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
313
314 if (!dai->active)
315 return 0;
316
317 ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
318 ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
319
320 return 0;
321}
322
323static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
324{
325 struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
326
327 if (!dai->active)
328 return 0;
329
330 ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
331 ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
332
333 return 0;
334}
335#else
336#define ep93xx_i2s_suspend NULL
337#define ep93xx_i2s_resume NULL
338#endif
339
340static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
341 .startup = ep93xx_i2s_startup,
342 .shutdown = ep93xx_i2s_shutdown,
343 .hw_params = ep93xx_i2s_hw_params,
344 .set_sysclk = ep93xx_i2s_set_sysclk,
345 .set_fmt = ep93xx_i2s_set_dai_fmt,
346};
347
348#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
349
350static struct snd_soc_dai_driver ep93xx_i2s_dai = {
351 .symmetric_rates= 1,
352 .suspend = ep93xx_i2s_suspend,
353 .resume = ep93xx_i2s_resume,
354 .playback = {
355 .channels_min = 2,
356 .channels_max = 2,
357 .rates = SNDRV_PCM_RATE_8000_192000,
358 .formats = EP93XX_I2S_FORMATS,
359 },
360 .capture = {
361 .channels_min = 2,
362 .channels_max = 2,
363 .rates = SNDRV_PCM_RATE_8000_192000,
364 .formats = EP93XX_I2S_FORMATS,
365 },
366 .ops = &ep93xx_i2s_dai_ops,
367};
368
369static int ep93xx_i2s_probe(struct platform_device *pdev)
370{
371 struct ep93xx_i2s_info *info;
372 struct resource *res;
373 int err;
374
375 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
376 if (!info)
377 return -ENOMEM;
378
379 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
380 if (!res)
381 return -ENODEV;
382
383 info->regs = devm_request_and_ioremap(&pdev->dev, res);
384 if (!info->regs)
385 return -ENXIO;
386
387 info->mclk = clk_get(&pdev->dev, "mclk");
388 if (IS_ERR(info->mclk)) {
389 err = PTR_ERR(info->mclk);
390 goto fail;
391 }
392
393 info->sclk = clk_get(&pdev->dev, "sclk");
394 if (IS_ERR(info->sclk)) {
395 err = PTR_ERR(info->sclk);
396 goto fail_put_mclk;
397 }
398
399 info->lrclk = clk_get(&pdev->dev, "lrclk");
400 if (IS_ERR(info->lrclk)) {
401 err = PTR_ERR(info->lrclk);
402 goto fail_put_sclk;
403 }
404
405 dev_set_drvdata(&pdev->dev, info);
406 info->dma_params = ep93xx_i2s_dma_params;
407
408 err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
409 if (err)
410 goto fail_put_lrclk;
411
412 return 0;
413
414fail_put_lrclk:
415 dev_set_drvdata(&pdev->dev, NULL);
416 clk_put(info->lrclk);
417fail_put_sclk:
418 clk_put(info->sclk);
419fail_put_mclk:
420 clk_put(info->mclk);
421fail:
422 return err;
423}
424
425static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
426{
427 struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
428
429 snd_soc_unregister_dai(&pdev->dev);
430 dev_set_drvdata(&pdev->dev, NULL);
431 clk_put(info->lrclk);
432 clk_put(info->sclk);
433 clk_put(info->mclk);
434 return 0;
435}
436
437static struct platform_driver ep93xx_i2s_driver = {
438 .probe = ep93xx_i2s_probe,
439 .remove = __devexit_p(ep93xx_i2s_remove),
440 .driver = {
441 .name = "ep93xx-i2s",
442 .owner = THIS_MODULE,
443 },
444};
445
446module_platform_driver(ep93xx_i2s_driver);
447
448MODULE_ALIAS("platform:ep93xx-i2s");
449MODULE_AUTHOR("Ryan Mallon");
450MODULE_DESCRIPTION("EP93XX I2S driver");
451MODULE_LICENSE("GPL");
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
new file mode 100644
index 000000000000..665d9c94cc17
--- /dev/null
+++ b/sound/soc/cirrus/ep93xx-pcm.c
@@ -0,0 +1,242 @@
1/*
2 * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
3 *
4 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
5 * Copyright (C) 2006 Applied Data Systems
6 *
7 * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
8 * Copyright (c) 2008 Ryan Mallon
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/device.h>
18#include <linux/slab.h>
19#include <linux/dmaengine.h>
20#include <linux/dma-mapping.h>
21
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/dmaengine_pcm.h>
27
28#include <linux/platform_data/dma-ep93xx.h>
29#include <mach/hardware.h>
30#include <mach/ep93xx-regs.h>
31
32#include "ep93xx-pcm.h"
33
34static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
35 .info = (SNDRV_PCM_INFO_MMAP |
36 SNDRV_PCM_INFO_MMAP_VALID |
37 SNDRV_PCM_INFO_INTERLEAVED |
38 SNDRV_PCM_INFO_BLOCK_TRANSFER),
39
40 .rates = SNDRV_PCM_RATE_8000_192000,
41 .rate_min = SNDRV_PCM_RATE_8000,
42 .rate_max = SNDRV_PCM_RATE_192000,
43
44 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
45 SNDRV_PCM_FMTBIT_S24_LE |
46 SNDRV_PCM_FMTBIT_S32_LE),
47
48 .buffer_bytes_max = 131072,
49 .period_bytes_min = 32,
50 .period_bytes_max = 32768,
51 .periods_min = 1,
52 .periods_max = 32,
53 .fifo_size = 32,
54};
55
56static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
57{
58 struct ep93xx_dma_data *data = filter_param;
59
60 if (data->direction == ep93xx_dma_chan_direction(chan)) {
61 chan->private = data;
62 return true;
63 }
64
65 return false;
66}
67
68static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
69{
70 struct snd_soc_pcm_runtime *rtd = substream->private_data;
71 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
72 struct ep93xx_pcm_dma_params *dma_params;
73 struct ep93xx_dma_data *dma_data;
74 int ret;
75
76 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
77
78 dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL);
79 if (!dma_data)
80 return -ENOMEM;
81
82 dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
83 dma_data->port = dma_params->dma_port;
84 dma_data->name = dma_params->name;
85 dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
86
87 ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
88 if (ret) {
89 kfree(dma_data);
90 return ret;
91 }
92
93 snd_dmaengine_pcm_set_data(substream, dma_data);
94
95 return 0;
96}
97
98static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
99{
100 struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
101
102 snd_dmaengine_pcm_close(substream);
103 kfree(dma_data);
104 return 0;
105}
106
107static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
108 struct snd_pcm_hw_params *params)
109{
110 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
111
112 return 0;
113}
114
115static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
116{
117 snd_pcm_set_runtime_buffer(substream, NULL);
118 return 0;
119}
120
121static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
122 struct vm_area_struct *vma)
123{
124 struct snd_pcm_runtime *runtime = substream->runtime;
125
126 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
127 runtime->dma_area,
128 runtime->dma_addr,
129 runtime->dma_bytes);
130}
131
132static struct snd_pcm_ops ep93xx_pcm_ops = {
133 .open = ep93xx_pcm_open,
134 .close = ep93xx_pcm_close,
135 .ioctl = snd_pcm_lib_ioctl,
136 .hw_params = ep93xx_pcm_hw_params,
137 .hw_free = ep93xx_pcm_hw_free,
138 .trigger = snd_dmaengine_pcm_trigger,
139 .pointer = snd_dmaengine_pcm_pointer_no_residue,
140 .mmap = ep93xx_pcm_mmap,
141};
142
143static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
144{
145 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
146 struct snd_dma_buffer *buf = &substream->dma_buffer;
147 size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
148
149 buf->dev.type = SNDRV_DMA_TYPE_DEV;
150 buf->dev.dev = pcm->card->dev;
151 buf->private_data = NULL;
152 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
153 &buf->addr, GFP_KERNEL);
154 buf->bytes = size;
155
156 return (buf->area == NULL) ? -ENOMEM : 0;
157}
158
159static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
160{
161 struct snd_pcm_substream *substream;
162 struct snd_dma_buffer *buf;
163 int stream;
164
165 for (stream = 0; stream < 2; stream++) {
166 substream = pcm->streams[stream].substream;
167 if (!substream)
168 continue;
169
170 buf = &substream->dma_buffer;
171 if (!buf->area)
172 continue;
173
174 dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
175 buf->addr);
176 buf->area = NULL;
177 }
178}
179
180static u64 ep93xx_pcm_dmamask = DMA_BIT_MASK(32);
181
182static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
183{
184 struct snd_card *card = rtd->card->snd_card;
185 struct snd_pcm *pcm = rtd->pcm;
186 int ret = 0;
187
188 if (!card->dev->dma_mask)
189 card->dev->dma_mask = &ep93xx_pcm_dmamask;
190 if (!card->dev->coherent_dma_mask)
191 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
192
193 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
194 ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
195 SNDRV_PCM_STREAM_PLAYBACK);
196 if (ret)
197 return ret;
198 }
199
200 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
201 ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
202 SNDRV_PCM_STREAM_CAPTURE);
203 if (ret)
204 return ret;
205 }
206
207 return 0;
208}
209
210static struct snd_soc_platform_driver ep93xx_soc_platform = {
211 .ops = &ep93xx_pcm_ops,
212 .pcm_new = &ep93xx_pcm_new,
213 .pcm_free = &ep93xx_pcm_free_dma_buffers,
214};
215
216static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
217{
218 return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
219}
220
221static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
222{
223 snd_soc_unregister_platform(&pdev->dev);
224 return 0;
225}
226
227static struct platform_driver ep93xx_pcm_driver = {
228 .driver = {
229 .name = "ep93xx-pcm-audio",
230 .owner = THIS_MODULE,
231 },
232
233 .probe = ep93xx_soc_platform_probe,
234 .remove = __devexit_p(ep93xx_soc_platform_remove),
235};
236
237module_platform_driver(ep93xx_pcm_driver);
238
239MODULE_AUTHOR("Ryan Mallon");
240MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
241MODULE_LICENSE("GPL");
242MODULE_ALIAS("platform:ep93xx-pcm-audio");
diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
new file mode 100644
index 000000000000..111e1121ecb8
--- /dev/null
+++ b/sound/soc/cirrus/ep93xx-pcm.h
@@ -0,0 +1,20 @@
1/*
2 * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
3 *
4 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
5 * Copyright (C) 2006 Applied Data Systems
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _EP93XX_SND_SOC_PCM_H
13#define _EP93XX_SND_SOC_PCM_H
14
15struct ep93xx_pcm_dma_params {
16 char *name;
17 int dma_port;
18};
19
20#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c
new file mode 100644
index 000000000000..dd997094eb30
--- /dev/null
+++ b/sound/soc/cirrus/simone.c
@@ -0,0 +1,90 @@
1/*
2 * simone.c -- ASoC audio for Simplemachines Sim.One board
3 *
4 * Copyright (c) 2010 Mika Westerberg
5 *
6 * Based on snappercl15 machine driver by Ryan Mallon.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/soc.h>
20
21#include <asm/mach-types.h>
22#include <mach/hardware.h>
23
24#include "ep93xx-pcm.h"
25
26static struct snd_soc_dai_link simone_dai = {
27 .name = "AC97",
28 .stream_name = "AC97 HiFi",
29 .cpu_dai_name = "ep93xx-ac97",
30 .codec_dai_name = "ac97-hifi",
31 .codec_name = "ac97-codec",
32 .platform_name = "ep93xx-pcm-audio",
33};
34
35static struct snd_soc_card snd_soc_simone = {
36 .name = "Sim.One",
37 .owner = THIS_MODULE,
38 .dai_link = &simone_dai,
39 .num_links = 1,
40};
41
42static struct platform_device *simone_snd_ac97_device;
43
44static int __devinit simone_probe(struct platform_device *pdev)
45{
46 struct snd_soc_card *card = &snd_soc_simone;
47 int ret;
48
49 simone_snd_ac97_device = platform_device_register_simple("ac97-codec",
50 -1, NULL, 0);
51 if (IS_ERR(simone_snd_ac97_device))
52 return PTR_ERR(simone_snd_ac97_device);
53
54 card->dev = &pdev->dev;
55
56 ret = snd_soc_register_card(card);
57 if (ret) {
58 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
59 ret);
60 platform_device_unregister(simone_snd_ac97_device);
61 }
62
63 return ret;
64}
65
66static int __devexit simone_remove(struct platform_device *pdev)
67{
68 struct snd_soc_card *card = platform_get_drvdata(pdev);
69
70 snd_soc_unregister_card(card);
71 platform_device_unregister(simone_snd_ac97_device);
72
73 return 0;
74}
75
76static struct platform_driver simone_driver = {
77 .driver = {
78 .name = "simone-audio",
79 .owner = THIS_MODULE,
80 },
81 .probe = simone_probe,
82 .remove = __devexit_p(simone_remove),
83};
84
85module_platform_driver(simone_driver);
86
87MODULE_DESCRIPTION("ALSA SoC Simplemachines Sim.One");
88MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
89MODULE_LICENSE("GPL");
90MODULE_ALIAS("platform:simone-audio");
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
new file mode 100644
index 000000000000..a193cea3cf3c
--- /dev/null
+++ b/sound/soc/cirrus/snappercl15.c
@@ -0,0 +1,146 @@
1/*
2 * snappercl15.c -- SoC audio for Bluewater Systems Snapper CL15 module
3 *
4 * Copyright (C) 2008 Bluewater Systems Ltd
5 * Author: Ryan Mallon
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/platform_device.h>
15#include <linux/module.h>
16#include <sound/core.h>
17#include <sound/pcm.h>
18#include <sound/soc.h>
19
20#include <asm/mach-types.h>
21#include <mach/hardware.h>
22
23#include "../codecs/tlv320aic23.h"
24#include "ep93xx-pcm.h"
25
26#define CODEC_CLOCK 5644800
27
28static int snappercl15_hw_params(struct snd_pcm_substream *substream,
29 struct snd_pcm_hw_params *params)
30{
31 struct snd_soc_pcm_runtime *rtd = substream->private_data;
32 struct snd_soc_dai *codec_dai = rtd->codec_dai;
33 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
34 int err;
35
36 err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK,
37 SND_SOC_CLOCK_IN);
38 if (err)
39 return err;
40
41 err = snd_soc_dai_set_sysclk(cpu_dai, 0, CODEC_CLOCK,
42 SND_SOC_CLOCK_OUT);
43 if (err)
44 return err;
45
46 return 0;
47}
48
49static struct snd_soc_ops snappercl15_ops = {
50 .hw_params = snappercl15_hw_params,
51};
52
53static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
54 SND_SOC_DAPM_HP("Headphone Jack", NULL),
55 SND_SOC_DAPM_LINE("Line In", NULL),
56 SND_SOC_DAPM_MIC("Mic Jack", NULL),
57};
58
59static const struct snd_soc_dapm_route audio_map[] = {
60 {"Headphone Jack", NULL, "LHPOUT"},
61 {"Headphone Jack", NULL, "RHPOUT"},
62
63 {"LLINEIN", NULL, "Line In"},
64 {"RLINEIN", NULL, "Line In"},
65
66 {"MICIN", NULL, "Mic Jack"},
67};
68
69static int snappercl15_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
70{
71 struct snd_soc_codec *codec = rtd->codec;
72 struct snd_soc_dapm_context *dapm = &codec->dapm;
73
74 snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
75 ARRAY_SIZE(tlv320aic23_dapm_widgets));
76
77 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
78 return 0;
79}
80
81static struct snd_soc_dai_link snappercl15_dai = {
82 .name = "tlv320aic23",
83 .stream_name = "AIC23",
84 .cpu_dai_name = "ep93xx-i2s",
85 .codec_dai_name = "tlv320aic23-hifi",
86 .codec_name = "tlv320aic23-codec.0-001a",
87 .platform_name = "ep93xx-pcm-audio",
88 .init = snappercl15_tlv320aic23_init,
89 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
90 SND_SOC_DAIFMT_CBS_CFS,
91 .ops = &snappercl15_ops,
92};
93
94static struct snd_soc_card snd_soc_snappercl15 = {
95 .name = "Snapper CL15",
96 .owner = THIS_MODULE,
97 .dai_link = &snappercl15_dai,
98 .num_links = 1,
99};
100
101static int __devinit snappercl15_probe(struct platform_device *pdev)
102{
103 struct snd_soc_card *card = &snd_soc_snappercl15;
104 int ret;
105
106 ret = ep93xx_i2s_acquire();
107 if (ret)
108 return ret;
109
110 card->dev = &pdev->dev;
111
112 ret = snd_soc_register_card(card);
113 if (ret) {
114 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
115 ret);
116 ep93xx_i2s_release();
117 }
118
119 return ret;
120}
121
122static int __devexit snappercl15_remove(struct platform_device *pdev)
123{
124 struct snd_soc_card *card = platform_get_drvdata(pdev);
125
126 snd_soc_unregister_card(card);
127 ep93xx_i2s_release();
128
129 return 0;
130}
131
132static struct platform_driver snappercl15_driver = {
133 .driver = {
134 .name = "snappercl15-audio",
135 .owner = THIS_MODULE,
136 },
137 .probe = snappercl15_probe,
138 .remove = __devexit_p(snappercl15_remove),
139};
140
141module_platform_driver(snappercl15_driver);
142
143MODULE_AUTHOR("Ryan Mallon");
144MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
145MODULE_LICENSE("GPL");
146MODULE_ALIAS("platform:snappercl15-audio");