]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.arch/ppc-efika-mpc52xx-ac97.patch
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / ppc-efika-mpc52xx-ac97.patch
1 From: Juergen Beisert <jbe@pengutronix.de>
2 Subject: RFC: MPC5200 PSC AC97 driver
3
4 if someone is interested: Here the full patch to get sound support for
5 MPC5200b and a current 2.6.25 kernel.
6
7 Acked-by: Olaf Hering <olh@novell.com>
8
9 ---
10 arch/powerpc/include/asm/mpc52xx_psc.h | 4
11 arch/powerpc/kernel/prom_init.c | 3
12 sound/ppc/Kconfig | 15
13 sound/ppc/Makefile | 2
14 sound/ppc/mpc52xx_ac97.c | 807 +++++++++++++++++++++++++++++++++
15 5 files changed, 831 insertions(+)
16
17 --- a/arch/powerpc/include/asm/mpc52xx_psc.h
18 +++ b/arch/powerpc/include/asm/mpc52xx_psc.h
19 @@ -28,6 +28,10 @@
20 #define MPC52xx_PSC_MAXNUM 6
21
22 /* Programmable Serial Controller (PSC) status register bits */
23 +#define MPC52xx_PSC_SR_UNEX_RX 0x0001
24 +#define MPC52xx_PSC_SR_DATA_VAL 0x0002
25 +#define MPC52xx_PSC_SR_DATA_OVR 0x0004
26 +#define MPC52xx_PSC_SR_CMDSEND 0x0008
27 #define MPC52xx_PSC_SR_CDE 0x0080
28 #define MPC52xx_PSC_SR_RXRDY 0x0100
29 #define MPC52xx_PSC_SR_RXFULL 0x0200
30 --- a/arch/powerpc/kernel/prom_init.c
31 +++ b/arch/powerpc/kernel/prom_init.c
32 @@ -2189,6 +2189,7 @@ static void __init fixup_device_tree_efi
33
34 static void __init fixup_device_tree_efika(void)
35 {
36 + int sound_cell[1] = { 1 };
37 int sound_irq[3] = { 2, 2, 0 };
38 int bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
39 3,4,0, 3,5,0, 3,6,0, 3,7,0,
40 @@ -2244,6 +2245,8 @@ static void __init fixup_device_tree_efi
41 prom_printf("Adding sound interrupts property\n");
42 prom_setprop(node, "/builtin/sound", "interrupts",
43 sound_irq, sizeof(sound_irq));
44 + prom_setprop(node, "/builtin/sound", "cell-index",
45 + sound_cell, sizeof(sound_cell));
46 }
47 }
48
49 --- a/sound/ppc/Kconfig
50 +++ b/sound/ppc/Kconfig
51 @@ -48,4 +48,19 @@ config SND_PS3_DEFAULT_START_DELAY
52 depends on SND_PS3
53 default "2000"
54
55 +
56 +# ALSA ppc drivers
57 +
58 +menu "ALSA PPC devices"
59 + depends on SND!=n && PPC
60 +
61 +config SND_PPC_MPC52xx_AC97
62 + tristate "Freescale MPC52xx AC97 interface support"
63 + depends on SND && PPC_MPC52xx
64 + select SND_AC97_CODEC
65 + help
66 + Say Y or M if you want to support any AC97 codec attached to
67 + the Freescqle MPC52xx AC97 interface.
68 +endmenu
69 +
70 endif # SND_PPC
71 --- a/sound/ppc/Makefile
72 +++ b/sound/ppc/Makefile
73 @@ -4,7 +4,9 @@
74 #
75
76 snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
77 +snd-mpc52xx-ac97-objs := mpc52xx_ac97.o
78
79 # Toplevel Module Dependency
80 obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
81 obj-$(CONFIG_SND_PS3) += snd_ps3.o
82 +obj-$(CONFIG_SND_PPC_MPC52xx_AC97) += snd-mpc52xx-ac97.o
83 --- /dev/null
84 +++ b/sound/ppc/mpc52xx_ac97.c
85 @@ -0,0 +1,807 @@
86 +/*
87 + * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface
88 + *
89 + *
90 + * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
91 + *
92 + * This file is licensed under the terms of the GNU General Public License
93 + * version 2. This program is licensed "as is" without any warranty of any
94 + * kind, whether express or implied.
95 + */
96 +#include <linux/kernel.h>
97 +#include <linux/module.h>
98 +#include <linux/interrupt.h>
99 +#include <linux/spinlock.h>
100 +
101 +#include <sound/core.h>
102 +#include <sound/initval.h>
103 +#include <sound/pcm.h>
104 +#include <sound/pcm_params.h>
105 +#include <sound/ac97_codec.h>
106 +
107 +#include <asm/of_platform.h>
108 +#include <linux/dma-mapping.h>
109 +#include <asm/mpc52xx_psc.h>
110 +
111 +#include <sysdev/bestcomm/bestcomm.h>
112 +#include <sysdev/bestcomm/gen_bd.h>
113 +
114 +
115 +#define DRV_NAME "mpc52xx-psc-ac97"
116 +
117 +
118 +/* ======================================================================== */
119 +/* Structs / Defines */
120 +/* ======================================================================== */
121 +
122 +/* Private structure */
123 +struct mpc52xx_ac97_priv {
124 + struct device *dev;
125 + resource_size_t mem_start;
126 + resource_size_t mem_len;
127 + int irq;
128 + struct mpc52xx_psc __iomem *psc;
129 + struct mpc52xx_psc_fifo __iomem *fifo;
130 +
131 + struct bcom_task *tsk_tx;
132 + spinlock_t dma_lock;
133 +
134 + struct snd_card *card;
135 + struct snd_pcm *pcm;
136 + struct snd_ac97 *ac97;
137 +
138 + struct snd_pcm_substream *substream_playback;
139 +
140 + int period_byte_size;
141 + u32 period_start, period_end, period_next_p;
142 +};
143 +
144 +/* Register bit definition (AC97 mode specific) */
145 +#define PSC_AC97_SLOT_BIT(n) (1<<(12-n))
146 +#define PSC_AC97_SLOTS_XMIT_SHIFT 16
147 +#define PSC_AC97_SLOTS_RECV_SHIFT 0
148 +
149 +/* Bestcomm options */
150 +#define AC97_TX_NUM_BD 32
151 +#define AC97_RX_NUM_BD 32
152 +
153 +static int mpc52xx_ac97_tx_fill(struct mpc52xx_ac97_priv *priv)
154 +{
155 + struct snd_pcm_runtime *rt;
156 +
157 + u32 dma_data_ptr;
158 +
159 + rt = priv->substream_playback->runtime;
160 +
161 + dma_data_ptr = virt_to_phys(rt->dma_area);
162 +
163 + priv->period_byte_size = frames_to_bytes(rt, rt->period_size);
164 + priv->period_start = dma_data_ptr;
165 + priv->period_end = dma_data_ptr + priv->period_byte_size * rt->periods;
166 + priv->period_next_p = dma_data_ptr;
167 +
168 + spin_lock(&priv->dma_lock);
169 + while (!bcom_queue_full(priv->tsk_tx)) {
170 + struct bcom_gen_bd *bd;
171 +
172 + /* Submit a new one */
173 + bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx);
174 + bd->status = priv->period_byte_size;
175 + bd->buf_pa = priv->period_next_p;
176 + bcom_submit_next_buffer(priv->tsk_tx, NULL);
177 +
178 + /* Next pointer */
179 + priv->period_next_p += priv->period_byte_size;
180 + if (priv->period_next_p >= priv->period_end)
181 + priv->period_next_p = priv->period_start;
182 + }
183 + spin_unlock(&priv->dma_lock);
184 +
185 + return 0;
186 +}
187 +
188 +
189 +/* ======================================================================== */
190 +/* ISR routine */
191 +/* ======================================================================== */
192 +
193 +static irqreturn_t mpc52xx_ac97_tx_irq(int irq, void *dev_id)
194 +{
195 + struct mpc52xx_ac97_priv *priv = dev_id;
196 + struct snd_pcm_runtime *rt;
197 + struct bcom_gen_bd *bd;
198 +
199 + rt = priv->substream_playback->runtime;
200 +
201 + if (!bcom_buffer_done(priv->tsk_tx)) {
202 + dev_dbg(priv->dev, "tx mismatch? Check correct output PSC\n");
203 + bcom_disable(priv->tsk_tx);
204 + }
205 +
206 + spin_lock(&priv->dma_lock);
207 + while (bcom_buffer_done(priv->tsk_tx)) {
208 + /* Get the buffer back */
209 + bcom_retrieve_buffer(priv->tsk_tx, NULL, NULL);
210 +
211 + /* Submit a new one */
212 + bd = (struct bcom_gen_bd *) bcom_prepare_next_buffer(priv->tsk_tx);
213 + bd->status = priv->period_byte_size;
214 + bd->buf_pa = priv->period_next_p;
215 + bcom_submit_next_buffer(priv->tsk_tx, NULL);
216 + bcom_enable(priv->tsk_tx);
217 +
218 + /* Next pointer */
219 + priv->period_next_p += priv->period_byte_size;
220 + if (priv->period_next_p >= priv->period_end)
221 + priv->period_next_p = priv->period_start;
222 + }
223 + spin_unlock(&priv->dma_lock);
224 +
225 + snd_pcm_period_elapsed(priv->substream_playback);
226 +
227 + return IRQ_HANDLED;
228 +}
229 +
230 +
231 +static irqreturn_t mpc52xx_ac97_irq(int irq, void *dev_id)
232 +{
233 + struct mpc52xx_ac97_priv *priv = dev_id;
234 +
235 + static int icnt = 0;
236 +
237 +#if 1
238 + /* Anti Crash during dev ;) */
239 + if ((icnt++) > 5000)
240 + out_be16(&priv->psc->mpc52xx_psc_imr, 0);
241 +#endif
242 +
243 + /* Print statuts */
244 + dev_dbg(priv->dev, "isr: %04x", in_be16(&priv->psc->mpc52xx_psc_imr));
245 + out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
246 +
247 + return IRQ_HANDLED;
248 +}
249 +
250 +/* ======================================================================== */
251 +/* PCM interface */
252 +/* ======================================================================== */
253 +
254 +/* HW desc */
255 +
256 +static struct snd_pcm_hardware mpc52xx_ac97_hw = {
257 + .info = SNDRV_PCM_INFO_INTERLEAVED |
258 + SNDRV_PCM_INFO_MMAP |
259 + SNDRV_PCM_INFO_MMAP_VALID,
260 + .formats = SNDRV_PCM_FMTBIT_S32_BE,
261 + .rates = SNDRV_PCM_RATE_8000_48000,
262 + .rate_min = 8000,
263 + .rate_max = 48000,
264 + .channels_min = 1,
265 + .channels_max = 2, /* Support for more ? */
266 + .buffer_bytes_max = 1024*1024,
267 + .period_bytes_min = 512,
268 + .period_bytes_max = 16*1024,
269 + .periods_min = 8,
270 + .periods_max = 1024,
271 + .fifo_size = 512,
272 +};
273 +
274 +
275 +/* Playback */
276 +
277 +static int mpc52xx_ac97_playback_open(struct snd_pcm_substream *substream)
278 +{
279 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
280 +
281 + dev_dbg(priv->dev, "mpc52xx_ac97_playback_open(%p)\n", substream);
282 +
283 + substream->runtime->hw = mpc52xx_ac97_hw;
284 +
285 + priv->substream_playback = substream;
286 +
287 + return 0; /* FIXME */
288 +}
289 +
290 +static int mpc52xx_ac97_playback_close(struct snd_pcm_substream *substream)
291 +{
292 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
293 + dev_dbg(priv->dev, "mpc52xx_ac97_playback_close(%p)\n", substream);
294 + priv->substream_playback = NULL;
295 + return 0; /* FIXME */
296 +}
297 +
298 +static int mpc52xx_ac97_playback_prepare(struct snd_pcm_substream *substream)
299 +{
300 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
301 +
302 + dev_dbg(priv->dev, "mpc52xx_ac97_playback_prepare(%p)\n", substream);
303 +
304 + /* FIXME, need a spinlock to protect access */
305 + if (substream->runtime->channels == 1)
306 + out_be32(&priv->psc->ac97_slots, 0x01000000);
307 + else
308 + out_be32(&priv->psc->ac97_slots, 0x03000000);
309 +
310 + snd_ac97_set_rate(priv->ac97, AC97_PCM_FRONT_DAC_RATE,
311 + substream->runtime->rate);
312 +
313 + return 0; /* FIXME */
314 +}
315 +
316 +
317 +/* Capture */
318 +
319 +static int mpc52xx_ac97_capture_open(struct snd_pcm_substream *substream)
320 +{
321 +/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
322 + return 0; /* FIXME */
323 +}
324 +
325 +static int mpc52xx_ac97_capture_close(struct snd_pcm_substream *substream)
326 +{
327 +/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
328 + return 0; /* FIXME */
329 +}
330 +
331 +static int
332 +mpc52xx_ac97_capture_prepare(struct snd_pcm_substream *substream)
333 +{
334 +/* struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
335 + return 0; /* FIXME */
336 +}
337 +
338 +
339 +/* Common */
340 +
341 +static int mpc52xx_ac97_hw_params(struct snd_pcm_substream *substream,
342 + struct snd_pcm_hw_params *params)
343 +{
344 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
345 + int rv;
346 +
347 + dev_dbg(priv->dev, "mpc52xx_ac97_hw_params(%p)\n", substream);
348 +
349 + rv = snd_pcm_lib_malloc_pages(substream,
350 + params_buffer_bytes(params));
351 + if (rv < 0) {
352 + printk(KERN_ERR "hw params failes\n"); /* FIXME */
353 + return rv;
354 + }
355 +
356 + dev_dbg(priv->dev, "%d %d %d\n", params_buffer_bytes(params),
357 + params_period_bytes(params), params_periods(params));
358 +
359 + return 0;
360 +}
361 +
362 +static int mpc52xx_ac97_hw_free(struct snd_pcm_substream *substream)
363 +{
364 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
365 +
366 + dev_dbg(priv->dev, "mpc52xx_ac97_hw_free(%p)\n", substream);
367 +
368 + return snd_pcm_lib_free_pages(substream);
369 +}
370 +
371 +static int mpc52xx_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
372 +{
373 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
374 + int rv = 0;
375 +
376 + dev_dbg(priv->dev, "mpc52xx_ac97_trigger(%p,%d)\n", substream, cmd);
377 +
378 + switch (cmd) {
379 + case SNDRV_PCM_TRIGGER_START:
380 + /* Enable TX taks */
381 + bcom_gen_bd_tx_reset(priv->tsk_tx);
382 + mpc52xx_ac97_tx_fill(priv);
383 + bcom_enable(priv->tsk_tx);
384 +/*
385 + out_be16(&priv->psc->mpc52xx_psc_imr, 0x0800); // 0x0100
386 + out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100
387 +*/
388 + /* FIXME: Shouldn't we check for overrun too ? */
389 + /* also, shouldn't we just activate TX here ? */
390 +
391 + break;
392 +
393 + case SNDRV_PCM_TRIGGER_STOP:
394 + /* Disable TX task */
395 + bcom_disable(priv->tsk_tx);
396 + out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); // 0x0100
397 +
398 + break;
399 +
400 + default:
401 + rv = -EINVAL;
402 + }
403 +
404 + /* FIXME */
405 + return rv;
406 +}
407 +
408 +static snd_pcm_uframes_t mpc52xx_ac97_pointer(struct snd_pcm_substream *substream)
409 +{
410 + struct snd_pcm_runtime *runtime = substream->runtime;
411 + struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
412 + u32 count;
413 +
414 + count = priv->tsk_tx->bd[priv->tsk_tx->outdex].data[0] - priv->period_start;
415 +
416 + return bytes_to_frames(runtime, count);
417 +}
418 +
419 +
420 +/* Ops */
421 +
422 +static struct snd_pcm_ops mpc52xx_ac97_playback_ops = {
423 + .open = mpc52xx_ac97_playback_open,
424 + .close = mpc52xx_ac97_playback_close,
425 + .ioctl = snd_pcm_lib_ioctl,
426 + .hw_params = mpc52xx_ac97_hw_params,
427 + .hw_free = mpc52xx_ac97_hw_free,
428 + .prepare = mpc52xx_ac97_playback_prepare,
429 + .trigger = mpc52xx_ac97_trigger,
430 + .pointer = mpc52xx_ac97_pointer,
431 +};
432 +
433 +static struct snd_pcm_ops mpc52xx_ac97_capture_ops = {
434 + .open = mpc52xx_ac97_capture_open,
435 + .close = mpc52xx_ac97_capture_close,
436 + .ioctl = snd_pcm_lib_ioctl,
437 + .hw_params = mpc52xx_ac97_hw_params,
438 + .hw_free = mpc52xx_ac97_hw_free,
439 + .prepare = mpc52xx_ac97_capture_prepare,
440 + .trigger = mpc52xx_ac97_trigger,
441 + .pointer = mpc52xx_ac97_pointer,
442 +};
443 +
444 +
445 +/* ======================================================================== */
446 +/* AC97 Bus interface */
447 +/* ======================================================================== */
448 +
449 +static unsigned short mpc52xx_ac97_bus_read(struct snd_ac97 *ac97,
450 + unsigned short reg)
451 +{
452 + struct mpc52xx_ac97_priv *priv = ac97->private_data;
453 + int timeout;
454 + unsigned int val;
455 +
456 + /* Wait for it to be ready */
457 + timeout = 1000;
458 + while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
459 + MPC52xx_PSC_SR_CMDSEND) )
460 + udelay(10);
461 +
462 + if (!timeout) {
463 + printk(KERN_ERR DRV_NAME ": timeout on ac97 bus (rdy)\n");
464 + return 0xffff;
465 + }
466 +
467 + /* Do the read */
468 + out_be32(&priv->psc->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
469 +
470 + /* Wait for the answer */
471 + timeout = 1000;
472 + while ((--timeout) && !(in_be16(&priv->psc->mpc52xx_psc_status) &
473 + MPC52xx_PSC_SR_DATA_VAL) )
474 + udelay(10);
475 +
476 + if (!timeout) {
477 + printk(KERN_ERR DRV_NAME ": timeout on ac97 read (val)\n");
478 + return 0xffff;
479 + }
480 +
481 + /* Get the data */
482 + val = in_be32(&priv->psc->ac97_data);
483 + if ( ((val>>24) & 0x7f) != reg ) {
484 + printk(KERN_ERR DRV_NAME ": reg echo error on ac97 read\n");
485 + return 0xffff;
486 + }
487 + val = (val >> 8) & 0xffff;
488 +
489 + return (unsigned short) val;
490 +}
491 +
492 +static void mpc52xx_ac97_bus_write(struct snd_ac97 *ac97,
493 + unsigned short reg, unsigned short val)
494 +{
495 + struct mpc52xx_ac97_priv *priv = ac97->private_data;
496 + int timeout;
497 +
498 + /* Wait for it to be ready */
499 + timeout = 1000;
500 + while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
501 + MPC52xx_PSC_SR_CMDSEND) )
502 + udelay(10);
503 +
504 + if (!timeout) {
505 + printk(KERN_ERR DRV_NAME ": timeout on ac97 write\n");
506 + return;
507 + }
508 +
509 + /* Write data */
510 + out_be32(&priv->psc->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8));
511 +}
512 +
513 +static void mpc52xx_ac97_bus_reset(struct snd_ac97 *ac97)
514 +{
515 + struct mpc52xx_ac97_priv *priv = ac97->private_data;
516 +
517 + dev_dbg(priv->dev, "ac97 codec reset\n");
518 +
519 + /* Do a cold reset */
520 + /*
521 + * Note: This could interfere with some external AC97 mixers, as it
522 + * could switch them into test mode, when SYNC or SDATA_OUT are not
523 + * low while RES is low!
524 + */
525 + out_8(&priv->psc->op1, 0x02);
526 + udelay(10);
527 + out_8(&priv->psc->op0, 0x02);
528 + udelay(50);
529 +
530 + /* PSC recover from cold reset (cfr user manual, not sure if useful) */
531 + out_be32(&priv->psc->sicr, in_be32(&priv->psc->sicr));
532 +}
533 +
534 +
535 +static struct snd_ac97_bus_ops mpc52xx_ac97_bus_ops = {
536 + .read = mpc52xx_ac97_bus_read,
537 + .write = mpc52xx_ac97_bus_write,
538 + .reset = mpc52xx_ac97_bus_reset,
539 +};
540 +
541 +
542 +/* ======================================================================== */
543 +/* Sound driver setup */
544 +/* ======================================================================== */
545 +
546 +static int mpc52xx_ac97_setup_pcm(struct mpc52xx_ac97_priv *priv)
547 +{
548 + int rv;
549 +
550 + rv = snd_pcm_new(priv->card, DRV_NAME "-pcm", 0, 1, 1, &priv->pcm);
551 + if (rv) {
552 + dev_dbg(priv->dev, "%s: snd_pcm_new failed\n", DRV_NAME);
553 + return rv;
554 + }
555 +
556 + rv = snd_pcm_lib_preallocate_pages_for_all(priv->pcm,
557 + SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL),
558 + 128*1024, 128*1024);
559 + if (rv) {
560 + dev_dbg(priv->dev,
561 + "%s: snd_pcm_lib_preallocate_pages_for_all failed\n",
562 + DRV_NAME);
563 + return rv;
564 + }
565 +
566 + snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_PLAYBACK,
567 + &mpc52xx_ac97_playback_ops);
568 + snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_CAPTURE,
569 + &mpc52xx_ac97_capture_ops);
570 +
571 + priv->pcm->private_data = priv;
572 + priv->pcm->info_flags = 0;
573 +
574 + strcpy(priv->pcm->name, "Freescale MPC52xx PSC-AC97 PCM");
575 +
576 + return 0;
577 +}
578 +
579 +static int mpc52xx_ac97_setup_mixer(struct mpc52xx_ac97_priv *priv)
580 +{
581 + struct snd_ac97_bus *ac97_bus;
582 + struct snd_ac97_template ac97_template;
583 + int rv;
584 +
585 + rv = snd_ac97_bus(priv->card, 0, &mpc52xx_ac97_bus_ops, NULL, &ac97_bus);
586 + if (rv) {
587 + printk(KERN_ERR DRV_NAME ": snd_ac97_bus failed\n");
588 + return rv;
589 + }
590 +
591 + memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
592 + ac97_template.private_data = priv;
593 +
594 + rv = snd_ac97_mixer(ac97_bus, &ac97_template, &priv->ac97);
595 + if (rv) {
596 + printk(KERN_ERR DRV_NAME ": snd_ac97_mixer failed\n");
597 + return rv;
598 + }
599 +
600 + return 0;
601 +}
602 +
603 +static int mpc52xx_ac97_hwinit(struct mpc52xx_ac97_priv *priv)
604 +{
605 + /* Reset everything first by safety */
606 + out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
607 + out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
608 + out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
609 +
610 + /* Do a cold reset of codec */
611 + /*
612 + * Note: This could interfere with some external AC97 mixers, as it
613 + * could switch them into test mode, when SYNC or SDATA_OUT are not
614 + * low while RES is low!
615 + */
616 + out_8(&priv->psc->op1, 0x02);
617 + udelay(10);
618 + out_8(&priv->psc->op0, 0x02);
619 + udelay(50);
620 +
621 + /* Configure AC97 enhanced mode */
622 + out_be32(&priv->psc->sicr, 0x03010000);
623 +
624 + /* No slots active */
625 + out_be32(&priv->psc->ac97_slots, 0x00000000);
626 +
627 + /* No IRQ */
628 + out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
629 +
630 + /* FIFO levels */
631 + out_8(&priv->fifo->rfcntl, 0x07);
632 + out_8(&priv->fifo->tfcntl, 0x07);
633 + out_be16(&priv->fifo->rfalarm, 0x80);
634 + out_be16(&priv->fifo->tfalarm, 0x80);
635 +
636 + /* Go */
637 + out_8(&priv->psc->command,MPC52xx_PSC_TX_ENABLE);
638 + out_8(&priv->psc->command,MPC52xx_PSC_RX_ENABLE);
639 +
640 + return 0;
641 +}
642 +
643 +static int mpc52xx_ac97_hwshutdown(struct mpc52xx_ac97_priv *priv)
644 +{
645 + /* No IRQ */
646 + out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
647 +
648 + /* Disable TB & RX */
649 + out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
650 + out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
651 +
652 + /* FIXME : Reset or put codec in low power ? */
653 +
654 + return 0;
655 +}
656 +
657 +/* ======================================================================== */
658 +/* OF Platform Driver */
659 +/* ======================================================================== */
660 +
661 +static int __devinit
662 +mpc52xx_ac97_probe(struct of_device *op, const struct of_device_id *match)
663 +{
664 + struct device_node *dn = op->node;
665 + struct mpc52xx_ac97_priv *priv;
666 + struct snd_card *card;
667 + struct resource res;
668 + int tx_initiator;
669 + int rv;
670 + const unsigned int *devno;
671 +
672 + dev_dbg(&op->dev, "probing MPC52xx PSC AC97 driver\n");
673 +
674 + /* Get card structure */
675 + rv = -ENOMEM;
676 + card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
677 + THIS_MODULE, sizeof(struct mpc52xx_ac97_priv));
678 + if (!card)
679 + goto err_early;
680 +
681 + priv = card->private_data;
682 +
683 + /* Init our private structure */
684 + priv->card = card;
685 + priv->dev = &op->dev;
686 +
687 + /* Get resources (mem,irq,...) */
688 + rv = of_address_to_resource(dn, 0, &res);
689 + if (rv)
690 + goto err_early;
691 +
692 + priv->mem_start = res.start;
693 + priv->mem_len = res.end - res.start + 1;
694 +
695 + if (!request_mem_region(priv->mem_start, priv->mem_len, DRV_NAME)) {
696 + dev_err(&op->dev, "%s: request_mem_region failed\n", DRV_NAME);
697 + rv = -EBUSY;
698 + goto err_early;
699 + }
700 +
701 + priv->psc = ioremap(priv->mem_start, priv->mem_len);
702 + if (!priv->psc) {
703 + dev_err(&op->dev, "%s: ioremap failed\n", DRV_NAME);
704 + rv = -ENOMEM;
705 + goto err_iomap;
706 + }
707 + /* the fifo starts right after psc ends */
708 + priv->fifo = (struct mpc52xx_psc_fifo*)&priv->psc[1]; /* FIXME */
709 +
710 + priv->irq = irq_of_parse_and_map(dn, 0);
711 + if (priv->irq == NO_IRQ) {
712 + dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
713 + DRV_NAME);
714 + rv = -EBUSY;
715 + goto err_irqmap;
716 + }
717 +
718 + /* Setup Bestcomm tasks */
719 + spin_lock_init(&priv->dma_lock);
720 +
721 + /*
722 + * PSC1 or PSC2 can be configured for AC97 usage. Select the right
723 + * channel, to let the BCOMM unit does its job correctly.
724 + */
725 + devno = of_get_property(dn, "cell-index", NULL);
726 + switch (*devno) {
727 + case 0: /* PSC1 */
728 + tx_initiator = 14;
729 + break;
730 + case 1: /* PSC2 */
731 + tx_initiator = 12;
732 + break;
733 + default:
734 + dev_dbg(priv->dev, "Unknown PSC unit for AC97 usage!\n");
735 + rv = -ENODEV;
736 + goto err_irq;
737 + }
738 +
739 + priv->tsk_tx = bcom_gen_bd_tx_init(AC97_TX_NUM_BD,
740 + priv->mem_start + sizeof(struct mpc52xx_psc) +
741 + offsetof(struct mpc52xx_psc_fifo, tfdata),
742 + tx_initiator,
743 + 2); /* ipr : FIXME */
744 + if (!priv->tsk_tx) {
745 + dev_err(&op->dev, "%s: bcom_gen_bd_tx_init failed\n",
746 + DRV_NAME);
747 + rv = -ENOMEM;
748 + goto err_bcomm;
749 + }
750 +
751 + /* Low level HW Init */
752 + mpc52xx_ac97_hwinit(priv);
753 +
754 + /* Request IRQ now that we're 'stable' */
755 + rv = request_irq(priv->irq, mpc52xx_ac97_irq, 0, DRV_NAME, priv);
756 + if (rv < 0) {
757 + dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME);
758 + goto err_irqreq;
759 + }
760 +
761 + rv = request_irq(bcom_get_task_irq(priv->tsk_tx),
762 + mpc52xx_ac97_tx_irq, 0, DRV_NAME "_tx", priv);
763 + if (rv < 0) {
764 + dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME);
765 + goto err_txirqreq;
766 + }
767 +
768 + /* Prepare sound stuff */
769 + rv = mpc52xx_ac97_setup_mixer(priv);
770 + if (rv)
771 + goto err_late;
772 +
773 + rv = mpc52xx_ac97_setup_pcm(priv);
774 + if (rv)
775 + goto err_late;
776 +
777 + /* Finally register the card */
778 + snprintf(card->shortname, sizeof(card->shortname), DRV_NAME);
779 + snprintf(card->longname, sizeof(card->longname),
780 + "Freescale MPC52xx PSC-AC97 (%s)", card->mixername);
781 +
782 + rv = snd_card_register(card);
783 + if (rv) {
784 + dev_err(&op->dev, "%s: snd_card_register failed\n", DRV_NAME);
785 + goto err_late;
786 + }
787 +
788 + dev_set_drvdata(&op->dev, priv);
789 +
790 + return 0;
791 +
792 +err_late:
793 + free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
794 +err_txirqreq:
795 + free_irq(priv->irq, priv);
796 +err_irqreq:
797 + bcom_gen_bd_tx_release(priv->tsk_tx);
798 +err_bcomm:
799 + mpc52xx_ac97_hwshutdown(priv);
800 +err_irq:
801 + irq_dispose_mapping(priv->irq);
802 +err_irqmap:
803 + iounmap(priv->psc);
804 +err_iomap:
805 + release_mem_region(priv->mem_start, priv->mem_len);
806 +err_early:
807 + if (card)
808 + snd_card_free(card);
809 + return rv;
810 +}
811 +
812 +static int mpc52xx_ac97_remove(struct of_device *op)
813 +{
814 + struct mpc52xx_ac97_priv *priv;
815 +
816 + dev_dbg(&op->dev, "removing MPC52xx PSC AC97 driver\n");
817 +
818 + priv = dev_get_drvdata(&op->dev);
819 + if (priv) {
820 + /* Sound subsys shutdown */
821 + snd_card_free(priv->card);
822 +
823 + /* Low level HW shutdown */
824 + mpc52xx_ac97_hwshutdown(priv);
825 +
826 + /* Release bestcomm tasks */
827 + free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
828 + bcom_gen_bd_tx_release(priv->tsk_tx);
829 +
830 + /* Release resources */
831 + iounmap(priv->psc);
832 + free_irq(priv->irq, priv);
833 + irq_dispose_mapping(priv->irq);
834 + release_mem_region(priv->mem_start, priv->mem_len);
835 + }
836 +
837 + dev_set_drvdata(&op->dev, NULL);
838 +
839 + return 0;
840 +}
841 +
842 +
843 +static struct of_device_id mpc52xx_ac97_of_match[] = {
844 + {
845 + .type = "sound",
846 + .compatible = "mpc5200b-psc-ac97", /* B only for now */
847 + }, { }
848 +};
849 +MODULE_DEVICE_TABLE(of, mpc52xx_ac97_of_match);
850 +static struct of_platform_driver mpc52xx_ac97_of_driver = {
851 + .owner = THIS_MODULE,
852 + .name = DRV_NAME,
853 + .match_table = mpc52xx_ac97_of_match,
854 + .probe = mpc52xx_ac97_probe,
855 + .remove = mpc52xx_ac97_remove,
856 + .driver = {
857 + .name = DRV_NAME,
858 + },
859 +};
860 +
861 +/* ======================================================================== */
862 +/* Module */
863 +/* ======================================================================== */
864 +
865 +static int __init mpc52xx_ac97_init(void)
866 +{
867 + int rv;
868 +
869 + printk(KERN_INFO "Sound: MPC52xx PSC AC97 driver\n");
870 +
871 + rv = of_register_platform_driver(&mpc52xx_ac97_of_driver);
872 + if (rv) {
873 + printk(KERN_ERR DRV_NAME ": "
874 + "of_register_platform_driver failed (%i)\n", rv);
875 + return rv;
876 + }
877 +
878 + return 0;
879 +}
880 +
881 +static void __exit mpc52xx_ac97_exit(void)
882 +{
883 + of_unregister_platform_driver(&mpc52xx_ac97_of_driver);
884 +}
885 +
886 +module_init(mpc52xx_ac97_init);
887 +module_exit(mpc52xx_ac97_exit);
888 +
889 +MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
890 +MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver");
891 +MODULE_LICENSE("GPL");
892 +