aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@iki.fi>2010-10-14 10:49:06 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-10-15 06:54:52 -0400
commitaa7e1b84c6d424264bab8c29b14ebbc906488853 (patch)
treeb844f197d114d2c900cb2edf6d8cb239cea466d7 /sound/soc
parenta34712391a66260e442a9ab1eb7edb22a2d0ca3c (diff)
ASoC: add ep93xx AC97 audio driver
Add support for AC97 controllers found in Cirrus Logic EP93xx family SoCs. Signed-off-by: Mika Westerberg <mika.westerberg@iki.fi> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/ep93xx/Kconfig7
-rw-r--r--sound/soc/ep93xx/Makefile2
-rw-r--r--sound/soc/ep93xx/ep93xx-ac97.c468
3 files changed, 476 insertions, 1 deletions
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index f617f560f46b..108e5ff3ffc2 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -3,11 +3,16 @@ config SND_EP93XX_SOC
3 depends on ARCH_EP93XX && SND_SOC 3 depends on ARCH_EP93XX && SND_SOC
4 help 4 help
5 Say Y or M if you want to add support for codecs attached to 5 Say Y or M if you want to add support for codecs attached to
6 the EP93xx I2S interface. 6 the EP93xx I2S or AC97 interfaces.
7 7
8config SND_EP93XX_SOC_I2S 8config SND_EP93XX_SOC_I2S
9 tristate 9 tristate
10 10
11config SND_EP93XX_SOC_AC97
12 tristate
13 select AC97_BUS
14 select SND_SOC_AC97_BUS
15
11config SND_EP93XX_SOC_SNAPPERCL15 16config SND_EP93XX_SOC_SNAPPERCL15
12 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" 17 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
13 depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 18 depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
index 272e60f57b9a..ac06e0092f95 100644
--- a/sound/soc/ep93xx/Makefile
+++ b/sound/soc/ep93xx/Makefile
@@ -1,9 +1,11 @@
1# EP93xx Platform Support 1# EP93xx Platform Support
2snd-soc-ep93xx-objs := ep93xx-pcm.o 2snd-soc-ep93xx-objs := ep93xx-pcm.o
3snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o 3snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
4snd-soc-ep93xx-ac97-objs := ep93xx-ac97.o
4 5
5obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o 6obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
6obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o 7obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
8obj-$(CONFIG_SND_EP93XX_SOC_AC97) += snd-soc-ep93xx-ac97.o
7 9
8# EP93XX Machine Support 10# EP93XX Machine Support
9snd-soc-snappercl15-objs := snappercl15.o 11snd-soc-snappercl15-objs := snappercl15.o
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
new file mode 100644
index 000000000000..68a0bae1208a
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -0,0 +1,468 @@
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 <mach/dma.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 * @mem: physical memory resource for the registers
91 * @regs: mapped AC97 controller registers
92 * @irq: AC97 interrupt number
93 * @done: bus ops wait here for an interrupt
94 */
95struct ep93xx_ac97_info {
96 struct mutex lock;
97 struct device *dev;
98 struct resource *mem;
99 void __iomem *regs;
100 int irq;
101 struct completion done;
102};
103
104/* currently ALSA only supports a single AC97 device */
105static struct ep93xx_ac97_info *ep93xx_ac97_info;
106
107static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
108 .name = "ac97-pcm-out",
109 .dma_port = EP93XX_DMA_M2P_PORT_AAC1,
110};
111
112static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
113 .name = "ac97-pcm-in",
114 .dma_port = EP93XX_DMA_M2P_PORT_AAC1,
115};
116
117static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
118 unsigned reg)
119{
120 return __raw_readl(info->regs + reg);
121}
122
123static inline void ep93xx_ac97_write_reg(struct ep93xx_ac97_info *info,
124 unsigned reg, unsigned val)
125{
126 __raw_writel(val, info->regs + reg);
127}
128
129static unsigned short ep93xx_ac97_read(struct snd_ac97 *ac97,
130 unsigned short reg)
131{
132 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
133 unsigned short val;
134
135 mutex_lock(&info->lock);
136
137 ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
138 ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2RXVALID);
139 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT)) {
140 dev_warn(info->dev, "timeout reading register %x\n", reg);
141 mutex_unlock(&info->lock);
142 return -ETIMEDOUT;
143 }
144 val = (unsigned short)ep93xx_ac97_read_reg(info, AC97S2DATA);
145
146 mutex_unlock(&info->lock);
147 return val;
148}
149
150static void ep93xx_ac97_write(struct snd_ac97 *ac97,
151 unsigned short reg,
152 unsigned short val)
153{
154 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
155
156 mutex_lock(&info->lock);
157
158 /*
159 * Writes to the codec need to be done so that slot 2 is filled in
160 * before slot 1.
161 */
162 ep93xx_ac97_write_reg(info, AC97S2DATA, val);
163 ep93xx_ac97_write_reg(info, AC97S1DATA, reg);
164
165 ep93xx_ac97_write_reg(info, AC97IM, AC97_SLOT2TXCOMPLETE);
166 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
167 dev_warn(info->dev, "timeout writing register %x\n", reg);
168
169 mutex_unlock(&info->lock);
170}
171
172static void ep93xx_ac97_warm_reset(struct snd_ac97 *ac97)
173{
174 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
175
176 mutex_lock(&info->lock);
177
178 /*
179 * We are assuming that before this functions gets called, the codec
180 * BIT_CLK is stopped by forcing the codec into powerdown mode. We can
181 * control the SYNC signal directly via AC97SYNC register. Using
182 * TIMEDSYNC the controller will keep the SYNC high > 1us.
183 */
184 ep93xx_ac97_write_reg(info, AC97SYNC, AC97SYNC_TIMEDSYNC);
185 ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
186 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
187 dev_warn(info->dev, "codec warm reset timeout\n");
188
189 mutex_unlock(&info->lock);
190}
191
192static void ep93xx_ac97_cold_reset(struct snd_ac97 *ac97)
193{
194 struct ep93xx_ac97_info *info = ep93xx_ac97_info;
195
196 mutex_lock(&info->lock);
197
198 /*
199 * For doing cold reset, we disable the AC97 controller interface, clear
200 * WINT and CODECREADY bits, and finally enable the interface again.
201 */
202 ep93xx_ac97_write_reg(info, AC97GCR, 0);
203 ep93xx_ac97_write_reg(info, AC97EOI, AC97EOI_CODECREADY | AC97EOI_WINT);
204 ep93xx_ac97_write_reg(info, AC97GCR, AC97GCR_AC97IFE);
205
206 /*
207 * Now, assert the reset and wait for the codec to become ready.
208 */
209 ep93xx_ac97_write_reg(info, AC97RESET, AC97RESET_TIMEDRESET);
210 ep93xx_ac97_write_reg(info, AC97IM, AC97_CODECREADY);
211 if (!wait_for_completion_timeout(&info->done, AC97_TIMEOUT))
212 dev_warn(info->dev, "codec cold reset timeout\n");
213
214 /*
215 * Give the codec some time to come fully out from the reset. This way
216 * we ensure that the subsequent reads/writes will work.
217 */
218 usleep_range(15000, 20000);
219
220 mutex_unlock(&info->lock);
221}
222
223static irqreturn_t ep93xx_ac97_interrupt(int irq, void *dev_id)
224{
225 struct ep93xx_ac97_info *info = dev_id;
226 unsigned status, mask;
227
228 /*
229 * Just mask out the interrupt and wake up the waiting thread.
230 * Interrupts are cleared via reading/writing to slot 1 & 2 registers by
231 * the waiting thread.
232 */
233 status = ep93xx_ac97_read_reg(info, AC97GIS);
234 mask = ep93xx_ac97_read_reg(info, AC97IM);
235 mask &= ~status;
236 ep93xx_ac97_write_reg(info, AC97IM, mask);
237
238 complete(&info->done);
239 return IRQ_HANDLED;
240}
241
242struct snd_ac97_bus_ops soc_ac97_ops = {
243 .read = ep93xx_ac97_read,
244 .write = ep93xx_ac97_write,
245 .reset = ep93xx_ac97_cold_reset,
246 .warm_reset = ep93xx_ac97_warm_reset,
247};
248EXPORT_SYMBOL_GPL(soc_ac97_ops);
249
250static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
251 int cmd, struct snd_soc_dai *dai)
252{
253 struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai);
254 unsigned v = 0;
255
256
257 switch (cmd) {
258 case SNDRV_PCM_TRIGGER_START:
259 case SNDRV_PCM_TRIGGER_RESUME:
260 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
261 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
262 /*
263 * Enable compact mode, TX slots 3 & 4, and the TX FIFO
264 * itself.
265 */
266 v |= AC97TXCR_CM;
267 v |= AC97TXCR_TX3 | AC97TXCR_TX4;
268 v |= AC97TXCR_TEN;
269 ep93xx_ac97_write_reg(info, AC97TXCR(1), v);
270 } else {
271 /*
272 * Enable compact mode, RX slots 3 & 4, and the RX FIFO
273 * itself.
274 */
275 v |= AC97RXCR_CM;
276 v |= AC97RXCR_RX3 | AC97RXCR_RX4;
277 v |= AC97RXCR_REN;
278 ep93xx_ac97_write_reg(info, AC97RXCR(1), v);
279 }
280 break;
281
282 case SNDRV_PCM_TRIGGER_STOP:
283 case SNDRV_PCM_TRIGGER_SUSPEND:
284 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
285 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
286 /*
287 * As per Cirrus EP93xx errata described below:
288 *
289 * http://www.cirrus.com/en/pubs/errata/ER667E2B.pdf
290 *
291 * we will wait for the TX FIFO to be empty before
292 * clearing the TEN bit.
293 */
294 unsigned long timeout = jiffies + AC97_TIMEOUT;
295
296 do {
297 v = ep93xx_ac97_read_reg(info, AC97SR(1));
298 if (time_after(jiffies, timeout)) {
299 dev_warn(info->dev, "TX timeout\n");
300 break;
301 }
302 } while (!(v & (AC97SR_TXFE | AC97SR_TXUE)));
303
304 /* disable the TX FIFO */
305 ep93xx_ac97_write_reg(info, AC97TXCR(1), 0);
306 } else {
307 /* disable the RX FIFO */
308 ep93xx_ac97_write_reg(info, AC97RXCR(1), 0);
309 }
310 break;
311
312 default:
313 dev_warn(info->dev, "unknown command %d\n", cmd);
314 return -EINVAL;
315 }
316
317 return 0;
318}
319
320static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
321 struct snd_soc_dai *dai)
322{
323 struct ep93xx_pcm_dma_params *dma_data;
324
325 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
326 dma_data = &ep93xx_ac97_pcm_out;
327 else
328 dma_data = &ep93xx_ac97_pcm_in;
329
330 snd_soc_dai_set_dma_data(dai, substream, dma_data);
331 return 0;
332}
333
334static struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
335 .startup = ep93xx_ac97_startup,
336 .trigger = ep93xx_ac97_trigger,
337};
338
339struct snd_soc_dai_driver ep93xx_ac97_dai = {
340 .name = "ep93xx-ac97",
341 .id = 0,
342 .ac97_control = 1,
343 .playback = {
344 .stream_name = "AC97 Playback",
345 .channels_min = 2,
346 .channels_max = 2,
347 .rates = SNDRV_PCM_RATE_8000_48000,
348 .formats = SNDRV_PCM_FMTBIT_S16_LE,
349 },
350 .capture = {
351 .stream_name = "AC97 Capture",
352 .channels_min = 2,
353 .channels_max = 2,
354 .rates = SNDRV_PCM_RATE_8000_48000,
355 .formats = SNDRV_PCM_FMTBIT_S16_LE,
356 },
357 .ops = &ep93xx_ac97_dai_ops,
358};
359
360static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
361{
362 struct ep93xx_ac97_info *info;
363 int ret;
364
365 info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
366 if (!info)
367 return -ENOMEM;
368
369 dev_set_drvdata(&pdev->dev, info);
370
371 mutex_init(&info->lock);
372 init_completion(&info->done);
373 info->dev = &pdev->dev;
374
375 info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
376 if (!info->mem) {
377 ret = -ENXIO;
378 goto fail_free_info;
379 }
380
381 info->irq = platform_get_irq(pdev, 0);
382 if (!info->irq) {
383 ret = -ENXIO;
384 goto fail_free_info;
385 }
386
387 if (!request_mem_region(info->mem->start, resource_size(info->mem),
388 pdev->name)) {
389 ret = -EBUSY;
390 goto fail_free_info;
391 }
392
393 info->regs = ioremap(info->mem->start, resource_size(info->mem));
394 if (!info->regs) {
395 ret = -ENOMEM;
396 goto fail_release_mem;
397 }
398
399 ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
400 pdev->name, info);
401 if (ret)
402 goto fail_unmap_mem;
403
404 ep93xx_ac97_info = info;
405 platform_set_drvdata(pdev, info);
406
407 ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
408 if (ret)
409 goto fail_free_irq;
410
411 return 0;
412
413fail_free_irq:
414 platform_set_drvdata(pdev, NULL);
415 free_irq(info->irq, info);
416fail_unmap_mem:
417 iounmap(info->regs);
418fail_release_mem:
419 release_mem_region(info->mem->start, resource_size(info->mem));
420fail_free_info:
421 kfree(info);
422
423 return ret;
424}
425
426static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
427{
428 struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
429
430 snd_soc_unregister_dai(&pdev->dev);
431
432 /* disable the AC97 controller */
433 ep93xx_ac97_write_reg(info, AC97GCR, 0);
434
435 free_irq(info->irq, info);
436 iounmap(info->regs);
437 release_mem_region(info->mem->start, resource_size(info->mem));
438 platform_set_drvdata(pdev, NULL);
439 kfree(info);
440
441 return 0;
442}
443
444static struct platform_driver ep93xx_ac97_driver = {
445 .probe = ep93xx_ac97_probe,
446 .remove = __devexit_p(ep93xx_ac97_remove),
447 .driver = {
448 .name = "ep93xx-ac97",
449 .owner = THIS_MODULE,
450 },
451};
452
453static int __init ep93xx_ac97_init(void)
454{
455 return platform_driver_register(&ep93xx_ac97_driver);
456}
457module_init(ep93xx_ac97_init);
458
459static void __exit ep93xx_ac97_exit(void)
460{
461 platform_driver_unregister(&ep93xx_ac97_driver);
462}
463module_exit(ep93xx_ac97_exit);
464
465MODULE_DESCRIPTION("EP93xx AC97 ASoC Driver");
466MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
467MODULE_LICENSE("GPL");
468MODULE_ALIAS("platform:ep93xx-ac97");