Hi,

if someone is interested: Here the full patch to get sound support for
MPC5200b and a current 2.6.25 kernel.

Index: sound/ppc/Kconfig
===================================================================
--- sound/ppc/Kconfig.orig      2008-04-17 15:33:27.000000000 +0200
+++ sound/ppc/Kconfig   2008-04-17 15:38:03.000000000 +0200
@@ -53,3 +53,19 @@ config SND_PS3_DEFAULT_START_DELAY
        depends on SND_PS3
        default "2000"
 endmenu
+
+
+# ALSA ppc drivers
+
+menu "ALSA PPC devices"
+       depends on SND!=n && PPC
+
+config SND_PPC_MPC52xx_AC97
+       tristate "Freescale MPC52xx AC97 interface support"
+       depends on SND && PPC_MPC52xx
+       select SND_AC97_CODEC
+       help
+         Say Y or M if you want to support any AC97 codec attached to
+         the Freescqle MPC52xx AC97 interface.
+
+endmenu
Index: sound/ppc/Makefile
===================================================================
--- sound/ppc/Makefile.orig     2008-04-17 15:33:27.000000000 +0200
+++ sound/ppc/Makefile  2008-04-17 15:38:03.000000000 +0200
@@ -4,7 +4,9 @@
 #
 
 snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o 
keywest.o beep.o
+snd-mpc52xx-ac97-objs := mpc52xx_ac97.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_POWERMAC)     += snd-powermac.o
 obj-$(CONFIG_SND_PS3)          += snd_ps3.o
+obj-$(CONFIG_SND_PPC_MPC52xx_AC97)    += snd-mpc52xx-ac97.o
Index: sound/ppc/mpc52xx_ac97.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ sound/ppc/mpc52xx_ac97.c    2008-04-17 16:13:46.000000000 +0200
@@ -0,0 +1,807 @@
+/*
+ * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface
+ *
+ *
+ * Copyright (C) 2006 Sylvain Munaut <[EMAIL PROTECTED]>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/ac97_codec.h>
+
+#include <asm/of_platform.h>
+#include <linux/dma-mapping.h>
+#include <asm/mpc52xx_psc.h>
+
+#include <sysdev/bestcomm/bestcomm.h>
+#include <sysdev/bestcomm/gen_bd.h>
+
+
+#define DRV_NAME "mpc52xx-psc-ac97"
+
+
+/* ======================================================================== */
+/* Structs / Defines                                                        */
+/* ======================================================================== */
+
+/* Private structure */
+struct mpc52xx_ac97_priv {
+       struct device *dev;
+       resource_size_t mem_start;
+       resource_size_t mem_len;
+       int irq;
+       struct mpc52xx_psc __iomem *psc;
+       struct mpc52xx_psc_fifo __iomem *fifo;
+
+       struct bcom_task *tsk_tx;
+       spinlock_t dma_lock;
+
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+       struct snd_ac97 *ac97;
+
+       struct snd_pcm_substream *substream_playback;
+
+       int period_byte_size;
+       u32 period_start, period_end, period_next_p;
+};
+
+/* Register bit definition (AC97 mode specific) */
+#define PSC_AC97_SLOT_BIT(n)           (1<<(12-n))
+#define PSC_AC97_SLOTS_XMIT_SHIFT      16
+#define PSC_AC97_SLOTS_RECV_SHIFT       0
+
+/* Bestcomm options */
+#define AC97_TX_NUM_BD 32
+#define AC97_RX_NUM_BD 32
+
+static int mpc52xx_ac97_tx_fill(struct mpc52xx_ac97_priv *priv)
+{
+       struct snd_pcm_runtime *rt;
+
+       u32 dma_data_ptr;
+
+       rt = priv->substream_playback->runtime;
+
+       dma_data_ptr = virt_to_phys(rt->dma_area);
+
+       priv->period_byte_size  = frames_to_bytes(rt, rt->period_size);
+       priv->period_start      = dma_data_ptr;
+       priv->period_end        = dma_data_ptr + priv->period_byte_size * 
rt->periods;
+       priv->period_next_p     = dma_data_ptr;
+
+       spin_lock(&priv->dma_lock);
+       while (!bcom_queue_full(priv->tsk_tx)) {
+               struct bcom_gen_bd *bd;
+
+               /* Submit a new one */
+               bd = (struct bcom_gen_bd *) 
bcom_prepare_next_buffer(priv->tsk_tx);
+               bd->status = priv->period_byte_size;
+               bd->buf_pa = priv->period_next_p;
+               bcom_submit_next_buffer(priv->tsk_tx, NULL);
+
+               /* Next pointer */
+               priv->period_next_p += priv->period_byte_size;
+               if (priv->period_next_p >= priv->period_end)
+                       priv->period_next_p = priv->period_start;
+       }
+       spin_unlock(&priv->dma_lock);
+
+       return 0;
+}
+
+
+/* ======================================================================== */
+/* ISR routine                                                              */
+/* ======================================================================== */
+
+static irqreturn_t mpc52xx_ac97_tx_irq(int irq, void *dev_id)
+{
+       struct mpc52xx_ac97_priv *priv = dev_id;
+       struct snd_pcm_runtime *rt;
+       struct bcom_gen_bd *bd;
+
+       rt = priv->substream_playback->runtime;
+
+       if (!bcom_buffer_done(priv->tsk_tx)) {
+               dev_dbg(priv->dev, "tx mismatch? Check correct output PSC\n");
+               bcom_disable(priv->tsk_tx);
+       }
+
+       spin_lock(&priv->dma_lock);
+       while (bcom_buffer_done(priv->tsk_tx)) {
+               /* Get the buffer back */
+               bcom_retrieve_buffer(priv->tsk_tx, NULL, NULL);
+
+               /* Submit a new one */
+               bd = (struct bcom_gen_bd *) 
bcom_prepare_next_buffer(priv->tsk_tx);
+               bd->status = priv->period_byte_size;
+               bd->buf_pa = priv->period_next_p;
+               bcom_submit_next_buffer(priv->tsk_tx, NULL);
+               bcom_enable(priv->tsk_tx);
+
+               /* Next pointer */
+               priv->period_next_p += priv->period_byte_size;
+               if (priv->period_next_p >= priv->period_end)
+                       priv->period_next_p = priv->period_start;
+       }
+       spin_unlock(&priv->dma_lock);
+
+       snd_pcm_period_elapsed(priv->substream_playback);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t mpc52xx_ac97_irq(int irq, void *dev_id)
+{
+       struct mpc52xx_ac97_priv *priv = dev_id;
+
+       static int icnt = 0;
+
+#if 1
+       /* Anti Crash during dev ;) */
+       if ((icnt++) > 5000)
+               out_be16(&priv->psc->mpc52xx_psc_imr, 0);
+#endif
+
+       /* Print statuts */
+       dev_dbg(priv->dev, "isr: %04x", in_be16(&priv->psc->mpc52xx_psc_imr));
+       out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
+
+       return IRQ_HANDLED;
+}
+
+/* ======================================================================== */
+/* PCM interface                                                            */
+/* ======================================================================== */
+
+/* HW desc */
+
+static struct snd_pcm_hardware mpc52xx_ac97_hw = {
+       .info                   = SNDRV_PCM_INFO_INTERLEAVED            |
+                                       SNDRV_PCM_INFO_MMAP             |
+                                       SNDRV_PCM_INFO_MMAP_VALID,
+       .formats                = SNDRV_PCM_FMTBIT_S32_BE,
+       .rates                  = SNDRV_PCM_RATE_8000_48000,
+       .rate_min               = 8000,
+       .rate_max               = 48000,
+       .channels_min           = 1,
+       .channels_max           = 2,    /* Support for more ? */
+       .buffer_bytes_max       = 1024*1024,
+       .period_bytes_min       = 512,
+       .period_bytes_max       = 16*1024,
+       .periods_min            = 8,
+       .periods_max            = 1024,
+       .fifo_size              = 512,
+};
+
+
+/* Playback */
+
+static int mpc52xx_ac97_playback_open(struct snd_pcm_substream *substream)
+{
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+
+       dev_dbg(priv->dev, "mpc52xx_ac97_playback_open(%p)\n", substream);
+
+       substream->runtime->hw = mpc52xx_ac97_hw;
+
+       priv->substream_playback = substream;
+
+       return 0;       /* FIXME */
+}
+
+static int mpc52xx_ac97_playback_close(struct snd_pcm_substream *substream)
+{
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+       dev_dbg(priv->dev, "mpc52xx_ac97_playback_close(%p)\n", substream);
+       priv->substream_playback = NULL;
+       return 0;       /* FIXME */
+}
+
+static int mpc52xx_ac97_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+
+       dev_dbg(priv->dev, "mpc52xx_ac97_playback_prepare(%p)\n", substream);
+
+       /* FIXME, need a spinlock to protect access */
+       if (substream->runtime->channels == 1)
+               out_be32(&priv->psc->ac97_slots, 0x01000000);
+       else
+               out_be32(&priv->psc->ac97_slots, 0x03000000);
+
+       snd_ac97_set_rate(priv->ac97, AC97_PCM_FRONT_DAC_RATE,
+                       substream->runtime->rate);
+
+       return 0;       /* FIXME */
+}
+
+
+/* Capture */
+
+static int mpc52xx_ac97_capture_open(struct snd_pcm_substream *substream)
+{
+/*     struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
+       return 0;       /* FIXME */
+}
+
+static int mpc52xx_ac97_capture_close(struct snd_pcm_substream *substream)
+{
+/*     struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
+       return 0;       /* FIXME */
+}
+
+static int
+mpc52xx_ac97_capture_prepare(struct snd_pcm_substream *substream)
+{
+/*     struct mpc52xx_ac97_priv *priv = substream->pcm->private_data; */
+       return 0;       /* FIXME */
+}
+
+
+/* Common */
+
+static int mpc52xx_ac97_hw_params(struct snd_pcm_substream *substream,
+                       struct snd_pcm_hw_params *params)
+{
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+       int rv;
+
+       dev_dbg(priv->dev, "mpc52xx_ac97_hw_params(%p)\n", substream);
+
+       rv = snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(params));
+       if (rv < 0) {
+               printk(KERN_ERR "hw params failes\n");  /* FIXME */
+               return rv;
+       }
+
+       dev_dbg(priv->dev, "%d %d %d\n", params_buffer_bytes(params),
+               params_period_bytes(params), params_periods(params));
+
+       return 0;
+}
+
+static int mpc52xx_ac97_hw_free(struct snd_pcm_substream *substream)
+{
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+
+       dev_dbg(priv->dev, "mpc52xx_ac97_hw_free(%p)\n", substream);
+
+       return snd_pcm_lib_free_pages(substream);
+}
+
+static int mpc52xx_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+       int rv = 0;
+
+       dev_dbg(priv->dev, "mpc52xx_ac97_trigger(%p,%d)\n", substream, cmd);
+
+       switch (cmd) {
+               case SNDRV_PCM_TRIGGER_START:
+                       /* Enable TX taks */
+                       bcom_gen_bd_tx_reset(priv->tsk_tx);
+                       mpc52xx_ac97_tx_fill(priv);
+                       bcom_enable(priv->tsk_tx);
+/*
+                       out_be16(&priv->psc->mpc52xx_psc_imr, 0x0800); // 0x0100
+                       out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100
+*/
+                               /* FIXME: Shouldn't we check for overrun too ? 
*/
+                               /* also, shouldn't we just activate TX here ? */
+
+                       break;
+
+               case SNDRV_PCM_TRIGGER_STOP:
+                       /* Disable TX task */
+                       bcom_disable(priv->tsk_tx);
+                       out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000); // 0x0100
+
+                       break;
+
+               default:
+                       rv = -EINVAL;
+       }
+
+       /* FIXME */
+       return rv;
+}
+
+static snd_pcm_uframes_t mpc52xx_ac97_pointer(struct snd_pcm_substream 
*substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
+       u32 count;
+
+       count = priv->tsk_tx->bd[priv->tsk_tx->outdex].data[0] - 
priv->period_start;
+
+       return bytes_to_frames(runtime, count);
+}
+
+
+/* Ops */
+
+static struct snd_pcm_ops mpc52xx_ac97_playback_ops = {
+       .open           = mpc52xx_ac97_playback_open,
+       .close          = mpc52xx_ac97_playback_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = mpc52xx_ac97_hw_params,
+       .hw_free        = mpc52xx_ac97_hw_free,
+       .prepare        = mpc52xx_ac97_playback_prepare,
+       .trigger        = mpc52xx_ac97_trigger,
+       .pointer        = mpc52xx_ac97_pointer,
+};
+
+static struct snd_pcm_ops mpc52xx_ac97_capture_ops = {
+       .open           = mpc52xx_ac97_capture_open,
+       .close          = mpc52xx_ac97_capture_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = mpc52xx_ac97_hw_params,
+       .hw_free        = mpc52xx_ac97_hw_free,
+       .prepare        = mpc52xx_ac97_capture_prepare,
+       .trigger        = mpc52xx_ac97_trigger,
+       .pointer        = mpc52xx_ac97_pointer,
+};
+
+
+/* ======================================================================== */
+/* AC97 Bus interface                                                       */
+/* ======================================================================== */
+
+static unsigned short mpc52xx_ac97_bus_read(struct snd_ac97 *ac97,
+                                               unsigned short reg)
+{
+       struct mpc52xx_ac97_priv *priv = ac97->private_data;
+       int timeout;
+       unsigned int val;
+
+       /* Wait for it to be ready */
+       timeout = 1000;
+       while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
+                                               MPC52xx_PSC_SR_CMDSEND) )
+               udelay(10);
+
+       if (!timeout) {
+               printk(KERN_ERR DRV_NAME ": timeout on ac97 bus (rdy)\n");
+               return 0xffff;
+       }
+
+       /* Do the read */
+       out_be32(&priv->psc->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
+
+       /* Wait for the answer */
+       timeout = 1000;
+       while ((--timeout) && !(in_be16(&priv->psc->mpc52xx_psc_status) &
+                                               MPC52xx_PSC_SR_DATA_VAL) )
+               udelay(10);
+
+       if (!timeout) {
+               printk(KERN_ERR DRV_NAME ": timeout on ac97 read (val)\n");
+               return 0xffff;
+       }
+
+       /* Get the data */
+       val = in_be32(&priv->psc->ac97_data);
+       if ( ((val>>24) & 0x7f) != reg ) {
+               printk(KERN_ERR DRV_NAME ": reg echo error on ac97 read\n");
+               return 0xffff;
+       }
+       val = (val >> 8) & 0xffff;
+
+       return (unsigned short) val;
+}
+
+static void mpc52xx_ac97_bus_write(struct snd_ac97 *ac97,
+                       unsigned short reg, unsigned short val)
+{
+       struct mpc52xx_ac97_priv *priv = ac97->private_data;
+       int timeout;
+
+       /* Wait for it to be ready */
+       timeout = 1000;
+       while ((--timeout) && (in_be16(&priv->psc->mpc52xx_psc_status) &
+                                               MPC52xx_PSC_SR_CMDSEND) )
+               udelay(10);
+
+       if (!timeout) {
+               printk(KERN_ERR DRV_NAME ": timeout on ac97 write\n");
+               return;
+       }
+
+       /* Write data */
+       out_be32(&priv->psc->ac97_cmd, ((reg & 0x7f) << 24) | (val << 8));
+}
+
+static void mpc52xx_ac97_bus_reset(struct snd_ac97 *ac97)
+{
+       struct mpc52xx_ac97_priv *priv = ac97->private_data;
+
+       dev_dbg(priv->dev, "ac97 codec reset\n");
+
+       /* Do a cold reset */
+       /*
+        * Note: This could interfere with some external AC97 mixers, as it
+        * could switch them into test mode, when SYNC or SDATA_OUT are not
+        * low while RES is low!
+        */
+       out_8(&priv->psc->op1, 0x02);
+       udelay(10);
+       out_8(&priv->psc->op0, 0x02);
+       udelay(50);
+
+       /* PSC recover from cold reset (cfr user manual, not sure if useful) */
+       out_be32(&priv->psc->sicr, in_be32(&priv->psc->sicr));
+}
+
+
+static struct snd_ac97_bus_ops mpc52xx_ac97_bus_ops = {
+       .read   = mpc52xx_ac97_bus_read,
+       .write  = mpc52xx_ac97_bus_write,
+       .reset  = mpc52xx_ac97_bus_reset,
+};
+
+
+/* ======================================================================== */
+/* Sound driver setup                                                       */
+/* ======================================================================== */
+
+static int mpc52xx_ac97_setup_pcm(struct mpc52xx_ac97_priv *priv)
+{
+       int rv;
+
+       rv = snd_pcm_new(priv->card, DRV_NAME "-pcm", 0, 1, 1, &priv->pcm);
+       if (rv) {
+               dev_dbg(priv->dev, "%s: snd_pcm_new failed\n", DRV_NAME);
+               return rv;
+       }
+
+       rv = snd_pcm_lib_preallocate_pages_for_all(priv->pcm,
+               SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL),
+               128*1024, 128*1024);
+       if (rv) {
+               dev_dbg(priv->dev,
+                       "%s: snd_pcm_lib_preallocate_pages_for_all  failed\n",
+                       DRV_NAME);
+               return rv;
+       }
+
+       snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &mpc52xx_ac97_playback_ops);
+       snd_pcm_set_ops(priv->pcm, SNDRV_PCM_STREAM_CAPTURE,
+                       &mpc52xx_ac97_capture_ops);
+
+       priv->pcm->private_data = priv;
+       priv->pcm->info_flags = 0;
+
+       strcpy(priv->pcm->name, "Freescale MPC52xx PSC-AC97 PCM");
+
+       return 0;
+}
+
+static int mpc52xx_ac97_setup_mixer(struct mpc52xx_ac97_priv *priv)
+{
+       struct snd_ac97_bus *ac97_bus;
+       struct snd_ac97_template ac97_template;
+       int rv;
+
+       rv = snd_ac97_bus(priv->card, 0, &mpc52xx_ac97_bus_ops, NULL, 
&ac97_bus);
+       if (rv) {
+               printk(KERN_ERR DRV_NAME ": snd_ac97_bus failed\n");
+               return rv;
+       }
+
+       memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
+       ac97_template.private_data = priv;
+
+       rv = snd_ac97_mixer(ac97_bus, &ac97_template, &priv->ac97);
+       if (rv) {
+               printk(KERN_ERR DRV_NAME ": snd_ac97_mixer failed\n");
+               return rv;
+       }
+
+       return 0;
+}
+
+static int mpc52xx_ac97_hwinit(struct mpc52xx_ac97_priv *priv)
+{
+       /* Reset everything first by safety */
+       out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
+       out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
+       out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
+
+       /* Do a cold reset of codec */
+       /*
+        * Note: This could interfere with some external AC97 mixers, as it
+        * could switch them into test mode, when SYNC or SDATA_OUT are not
+        * low while RES is low!
+        */
+       out_8(&priv->psc->op1, 0x02);
+       udelay(10);
+       out_8(&priv->psc->op0, 0x02);
+       udelay(50);
+
+       /* Configure AC97 enhanced mode */
+       out_be32(&priv->psc->sicr, 0x03010000);
+
+       /* No slots active */
+       out_be32(&priv->psc->ac97_slots, 0x00000000);
+
+       /* No IRQ */
+       out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
+
+       /* FIFO levels */
+       out_8(&priv->fifo->rfcntl, 0x07);
+       out_8(&priv->fifo->tfcntl, 0x07);
+       out_be16(&priv->fifo->rfalarm, 0x80);
+       out_be16(&priv->fifo->tfalarm, 0x80);
+
+       /* Go */
+       out_8(&priv->psc->command,MPC52xx_PSC_TX_ENABLE);
+       out_8(&priv->psc->command,MPC52xx_PSC_RX_ENABLE);
+
+       return 0;
+}
+
+static int mpc52xx_ac97_hwshutdown(struct mpc52xx_ac97_priv *priv)
+{
+       /* No IRQ */
+       out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
+
+       /* Disable TB & RX */
+       out_8(&priv->psc->command,MPC52xx_PSC_RST_RX);
+       out_8(&priv->psc->command,MPC52xx_PSC_RST_TX);
+
+       /* FIXME : Reset or put codec in low power ? */
+
+       return 0;
+}
+
+/* ======================================================================== */
+/* OF Platform Driver                                                       */
+/* ======================================================================== */
+
+static int __devinit
+mpc52xx_ac97_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct device_node *dn = op->node;
+       struct mpc52xx_ac97_priv *priv;
+       struct snd_card *card;
+       struct resource res;
+       int tx_initiator;
+       int rv;
+       const unsigned int *devno;
+
+       dev_dbg(&op->dev, "probing MPC52xx PSC AC97 driver\n");
+
+       /* Get card structure */
+       rv = -ENOMEM;
+       card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                               THIS_MODULE, sizeof(struct mpc52xx_ac97_priv));
+       if (!card)
+               goto err_early;
+
+       priv = card->private_data;
+
+       /* Init our private structure */
+       priv->card = card;
+       priv->dev = &op->dev;
+
+       /* Get resources (mem,irq,...) */
+       rv = of_address_to_resource(dn, 0, &res);
+       if (rv)
+               goto err_early;
+
+       priv->mem_start = res.start;
+       priv->mem_len = res.end - res.start + 1;
+
+       if (!request_mem_region(priv->mem_start, priv->mem_len, DRV_NAME)) {
+               dev_err(&op->dev, "%s: request_mem_region failed\n", DRV_NAME);
+               rv = -EBUSY;
+               goto err_early;
+       }
+
+       priv->psc = ioremap(priv->mem_start, priv->mem_len);
+       if (!priv->psc) {
+               dev_err(&op->dev, "%s: ioremap failed\n", DRV_NAME);
+               rv = -ENOMEM;
+               goto err_iomap;
+       }
+       /* the fifo starts right after psc ends */
+       priv->fifo = (struct mpc52xx_psc_fifo*)&priv->psc[1];   /* FIXME */
+
+       priv->irq = irq_of_parse_and_map(dn, 0);
+       if (priv->irq == NO_IRQ) {
+               dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
+                       DRV_NAME);
+               rv = -EBUSY;
+               goto err_irqmap;
+       }
+
+       /* Setup Bestcomm tasks */
+       spin_lock_init(&priv->dma_lock);
+
+       /*
+        * PSC1 or PSC2 can be configured for AC97 usage. Select the right
+        * channel, to let the BCOMM unit does its job correctly.
+        */
+       devno = of_get_property(dn, "cell-index", NULL);
+       switch (*devno) {
+       case 0: /* PSC1 */
+               tx_initiator = 14;
+               break;
+       case 1: /* PSC2 */
+               tx_initiator = 12;
+               break;
+       default:
+               dev_dbg(priv->dev, "Unknown PSC unit for AC97 usage!\n");
+               rv = -ENODEV;
+               goto err_irq;
+       }
+
+       priv->tsk_tx = bcom_gen_bd_tx_init(AC97_TX_NUM_BD,
+                       priv->mem_start + sizeof(struct mpc52xx_psc) +
+                               offsetof(struct mpc52xx_psc_fifo, tfdata),
+                       tx_initiator,
+                       2);     /* ipr : FIXME */
+       if (!priv->tsk_tx) {
+               dev_err(&op->dev, "%s: bcom_gen_bd_tx_init failed\n",
+                       DRV_NAME);
+               rv = -ENOMEM;
+               goto err_bcomm;
+       }
+
+       /* Low level HW Init */
+       mpc52xx_ac97_hwinit(priv);
+
+       /* Request IRQ now that we're 'stable' */
+       rv = request_irq(priv->irq, mpc52xx_ac97_irq, 0, DRV_NAME, priv);
+       if (rv < 0) {
+               dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME);
+               goto err_irqreq;
+       }
+
+       rv = request_irq(bcom_get_task_irq(priv->tsk_tx),
+                               mpc52xx_ac97_tx_irq, 0, DRV_NAME "_tx", priv);
+       if (rv < 0) {
+               dev_err(&op->dev, "%s: request_irq failed\n", DRV_NAME);
+               goto err_txirqreq;
+       }
+
+       /* Prepare sound stuff */
+       rv = mpc52xx_ac97_setup_mixer(priv);
+       if (rv)
+               goto err_late;
+
+       rv = mpc52xx_ac97_setup_pcm(priv);
+       if (rv)
+               goto err_late;
+
+       /* Finally register the card */
+       snprintf(card->shortname, sizeof(card->shortname), DRV_NAME);
+       snprintf(card->longname, sizeof(card->longname),
+               "Freescale MPC52xx PSC-AC97 (%s)", card->mixername);
+
+       rv = snd_card_register(card);
+       if (rv) {
+               dev_err(&op->dev, "%s: snd_card_register failed\n", DRV_NAME);
+               goto err_late;
+       }
+
+       dev_set_drvdata(&op->dev, priv);
+
+       return 0;
+
+err_late:
+       free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
+err_txirqreq:
+       free_irq(priv->irq, priv);
+err_irqreq:
+       bcom_gen_bd_tx_release(priv->tsk_tx);
+err_bcomm:
+       mpc52xx_ac97_hwshutdown(priv);
+err_irq:
+       irq_dispose_mapping(priv->irq);
+err_irqmap:
+       iounmap(priv->psc);
+err_iomap:
+       release_mem_region(priv->mem_start, priv->mem_len);
+err_early:
+       if (card)
+               snd_card_free(card);
+       return rv;
+}
+
+static int mpc52xx_ac97_remove(struct of_device *op)
+{
+       struct mpc52xx_ac97_priv *priv;
+
+       dev_dbg(&op->dev, "removing MPC52xx PSC AC97 driver\n");
+
+       priv = dev_get_drvdata(&op->dev);
+       if (priv) {
+               /* Sound subsys shutdown */
+               snd_card_free(priv->card);
+
+               /* Low level HW shutdown */
+               mpc52xx_ac97_hwshutdown(priv);
+
+               /* Release bestcomm tasks */
+               free_irq(bcom_get_task_irq(priv->tsk_tx), priv);
+               bcom_gen_bd_tx_release(priv->tsk_tx);
+
+               /* Release resources */
+               iounmap(priv->psc);
+               free_irq(priv->irq, priv);
+               irq_dispose_mapping(priv->irq);
+               release_mem_region(priv->mem_start, priv->mem_len);
+       }
+
+       dev_set_drvdata(&op->dev, NULL);
+
+       return 0;
+}
+
+
+static struct of_device_id mpc52xx_ac97_of_match[] = {
+       {
+               .type           = "sound",
+               .compatible     = "mpc5200b-psc-ac97",  /* B only for now */
+       },
+};
+
+static struct of_platform_driver mpc52xx_ac97_of_driver = {
+       .owner          = THIS_MODULE,
+       .name           = DRV_NAME,
+       .match_table    = mpc52xx_ac97_of_match,
+       .probe          = mpc52xx_ac97_probe,
+       .remove         = mpc52xx_ac97_remove,
+       .driver         = {
+               .name   = DRV_NAME,
+       },
+};
+
+/* ======================================================================== */
+/* Module                                                                   */
+/* ======================================================================== */
+
+static int __init mpc52xx_ac97_init(void)
+{
+       int rv;
+
+       printk(KERN_INFO "Sound: MPC52xx PSC AC97 driver\n");
+
+       rv = of_register_platform_driver(&mpc52xx_ac97_of_driver);
+       if (rv) {
+               printk(KERN_ERR DRV_NAME ": "
+                       "of_register_platform_driver failed (%i)\n", rv);
+               return rv;
+       }
+
+       return 0;
+}
+
+static void __exit mpc52xx_ac97_exit(void)
+{
+       of_unregister_platform_driver(&mpc52xx_ac97_of_driver);
+}
+
+module_init(mpc52xx_ac97_init);
+module_exit(mpc52xx_ac97_exit);
+
+MODULE_AUTHOR("Sylvain Munaut <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver");
+MODULE_LICENSE("GPL");
+
Index: include/asm-powerpc/mpc52xx_psc.h
===================================================================
--- include/asm-powerpc/mpc52xx_psc.h.orig      2008-04-17 16:12:09.000000000 
+0200
+++ include/asm-powerpc/mpc52xx_psc.h   2008-04-17 16:13:38.000000000 +0200
@@ -28,6 +28,10 @@
 #define MPC52xx_PSC_MAXNUM     6
 
 /* Programmable Serial Controller (PSC) status register bits */
+#define MPC52xx_PSC_SR_UNEX_RX 0x0001
+#define MPC52xx_PSC_SR_DATA_VAL        0x0002
+#define MPC52xx_PSC_SR_DATA_OVR        0x0004
+#define MPC52xx_PSC_SR_CMDSEND 0x0008
 #define MPC52xx_PSC_SR_CDE     0x0080
 #define MPC52xx_PSC_SR_RXRDY   0x0100
 #define MPC52xx_PSC_SR_RXFULL  0x0200
@@ -132,8 +136,10 @@ struct mpc52xx_psc {
        u8              reserved5[3];
        u8              ctlr;           /* PSC + 0x1c */
        u8              reserved6[3];
-       u16             ccr;            /* PSC + 0x20 */
-       u8              reserved7[14];
+       u32             ccr;            /* PSC + 0x20 */
+       u32             ac97_slots;     /* PSC + 0x24 */
+       u32             ac97_cmd;       /* PSC + 0x28 */
+       u32             ac97_data;      /* PSC + 0x2c */
        u8              ivr;            /* PSC + 0x30 */
        u8              reserved8[3];
        u8              ip;             /* PSC + 0x34 */

Regards,
Juergen

-- 
Dipl.-Ing. Juergen Beisert | http://www.pengutronix.de
 Pengutronix - Linux Solutions for Science and Industry
    Handelsregister: Amtsgericht Hildesheim, HRA 2686
         Vertretung Sued/Muenchen, Germany
   Phone: +49-8766-939 228 |  Fax: +49-5121-206917-9
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to