linux-efika: Sound driver altered to keep hands of register bits it shouldn't touch.
authorLeon Woestenberg <leon.woestenberg@gmail.com>
Sun, 14 Jan 2007 23:13:21 +0000 (23:13 +0000)
committerLeon Woestenberg <leon.woestenberg@gmail.com>
Sun, 14 Jan 2007 23:13:21 +0000 (23:13 +0000)
packages/linux/linux-efika/0001-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt [new file with mode: 0644]
packages/linux/linux-efika_2.6.18+2.6.19-rc6.bb

diff --git a/packages/linux/linux-efika/0001-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt b/packages/linux/linux-efika/0001-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt
new file mode 100644 (file)
index 0000000..a352f0e
--- /dev/null
@@ -0,0 +1,834 @@
+I cleaned up the setting of the port_config register on the MPC5200B.
+This driver now touches only the two relevant bits without overriding
+the others.
+
+Signed-off-by: Leon Woestenberg <leonw@mailcan.com>
+
+From 144658ad3d23bb426e29562235e40f0f9797a9c7 Mon Sep 17 00:00:00 2001
+From: Sylvain Munaut <tnt@246tNt.com>
+Date: Mon, 18 Dec 2006 22:51:38 +0100
+Subject: [PATCH] sound: Add support for the MPC52xx PSC AC97 Link
+
+Messy driver, to be cleaned ... a lot ...
+
+Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
+---
+ include/asm-ppc/mpc52xx_psc.h |   10 -
+ sound/ppc/Kconfig             |   16 +
+ sound/ppc/Makefile            |    3 
+ sound/ppc/mpc52xx_ac97.c      |  738 +++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 765 insertions(+), 2 deletions(-)
+
+Index: linux-2.6.19-rc6_efika/include/asm-ppc/mpc52xx_psc.h
+===================================================================
+--- linux-2.6.19-rc6_efika.orig/include/asm-ppc/mpc52xx_psc.h  2007-01-14 19:45:07.000000000 +0100
++++ linux-2.6.19-rc6_efika/include/asm-ppc/mpc52xx_psc.h       2007-01-14 19:45:07.000000000 +0100
+@@ -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 @@
+       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 */
+Index: linux-2.6.19-rc6_efika/sound/ppc/Kconfig
+===================================================================
+--- linux-2.6.19-rc6_efika.orig/sound/ppc/Kconfig      2007-01-14 19:45:07.000000000 +0100
++++ linux-2.6.19-rc6_efika/sound/ppc/Kconfig   2007-01-14 19:45:07.000000000 +0100
+@@ -33,3 +33,19 @@
+         option.
+ 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: linux-2.6.19-rc6_efika/sound/ppc/Makefile
+===================================================================
+--- linux-2.6.19-rc6_efika.orig/sound/ppc/Makefile     2007-01-14 19:45:07.000000000 +0100
++++ linux-2.6.19-rc6_efika/sound/ppc/Makefile  2007-01-14 19:45:07.000000000 +0100
+@@ -4,6 +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_PPC_MPC52xx_AC97)    += snd-mpc52xx-ac97.o
+Index: linux-2.6.19-rc6_efika/sound/ppc/mpc52xx_ac97.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.19-rc6_efika/sound/ppc/mpc52xx_ac97.c    2007-01-14 22:45:55.000000000 +0100
+@@ -0,0 +1,742 @@
++/*
++ * Driver for the PSC of the Freescale MPC52xx configured as AC97 interface
++ *
++ *
++ * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com>
++ *
++ * 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.
++ */
++
++#define DEBUG
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++
++#include <sound/driver.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 <asm/mpc52xx_psc.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 snd_card *card;
++      struct snd_pcm *pcm;
++      struct snd_ac97 *ac97;
++
++      struct snd_pcm_substream *substream_playback;
++      unsigned int buf_pos;
++};
++
++/* 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
++
++
++
++/* ======================================================================== */
++/* ISR routine                                                              */
++/* ======================================================================== */
++
++static irqreturn_t
++mpc52xx_ac97_irq(int irq, void *dev_id)
++{
++      struct mpc52xx_ac97_priv *priv = dev_id;
++
++      static int icnt = 0;
++      #if 0
++      {
++      unsigned int val;
++//    val = in_be32(&priv->psc->ac97_data);
++      printk(KERN_INFO "mpc52xx_ac97_irq fired (isr=%04x, status=%04x) %08x\n", in_be16(&priv->psc->mpc52xx_psc_imr), in_be16(&priv->psc->mpc52xx_psc_status), val);
++      out_8(&priv->psc->command,MPC52xx_PSC_RST_ERR_STAT);
++      }
++      #endif
++
++      /* Anti Crash during dev ;) */
++      #if 0
++      if ((icnt++) > 50000)
++              out_be16(&priv->psc->mpc52xx_psc_imr, 0);
++      #endif
++
++      /* Copy 64 data into the buffer */
++      if (in_be16(&priv->psc->mpc52xx_psc_imr) & 0x0100) {
++              if (priv->substream_playback) {
++                      struct snd_pcm_runtime *rt;
++
++                      rt = priv->substream_playback->runtime;
++
++                      if (snd_pcm_playback_hw_avail(rt) < bytes_to_frames(rt,128)) {
++                              int i;
++                              /* Push silence */
++                              for (i=0; i<64; i++)
++                                      out_be32(&priv->psc->mpc52xx_psc_buffer_32, 0x00000800);
++                              printk(KERN_DEBUG "pushed silence ...\n");
++                      } else {
++                              int i;
++                              unsigned short *data;
++
++                              data = (unsigned short *)
++                                      (&rt->dma_area[frames_to_bytes(rt, priv->buf_pos)]);
++
++                              for (i=0; i<64; i++)
++                                      out_be32(&priv->psc->mpc52xx_psc_buffer_32,
++                                              (((unsigned int)data[i]) << 16) | 0x00000000);
++                                                      /* Setting the sof bit looks useless */
++
++                              priv->buf_pos += bytes_to_frames(rt,128);;
++                              if (priv->buf_pos >= rt->buffer_size)
++                                      priv->buf_pos = 0;
++
++                              snd_pcm_period_elapsed(priv->substream_playback);
++                      }
++              } else {
++                      out_be16(&priv->psc->mpc52xx_psc_imr, 0);
++                      printk(KERN_DEBUG "Interrupt with no stream ...\n");
++              }
++      } else {
++              printk(KERN_ERR "Spurious int\n");
++      }
++
++      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_S16_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       = 128*1024,
++      .period_bytes_min       = 128, /* 32, */
++      .period_bytes_max       = 128, /* 16*1024, */
++      .periods_min            = 8,
++      .periods_max            = 256,
++      .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;
++      priv->buf_pos = 0;      /* FIXME Do that where ? */
++
++      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;
++      }
++
++      printk(KERN_DEBUG "%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 interrupt */
++                      out_be16(&priv->psc->mpc52xx_psc_imr, 0x0100); // 0x0100
++
++                      break;
++
++              case SNDRV_PCM_TRIGGER_STOP:
++                      /* Disable TX interrupt */
++                      out_be16(&priv->psc->mpc52xx_psc_imr, 0x0000);
++
++                      break;
++
++              default:
++                      rv = -EINVAL;
++      }
++
++      /* FIXME */
++      return rv;
++}
++
++static snd_pcm_uframes_t
++mpc52xx_ac97_pointer(struct snd_pcm_substream *substream)
++{
++      struct mpc52xx_ac97_priv *priv = substream->pcm->private_data;
++
++//    dev_dbg(priv->dev, "mpc52xx_ac97_pointer(%p)\n", substream);
++
++      if (substream->runtime->channels == 1)
++              return priv->buf_pos;   /* FIXME */
++      else
++              return priv->buf_pos >> 1;      /* FIXME */
++}
++
++
++/* 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;
++
++      dev_dbg(priv->dev, "ac97 read: reg %04x\n", reg);
++
++      /* 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;
++
++      dev_dbg(priv->dev, "ac97 read ok: reg %04x  val %04x\n",
++                              reg, val);
++
++      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;
++
++      dev_dbg(priv->dev, "ac97 write: reg %04x  val %04x\n",
++                              reg, 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 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 */
++      out_8(&priv->psc->op1, 0x03);
++      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) {
++              printk(KERN_ERR DRV_NAME ": snd_pcm_new failed\n");
++              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) {
++              printk(KERN_ERR DRV_NAME
++                      ": snd_pcm_lib_preallocate_pages_for_all  failed\n");
++              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 */
++      out_8(&priv->psc->op1, 0x03);
++      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->psc->rfcntl, 0x07);
++      out_8(&priv->psc->tfcntl, 0x07);
++      out_be16(&priv->psc->rfalarm, 0x80);
++      out_be16(&priv->psc->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 rv;
++
++      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)) {
++              printk(KERN_ERR DRV_NAME ": request_mem_region failed\n");
++              rv = -EBUSY;
++              goto err_early;
++      }
++
++      priv->psc = ioremap(priv->mem_start, priv->mem_len);
++      if (!priv->psc) {
++              printk(KERN_ERR DRV_NAME ": ioremap failed\n");
++              rv = -ENOMEM;
++              goto err_iomap;
++      }
++
++      priv->irq = irq_of_parse_and_map(dn, 0);
++      if (priv->irq == NO_IRQ) {
++              printk(KERN_ERR DRV_NAME ": irq_of_parse_and_map failed\n");
++              rv = -EBUSY;
++              goto err_irqmap;
++      }
++
++      /* 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) {
++              printk(KERN_ERR DRV_NAME ": request_irq failed\n");
++              goto err_irqreq;
++      }
++
++      /* 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) {
++              printk(KERN_ERR DRV_NAME ": snd_card_register failed\n");
++              goto err_late;
++      }
++
++      dev_set_drvdata(&op->dev, priv);
++
++      return 0;
++
++err_late:
++      free_irq(priv->irq, priv);
++err_irqreq:
++      mpc52xx_ac97_hwshutdown(priv);
++      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 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           = "ac97",       FIXME Efika ... */
++              .compatible     = "mpc5200b-psc-ac97",  /* B only for now */
++      },
++};
++/* Prevent autoload during developpment phase ... */
++/* MODULE_DEVICE_TABLE(of, mpc52xx_ac97_of_match); */
++
++
++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;
++
++      /* Set port_config bits[25:26] to 01, keep the others as-is. This
++     sets PSC2 to AC97 mode. */
++      {
++              void *mbar;
++    u32 port_config;
++              mbar = ioremap(0xf0000000, 0x100000);
++    port_config = in_be32(mbar + 0xb00);
++              printk(KERN_INFO "port_config was: %08x\n", port_config);
++    port_config &= ~0x00000060;
++    port_config |=  0x00000020;
++              out_be32(mbar + 0xb00, port_config);
++              printk(KERN_INFO "port_config now: %08x\n", port_config);
++              iounmap(mbar);
++      }
++
++      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 <tnt@246tNt.com>");
++MODULE_DESCRIPTION(DRV_NAME ": Freescale MPC52xx PSC AC97 driver");
++MODULE_LICENSE("GPL");
++
index 679bd66..fec05ad 100644 (file)
@@ -1,15 +1,16 @@
 DESCRIPTION = "Linux Kernel for the EFIKA dev platform"
 SECTION = "kernel"
 LICENSE = "GPL"
-PR = "r1"
+PR = "r2"
 
 COMPATIBLE_MACHINE = "efika"
 
 SRC_URI = "http://www.efika.de/download/linux-2.6.19-rc6_efika.tgz \
-           http://www.246tnt.com/files/0001-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt;patch=1 \
+           file://0001-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt;patch=1 \
            http://www.246tnt.com/files/0001-powerpc-Add-device-tree-fixup-for-the-EFIKA.txt;patch=1 \
            file://defconfig \
                   "
+#      http://www.246tnt.com/files/0001-sound-Add-support-for-the-MPC52xx-PSC-AC97-Link.txt;patch=1 \
 #           http://lkml.org/lkml/2006/11/29/335;patch=1 \
 
 S = "${WORKDIR}/linux-2.6.19-rc6_efika"