aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorJon Smirl <jonsmirl@gmail.com>2009-05-26 08:34:10 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-05-26 16:13:00 -0400
commit20d0e1520ed1ba8aad05f416245446de0f7ec4bb (patch)
tree21bb0fbfde9f1f10b03835639287347c068fe861 /sound/soc
parentdbcc34756234596993a3b1304636f032e66d401f (diff)
ASoC: AC97 driver for mpc5200
I've implemented retries for when the AC97 hardware doesn't reset on first try. About 10% of the time both the Efika and pcm030 AC97 codecs don't reset on first try and need to be poked multiple times. Failure is indicated by not having the link clock start ticking. Every once in a while even five pokes won't get the link started and I have to power cycle. Signed-off-by: Jon Smirl <jonsmirl@gmail.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/fsl/Kconfig11
-rw-r--r--sound/soc/fsl/Makefile1
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c331
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.h15
4 files changed, 358 insertions, 0 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 1918c78b858e..3bce952d7c5f 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -29,3 +29,14 @@ config SND_SOC_MPC5200_I2S
29 select PPC_BESTCOMM_GEN_BD 29 select PPC_BESTCOMM_GEN_BD
30 help 30 help
31 Say Y here to support the MPC5200 PSCs in I2S mode. 31 Say Y here to support the MPC5200 PSCs in I2S mode.
32
33config SND_SOC_MPC5200_AC97
34 tristate "Freescale MPC5200 PSC in AC97 mode driver"
35 depends on PPC_MPC52xx && PPC_BESTCOMM
36 select AC97_BUS
37 select SND_MPC52xx_DMA
38 select PPC_BESTCOMM_GEN_BD
39 help
40 Say Y here to support the MPC5200 PSCs in AC97 mode.
41
42
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 7731ef2539bb..14631a1732eb 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -13,4 +13,5 @@ obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
13# MPC5200 Platform Support 13# MPC5200 Platform Support
14obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o 14obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
15obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o 15obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
16obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
16 17
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
new file mode 100644
index 000000000000..9f2df1552f02
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -0,0 +1,331 @@
1/*
2 * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
3 *
4 * Copyright (C) 2009 Jon Smirl, Digispeaker
5 * Author: Jon Smirl <jonsmirl@gmail.com>
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#include <linux/module.h>
13#include <linux/of_device.h>
14#include <linux/of_platform.h>
15
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19
20#include <asm/time.h>
21#include <asm/delay.h>
22#include <asm/mpc52xx_psc.h>
23
24#include "mpc5200_dma.h"
25#include "mpc5200_psc_ac97.h"
26
27#define DRV_NAME "mpc5200-psc-ac97"
28
29/* ALSA only supports a single AC97 device so static is recommend here */
30static struct psc_dma *psc_dma;
31
32static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
33{
34 int rc;
35 unsigned int val;
36
37 /* Wait for command send status zero = ready */
38 spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
39 MPC52xx_PSC_SR_CMDSEND), 100, 0, rc);
40 if (rc == 0) {
41 pr_err("timeout on ac97 bus (rdy)\n");
42 return -ENODEV;
43 }
44 /* Send the read */
45 out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
46
47 /* Wait for the answer */
48 spin_event_timeout((in_be16(&psc_dma->psc_regs->sr_csr.status) &
49 MPC52xx_PSC_SR_DATA_VAL), 100, 0, rc);
50 if (rc == 0) {
51 pr_err("timeout on ac97 read (val) %x\n",
52 in_be16(&psc_dma->psc_regs->sr_csr.status));
53 return -ENODEV;
54 }
55 /* Get the data */
56 val = in_be32(&psc_dma->psc_regs->ac97_data);
57 if (((val >> 24) & 0x7f) != reg) {
58 pr_err("reg echo error on ac97 read\n");
59 return -ENODEV;
60 }
61 val = (val >> 8) & 0xffff;
62
63 return (unsigned short) val;
64}
65
66static void psc_ac97_write(struct snd_ac97 *ac97,
67 unsigned short reg, unsigned short val)
68{
69 int rc;
70
71 /* Wait for command status zero = ready */
72 spin_event_timeout(!(in_be16(&psc_dma->psc_regs->sr_csr.status) &
73 MPC52xx_PSC_SR_CMDSEND), 100, 0, rc);
74 if (rc == 0) {
75 pr_err("timeout on ac97 bus (write)\n");
76 return;
77 }
78 /* Write data */
79 out_be32(&psc_dma->psc_regs->ac97_cmd,
80 ((reg & 0x7f) << 24) | (val << 8));
81}
82
83static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
84{
85 int rc;
86 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
87
88 out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
89 spin_event_timeout(0, 3, 0, rc);
90 out_be32(&regs->sicr, psc_dma->sicr);
91}
92
93static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
94{
95 int rc;
96 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
97
98 /* Do a cold reset */
99 out_8(&regs->op1, MPC52xx_PSC_OP_RES);
100 spin_event_timeout(0, 10, 0, rc);
101 out_8(&regs->op0, MPC52xx_PSC_OP_RES);
102 spin_event_timeout(0, 50, 0, rc);
103 psc_ac97_warm_reset(ac97);
104}
105
106struct snd_ac97_bus_ops soc_ac97_ops = {
107 .read = psc_ac97_read,
108 .write = psc_ac97_write,
109 .reset = psc_ac97_cold_reset,
110 .warm_reset = psc_ac97_warm_reset,
111};
112EXPORT_SYMBOL_GPL(soc_ac97_ops);
113
114static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
115 struct snd_pcm_hw_params *params,
116 struct snd_soc_dai *cpu_dai)
117{
118 struct psc_dma *psc_dma = cpu_dai->private_data;
119
120 dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
121 " periods=%i buffer_size=%i buffer_bytes=%i channels=%i"
122 " rate=%i format=%i\n",
123 __func__, substream, params_period_size(params),
124 params_period_bytes(params), params_periods(params),
125 params_buffer_size(params), params_buffer_bytes(params),
126 params_channels(params), params_rate(params),
127 params_format(params));
128
129
130 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
131 if (params_channels(params) == 1)
132 psc_dma->slots |= 0x00000100;
133 else
134 psc_dma->slots |= 0x00000300;
135 } else {
136 if (params_channels(params) == 1)
137 psc_dma->slots |= 0x01000000;
138 else
139 psc_dma->slots |= 0x03000000;
140 }
141 out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
142
143 return 0;
144}
145
146static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
147 struct snd_pcm_hw_params *params,
148 struct snd_soc_dai *cpu_dai)
149{
150 struct psc_dma *psc_dma = cpu_dai->private_data;
151
152 if (params_channels(params) == 1)
153 out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
154 else
155 out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000);
156
157 return 0;
158}
159
160static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
161 struct snd_soc_dai *dai)
162{
163 struct snd_soc_pcm_runtime *rtd = substream->private_data;
164 struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
165
166 switch (cmd) {
167 case SNDRV_PCM_TRIGGER_STOP:
168 if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
169 psc_dma->slots &= 0xFFFF0000;
170 else
171 psc_dma->slots &= 0x0000FFFF;
172
173 out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
174 break;
175 }
176 return 0;
177}
178
179static int psc_ac97_probe(struct platform_device *pdev,
180 struct snd_soc_dai *cpu_dai)
181{
182 struct psc_dma *psc_dma = cpu_dai->private_data;
183 struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
184
185 /* Go */
186 out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
187 return 0;
188}
189
190/* ---------------------------------------------------------------------
191 * ALSA SoC Bindings
192 *
193 * - Digital Audio Interface (DAI) template
194 * - create/destroy dai hooks
195 */
196
197/**
198 * psc_ac97_dai_template: template CPU Digital Audio Interface
199 */
200static struct snd_soc_dai_ops psc_ac97_analog_ops = {
201 .hw_params = psc_ac97_hw_analog_params,
202 .trigger = psc_ac97_trigger,
203};
204
205static struct snd_soc_dai_ops psc_ac97_digital_ops = {
206 .hw_params = psc_ac97_hw_digital_params,
207};
208
209struct snd_soc_dai psc_ac97_dai[] = {
210{
211 .name = "AC97",
212 .ac97_control = 1,
213 .probe = psc_ac97_probe,
214 .playback = {
215 .channels_min = 1,
216 .channels_max = 6,
217 .rates = SNDRV_PCM_RATE_8000_48000,
218 .formats = SNDRV_PCM_FMTBIT_S32_BE,
219 },
220 .capture = {
221 .channels_min = 1,
222 .channels_max = 2,
223 .rates = SNDRV_PCM_RATE_8000_48000,
224 .formats = SNDRV_PCM_FMTBIT_S32_BE,
225 },
226 .ops = &psc_ac97_analog_ops,
227},
228{
229 .name = "SPDIF",
230 .ac97_control = 1,
231 .playback = {
232 .channels_min = 1,
233 .channels_max = 2,
234 .rates = SNDRV_PCM_RATE_32000 | \
235 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
236 .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
237 },
238 .ops = &psc_ac97_digital_ops,
239} };
240EXPORT_SYMBOL_GPL(psc_ac97_dai);
241
242
243
244/* ---------------------------------------------------------------------
245 * OF platform bus binding code:
246 * - Probe/remove operations
247 * - OF device match table
248 */
249static int __devinit psc_ac97_of_probe(struct of_device *op,
250 const struct of_device_id *match)
251{
252 int rc, i;
253 struct snd_ac97 ac97;
254 struct mpc52xx_psc __iomem *regs;
255
256 rc = mpc5200_audio_dma_create(op);
257 if (rc != 0)
258 return rc;
259
260 for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
261 psc_ac97_dai[i].dev = &op->dev;
262
263 rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
264 if (rc != 0) {
265 dev_err(&op->dev, "Failed to register DAI\n");
266 return rc;
267 }
268
269 psc_dma = dev_get_drvdata(&op->dev);
270 regs = psc_dma->psc_regs;
271 ac97.private_data = psc_dma;
272
273 for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
274 psc_ac97_dai[i].private_data = psc_dma;
275
276 psc_dma->imr = 0;
277 out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
278
279 /* Configure the serial interface mode to AC97 */
280 psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97;
281 out_be32(&regs->sicr, psc_dma->sicr);
282
283 /* No slots active */
284 out_be32(&regs->ac97_slots, 0x00000000);
285
286 return 0;
287}
288
289static int __devexit psc_ac97_of_remove(struct of_device *op)
290{
291 return mpc5200_audio_dma_destroy(op);
292}
293
294/* Match table for of_platform binding */
295static struct of_device_id psc_ac97_match[] __devinitdata = {
296 { .compatible = "fsl,mpc5200-psc-ac97", },
297 { .compatible = "fsl,mpc5200b-psc-ac97", },
298 {}
299};
300MODULE_DEVICE_TABLE(of, psc_ac97_match);
301
302static struct of_platform_driver psc_ac97_driver = {
303 .match_table = psc_ac97_match,
304 .probe = psc_ac97_of_probe,
305 .remove = __devexit_p(psc_ac97_of_remove),
306 .driver = {
307 .name = "mpc5200-psc-ac97",
308 .owner = THIS_MODULE,
309 },
310};
311
312/* ---------------------------------------------------------------------
313 * Module setup and teardown; simply register the of_platform driver
314 * for the PSC in AC97 mode.
315 */
316static int __init psc_ac97_init(void)
317{
318 return of_register_platform_driver(&psc_ac97_driver);
319}
320module_init(psc_ac97_init);
321
322static void __exit psc_ac97_exit(void)
323{
324 of_unregister_platform_driver(&psc_ac97_driver);
325}
326module_exit(psc_ac97_exit);
327
328MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
329MODULE_DESCRIPTION("mpc5200 AC97 module");
330MODULE_LICENSE("GPL");
331
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
new file mode 100644
index 000000000000..4bc18c35c369
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -0,0 +1,15 @@
1/*
2 * Freescale MPC5200 PSC in AC97 mode
3 * ALSA SoC Digital Audio Interface (DAI) driver
4 *
5 */
6
7#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
8#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
9
10extern struct snd_soc_dai psc_ac97_dai[];
11
12#define MPC5200_AC97_NORMAL 0
13#define MPC5200_AC97_SPDIF 1
14
15#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */