linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3 0/4] mpc5200 audio rework for AC97
@ 2009-05-25  1:38 Jon Smirl
  2009-05-25  1:38 ` [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code Jon Smirl
                   ` (4 more replies)
  0 siblings, 5 replies; 22+ messages in thread
From: Jon Smirl @ 2009-05-25  1:38 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie

The following series implements audio support for the mpc5200. It adds an AC97 driver and STAC9766 codec driver. 
Board support for the Efika and Phytec pcm030 are also included.

I've tried to implement the feedback received on the previous two versions.

based on commit 0bc53a67ac831ec84f730a657dbcadd80a589ef5 on broonie/for-2.6.31 at
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git

---

Jon Smirl (4):
      Fabric bindings for STAC9766 on the Efika
      Support for AC97 on Phytec pmc030 base board.
      AC97 driver for mpc5200
      Main rewite of the mpc5200 audio DMA code


 sound/soc/fsl/Kconfig               |   27 ++
 sound/soc/fsl/Makefile              |    5 
 sound/soc/fsl/efika-audio-fabric.c  |   95 +++++++
 sound/soc/fsl/mpc5200_dma.c         |  504 +++++++++++++++++++++++------------
 sound/soc/fsl/mpc5200_dma.h         |   33 +-
 sound/soc/fsl/mpc5200_psc_ac97.c    |  392 +++++++++++++++++++++++++++
 sound/soc/fsl/mpc5200_psc_ac97.h    |   15 +
 sound/soc/fsl/mpc5200_psc_i2s.c     |  247 +++--------------
 sound/soc/fsl/mpc5200_psc_i2s.h     |   12 +
 sound/soc/fsl/pcm030-audio-fabric.c |   95 +++++++
 10 files changed, 1036 insertions(+), 389 deletions(-)
 create mode 100644 sound/soc/fsl/efika-audio-fabric.c
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.c
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.h
 create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h
 create mode 100644 sound/soc/fsl/pcm030-audio-fabric.c

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code
  2009-05-25  1:38 [PATCH V3 0/4] mpc5200 audio rework for AC97 Jon Smirl
@ 2009-05-25  1:38 ` Jon Smirl
  2009-05-25  6:26   ` Grant Likely
  2009-05-25  1:38 ` [PATCH V3 2/4] AC97 driver for mpc5200 Jon Smirl
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 22+ messages in thread
From: Jon Smirl @ 2009-05-25  1:38 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie

Rewrite the mpc5200 audio DMA code to support both I2S and AC97.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig           |    1 
 sound/soc/fsl/mpc5200_dma.c     |  504 ++++++++++++++++++++++++++-------------
 sound/soc/fsl/mpc5200_dma.h     |   33 +--
 sound/soc/fsl/mpc5200_psc_i2s.c |  247 +++----------------
 sound/soc/fsl/mpc5200_psc_i2s.h |   12 +
 5 files changed, 408 insertions(+), 389 deletions(-)
 create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index dc79bdf..1918c78 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -25,7 +25,6 @@ config SND_SOC_MPC8610_HPCD
 config SND_SOC_MPC5200_I2S
 	tristate "Freescale MPC5200 PSC in I2S mode driver"
 	depends on PPC_MPC52xx && PPC_BESTCOMM
-	select SND_SOC_OF_SIMPLE
 	select SND_MPC52xx_DMA
 	select PPC_BESTCOMM_GEN_BD
 	help
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 6850392..4e1f1f8 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -3,23 +3,13 @@
  * ALSA SoC Platform driver
  *
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
 #include <sysdev/bestcomm/bestcomm.h>
 #include <sysdev/bestcomm/gen_bd.h>
@@ -27,10 +17,6 @@
 
 #include "mpc5200_dma.h"
 
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
-MODULE_LICENSE("GPL");
-
 /*
  * Interrupt handlers
  */
@@ -50,7 +36,7 @@ static irqreturn_t psc_dma_status_irq(int irq, void *_psc_dma)
 	if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORERR))
 		psc_dma->stats.overrun_count++;
 
-	out_8(&regs->command, 4 << 4);	/* reset the error status */
+	out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
 
 	return IRQ_HANDLED;
 }
@@ -81,8 +67,21 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
 		s->period_next_pt = s->period_start;
 }
 
+static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
+{
+	while (s->appl_ptr < s->runtime->control->appl_ptr) {
+
+		if (bcom_queue_full(s->bcom_task))
+			return;
+
+		s->appl_ptr += s->period_size;
+
+		psc_dma_bcom_enqueue_next_buffer(s);
+	}
+}
+
 /* Bestcomm DMA irq handler */
-static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
+static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
 {
 	struct psc_dma_stream *s = _psc_dma_stream;
 
@@ -90,12 +89,12 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
 	 * and enqueue a new one in it's place. */
 	while (bcom_buffer_done(s->bcom_task)) {
 		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+
 		s->period_current_pt += s->period_bytes;
 		if (s->period_current_pt >= s->period_end)
 			s->period_current_pt = s->period_start;
-		psc_dma_bcom_enqueue_next_buffer(s);
-		bcom_enable(s->bcom_task);
 	}
+	psc_dma_bcom_enqueue_tx(s);
 
 	/* If the stream is active, then also inform the PCM middle layer
 	 * of the period finished event. */
@@ -105,49 +104,31 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
 	return IRQ_HANDLED;
 }
 
-/**
- * psc_dma_startup: create a new substream
- *
- * This is the first function called when a stream is opened.
- *
- * If this is the first stream open, then grab the IRQ and program most of
- * the PSC registers.
- */
-int psc_dma_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
+static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
 {
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
-	int rc;
+	struct psc_dma_stream *s = _psc_dma_stream;
 
-	dev_dbg(psc_dma->dev, "psc_dma_startup(substream=%p)\n", substream);
+	/* For each finished period, dequeue the completed period buffer
+	 * and enqueue a new one in it's place. */
+	while (bcom_buffer_done(s->bcom_task)) {
+		bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
 
-	if (!psc_dma->playback.active &&
-	    !psc_dma->capture.active) {
-		/* Setup the IRQs */
-		rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
-				 "psc-dma-status", psc_dma);
-		rc |= request_irq(psc_dma->capture.irq,
-				  &psc_dma_bcom_irq, IRQF_SHARED,
-				  "psc-dma-capture", &psc_dma->capture);
-		rc |= request_irq(psc_dma->playback.irq,
-				  &psc_dma_bcom_irq, IRQF_SHARED,
-				  "psc-dma-playback", &psc_dma->playback);
-		if (rc) {
-			free_irq(psc_dma->irq, psc_dma);
-			free_irq(psc_dma->capture.irq,
-				 &psc_dma->capture);
-			free_irq(psc_dma->playback.irq,
-				 &psc_dma->playback);
-			return -ENODEV;
-		}
+		s->period_current_pt += s->period_bytes;
+		if (s->period_current_pt >= s->period_end)
+			s->period_current_pt = s->period_start;
+
+		psc_dma_bcom_enqueue_next_buffer(s);
 	}
 
-	return 0;
+	/* If the stream is active, then also inform the PCM middle layer
+	 * of the period finished event. */
+	if (s->active)
+		snd_pcm_period_elapsed(s->stream);
+
+	return IRQ_HANDLED;
 }
 
-int psc_dma_hw_free(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai)
+static int psc_dma_hw_free(struct snd_pcm_substream *substream)
 {
 	snd_pcm_set_runtime_buffer(substream, NULL);
 	return 0;
@@ -159,8 +140,7 @@ int psc_dma_hw_free(struct snd_pcm_substream *substream,
  * This function is called by ALSA to start, stop, pause, and resume the DMA
  * transfer of data.
  */
-int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
-			   struct snd_soc_dai *dai)
+static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
@@ -168,8 +148,8 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
 	struct psc_dma_stream *s;
 	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
 	u16 imr;
-	u8 psc_cmd;
 	unsigned long flags;
+	int i;
 
 	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
 		s = &psc_dma->capture;
@@ -189,68 +169,45 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
 				(s->period_bytes * runtime->periods);
 		s->period_next_pt = s->period_start;
 		s->period_current_pt = s->period_start;
+		s->period_size = runtime->period_size;
 		s->active = 1;
 
-		/* First; reset everything */
+		/* track appl_ptr so that we have a better chance of detecting
+		 * end of stream and not over running it.
+		 */
+		s->runtime = runtime;
+		s->appl_ptr = s->runtime->control->appl_ptr -
+				(runtime->period_size * runtime->periods);
+
+		/* Fill up the bestcomm bd queue and enable DMA.
+		 * This will begin filling the PSC's fifo.
+		 */
 		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			out_8(&regs->command, MPC52xx_PSC_RST_RX);
-			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+			bcom_gen_bd_rx_reset(s->bcom_task);
+			for (i = 0; i < runtime->periods; i++)
+				if (!bcom_queue_full(s->bcom_task))
+					psc_dma_bcom_enqueue_next_buffer(s);
 		} else {
-			out_8(&regs->command, MPC52xx_PSC_RST_TX);
-			out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
+			bcom_gen_bd_tx_reset(s->bcom_task);
+			psc_dma_bcom_enqueue_tx(s);
 		}
 
-		/* Next, fill up the bestcomm bd queue and enable DMA.
-		 * This will begin filling the PSC's fifo. */
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
-			bcom_gen_bd_rx_reset(s->bcom_task);
-		else
-			bcom_gen_bd_tx_reset(s->bcom_task);
-		while (!bcom_queue_full(s->bcom_task))
-			psc_dma_bcom_enqueue_next_buffer(s);
 		bcom_enable(s->bcom_task);
 
-		/* Due to errata in the dma mode; need to line up enabling
-		 * the transmitter with a transition on the frame sync
-		 * line */
-
 		spin_lock_irqsave(&psc_dma->lock, flags);
-		/* first make sure it is low */
-		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
-			;
-		/* then wait for the transition to high */
-		while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
-			;
-		/* Finally, enable the PSC.
-		 * Receiver must always be enabled; even when we only want
-		 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
-		psc_cmd = MPC52xx_PSC_RX_ENABLE;
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK)
-			psc_cmd |= MPC52xx_PSC_TX_ENABLE;
-		out_8(&regs->command, psc_cmd);
+		out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
 		spin_unlock_irqrestore(&psc_dma->lock, flags);
 
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-		/* Turn off the PSC */
 		s->active = 0;
-		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
-			if (!psc_dma->playback.active) {
-				out_8(&regs->command, 2 << 4);	/* reset rx */
-				out_8(&regs->command, 3 << 4);	/* reset tx */
-				out_8(&regs->command, 4 << 4);	/* reset err */
-			}
-		} else {
-			out_8(&regs->command, 3 << 4);	/* reset tx */
-			out_8(&regs->command, 4 << 4);	/* reset err */
-			if (!psc_dma->capture.active)
-				out_8(&regs->command, 2 << 4);	/* reset rx */
-		}
 
 		bcom_disable(s->bcom_task);
-		while (!bcom_queue_empty(s->bcom_task))
-			bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			bcom_gen_bd_rx_reset(s->bcom_task);
+		else
+			bcom_gen_bd_tx_reset(s->bcom_task);
 
 		break;
 
@@ -265,44 +222,11 @@ int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
 		imr |= MPC52xx_PSC_IMR_TXEMP;
 	if (psc_dma->capture.active)
 		imr |= MPC52xx_PSC_IMR_ORERR;
-	out_be16(&regs->isr_imr.imr, imr);
+	out_be16(&regs->isr_imr.imr, psc_dma->imr | imr);
 
 	return 0;
 }
 
-/**
- * psc_dma_shutdown: shutdown the data transfer on a stream
- *
- * Shutdown the PSC if there are no other substreams open.
- */
-void psc_dma_shutdown(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
-
-	dev_dbg(psc_dma->dev, "psc_dma_shutdown(substream=%p)\n", substream);
-
-	/*
-	 * If this is the last active substream, disable the PSC and release
-	 * the IRQ.
-	 */
-	if (!psc_dma->playback.active &&
-	    !psc_dma->capture.active) {
-
-		/* Disable all interrupts and reset the PSC */
-		out_be16(&psc_dma->psc_regs->isr_imr.imr, 0);
-		out_8(&psc_dma->psc_regs->command, 3 << 4); /* reset tx */
-		out_8(&psc_dma->psc_regs->command, 2 << 4); /* reset rx */
-		out_8(&psc_dma->psc_regs->command, 1 << 4); /* reset mode */
-		out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
-
-		/* Release irqs */
-		free_irq(psc_dma->irq, psc_dma);
-		free_irq(psc_dma->capture.irq, &psc_dma->capture);
-		free_irq(psc_dma->playback.irq, &psc_dma->playback);
-	}
-}
 
 /* ---------------------------------------------------------------------
  * The PSC DMA 'ASoC platform' driver
@@ -312,62 +236,78 @@ void psc_dma_shutdown(struct snd_pcm_substream *substream,
  * interaction with the attached codec
  */
 
-static const struct snd_pcm_hardware psc_dma_pcm_hardware = {
+static const struct snd_pcm_hardware psc_dma_hardware = {
 	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
 		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
 		SNDRV_PCM_INFO_BATCH,
 	.formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
-		   SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+		SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
 	.rate_min = 8000,
 	.rate_max = 48000,
-	.channels_min = 2,
+	.channels_min = 1,
 	.channels_max = 2,
 	.period_bytes_max	= 1024 * 1024,
 	.period_bytes_min	= 32,
 	.periods_min		= 2,
 	.periods_max		= 256,
 	.buffer_bytes_max	= 2 * 1024 * 1024,
-	.fifo_size		= 0,
+	.fifo_size		= 512,
 };
 
-static int psc_dma_pcm_open(struct snd_pcm_substream *substream)
+static int psc_dma_open(struct snd_pcm_substream *substream)
 {
+	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 	struct psc_dma_stream *s;
+	int rc;
 
-	dev_dbg(psc_dma->dev, "psc_dma_pcm_open(substream=%p)\n", substream);
+	dev_dbg(psc_dma->dev, "psc_dma_open(substream=%p)\n", substream);
 
 	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
 		s = &psc_dma->capture;
 	else
 		s = &psc_dma->playback;
 
-	snd_soc_set_runtime_hwparams(substream, &psc_dma_pcm_hardware);
+	snd_soc_set_runtime_hwparams(substream, &psc_dma_hardware);
+
+	rc = snd_pcm_hw_constraint_integer(runtime,
+		SNDRV_PCM_HW_PARAM_PERIODS);
+	if (rc < 0) {
+		dev_err(substream->pcm->card->dev, "invalid buffer size\n");
+		return rc;
+	}
 
 	s->stream = substream;
 	return 0;
 }
 
-static int psc_dma_pcm_close(struct snd_pcm_substream *substream)
+static int psc_dma_close(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 	struct psc_dma_stream *s;
 
-	dev_dbg(psc_dma->dev, "psc_dma_pcm_close(substream=%p)\n", substream);
+	dev_dbg(psc_dma->dev, "psc_dma_close(substream=%p)\n", substream);
 
 	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
 		s = &psc_dma->capture;
 	else
 		s = &psc_dma->playback;
 
+	if (!psc_dma->playback.active &&
+	    !psc_dma->capture.active) {
+
+		/* Disable all interrupts and reset the PSC */
+		out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+		out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
+	}
 	s->stream = NULL;
 	return 0;
 }
 
 static snd_pcm_uframes_t
-psc_dma_pcm_pointer(struct snd_pcm_substream *substream)
+psc_dma_pointer(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
@@ -384,60 +324,78 @@ psc_dma_pcm_pointer(struct snd_pcm_substream *substream)
 	return bytes_to_frames(substream->runtime, count);
 }
 
-static struct snd_pcm_ops psc_dma_pcm_ops = {
-	.open		= psc_dma_pcm_open,
-	.close		= psc_dma_pcm_close,
+static int
+psc_dma_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static struct snd_pcm_ops psc_dma_ops = {
+	.open		= psc_dma_open,
+	.close		= psc_dma_close,
+	.hw_free	= psc_dma_hw_free,
 	.ioctl		= snd_pcm_lib_ioctl,
-	.pointer	= psc_dma_pcm_pointer,
+	.pointer	= psc_dma_pointer,
+	.trigger	= psc_dma_trigger,
+	.hw_params	= psc_dma_hw_params,
 };
 
-static u64 psc_dma_pcm_dmamask = 0xffffffff;
-static int psc_dma_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+static u64 psc_dma_dmamask = 0xffffffff;
+static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
 			   struct snd_pcm *pcm)
 {
 	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
-	size_t size = psc_dma_pcm_hardware.buffer_bytes_max;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+	size_t size = psc_dma_hardware.buffer_bytes_max;
 	int rc = 0;
 
-	dev_dbg(rtd->socdev->dev, "psc_dma_pcm_new(card=%p, dai=%p, pcm=%p)\n",
+	dev_dbg(rtd->socdev->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n",
 		card, dai, pcm);
 
 	if (!card->dev->dma_mask)
-		card->dev->dma_mask = &psc_dma_pcm_dmamask;
+		card->dev->dma_mask = &psc_dma_dmamask;
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = 0xffffffff;
 
 	if (pcm->streams[0].substream) {
-		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-					&pcm->streams[0].substream->dma_buffer);
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+				size, &pcm->streams[0].substream->dma_buffer);
 		if (rc)
 			goto playback_alloc_err;
 	}
 
 	if (pcm->streams[1].substream) {
-		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
-					&pcm->streams[1].substream->dma_buffer);
+		rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->card->dev,
+				size, &pcm->streams[1].substream->dma_buffer);
 		if (rc)
 			goto capture_alloc_err;
 	}
 
+	if (rtd->socdev->card->codec->ac97)
+		rtd->socdev->card->codec->ac97->private_data = psc_dma;
+
 	return 0;
 
  capture_alloc_err:
 	if (pcm->streams[0].substream)
 		snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+
  playback_alloc_err:
 	dev_err(card->dev, "Cannot allocate buffer(s)\n");
+
 	return -ENOMEM;
 }
 
-static void psc_dma_pcm_free(struct snd_pcm *pcm)
+static void psc_dma_free(struct snd_pcm *pcm)
 {
 	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
 	struct snd_pcm_substream *substream;
 	int stream;
 
-	dev_dbg(rtd->socdev->dev, "psc_dma_pcm_free(pcm=%p)\n", pcm);
+	dev_dbg(rtd->socdev->dev, "psc_dma_free(pcm=%p)\n", pcm);
 
 	for (stream = 0; stream < 2; stream++) {
 		substream = pcm->streams[stream].substream;
@@ -449,10 +407,224 @@ static void psc_dma_pcm_free(struct snd_pcm *pcm)
 	}
 }
 
-struct snd_soc_platform psc_dma_pcm_soc_platform = {
+struct snd_soc_platform mpc5200_audio_dma_platform = {
 	.name		= "mpc5200-psc-audio",
-	.pcm_ops	= &psc_dma_pcm_ops,
-	.pcm_new	= &psc_dma_pcm_new,
-	.pcm_free	= &psc_dma_pcm_free,
+	.pcm_ops	= &psc_dma_ops,
+	.pcm_new	= &psc_dma_new,
+	.pcm_free	= &psc_dma_free,
 };
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_platform);
+
+/* ---------------------------------------------------------------------
+ * Sysfs attributes for error monitoring
+ */
+
+static ssize_t psc_dma_status_show(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct psc_dma *psc_dma = dev_get_drvdata(dev);
+
+	return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
+			"tfnum=%i tfstat=0x%.4x\n",
+			in_be16(&psc_dma->psc_regs->sr_csr.status),
+			in_be32(&psc_dma->psc_regs->sicr),
+			in_be16(&psc_dma->fifo_regs->rfnum) & 0x1ff,
+			in_be16(&psc_dma->fifo_regs->rfstat),
+			in_be16(&psc_dma->fifo_regs->tfnum) & 0x1ff,
+			in_be16(&psc_dma->fifo_regs->tfstat));
+}
+
+static unsigned long *psc_dma_get_stat_attr(struct psc_dma *psc_dma,
+							const char *name)
+{
+	if (strcmp(name, "playback_underrun") == 0)
+		return &psc_dma->stats.underrun_count;
+	if (strcmp(name, "capture_overrun") == 0)
+		return &psc_dma->stats.overrun_count;
+
+	return 0;
+}
+
+static ssize_t psc_dma_stat_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct psc_dma *psc_dma = dev_get_drvdata(dev);
+	unsigned long *attrib;
+
+	attrib = psc_dma_get_stat_attr(psc_dma, attr->attr.name);
+	if (!attrib)
+		return 0;
+
+	return sprintf(buf, "%lu\n", *attrib);
+}
 
+static ssize_t psc_dma_stat_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf,
+				  size_t count)
+{
+	struct psc_dma *psc_dma = dev_get_drvdata(dev);
+	unsigned long *attrib;
+
+	attrib = psc_dma_get_stat_attr(psc_dma, attr->attr.name);
+	if (!attrib)
+		return 0;
+
+	strict_strtoul(buf, 10, attrib);
+	return count;
+}
+
+static DEVICE_ATTR(status, 0644, psc_dma_status_show, NULL);
+static DEVICE_ATTR(playback_underrun, 0644, psc_dma_stat_show,
+			psc_dma_stat_store);
+static DEVICE_ATTR(capture_overrun, 0644, psc_dma_stat_show,
+			psc_dma_stat_store);
+
+
+int mpc5200_audio_dma_create(struct of_device *op)
+{
+	phys_addr_t fifo;
+	struct psc_dma *psc_dma;
+	struct resource res;
+	int size, irq, rc;
+	const __be32 *prop;
+	void __iomem *regs;
+
+	/* Fetch the registers and IRQ of the PSC */
+	irq = irq_of_parse_and_map(op->node, 0);
+	if (of_address_to_resource(op->node, 0, &res)) {
+		dev_err(&op->dev, "Missing reg property\n");
+		return -ENODEV;
+	}
+	regs = ioremap(res.start, 1 + res.end - res.start);
+	if (!regs) {
+		dev_err(&op->dev, "Could not map registers\n");
+		return -ENODEV;
+	}
+
+	/* Allocate and initialize the driver private data */
+	psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
+	if (!psc_dma) {
+		iounmap(regs);
+		return -ENOMEM;
+	}
+
+	/* Get the PSC ID */
+	prop = of_get_property(op->node, "cell-index", &size);
+	if (!prop || size < sizeof *prop)
+		return -ENODEV;
+
+	spin_lock_init(&psc_dma->lock);
+	psc_dma->id = be32_to_cpu(*prop);
+	psc_dma->irq = irq;
+	psc_dma->psc_regs = regs;
+	psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
+	psc_dma->dev = &op->dev;
+	psc_dma->playback.psc_dma = psc_dma;
+	psc_dma->capture.psc_dma = psc_dma;
+	snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_dma->id);
+
+	/* Find the address of the fifo data registers and setup the
+	 * DMA tasks */
+	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
+	psc_dma->capture.bcom_task =
+		bcom_psc_gen_bd_rx_init(psc_dma->id, 10, fifo, 512);
+	psc_dma->playback.bcom_task =
+		bcom_psc_gen_bd_tx_init(psc_dma->id, 10, fifo);
+	if (!psc_dma->capture.bcom_task ||
+	    !psc_dma->playback.bcom_task) {
+		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
+		iounmap(regs);
+		kfree(psc_dma);
+		return -ENODEV;
+	}
+
+	/* Disable all interrupts and reset the PSC */
+	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+	 /* reset receiver */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_RX);
+	 /* reset transmitter */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_TX);
+	 /* reset error */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_RST_ERR_STAT);
+	 /* reset mode */
+	out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_SEL_MODE_REG_1);
+
+	/* Set up mode register;
+	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
+	 * Second write: register Normal mode for non loopback
+	 */
+	out_8(&psc_dma->psc_regs->mode, 0);
+	out_8(&psc_dma->psc_regs->mode, 0);
+
+	/* Set the TX and RX fifo alarm thresholds */
+	out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
+	out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
+	out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
+	out_8(&psc_dma->fifo_regs->tfcntl, 0x7);
+
+	/* Lookup the IRQ numbers */
+	psc_dma->playback.irq =
+		bcom_get_task_irq(psc_dma->playback.bcom_task);
+	psc_dma->capture.irq =
+		bcom_get_task_irq(psc_dma->capture.bcom_task);
+
+	rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
+			 "psc-dma-status", psc_dma);
+	rc |= request_irq(psc_dma->capture.irq,
+			  &psc_dma_bcom_irq_rx, IRQF_SHARED,
+			  "psc-dma-capture", &psc_dma->capture);
+	rc |= request_irq(psc_dma->playback.irq,
+			  &psc_dma_bcom_irq_tx, IRQF_SHARED,
+			  "psc-dma-playback", &psc_dma->playback);
+	if (rc) {
+		free_irq(psc_dma->irq, psc_dma);
+		free_irq(psc_dma->capture.irq,
+			 &psc_dma->capture);
+		free_irq(psc_dma->playback.irq,
+			 &psc_dma->playback);
+		return -ENODEV;
+	}
+
+	/* Save what we've done so it can be found again later */
+	dev_set_drvdata(&op->dev, psc_dma);
+
+	/* Register the SYSFS files */
+	rc = device_create_file(psc_dma->dev, &dev_attr_status);
+	rc |= device_create_file(psc_dma->dev, &dev_attr_capture_overrun);
+	rc |= device_create_file(psc_dma->dev, &dev_attr_playback_underrun);
+	if (rc)
+		dev_info(psc_dma->dev, "error creating sysfs files\n");
+
+	/* Tell the ASoC OF helpers about it */
+	return snd_soc_register_platform(&mpc5200_audio_dma_platform);
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create);
+
+int mpc5200_audio_dma_destroy(struct of_device *op)
+{
+	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
+
+	dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n");
+
+	snd_soc_unregister_platform(&mpc5200_audio_dma_platform);
+
+	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
+	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
+
+	/* Release irqs */
+	free_irq(psc_dma->irq, psc_dma);
+	free_irq(psc_dma->capture.irq, &psc_dma->capture);
+	free_irq(psc_dma->playback.irq, &psc_dma->playback);
+
+	iounmap(psc_dma->psc_regs);
+	kfree(psc_dma);
+	dev_set_drvdata(&op->dev, NULL);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mpc5200_audio_dma_destroy);
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index a33232c..2000803 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -5,8 +5,10 @@
 #ifndef __SOUND_SOC_FSL_MPC5200_DMA_H__
 #define __SOUND_SOC_FSL_MPC5200_DMA_H__
 
+#define PSC_STREAM_NAME_LEN 32
+
 /**
- * psc_dma_stream - Data specific to a single stream (playback or capture)
+ * psc_ac97_stream - Data specific to a single stream (playback or capture)
  * @active:		flag indicating if the stream is active
  * @psc_dma:		pointer back to parent psc_dma data structure
  * @bcom_task:		bestcomm task structure
@@ -17,6 +19,9 @@
  * @period_bytes:	size of DMA period in bytes
  */
 struct psc_dma_stream {
+	struct snd_pcm_runtime *runtime;
+	snd_pcm_uframes_t appl_ptr;
+
 	int active;
 	struct psc_dma *psc_dma;
 	struct bcom_task *bcom_task;
@@ -27,6 +32,7 @@ struct psc_dma_stream {
 	dma_addr_t period_next_pt;
 	dma_addr_t period_current_pt;
 	int period_bytes;
+	int period_size;
 };
 
 /**
@@ -48,9 +54,12 @@ struct psc_dma {
 	struct mpc52xx_psc_fifo __iomem *fifo_regs;
 	unsigned int irq;
 	struct device *dev;
-	struct snd_soc_dai dai;
 	spinlock_t lock;
 	u32 sicr;
+	uint sysclk;
+	int imr;
+	int id;
+	unsigned int slots;
 
 	/* per-stream data */
 	struct psc_dma_stream playback;
@@ -58,24 +67,14 @@ struct psc_dma {
 
 	/* Statistics */
 	struct {
-		int overrun_count;
-		int underrun_count;
+		unsigned long overrun_count;
+		unsigned long underrun_count;
 	} stats;
 };
 
+int mpc5200_audio_dma_create(struct of_device *op);
+int mpc5200_audio_dma_destroy(struct of_device *op);
 
-int psc_dma_startup(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai);
-
-int psc_dma_hw_free(struct snd_pcm_substream *substream,
-			   struct snd_soc_dai *dai);
-
-void psc_dma_shutdown(struct snd_pcm_substream *substream,
-			     struct snd_soc_dai *dai);
-
-int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
-			   struct snd_soc_dai *dai);
-
-extern struct snd_soc_platform psc_dma_pcm_soc_platform;
+extern struct snd_soc_platform mpc5200_audio_dma_platform;
 
 #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 12a7917..ce8de90 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -3,34 +3,22 @@
  * ALSA SoC Digital Audio Interface (DAI) driver
  *
  * Copyright (C) 2008 Secret Lab Technologies Ltd.
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/delay.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#include <linux/dma-mapping.h>
 
-#include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/initval.h>
 #include <sound/soc.h>
-#include <sound/soc-of-simple.h>
 
-#include <sysdev/bestcomm/bestcomm.h>
-#include <sysdev/bestcomm/gen_bd.h>
 #include <asm/mpc52xx_psc.h>
 
+#include "mpc5200_psc_i2s.h"
 #include "mpc5200_dma.h"
 
-MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
-MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
-MODULE_LICENSE("GPL");
-
 /**
  * PSC_I2S_RATES: sample rates supported by the I2S
  *
@@ -46,8 +34,7 @@ MODULE_LICENSE("GPL");
  * PSC_I2S_FORMATS: audio formats supported by the PSC I2S mode
  */
 #define PSC_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \
-			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE | \
-			 SNDRV_PCM_FMTBIT_S32_BE)
+			 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE)
 
 static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
@@ -82,8 +69,6 @@ static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
 	}
 	out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr | mode);
 
-	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
 	return 0;
 }
 
@@ -140,16 +125,13 @@ static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
  * psc_i2s_dai_template: template CPU Digital Audio Interface
  */
 static struct snd_soc_dai_ops psc_i2s_dai_ops = {
-	.startup	= psc_dma_startup,
 	.hw_params	= psc_i2s_hw_params,
-	.hw_free	= psc_dma_hw_free,
-	.shutdown	= psc_dma_shutdown,
-	.trigger	= psc_dma_trigger,
 	.set_sysclk	= psc_i2s_set_sysclk,
 	.set_fmt	= psc_i2s_set_fmt,
 };
 
-static struct snd_soc_dai psc_i2s_dai_template = {
+struct snd_soc_dai psc_i2s_dai[] = {{
+	.name   = "I2S",
 	.playback = {
 		.channels_min = 2,
 		.channels_max = 2,
@@ -163,71 +145,8 @@ static struct snd_soc_dai psc_i2s_dai_template = {
 		.formats = PSC_I2S_FORMATS,
 	},
 	.ops = &psc_i2s_dai_ops,
-};
-
-/* ---------------------------------------------------------------------
- * Sysfs attributes for debugging
- */
-
-static ssize_t psc_i2s_status_show(struct device *dev,
-			   struct device_attribute *attr, char *buf)
-{
-	struct psc_dma *psc_dma = dev_get_drvdata(dev);
-
-	return sprintf(buf, "status=%.4x sicr=%.8x rfnum=%i rfstat=0x%.4x "
-			"tfnum=%i tfstat=0x%.4x\n",
-			in_be16(&psc_dma->psc_regs->sr_csr.status),
-			in_be32(&psc_dma->psc_regs->sicr),
-			in_be16(&psc_dma->fifo_regs->rfnum) & 0x1ff,
-			in_be16(&psc_dma->fifo_regs->rfstat),
-			in_be16(&psc_dma->fifo_regs->tfnum) & 0x1ff,
-			in_be16(&psc_dma->fifo_regs->tfstat));
-}
-
-static int *psc_i2s_get_stat_attr(struct psc_dma *psc_dma, const char *name)
-{
-	if (strcmp(name, "playback_underrun") == 0)
-		return &psc_dma->stats.underrun_count;
-	if (strcmp(name, "capture_overrun") == 0)
-		return &psc_dma->stats.overrun_count;
-
-	return NULL;
-}
-
-static ssize_t psc_i2s_stat_show(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	struct psc_dma *psc_dma = dev_get_drvdata(dev);
-	int *attrib;
-
-	attrib = psc_i2s_get_stat_attr(psc_dma, attr->attr.name);
-	if (!attrib)
-		return 0;
-
-	return sprintf(buf, "%i\n", *attrib);
-}
-
-static ssize_t psc_i2s_stat_store(struct device *dev,
-				  struct device_attribute *attr,
-				  const char *buf,
-				  size_t count)
-{
-	struct psc_dma *psc_dma = dev_get_drvdata(dev);
-	int *attrib;
-
-	attrib = psc_i2s_get_stat_attr(psc_dma, attr->attr.name);
-	if (!attrib)
-		return 0;
-
-	*attrib = simple_strtoul(buf, NULL, 0);
-	return count;
-}
-
-static DEVICE_ATTR(status, 0644, psc_i2s_status_show, NULL);
-static DEVICE_ATTR(playback_underrun, 0644, psc_i2s_stat_show,
-			psc_i2s_stat_store);
-static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
-			psc_i2s_stat_store);
+} };
+EXPORT_SYMBOL_GPL(psc_i2s_dai);
 
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
@@ -237,82 +156,26 @@ static DEVICE_ATTR(capture_overrun, 0644, psc_i2s_stat_show,
 static int __devinit psc_i2s_of_probe(struct of_device *op,
 				      const struct of_device_id *match)
 {
-	phys_addr_t fifo;
+	int rc;
 	struct psc_dma *psc_dma;
-	struct resource res;
-	int size, psc_id, irq, rc;
-	const __be32 *prop;
-	void __iomem *regs;
-
-	dev_dbg(&op->dev, "probing psc i2s device\n");
-
-	/* Get the PSC ID */
-	prop = of_get_property(op->node, "cell-index", &size);
-	if (!prop || size < sizeof *prop)
-		return -ENODEV;
-	psc_id = be32_to_cpu(*prop);
-
-	/* Fetch the registers and IRQ of the PSC */
-	irq = irq_of_parse_and_map(op->node, 0);
-	if (of_address_to_resource(op->node, 0, &res)) {
-		dev_err(&op->dev, "Missing reg property\n");
-		return -ENODEV;
-	}
-	regs = ioremap(res.start, 1 + res.end - res.start);
-	if (!regs) {
-		dev_err(&op->dev, "Could not map registers\n");
-		return -ENODEV;
-	}
+	struct mpc52xx_psc __iomem *regs;
 
-	/* Allocate and initialize the driver private data */
-	psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL);
-	if (!psc_dma) {
-		iounmap(regs);
-		return -ENOMEM;
-	}
-	spin_lock_init(&psc_dma->lock);
-	psc_dma->irq = irq;
-	psc_dma->psc_regs = regs;
-	psc_dma->fifo_regs = regs + sizeof *psc_dma->psc_regs;
-	psc_dma->dev = &op->dev;
-	psc_dma->playback.psc_dma = psc_dma;
-	psc_dma->capture.psc_dma = psc_dma;
-	snprintf(psc_dma->name, sizeof psc_dma->name, "PSC%u", psc_id+1);
-
-	/* Fill out the CPU DAI structure */
-	memcpy(&psc_dma->dai, &psc_i2s_dai_template, sizeof psc_dma->dai);
-	psc_dma->dai.private_data = psc_dma;
-	psc_dma->dai.name = psc_dma->name;
-	psc_dma->dai.id = psc_id;
-
-	/* Find the address of the fifo data registers and setup the
-	 * DMA tasks */
-	fifo = res.start + offsetof(struct mpc52xx_psc, buffer.buffer_32);
-	psc_dma->capture.bcom_task =
-		bcom_psc_gen_bd_rx_init(psc_id, 10, fifo, 512);
-	psc_dma->playback.bcom_task =
-		bcom_psc_gen_bd_tx_init(psc_id, 10, fifo);
-	if (!psc_dma->capture.bcom_task ||
-	    !psc_dma->playback.bcom_task) {
-		dev_err(&op->dev, "Could not allocate bestcomm tasks\n");
-		iounmap(regs);
-		kfree(psc_dma);
-		return -ENODEV;
+	rc = mpc5200_audio_dma_create(op);
+	if (rc != 0)
+		return rc;
+
+	rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+	if (rc != 0) {
+		pr_err("Failed to register DAI\n");
+		return 0;
 	}
 
-	/* Disable all interrupts and reset the PSC */
-	out_be16(&psc_dma->psc_regs->isr_imr.imr, 0);
-	out_8(&psc_dma->psc_regs->command, 3 << 4); /* reset transmitter */
-	out_8(&psc_dma->psc_regs->command, 2 << 4); /* reset receiver */
-	out_8(&psc_dma->psc_regs->command, 1 << 4); /* reset mode */
-	out_8(&psc_dma->psc_regs->command, 4 << 4); /* reset error */
+	psc_dma = dev_get_drvdata(&op->dev);
+	regs = psc_dma->psc_regs;
 
 	/* Configure the serial interface mode; defaulting to CODEC8 mode */
 	psc_dma->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
 			MPC52xx_PSC_SICR_CLKPOL;
-	if (of_get_property(op->node, "fsl,cellslave", NULL))
-		psc_dma->sicr |= MPC52xx_PSC_SICR_CELLSLAVE |
-				 MPC52xx_PSC_SICR_GENCLK;
 	out_be32(&psc_dma->psc_regs->sicr,
 		 psc_dma->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
 
@@ -321,66 +184,37 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,
 	if (!of_get_property(op->node, "codec-handle", NULL))
 		return 0;
 
-	/* Set up mode register;
-	 * First write: RxRdy (FIFO Alarm) generates rx FIFO irq
-	 * Second write: register Normal mode for non loopback
-	 */
-	out_8(&psc_dma->psc_regs->mode, 0);
-	out_8(&psc_dma->psc_regs->mode, 0);
-
-	/* Set the TX and RX fifo alarm thresholds */
-	out_be16(&psc_dma->fifo_regs->rfalarm, 0x100);
-	out_8(&psc_dma->fifo_regs->rfcntl, 0x4);
-	out_be16(&psc_dma->fifo_regs->tfalarm, 0x100);
-	out_8(&psc_dma->fifo_regs->tfcntl, 0x7);
-
-	/* Lookup the IRQ numbers */
-	psc_dma->playback.irq =
-		bcom_get_task_irq(psc_dma->playback.bcom_task);
-	psc_dma->capture.irq =
-		bcom_get_task_irq(psc_dma->capture.bcom_task);
-
-	/* Save what we've done so it can be found again later */
-	dev_set_drvdata(&op->dev, psc_dma);
-
-	/* Register the SYSFS files */
-	rc = device_create_file(psc_dma->dev, &dev_attr_status);
-	rc |= device_create_file(psc_dma->dev, &dev_attr_capture_overrun);
-	rc |= device_create_file(psc_dma->dev, &dev_attr_playback_underrun);
-	if (rc)
-		dev_info(psc_dma->dev, "error creating sysfs files\n");
-
-	snd_soc_register_platform(&psc_dma_pcm_soc_platform);
-
-	/* Tell the ASoC OF helpers about it */
-	of_snd_soc_register_platform(&psc_dma_pcm_soc_platform, op->node,
-				     &psc_dma->dai);
+	/* Due to errata in the dma mode; need to line up enabling
+	 * the transmitter with a transition on the frame sync
+	 * line */
+
+	/* first make sure it is low */
+	while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0)
+		;
+	/* then wait for the transition to high */
+	while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0)
+		;
+	/* Finally, enable the PSC.
+	 * Receiver must always be enabled; even when we only want
+	 * transmit.  (see 15.3.2.3 of MPC5200B User's Guide) */
+
+	/* Go */
+	out_8(&psc_dma->psc_regs->command,
+			MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
 
 	return 0;
+
 }
 
 static int __devexit psc_i2s_of_remove(struct of_device *op)
 {
-	struct psc_dma *psc_dma = dev_get_drvdata(&op->dev);
-
-	dev_dbg(&op->dev, "psc_i2s_remove()\n");
-
-	snd_soc_unregister_platform(&psc_dma_pcm_soc_platform);
-
-	bcom_gen_bd_rx_release(psc_dma->capture.bcom_task);
-	bcom_gen_bd_tx_release(psc_dma->playback.bcom_task);
-
-	iounmap(psc_dma->psc_regs);
-	iounmap(psc_dma->fifo_regs);
-	kfree(psc_dma);
-	dev_set_drvdata(&op->dev, NULL);
-
-	return 0;
+	return mpc5200_audio_dma_destroy(op);
 }
 
 /* Match table for of_platform binding */
 static struct of_device_id psc_i2s_match[] __devinitdata = {
 	{ .compatible = "fsl,mpc5200-psc-i2s", },
+	{ .compatible = "fsl,mpc5200b-psc-i2s", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, psc_i2s_match);
@@ -411,4 +245,7 @@ static void __exit psc_i2s_exit(void)
 }
 module_exit(psc_i2s_exit);
 
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
+MODULE_LICENSE("GPL");
 
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
new file mode 100644
index 0000000..ce55e07
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.h
@@ -0,0 +1,12 @@
+/*
+ * Freescale MPC5200 PSC in I2S mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
+
+extern struct snd_soc_dai psc_i2s_dai[];
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25  1:38 [PATCH V3 0/4] mpc5200 audio rework for AC97 Jon Smirl
  2009-05-25  1:38 ` [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code Jon Smirl
@ 2009-05-25  1:38 ` Jon Smirl
  2009-05-25  6:16   ` Grant Likely
  2009-05-25 10:26   ` Mark Brown
  2009-05-25  1:38 ` [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board Jon Smirl
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 22+ messages in thread
From: Jon Smirl @ 2009-05-25  1:38 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie

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>
---
 sound/soc/fsl/Kconfig            |   11 +
 sound/soc/fsl/Makefile           |    1 
 sound/soc/fsl/mpc5200_psc_ac97.c |  392 ++++++++++++++++++++++++++++++++++++++
 sound/soc/fsl/mpc5200_psc_ac97.h |   15 +
 4 files changed, 419 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.c
 create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.h

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 1918c78..3bce952 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -29,3 +29,14 @@ config SND_SOC_MPC5200_I2S
 	select PPC_BESTCOMM_GEN_BD
 	help
 	  Say Y here to support the MPC5200 PSCs in I2S mode.
+
+config SND_SOC_MPC5200_AC97
+	tristate "Freescale MPC5200 PSC in AC97 mode driver"
+	depends on PPC_MPC52xx && PPC_BESTCOMM
+	select AC97_BUS
+	select SND_MPC52xx_DMA
+	select PPC_BESTCOMM_GEN_BD
+	help
+	  Say Y here to support the MPC5200 PSCs in AC97 mode.
+
+
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 7731ef2..14631a1 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
 # MPC5200 Platform Support
 obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
+obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
new file mode 100644
index 0000000..480b677
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -0,0 +1,392 @@
+/*
+ * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
+ *
+ * Copyright (C) 2009 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+
+#define DRV_NAME "mpc5200-psc-ac97"
+
+/* ALSA only supports a single AC97 device so static is recommend here */
+static struct psc_dma *psc_dma;
+
+static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+	int timeout;
+	unsigned int val;
+
+	spin_lock(&psc_dma->lock);
+
+	/* Wait for it to be ready */
+	timeout = 1000;
+	while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr.status) &
+						MPC52xx_PSC_SR_CMDSEND))
+		udelay(10);
+
+	if (!timeout) {
+		pr_err("timeout on ac97 bus (rdy)\n");
+		return 0xffff;
+	}
+
+	/* Do the read */
+	out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x7f) << 24));
+
+	/* Wait for the answer */
+	timeout = 1000;
+	while ((--timeout) && !(in_be16(&psc_dma->psc_regs->sr_csr.status) &
+						MPC52xx_PSC_SR_DATA_VAL))
+		udelay(10);
+
+	if (!timeout) {
+		pr_err("timeout on ac97 read (val) %x\n",
+				in_be16(&psc_dma->psc_regs->sr_csr.status));
+		return 0xffff;
+	}
+
+	/* Get the data */
+	val = in_be32(&psc_dma->psc_regs->ac97_data);
+	if (((val>>24) & 0x7f) != reg) {
+		pr_err("reg echo error on ac97 read\n");
+		return 0xffff;
+	}
+	val = (val >> 8) & 0xffff;
+
+	spin_unlock(&psc_dma->lock);
+	return (unsigned short) val;
+}
+
+static void psc_ac97_write(struct snd_ac97 *ac97,
+				unsigned short reg, unsigned short val)
+{
+	int timeout;
+
+	spin_lock(&psc_dma->lock);
+
+	/* Wait for it to be ready */
+	timeout = 1000;
+	while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr.status) &
+						MPC52xx_PSC_SR_CMDSEND))
+		udelay(10);
+
+	if (!timeout) {
+		pr_err("timeout on ac97 write\n");
+		return;
+	}
+
+	/* Write data */
+	out_be32(&psc_dma->psc_regs->ac97_cmd,
+			((reg & 0x7f) << 24) | (val << 8));
+
+	spin_unlock(&psc_dma->lock);
+}
+
+static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
+	udelay(3);
+	out_be32(&regs->sicr, psc_dma->sicr);
+}
+
+static int psc_ac97_cold_reset_check(struct snd_ac97 *ac97)
+{
+	int max_reset, timeout;
+	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
+
+	/* AC97 clock is generated by the codec.
+	 * Ensure that it starts ticking after codec reset.
+	 */
+	for (max_reset = 0; max_reset < 5; max_reset++) {
+
+		/* Do a cold reset */
+		out_8(&regs->op1, MPC52xx_PSC_OP_RES);
+		udelay(10);
+		out_8(&regs->op0, MPC52xx_PSC_OP_RES);
+		udelay(50);
+
+		/* PSC recover from cold reset
+		 * (cfr user manual, not sure if useful)
+		 */
+		out_be32(&regs->sicr, in_be32(&regs->sicr));
+
+		psc_ac97_warm_reset(ac97);
+
+		/* first make sure AC97 clock is low */
+		for (timeout = 0; ((in_8(&regs->ipcr_acr.ipcr) & 0x80) != 0) &&
+				(timeout < 100); timeout++)
+			udelay(10);
+		if (timeout == 100)
+			continue;
+
+		/* then wait for the transition to high */
+		for (timeout = 0; ((in_8(&regs->ipcr_acr.ipcr) & 0x80) == 0) &&
+				(timeout < 100); timeout++)
+			udelay(10);
+		if (timeout == 100)
+			continue;
+
+		break;
+	}
+	if (max_reset == 5)
+		return -ENODEV;
+	return 0;
+}
+
+static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+	psc_ac97_cold_reset_check(ac97);
+
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+	.read		= psc_ac97_read,
+	.write		= psc_ac97_write,
+	.reset		= psc_ac97_cold_reset,
+	.warm_reset	= psc_ac97_warm_reset,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+
+	dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
+		" periods=%i buffer_size=%i  buffer_bytes=%i channels=%i"
+		" rate=%i format=%i\n",
+		__func__, substream, params_period_size(params),
+		params_period_bytes(params), params_periods(params),
+		params_buffer_size(params), params_buffer_bytes(params),
+		params_channels(params), params_rate(params),
+		params_format(params));
+
+
+	if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		if (params_channels(params) == 1)
+			psc_dma->slots |= 0x00000100;
+		else
+			psc_dma->slots |= 0x00000300;
+	} else {
+		if (params_channels(params) == 1)
+			psc_dma->slots |= 0x01000000;
+		else
+			psc_dma->slots |= 0x03000000;
+	}
+
+	spin_lock(&psc_dma->lock);
+	out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+	spin_unlock(&psc_dma->lock);
+
+	return 0;
+}
+
+static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *cpu_dai)
+{
+	struct psc_dma *psc_dma = cpu_dai->private_data;
+
+	spin_lock(&psc_dma->lock);
+	if (params_channels(params) == 1)
+		out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
+	else
+		out_be32(&psc_dma->psc_regs->ac97_slots, 0x03000000);
+	spin_unlock(&psc_dma->lock);
+
+	return 0;
+}
+
+static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+							struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+			psc_dma->slots &= 0xFFFF0000;
+		else
+			psc_dma->slots &= 0x0000FFFF;
+
+		spin_lock(&psc_dma->lock);
+		out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+		spin_unlock(&psc_dma->lock);
+		break;
+	}
+	return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * ALSA SoC Bindings
+ *
+ * - Digital Audio Interface (DAI) template
+ * - create/destroy dai hooks
+ */
+
+/**
+ * psc_ac97_dai_template: template CPU Digital Audio Interface
+ */
+static struct snd_soc_dai_ops psc_ac97_analog_ops = {
+	.hw_params	= psc_ac97_hw_analog_params,
+	.trigger	= psc_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops psc_ac97_digital_ops = {
+	.hw_params	= psc_ac97_hw_digital_params,
+};
+
+struct snd_soc_dai psc_ac97_dai[] = {
+{
+	.name   = "AC97",
+	.ac97_control = 1,
+	.playback = {
+		.channels_min   = 1,
+		.channels_max   = 6,
+		.rates          = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_BE,
+	},
+	.capture = {
+		.channels_min   = 1,
+		.channels_max   = 2,
+		.rates          = SNDRV_PCM_RATE_8000_48000,
+		.formats = SNDRV_PCM_FMTBIT_S32_BE,
+	},
+	.ops = &psc_ac97_analog_ops,
+},
+{
+	.name   = "SPDIF",
+	.ac97_control = 1,
+	.playback = {
+		.channels_min   = 1,
+		.channels_max   = 2,
+		.rates          = SNDRV_PCM_RATE_32000 | \
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE,
+	},
+	.ops = &psc_ac97_digital_ops,
+} };
+EXPORT_SYMBOL_GPL(psc_ac97_dai);
+
+
+
+/* ---------------------------------------------------------------------
+ * OF platform bus binding code:
+ * - Probe/remove operations
+ * - OF device match table
+ */
+static int __devinit psc_ac97_of_probe(struct of_device *op,
+				      const struct of_device_id *match)
+{
+	int rc, i, id1, id2;
+	struct snd_ac97 ac97;
+	struct mpc52xx_psc __iomem *regs;
+
+	rc = mpc5200_audio_dma_create(op);
+	if (rc != 0)
+		return rc;
+
+	for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+		psc_ac97_dai[i].dev = &op->dev;
+
+	rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+	if (rc != 0) {
+		dev_err(&op->dev, "Failed to register DAI\n");
+		return rc;
+	}
+
+	psc_dma = dev_get_drvdata(&op->dev);
+	regs = psc_dma->psc_regs;
+	ac97.private_data = psc_dma;
+
+	for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
+		psc_ac97_dai[i].private_data = psc_dma;
+
+	psc_dma->imr = 0;
+	out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+
+	/* Configure the serial interface mode to AC97 */
+	psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97;
+	out_be32(&regs->sicr, psc_dma->sicr);
+
+	/* No slots active */
+	out_be32(&regs->ac97_slots, 0x00000000);
+
+	/* AC97 clock is generated by the codec.
+	 * Ensure that it starts ticking after codec reset.
+	 */
+	rc = psc_ac97_cold_reset_check(&ac97);
+	if (rc != 0) {
+		dev_err(&op->dev, "AC97 codec failed to reset\n");
+		mpc5200_audio_dma_destroy(op);
+		return rc;
+	}
+
+	/* Go */
+	out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+
+	return 0;
+}
+
+static int __devexit psc_ac97_of_remove(struct of_device *op)
+{
+	return mpc5200_audio_dma_destroy(op);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id psc_ac97_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5200-psc-ac97", },
+	{ .compatible = "fsl,mpc5200b-psc-ac97", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, psc_ac97_match);
+
+static struct of_platform_driver psc_ac97_driver = {
+	.match_table = psc_ac97_match,
+	.probe = psc_ac97_of_probe,
+	.remove = __devexit_p(psc_ac97_of_remove),
+	.driver = {
+		.name = "mpc5200-psc-ac97",
+		.owner = THIS_MODULE,
+	},
+};
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown; simply register the of_platform driver
+ * for the PSC in AC97 mode.
+ */
+static int __init psc_ac97_init(void)
+{
+	return of_register_platform_driver(&psc_ac97_driver);
+}
+module_init(psc_ac97_init);
+
+static void __exit psc_ac97_exit(void)
+{
+	of_unregister_platform_driver(&psc_ac97_driver);
+}
+module_exit(psc_ac97_exit);
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION("mpc5200 AC97 module");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
new file mode 100644
index 0000000..4bc18c3
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -0,0 +1,15 @@
+/*
+ * Freescale MPC5200 PSC in AC97 mode
+ * ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ */
+
+#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+#define __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__
+
+extern struct snd_soc_dai psc_ac97_dai[];
+
+#define MPC5200_AC97_NORMAL 0
+#define MPC5200_AC97_SPDIF 1
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board.
  2009-05-25  1:38 [PATCH V3 0/4] mpc5200 audio rework for AC97 Jon Smirl
  2009-05-25  1:38 ` [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code Jon Smirl
  2009-05-25  1:38 ` [PATCH V3 2/4] AC97 driver for mpc5200 Jon Smirl
@ 2009-05-25  1:38 ` Jon Smirl
  2009-05-25  6:34   ` Grant Likely
  2009-05-25  9:48   ` Mark Brown
  2009-05-25  1:38 ` [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika Jon Smirl
  2009-05-25 10:43 ` [PATCH V3 0/4] mpc5200 audio rework for AC97 Mark Brown
  4 siblings, 2 replies; 22+ messages in thread
From: Jon Smirl @ 2009-05-25  1:38 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie

Support for AC97 on Phytec pmc030 base board. A wm9712 AC97 codec is used.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig               |    7 +++
 sound/soc/fsl/Makefile              |    3 +
 sound/soc/fsl/pcm030-audio-fabric.c |   95 +++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/fsl/pcm030-audio-fabric.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3bce952..79579ae 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -39,4 +39,11 @@ config SND_SOC_MPC5200_AC97
 	help
 	  Say Y here to support the MPC5200 PSCs in AC97 mode.
 
+config SND_MPC52xx_SOC_PCM030
+	tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712"
+	depends on PPC_MPC5200_SIMPLE
+	select SND_SOC_MPC5200_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for sound on the Phytec pcm030 baseboard.
 
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 14631a1..66d88c8 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -15,3 +15,6 @@ obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
 obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
 obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 
+# MPC5200 Machine Support
+obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
+
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
new file mode 100644
index 0000000..2c426d5
--- /dev/null
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -0,0 +1,95 @@
+/*
+ * Phytec pcm030 driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/wm9712.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link pcm030_fabric_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 Analog",
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+	.name = "AC97",
+	.stream_name = "AC97 IEC958",
+	.codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int pcm030_fabric_init(void)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	if (!machine_is_compatible("phytec,pcm030"))
+		return -ENODEV;
+
+	card.platform = &mpc5200_audio_dma_platform;
+	card.name = "pcm030";
+	card.dai_link = pcm030_fabric_dai;
+	card.num_links = ARRAY_SIZE(pcm030_fabric_dai);
+
+	device.card = &card;
+	device.codec_dev = &soc_codec_dev_wm9712;
+
+	pdev = platform_device_alloc("soc-audio", 1);
+	if (!pdev) {
+		pr_err("pcm030_fabric_init: platform_device_alloc() failed\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, &device);
+	device.dev = &pdev->dev;
+
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("pcm030_fabric_init: platform_device_add() failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static __exit void pcm030_fabric_exit(void)
+{
+}
+
+module_init(pcm030_fabric_init);
+module_exit(pcm030_fabric_exit);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 pcm030 fabric driver");
+MODULE_LICENSE("GPL");
+

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika
  2009-05-25  1:38 [PATCH V3 0/4] mpc5200 audio rework for AC97 Jon Smirl
                   ` (2 preceding siblings ...)
  2009-05-25  1:38 ` [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board Jon Smirl
@ 2009-05-25  1:38 ` Jon Smirl
  2009-05-28 14:00   ` Peter Korsgaard
  2009-05-25 10:43 ` [PATCH V3 0/4] mpc5200 audio rework for AC97 Mark Brown
  4 siblings, 1 reply; 22+ messages in thread
From: Jon Smirl @ 2009-05-25  1:38 UTC (permalink / raw)
  To: grant.likely, linuxppc-dev, alsa-devel, broonie

Fabric bindings for STAC9766 AC97 codec on the Efika.

Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
---
 sound/soc/fsl/Kconfig              |    8 +++
 sound/soc/fsl/Makefile             |    1 
 sound/soc/fsl/efika-audio-fabric.c |   95 ++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/fsl/efika-audio-fabric.c

diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 79579ae..f571c6e 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -47,3 +47,11 @@ config SND_MPC52xx_SOC_PCM030
 	help
 	  Say Y if you want to add support for sound on the Phytec pcm030 baseboard.
 
+config SND_MPC52xx_SOC_EFIKA
+	tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
+	depends on PPC_EFIKA
+	select SND_SOC_MPC5200_AC97
+	select SND_SOC_STAC9766
+	help
+	  Say Y if you want to add support for sound on the Efika.
+
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 66d88c8..a83a739 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
 
 # MPC5200 Machine Support
 obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
+obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
 
diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c
new file mode 100644
index 0000000..4b7ed2b
--- /dev/null
+++ b/sound/soc/fsl/efika-audio-fabric.c
@@ -0,0 +1,95 @@
+/*
+ * Efika driver for the PSC of the Freescale MPC52xx
+ * configured as AC97 interface
+ *
+ * Copyright 2008 Jon Smirl, Digispeaker
+ * Author: Jon Smirl <jonsmirl@gmail.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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/soc-of-simple.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+#include "../codecs/stac9766.h"
+
+static struct snd_soc_device device;
+static struct snd_soc_card card;
+
+static struct snd_soc_dai_link efika_fabric_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 Analog",
+	.codec_dai = &stac9766_dai[STAC9766_DAI_AC97_ANALOG],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_NORMAL],
+},
+{
+	.name = "AC97",
+	.stream_name = "AC97 IEC958",
+	.codec_dai = &stac9766_dai[STAC9766_DAI_AC97_DIGITAL],
+	.cpu_dai = &psc_ac97_dai[MPC5200_AC97_SPDIF],
+},
+};
+
+static __init int efika_fabric_init(void)
+{
+	struct platform_device *pdev;
+	int rc;
+
+	if (!machine_is_compatible("bplan,efika"))
+		return -ENODEV;
+
+	card.platform = &mpc5200_audio_dma_platform;
+	card.name = "Efika";
+	card.dai_link = efika_fabric_dai;
+	card.num_links = ARRAY_SIZE(efika_fabric_dai);
+
+	device.card = &card;
+	device.codec_dev = &soc_codec_dev_stac9766;
+
+	pdev = platform_device_alloc("soc-audio", 1);
+	if (!pdev) {
+		pr_err("efika_fabric_init: platform_device_alloc() failed\n");
+		return -ENODEV;
+	}
+
+	platform_set_drvdata(pdev, &device);
+	device.dev = &pdev->dev;
+
+	rc = platform_device_add(pdev);
+	if (rc) {
+		pr_err("efika_fabric_init: platform_device_add() failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static __exit void efika_fabric_exit(void)
+{
+}
+
+module_init(efika_fabric_init);
+module_exit(efika_fabric_exit);
+
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION(DRV_NAME ": mpc5200 Efika fabric driver");
+MODULE_LICENSE("GPL");
+

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25  1:38 ` [PATCH V3 2/4] AC97 driver for mpc5200 Jon Smirl
@ 2009-05-25  6:16   ` Grant Likely
  2009-05-25 15:15     ` Jon Smirl
  2009-05-25 10:26   ` Mark Brown
  1 sibling, 1 reply; 22+ messages in thread
From: Grant Likely @ 2009-05-25  6:16 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie

On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
> 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. =A0Failure
> 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>
> ---
> =A0sound/soc/fsl/Kconfig =A0 =A0 =A0 =A0 =A0 =A0| =A0 11 +
> =A0sound/soc/fsl/Makefile =A0 =A0 =A0 =A0 =A0 | =A0 =A01
> =A0sound/soc/fsl/mpc5200_psc_ac97.c | =A0392 ++++++++++++++++++++++++++++=
++++++++++
> =A0sound/soc/fsl/mpc5200_psc_ac97.h | =A0 15 +
> =A04 files changed, 419 insertions(+), 0 deletions(-)
> =A0create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.c
> =A0create mode 100644 sound/soc/fsl/mpc5200_psc_ac97.h
>
> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> index 1918c78..3bce952 100644
> --- a/sound/soc/fsl/Kconfig
> +++ b/sound/soc/fsl/Kconfig
> @@ -29,3 +29,14 @@ config SND_SOC_MPC5200_I2S
> =A0 =A0 =A0 =A0select PPC_BESTCOMM_GEN_BD
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0Say Y here to support the MPC5200 PSCs in I2S mode.
> +
> +config SND_SOC_MPC5200_AC97
> + =A0 =A0 =A0 tristate "Freescale MPC5200 PSC in AC97 mode driver"
> + =A0 =A0 =A0 depends on PPC_MPC52xx && PPC_BESTCOMM
> + =A0 =A0 =A0 select AC97_BUS
> + =A0 =A0 =A0 select SND_MPC52xx_DMA
> + =A0 =A0 =A0 select PPC_BESTCOMM_GEN_BD
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 Say Y here to support the MPC5200 PSCs in AC97 mode.
> +
> +
> diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
> index 7731ef2..14631a1 100644
> --- a/sound/soc/fsl/Makefile
> +++ b/sound/soc/fsl/Makefile
> @@ -13,4 +13,5 @@ obj-$(CONFIG_SND_SOC_MPC8610) +=3D snd-soc-fsl-ssi.o sn=
d-soc-fsl-dma.o
> =A0# MPC5200 Platform Support
> =A0obj-$(CONFIG_SND_MPC52xx_DMA) +=3D mpc5200_dma.o
> =A0obj-$(CONFIG_SND_SOC_MPC5200_I2S) +=3D mpc5200_psc_i2s.o
> +obj-$(CONFIG_SND_SOC_MPC5200_AC97) +=3D mpc5200_psc_ac97.o
>
> diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc=
_ac97.c
> new file mode 100644
> index 0000000..480b677
> --- /dev/null
> +++ b/sound/soc/fsl/mpc5200_psc_ac97.c
> @@ -0,0 +1,392 @@
> +/*
> + * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx =
chip.
> + *
> + * Copyright (C) 2009 Jon Smirl, Digispeaker
> + * Author: Jon Smirl <jonsmirl@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +
> +#include <asm/mpc52xx_psc.h>
> +
> +#include "mpc5200_dma.h"
> +#include "mpc5200_psc_ac97.h"
> +
> +#define DRV_NAME "mpc5200-psc-ac97"
> +
> +/* ALSA only supports a single AC97 device so static is recommend here *=
/
> +static struct psc_dma *psc_dma;
> +
> +static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned shor=
t reg)
> +{
> + =A0 =A0 =A0 int timeout;
> + =A0 =A0 =A0 unsigned int val;
> +
> + =A0 =A0 =A0 spin_lock(&psc_dma->lock);
> +
> + =A0 =A0 =A0 /* Wait for it to be ready */
> + =A0 =A0 =A0 timeout =3D 1000;
> + =A0 =A0 =A0 while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr.s=
tatus) &
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_CMDSEND))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);

Holy unbounded latency Batman!  This code waits up to 10ms for a register r=
ead!

I hate spinning, but if it must be done; I'd like to see it small.
What is the worst case latency? 125us for 8000Hz bus speed?  If you
must spin; can a cpu_relax() be used instead of the udelay() while
watch the timebase?  Timur recently posted a patch which makes this
easier.

http://patchwork.ozlabs.org/patch/27414/

They *should* be appearing in Ben's -next branch soon.

> +
> + =A0 =A0 =A0 if (!timeout) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("timeout on ac97 bus (rdy)\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0xffff;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Do the read */
> + =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0x=
7f) << 24));
> +
> + =A0 =A0 =A0 /* Wait for the answer */
> + =A0 =A0 =A0 timeout =3D 1000;
> + =A0 =A0 =A0 while ((--timeout) && !(in_be16(&psc_dma->psc_regs->sr_csr.=
status) &
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_DATA_VAL))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);

ditto.

> +static int psc_ac97_cold_reset_check(struct snd_ac97 *ac97)
> +{
> + =A0 =A0 =A0 int max_reset, timeout;
> + =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_dma->psc_regs;
> +
> + =A0 =A0 =A0 /* AC97 clock is generated by the codec.
> + =A0 =A0 =A0 =A0* Ensure that it starts ticking after codec reset.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 for (max_reset =3D 0; max_reset < 5; max_reset++) {
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Do a cold reset */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->op1, MPC52xx_PSC_OP_RES);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->op0, MPC52xx_PSC_OP_RES);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(50);

:-/  Don't like, but don't know if there is an alternative.

> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* PSC recover from cold reset
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* (cfr user manual, not sure if useful)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&regs->sicr, in_be32(&regs->sicr))=
;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_ac97_warm_reset(ac97);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* first make sure AC97 clock is low */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (timeout =3D 0; ((in_8(&regs->ipcr_acr.=
ipcr) & 0x80) !=3D 0) &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (timeout < =
100); timeout++)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (timeout =3D=3D 100)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* then wait for the transition to high */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (timeout =3D 0; ((in_8(&regs->ipcr_acr.=
ipcr) & 0x80) =3D=3D 0) &&
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (timeout < =
100); timeout++)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (timeout =3D=3D 100)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;

Using udelay makes this less accurate.  Only possible reason to use a
udelay is if the register cannot be polled at full speed (which is
possibly the case if it adds bus contention; but I don't think it is
an issue here).

g.


--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code
  2009-05-25  1:38 ` [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code Jon Smirl
@ 2009-05-25  6:26   ` Grant Likely
  2009-05-25  9:34     ` Mark Brown
  0 siblings, 1 reply; 22+ messages in thread
From: Grant Likely @ 2009-05-25  6:26 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie

On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
> Rewrite the mpc5200 audio DMA code to support both I2S and AC97.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
> ---
> =A0sound/soc/fsl/Kconfig =A0 =A0 =A0 =A0 =A0 | =A0 =A01
> =A0sound/soc/fsl/mpc5200_dma.c =A0 =A0 | =A0504 +++++++++++++++++++++++++=
+-------------
> =A0sound/soc/fsl/mpc5200_dma.h =A0 =A0 | =A0 33 +--
> =A0sound/soc/fsl/mpc5200_psc_i2s.c | =A0247 +++----------------
> =A0sound/soc/fsl/mpc5200_psc_i2s.h | =A0 12 +
> =A05 files changed, 408 insertions(+), 389 deletions(-)
> =A0create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h
>
> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> index dc79bdf..1918c78 100644
> --- a/sound/soc/fsl/Kconfig
> +++ b/sound/soc/fsl/Kconfig
> @@ -25,7 +25,6 @@ config SND_SOC_MPC8610_HPCD
> =A0config SND_SOC_MPC5200_I2S
> =A0 =A0 =A0 =A0tristate "Freescale MPC5200 PSC in I2S mode driver"
> =A0 =A0 =A0 =A0depends on PPC_MPC52xx && PPC_BESTCOMM
> - =A0 =A0 =A0 select SND_SOC_OF_SIMPLE
> =A0 =A0 =A0 =A0select SND_MPC52xx_DMA
> =A0 =A0 =A0 =A0select PPC_BESTCOMM_GEN_BD
> =A0 =A0 =A0 =A0help
> diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
> index 6850392..4e1f1f8 100644
> --- a/sound/soc/fsl/mpc5200_dma.c
> +++ b/sound/soc/fsl/mpc5200_dma.c
> @@ -3,23 +3,13 @@
> =A0* ALSA SoC Platform driver
> =A0*
> =A0* Copyright (C) 2008 Secret Lab Technologies Ltd.
> + * Copyright (C) 2009 Jon Smirl, Digispeaker
> =A0*/
>
> -#include <linux/init.h>
> =A0#include <linux/module.h>
> -#include <linux/interrupt.h>
> -#include <linux/device.h>
> -#include <linux/delay.h>
> =A0#include <linux/of_device.h>
> -#include <linux/of_platform.h>
> -#include <linux/dma-mapping.h>
>
> -#include <sound/core.h>
> -#include <sound/pcm.h>
> -#include <sound/pcm_params.h>
> -#include <sound/initval.h>
> =A0#include <sound/soc.h>
> -#include <sound/soc-of-simple.h>
>
> =A0#include <sysdev/bestcomm/bestcomm.h>
> =A0#include <sysdev/bestcomm/gen_bd.h>
> @@ -27,10 +17,6 @@
>
> =A0#include "mpc5200_dma.h"
>
> -MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
> -MODULE_DESCRIPTION("Freescale MPC5200 PSC in DMA mode ASoC Driver");
> -MODULE_LICENSE("GPL");
> -
> =A0/*
> =A0* Interrupt handlers
> =A0*/
> @@ -50,7 +36,7 @@ static irqreturn_t psc_dma_status_irq(int irq, void *_p=
sc_dma)
> =A0 =A0 =A0 =A0if (psc_dma->capture.active && (isr & MPC52xx_PSC_IMR_ORER=
R))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0psc_dma->stats.overrun_count++;
>
> - =A0 =A0 =A0 out_8(&regs->command, 4 << 4); =A0/* reset the error status=
 */
> + =A0 =A0 =A0 out_8(&regs->command, MPC52xx_PSC_RST_ERR_STAT);
>
> =A0 =A0 =A0 =A0return IRQ_HANDLED;
> =A0}
> @@ -81,8 +67,21 @@ static void psc_dma_bcom_enqueue_next_buffer(struct ps=
c_dma_stream *s)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->period_next_pt =3D s->period_start;
> =A0}
>
> +static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
> +{
> + =A0 =A0 =A0 while (s->appl_ptr < s->runtime->control->appl_ptr) {
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (bcom_queue_full(s->bcom_task))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->appl_ptr +=3D s->period_size;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_dma_bcom_enqueue_next_buffer(s);
> + =A0 =A0 =A0 }
> +}
> +
> =A0/* Bestcomm DMA irq handler */
> -static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
> +static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
> =A0{
> =A0 =A0 =A0 =A0struct psc_dma_stream *s =3D _psc_dma_stream;
>
> @@ -90,12 +89,12 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *_p=
sc_dma_stream)
> =A0 =A0 =A0 =A0 * and enqueue a new one in it's place. */
> =A0 =A0 =A0 =A0while (bcom_buffer_done(s->bcom_task)) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bcom_retrieve_buffer(s->bcom_task, NULL, N=
ULL);
> +
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->period_current_pt +=3D s->period_bytes;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (s->period_current_pt >=3D s->period_en=
d)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->period_current_pt =3D s=
->period_start;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_dma_bcom_enqueue_next_buffer(s);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_enable(s->bcom_task);
> =A0 =A0 =A0 =A0}
> + =A0 =A0 =A0 psc_dma_bcom_enqueue_tx(s);
>
> =A0 =A0 =A0 =A0/* If the stream is active, then also inform the PCM middl=
e layer
> =A0 =A0 =A0 =A0 * of the period finished event. */
> @@ -105,49 +104,31 @@ static irqreturn_t psc_dma_bcom_irq(int irq, void *=
_psc_dma_stream)
> =A0 =A0 =A0 =A0return IRQ_HANDLED;
> =A0}
>
> -/**
> - * psc_dma_startup: create a new substream
> - *
> - * This is the first function called when a stream is opened.
> - *
> - * If this is the first stream open, then grab the IRQ and program most =
of
> - * the PSC registers.
> - */
> -int psc_dma_startup(struct snd_pcm_substream *substream,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> +static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
> =A0{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_dma *psc_dma =3D rtd->dai->cpu_dai->private_data=
;
> - =A0 =A0 =A0 int rc;
> + =A0 =A0 =A0 struct psc_dma_stream *s =3D _psc_dma_stream;
>
> - =A0 =A0 =A0 dev_dbg(psc_dma->dev, "psc_dma_startup(substream=3D%p)\n", =
substream);
> + =A0 =A0 =A0 /* For each finished period, dequeue the completed period b=
uffer
> + =A0 =A0 =A0 =A0* and enqueue a new one in it's place. */
> + =A0 =A0 =A0 while (bcom_buffer_done(s->bcom_task)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_retrieve_buffer(s->bcom_task, NULL, NU=
LL);
>
> - =A0 =A0 =A0 if (!psc_dma->playback.active &&
> - =A0 =A0 =A0 =A0 =A0 !psc_dma->capture.active) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Setup the IRQs */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D request_irq(psc_dma->irq, &psc_dma_s=
tatus_irq, IRQF_SHARED,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"psc-dma=
-status", psc_dma);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc |=3D request_irq(psc_dma->capture.irq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &psc_dm=
a_bcom_irq, IRQF_SHARED,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "psc-dm=
a-capture", &psc_dma->capture);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc |=3D request_irq(psc_dma->playback.irq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &psc_dm=
a_bcom_irq, IRQF_SHARED,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "psc-dm=
a-playback", &psc_dma->playback);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (rc) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_dma->irq, psc_=
dma);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_dma->capture.i=
rq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&psc_dma=
->capture);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_dma->playback.=
irq,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&psc_dma=
->playback);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt +=3D s->period_bytes;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (s->period_current_pt >=3D s->period_end=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_current_pt =3D s-=
>period_start;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_dma_bcom_enqueue_next_buffer(s);
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 return 0;
> + =A0 =A0 =A0 /* If the stream is active, then also inform the PCM middle=
 layer
> + =A0 =A0 =A0 =A0* of the period finished event. */
> + =A0 =A0 =A0 if (s->active)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 snd_pcm_period_elapsed(s->stream);
> +
> + =A0 =A0 =A0 return IRQ_HANDLED;
> =A0}
>
> -int psc_dma_hw_free(struct snd_pcm_substream *substream,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> +static int psc_dma_hw_free(struct snd_pcm_substream *substream)
> =A0{
> =A0 =A0 =A0 =A0snd_pcm_set_runtime_buffer(substream, NULL);
> =A0 =A0 =A0 =A0return 0;
> @@ -159,8 +140,7 @@ int psc_dma_hw_free(struct snd_pcm_substream *substre=
am,
> =A0* This function is called by ALSA to start, stop, pause, and resume th=
e DMA
> =A0* transfer of data.
> =A0*/
> -int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *=
dai)
> +static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
> =A0{
> =A0 =A0 =A0 =A0struct snd_soc_pcm_runtime *rtd =3D substream->private_dat=
a;
> =A0 =A0 =A0 =A0struct psc_dma *psc_dma =3D rtd->dai->cpu_dai->private_dat=
a;
> @@ -168,8 +148,8 @@ int psc_dma_trigger(struct snd_pcm_substream *substre=
am, int cmd,
> =A0 =A0 =A0 =A0struct psc_dma_stream *s;
> =A0 =A0 =A0 =A0struct mpc52xx_psc __iomem *regs =3D psc_dma->psc_regs;
> =A0 =A0 =A0 =A0u16 imr;
> - =A0 =A0 =A0 u8 psc_cmd;
> =A0 =A0 =A0 =A0unsigned long flags;
> + =A0 =A0 =A0 int i;
>
> =A0 =A0 =A0 =A0if (substream->pstr->stream =3D=3D SNDRV_PCM_STREAM_CAPTUR=
E)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s =3D &psc_dma->capture;
> @@ -189,68 +169,45 @@ int psc_dma_trigger(struct snd_pcm_substream *subst=
ream, int cmd,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(s->period=
_bytes * runtime->periods);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->period_next_pt =3D s->period_start;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->period_current_pt =3D s->period_start;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->period_size =3D runtime->period_size;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->active =3D 1;
>
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* First; reset everything */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* track appl_ptr so that we have a better =
chance of detecting
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* end of stream and not over running it.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->runtime =3D runtime;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s->appl_ptr =3D s->runtime->control->appl_p=
tr -
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (runtime->p=
eriod_size * runtime->periods);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Fill up the bestcomm bd queue and enable=
 DMA.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* This will begin filling the PSC's fifo=
.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (substream->pstr->stream =3D=3D SNDRV_P=
CM_STREAM_CAPTURE) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, MPC52=
xx_PSC_RST_RX);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, MPC52=
xx_PSC_RST_ERR_STAT);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_rx_reset(s->bco=
m_task);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (i =3D 0; i < runtime->=
periods; i++)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!bcom_q=
ueue_full(s->bcom_task))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 psc_dma_bcom_enqueue_next_buffer(s);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} else {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, MPC52=
xx_PSC_RST_TX);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, MPC52=
xx_PSC_RST_ERR_STAT);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_tx_reset(s->bco=
m_task);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_dma_bcom_enqueue_tx(s);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Next, fill up the bestcomm bd queue and =
enable DMA.
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* This will begin filling the PSC's fifo=
. */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_rx_reset(s->bco=
m_task);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_tx_reset(s->bco=
m_task);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (!bcom_queue_full(s->bcom_task))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_dma_bcom_enqueue_next_b=
uffer(s);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bcom_enable(s->bcom_task);
>
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Due to errata in the dma mode; need to l=
ine up enabling
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* the transmitter with a transition on t=
he frame sync
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* line */
> -
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spin_lock_irqsave(&psc_dma->lock, flags);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* first make sure it is low */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) =
!=3D 0)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* then wait for the transition to high */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while ((in_8(&regs->ipcr_acr.ipcr) & 0x80) =
=3D=3D 0)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Finally, enable the PSC.
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Receiver must always be enabled; even =
when we only want
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* transmit. =A0(see 15.3.2.3 of MPC5200B=
 User's Guide) */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_cmd =3D MPC52xx_PSC_RX_ENABLE;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_PLAYBACK)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_cmd |=3D MPC52xx_PSC_TX=
_ENABLE;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, psc_cmd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, MPC52xx_PSC_RST_ERR_S=
TAT);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0spin_unlock_irqrestore(&psc_dma->lock, fla=
gs);
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
>
> =A0 =A0 =A0 =A0case SNDRV_PCM_TRIGGER_STOP:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Turn off the PSC */
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s->active =3D 0;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc_dma->playback.acti=
ve) {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs=
->command, 2 << 4); =A0/* reset rx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs=
->command, 3 << 4); =A0/* reset tx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs=
->command, 4 << 4); =A0/* reset err */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, 3 << =
4); =A0/* reset tx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->command, 4 << =
4); =A0/* reset err */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!psc_dma->capture.activ=
e)
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs=
->command, 2 << 4); =A0/* reset rx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0bcom_disable(s->bcom_task);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 while (!bcom_queue_empty(s->bcom_task))
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_retrieve_buffer(s->bco=
m_task, NULL, NULL);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (substream->pstr->stream =3D=3D SNDRV_PC=
M_STREAM_CAPTURE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_rx_reset(s->bco=
m_task);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bcom_gen_bd_tx_reset(s->bco=
m_task);
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
>
> @@ -265,44 +222,11 @@ int psc_dma_trigger(struct snd_pcm_substream *subst=
ream, int cmd,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0imr |=3D MPC52xx_PSC_IMR_TXEMP;
> =A0 =A0 =A0 =A0if (psc_dma->capture.active)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0imr |=3D MPC52xx_PSC_IMR_ORERR;
> - =A0 =A0 =A0 out_be16(&regs->isr_imr.imr, imr);
> + =A0 =A0 =A0 out_be16(&regs->isr_imr.imr, psc_dma->imr | imr);
>
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> -/**
> - * psc_dma_shutdown: shutdown the data transfer on a stream
> - *
> - * Shutdown the PSC if there are no other substreams open.
> - */
> -void psc_dma_shutdown(struct snd_pcm_substream *substream,
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_d=
ai *dai)
> -{
> - =A0 =A0 =A0 struct snd_soc_pcm_runtime *rtd =3D substream->private_data=
;
> - =A0 =A0 =A0 struct psc_dma *psc_dma =3D rtd->dai->cpu_dai->private_data=
;
> -
> - =A0 =A0 =A0 dev_dbg(psc_dma->dev, "psc_dma_shutdown(substream=3D%p)\n",=
 substream);
> -
> - =A0 =A0 =A0 /*
> - =A0 =A0 =A0 =A0* If this is the last active substream, disable the PSC =
and release
> - =A0 =A0 =A0 =A0* the IRQ.
> - =A0 =A0 =A0 =A0*/
> - =A0 =A0 =A0 if (!psc_dma->playback.active &&
> - =A0 =A0 =A0 =A0 =A0 !psc_dma->capture.active) {
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Disable all interrupts and reset the PSC=
 */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be16(&psc_dma->psc_regs->isr_imr.imr, 0=
);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_dma->psc_regs->command, 3 << 4);=
 /* reset tx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_dma->psc_regs->command, 2 << 4);=
 /* reset rx */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_dma->psc_regs->command, 1 << 4);=
 /* reset mode */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&psc_dma->psc_regs->command, 4 << 4);=
 /* reset error */
> -
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Release irqs */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_dma->irq, psc_dma);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_dma->capture.irq, &psc_dma->ca=
pture);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 free_irq(psc_dma->playback.irq, &psc_dma->p=
layback);
> - =A0 =A0 =A0 }
> -}
>
> =A0/* -------------------------------------------------------------------=
--
> =A0* The PSC DMA 'ASoC platform' driver
> @@ -312,62 +236,78 @@ void psc_dma_shutdown(struct snd_pcm_substream *sub=
stream,
> =A0* interaction with the attached codec
> =A0*/
>
> -static const struct snd_pcm_hardware psc_dma_pcm_hardware =3D {
> +static const struct snd_pcm_hardware psc_dma_hardware =3D {
> =A0 =A0 =A0 =A0.info =3D SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID =
|
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INF=
O_BLOCK_TRANSFER |
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0SNDRV_PCM_INFO_BATCH,
> =A0 =A0 =A0 =A0.formats =3D SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE=
 |
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_=
FMTBIT_S32_BE,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_=
S32_BE,

Unrelated whitespace changes?

> +/* ---------------------------------------------------------------------
> + * Sysfs attributes for error monitoring
> + */

All this sysfs stuff should be dropped from this patch.  It is an
abuse of sysfs and I never should have written it this way.  Feel free
to put it in a separate patch so others can use it if they really need
it, but I'd like it to not be kept in mainline.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board.
  2009-05-25  1:38 ` [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board Jon Smirl
@ 2009-05-25  6:34   ` Grant Likely
  2009-05-25  9:46     ` Mark Brown
  2009-05-25 14:39     ` Jon Smirl
  2009-05-25  9:48   ` Mark Brown
  1 sibling, 2 replies; 22+ messages in thread
From: Grant Likely @ 2009-05-25  6:34 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie

On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
> Support for AC97 on Phytec pmc030 base board. A wm9712 AC97 codec is used=
.
>
> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
> ---
> =A0sound/soc/fsl/Kconfig =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A07 +++
> =A0sound/soc/fsl/Makefile =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 =A03 +
> =A0sound/soc/fsl/pcm030-audio-fabric.c | =A0 95 +++++++++++++++++++++++++=
++++++++++
> =A03 files changed, 105 insertions(+), 0 deletions(-)
> =A0create mode 100644 sound/soc/fsl/pcm030-audio-fabric.c
>
> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> index 3bce952..79579ae 100644
> --- a/sound/soc/fsl/Kconfig
> +++ b/sound/soc/fsl/Kconfig
> @@ -39,4 +39,11 @@ config SND_SOC_MPC5200_AC97
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0Say Y here to support the MPC5200 PSCs in AC97 mode.
>
> +config SND_MPC52xx_SOC_PCM030
> + =A0 =A0 =A0 tristate "SoC AC97 Audio support for Phytec pcm030 and WM97=
12"
> + =A0 =A0 =A0 depends on PPC_MPC5200_SIMPLE
> + =A0 =A0 =A0 select SND_SOC_MPC5200_AC97
> + =A0 =A0 =A0 select SND_SOC_WM9712
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 Say Y if you want to add support for sound on the Phyte=
c pcm030 baseboard.
>
> diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
> index 14631a1..66d88c8 100644
> --- a/sound/soc/fsl/Makefile
> +++ b/sound/soc/fsl/Makefile
> @@ -15,3 +15,6 @@ obj-$(CONFIG_SND_MPC52xx_DMA) +=3D mpc5200_dma.o
> =A0obj-$(CONFIG_SND_SOC_MPC5200_I2S) +=3D mpc5200_psc_i2s.o
> =A0obj-$(CONFIG_SND_SOC_MPC5200_AC97) +=3D mpc5200_psc_ac97.o
>
> +# MPC5200 Machine Support
> +obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) +=3D pcm030-audio-fabric.o
> +
> diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-a=
udio-fabric.c
> new file mode 100644
> index 0000000..2c426d5
> --- /dev/null
> +++ b/sound/soc/fsl/pcm030-audio-fabric.c
> @@ -0,0 +1,95 @@
> +/*
> + * Phytec pcm030 driver for the PSC of the Freescale MPC52xx
> + * configured as AC97 interface
> + *
> + * Copyright 2008 Jon Smirl, Digispeaker
> + * Author: Jon Smirl <jonsmirl@gmail.com>
> + *
> + * This file is licensed under the terms of the GNU General Public Licen=
se
> + * version 2. This program is licensed "as is" without any warranty of a=
ny
> + * kind, whether express or implied.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/initval.h>
> +#include <sound/soc.h>
> +#include <sound/soc-of-simple.h>
> +
> +#include "mpc5200_dma.h"
> +#include "mpc5200_psc_ac97.h"
> +#include "../codecs/wm9712.h"
> +
> +static struct snd_soc_device device;
> +static struct snd_soc_card card;
> +
> +static struct snd_soc_dai_link pcm030_fabric_dai[] =3D {
> +{
> + =A0 =A0 =A0 .name =3D "AC97",
> + =A0 =A0 =A0 .stream_name =3D "AC97 Analog",
> + =A0 =A0 =A0 .codec_dai =3D &wm9712_dai[WM9712_DAI_AC97_HIFI],
> + =A0 =A0 =A0 .cpu_dai =3D &psc_ac97_dai[MPC5200_AC97_NORMAL],
> +},
> +{
> + =A0 =A0 =A0 .name =3D "AC97",
> + =A0 =A0 =A0 .stream_name =3D "AC97 IEC958",
> + =A0 =A0 =A0 .codec_dai =3D &wm9712_dai[WM9712_DAI_AC97_AUX],
> + =A0 =A0 =A0 .cpu_dai =3D &psc_ac97_dai[MPC5200_AC97_SPDIF],
> +},
> +};
> +
> +static __init int pcm030_fabric_init(void)
> +{
> + =A0 =A0 =A0 struct platform_device *pdev;
> + =A0 =A0 =A0 int rc;
> +
> + =A0 =A0 =A0 if (!machine_is_compatible("phytec,pcm030"))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> +
> + =A0 =A0 =A0 card.platform =3D &mpc5200_audio_dma_platform;
> + =A0 =A0 =A0 card.name =3D "pcm030";
> + =A0 =A0 =A0 card.dai_link =3D pcm030_fabric_dai;
> + =A0 =A0 =A0 card.num_links =3D ARRAY_SIZE(pcm030_fabric_dai);
> +
> + =A0 =A0 =A0 device.card =3D &card;
> + =A0 =A0 =A0 device.codec_dev =3D &soc_codec_dev_wm9712;
> +
> + =A0 =A0 =A0 pdev =3D platform_device_alloc("soc-audio", 1);
> + =A0 =A0 =A0 if (!pdev) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("pcm030_fabric_init: platform_device=
_alloc() failed\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 platform_set_drvdata(pdev, &device);
> + =A0 =A0 =A0 device.dev =3D &pdev->dev;
> +
> + =A0 =A0 =A0 rc =3D platform_device_add(pdev);
> + =A0 =A0 =A0 if (rc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("pcm030_fabric_init: platform_device=
_add() failed\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return 0;
> +}

This is ugly.  I'd really rather have a generic mechanism for creating
a fabric driver based on the OF data.  But failing that, it seems to
me that this platform device registration should be done in the
platform code (arch/powerpc/platforms/52xx).  Doing it in a module
init looks wrong.

I was trying to do a sort of generic matching mechanism with the of
simple stuff; but admittedly it was hacky and half-assed.  However, I
do still think it is viable to have OF hooks that kick in when codec
and machine drivers are registered.  If linkage data is encoded in the
device tree, then generic code should be able to hook them up; pulling
additional data out of the device tree as needed to configure the
coded.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code
  2009-05-25  6:26   ` Grant Likely
@ 2009-05-25  9:34     ` Mark Brown
  2009-05-25 13:22       ` Grant Likely
  0 siblings, 1 reply; 22+ messages in thread
From: Mark Brown @ 2009-05-25  9:34 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, alsa-devel

On Mon, May 25, 2009 at 12:26:27AM -0600, Grant Likely wrote:
> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:

> > +/* ---------------------------------------------------------------------
> > + * Sysfs attributes for error monitoring
> > + */

> All this sysfs stuff should be dropped from this patch.  It is an
> abuse of sysfs and I never should have written it this way.  Feel free
> to put it in a separate patch so others can use it if they really need
> it, but I'd like it to not be kept in mainline.

If this is going to be kept it should be in debugfs like I said in
response to the v2 posting.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board.
  2009-05-25  6:34   ` Grant Likely
@ 2009-05-25  9:46     ` Mark Brown
  2009-05-25 14:39     ` Jon Smirl
  1 sibling, 0 replies; 22+ messages in thread
From: Mark Brown @ 2009-05-25  9:46 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, alsa-devel

On Mon, May 25, 2009 at 12:34:57AM -0600, Grant Likely wrote:

> This is ugly.  I'd really rather have a generic mechanism for creating
> a fabric driver based on the OF data.  But failing that, it seems to
> me that this platform device registration should be done in the
> platform code (arch/powerpc/platforms/52xx).  Doing it in a module
> init looks wrong.

It's ugly but it's idiomatic for ASoC until someone has time to
implement multiple card support.

> I was trying to do a sort of generic matching mechanism with the of
> simple stuff; but admittedly it was hacky and half-assed.  However, I

It's adequate for the cases it tries to cover, it just needs to be
merged into the core.  The problem here is AC97 since it can't be probed
until the platform comes up.

> do still think it is viable to have OF hooks that kick in when codec
> and machine drivers are registered.  If linkage data is encoded in the
> device tree, then generic code should be able to hook them up; pulling
> additional data out of the device tree as needed to configure the
> coded.

As I explained in response to Jon's original posting AC97 is a
particular problem here since it can only be probed using the CPU DAI
and may require machine-specific work to set it up prior to use.
There's problems fixing this due to AC97 not having fully developed bus
infrastructure in the kernel at the minute.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board.
  2009-05-25  1:38 ` [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board Jon Smirl
  2009-05-25  6:34   ` Grant Likely
@ 2009-05-25  9:48   ` Mark Brown
  1 sibling, 0 replies; 22+ messages in thread
From: Mark Brown @ 2009-05-25  9:48 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel

On Sun, May 24, 2009 at 09:38:51PM -0400, Jon Smirl wrote:

> +static __exit void pcm030_fabric_exit(void)
> +{
> +}

Remove or implement, please.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25  1:38 ` [PATCH V3 2/4] AC97 driver for mpc5200 Jon Smirl
  2009-05-25  6:16   ` Grant Likely
@ 2009-05-25 10:26   ` Mark Brown
  2009-05-25 15:21     ` Jon Smirl
  1 sibling, 1 reply; 22+ messages in thread
From: Mark Brown @ 2009-05-25 10:26 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel

On Sun, May 24, 2009 at 09:38:49PM -0400, Jon Smirl wrote:

> 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.

This smells like either a very broken board or some issue with starting
the master clock for the CODEC - if the CODEC is clocked by the AC97
controller you may need to do something to ensure that it has finished
starting up before initiating the reset.

> +static int psc_ac97_cold_reset_check(struct snd_ac97 *ac97)
> +{
> +	int max_reset, timeout;
> +	struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
> +
> +	/* AC97 clock is generated by the codec.
> +	 * Ensure that it starts ticking after codec reset.
> +	 */

The AC97 standard allows CODECs to come out of cold reset with the link
disabled.  With those CODECs this is going fail every time - they need a
warm reset to come on-line.

If this really is a general issue with the AC97 controller here you'll
need to do a warm reset in here.  It's not ideal but extra warm resets
will cause less harm than completely failing to come on-line.

> +static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
> +							struct snd_soc_dai *dai)

I keep mentioning the indentation issues with your code without seeing
any response from you.  If you run checkpatch over your code you'll also
see a bunch of complaints about using spaces instead of tabs for
indentation.  It looks for all the world like you're using 4 character
tabs instead of the 8 character tabs which are the kernel standard.

> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_STOP:
> +		if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
> +			psc_dma->slots &= 0xFFFF0000;
> +		else
> +			psc_dma->slots &= 0x0000FFFF;
> +
> +		spin_lock(&psc_dma->lock);
> +		out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
> +		spin_unlock(&psc_dma->lock);
> +		break;

This locking looks wrong - I'd expect it to also cover the modification
of psc_dma->slots?  Otherwise it's hard to see what it buys you.

> +	/* AC97 clock is generated by the codec.
> +	 * Ensure that it starts ticking after codec reset.
> +	 */
> +	rc = psc_ac97_cold_reset_check(&ac97);
> +	if (rc != 0) {
> +		dev_err(&op->dev, "AC97 codec failed to reset\n");
> +		mpc5200_audio_dma_destroy(op);
> +		return rc;
> +	}

Your AC97 driver should not be doing this - leave it to the card and
CODEC driver to bring things on line.

> +
> +	/* Go */
> +	out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);

As I said last time I'd expect this to be deferred to the ASoC device
probe.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 0/4] mpc5200 audio rework for AC97
  2009-05-25  1:38 [PATCH V3 0/4] mpc5200 audio rework for AC97 Jon Smirl
                   ` (3 preceding siblings ...)
  2009-05-25  1:38 ` [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika Jon Smirl
@ 2009-05-25 10:43 ` Mark Brown
  4 siblings, 0 replies; 22+ messages in thread
From: Mark Brown @ 2009-05-25 10:43 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel

On Sun, May 24, 2009 at 09:38:45PM -0400, Jon Smirl wrote:
> The following series implements audio support for the mpc5200. It adds an AC97 driver and STAC9766 codec driver. 
> Board support for the Efika and Phytec pcm030 are also included.

> I've tried to implement the feedback received on the previous two versions.

Please also add the fixes for the reset code in the CODEC driver that I
asked for.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code
  2009-05-25  9:34     ` Mark Brown
@ 2009-05-25 13:22       ` Grant Likely
  0 siblings, 0 replies; 22+ messages in thread
From: Grant Likely @ 2009-05-25 13:22 UTC (permalink / raw)
  To: Mark Brown; +Cc: linuxppc-dev, alsa-devel

On Mon, May 25, 2009 at 3:34 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, May 25, 2009 at 12:26:27AM -0600, Grant Likely wrote:
>> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>
>> > +/* ------------------------------------------------------------------=
---
>> > + * Sysfs attributes for error monitoring
>> > + */
>
>> All this sysfs stuff should be dropped from this patch. =A0It is an
>> abuse of sysfs and I never should have written it this way. =A0Feel free
>> to put it in a separate patch so others can use it if they really need
>> it, but I'd like it to not be kept in mainline.
>
> If this is going to be kept it should be in debugfs like I said in
> response to the v2 posting.

exactly.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board.
  2009-05-25  6:34   ` Grant Likely
  2009-05-25  9:46     ` Mark Brown
@ 2009-05-25 14:39     ` Jon Smirl
  1 sibling, 0 replies; 22+ messages in thread
From: Jon Smirl @ 2009-05-25 14:39 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, broonie

On Mon, May 25, 2009 at 2:34 AM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>
> This is ugly. =A0I'd really rather have a generic mechanism for creating
> a fabric driver based on the OF data. =A0But failing that, it seems to
> me that this platform device registration should be done in the
> platform code (arch/powerpc/platforms/52xx). =A0Doing it in a module
> init looks wrong.

I'm all for deleting it as soon as AC97 is capable of auto-loading.  I
thought it was better to leave it in the sound directories to keep it
isolated since the intention is to remove it when possible.

BTW, my binding files are quite simple compared to mpc8610_hpcd.c.


>
> I was trying to do a sort of generic matching mechanism with the of
> simple stuff; but admittedly it was hacky and half-assed. =A0However, I
> do still think it is viable to have OF hooks that kick in when codec
> and machine drivers are registered. =A0If linkage data is encoded in the
> device tree, then generic code should be able to hook them up; pulling
> additional data out of the device tree as needed to configure the
> coded.
>
> g.
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
>



--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25  6:16   ` Grant Likely
@ 2009-05-25 15:15     ` Jon Smirl
  2009-05-25 15:22       ` Mark Brown
  2009-05-25 15:59       ` Grant Likely
  0 siblings, 2 replies; 22+ messages in thread
From: Jon Smirl @ 2009-05-25 15:15 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, alsa-devel, broonie

On Mon, May 25, 2009 at 2:16 AM, Grant Likely <grant.likely@secretlab.ca> w=
rote:
> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>> +static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned sho=
rt reg)
>> +{
>> + =A0 =A0 =A0 int timeout;
>> + =A0 =A0 =A0 unsigned int val;
>> +
>> + =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>> +
>> + =A0 =A0 =A0 /* Wait for it to be ready */
>> + =A0 =A0 =A0 timeout =3D 1000;
>> + =A0 =A0 =A0 while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr.=
status) &
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_CMDSEND))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>
> Holy unbounded latency Batman! =A0This code waits up to 10ms for a regist=
er read!
>
> I hate spinning, but if it must be done; I'd like to see it small.
> What is the worst case latency? 125us for 8000Hz bus speed? =A0If you
> must spin; can a cpu_relax() be used instead of the udelay() while
> watch the timebase? =A0Timur recently posted a patch which makes this
> easier.
>
> http://patchwork.ozlabs.org/patch/27414/
>
> They *should* be appearing in Ben's -next branch soon.


The link always runs at 12.288Mhz. Each frame is 256 bits. Worst case
you wait for two frames, 42us. If it doesn't respond in 42us the codec
clock is not ticking ( a recurring problem I am running into). These
codecs may be going into a sleep mode I don't understand, but this is
not the right place to try and wake them up. I'll lower the retry
counts to 10 instead of 1000.

I played around with implementing this on a kernel thread with
interrupts. It can be done but the code is a lot more complex.

BTW, 8000Hz is implemented by slot stuffing. The link always runs at
12.288Mhz. The DACs are double buffered. When a sample is transfered
between buffers it sets a bit on the link back to the host, and the
host sends the next sample in the appropriate slot.


>
>> +
>> + =A0 =A0 =A0 if (!timeout) {
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("timeout on ac97 bus (rdy)\n");
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0xffff;
>> + =A0 =A0 =A0 }
>> +
>> + =A0 =A0 =A0 /* Do the read */
>> + =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_cmd, (1<<31) | ((reg & 0=
x7f) << 24));
>> +
>> + =A0 =A0 =A0 /* Wait for the answer */
>> + =A0 =A0 =A0 timeout =3D 1000;
>> + =A0 =A0 =A0 while ((--timeout) && !(in_be16(&psc_dma->psc_regs->sr_csr=
.status) &
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_DATA_VAL))
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>
> ditto.
>
>> +static int psc_ac97_cold_reset_check(struct snd_ac97 *ac97)
>> +{
>> + =A0 =A0 =A0 int max_reset, timeout;
>> + =A0 =A0 =A0 struct mpc52xx_psc __iomem *regs =3D psc_dma->psc_regs;
>> +
>> + =A0 =A0 =A0 /* AC97 clock is generated by the codec.
>> + =A0 =A0 =A0 =A0* Ensure that it starts ticking after codec reset.
>> + =A0 =A0 =A0 =A0*/
>> + =A0 =A0 =A0 for (max_reset =3D 0; max_reset < 5; max_reset++) {
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Do a cold reset */
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->op1, MPC52xx_PSC_OP_RES);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->op0, MPC52xx_PSC_OP_RES);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(50);
>
> :-/ =A0Don't like, but don't know if there is an alternative.
>
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* PSC recover from cold reset
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* (cfr user manual, not sure if useful)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&regs->sicr, in_be32(&regs->sicr)=
);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 psc_ac97_warm_reset(ac97);
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* first make sure AC97 clock is low */
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (timeout =3D 0; ((in_8(&regs->ipcr_acr=
.ipcr) & 0x80) !=3D 0) &&
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (timeout <=
 100); timeout++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (timeout =3D=3D 100)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
>> +
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* then wait for the transition to high */
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (timeout =3D 0; ((in_8(&regs->ipcr_acr=
.ipcr) & 0x80) =3D=3D 0) &&
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (timeout <=
 100); timeout++)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (timeout =3D=3D 100)
>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
>
> Using udelay makes this less accurate. =A0Only possible reason to use a
> udelay is if the register cannot be polled at full speed (which is
> possibly the case if it adds bus contention; but I don't think it is
> an issue here).
>
> g.
>
>
> --
> Grant Likely, B.Sc., P.Eng.
> Secret Lab Technologies Ltd.
>



--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25 10:26   ` Mark Brown
@ 2009-05-25 15:21     ` Jon Smirl
  2009-05-25 16:00       ` Grant Likely
  0 siblings, 1 reply; 22+ messages in thread
From: Jon Smirl @ 2009-05-25 15:21 UTC (permalink / raw)
  To: grant.likely; +Cc: linuxppc-dev, alsa-devel, Mark Brown

On Mon, May 25, 2009 at 6:26 AM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>> + =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_slots, psc_d=
ma->slots);
>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&psc_dma->lock);
>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>
> This locking looks wrong - I'd expect it to also cover the modification
> of psc_dma->slots? =A0Otherwise it's hard to see what it buys you.

Grant, why are you spin locking around register access?


--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25 15:15     ` Jon Smirl
@ 2009-05-25 15:22       ` Mark Brown
  2009-05-25 15:59       ` Grant Likely
  1 sibling, 0 replies; 22+ messages in thread
From: Mark Brown @ 2009-05-25 15:22 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel

On Mon, May 25, 2009 at 11:15:34AM -0400, Jon Smirl wrote:

> The link always runs at 12.288Mhz. Each frame is 256 bits. Worst case
> you wait for two frames, 42us. If it doesn't respond in 42us the codec

Note that some embedded systems will choose to vary the AC97 link clock.
The most common case is where there's a PLL on the CODEC - the CODEC
will start up misclocked at whatever the input frequency it's got is and
then be reclocked using register writes to configure the PLL.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25 15:15     ` Jon Smirl
  2009-05-25 15:22       ` Mark Brown
@ 2009-05-25 15:59       ` Grant Likely
  1 sibling, 0 replies; 22+ messages in thread
From: Grant Likely @ 2009-05-25 15:59 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie

On Mon, May 25, 2009 at 9:15 AM, Jon Smirl <jonsmirl@gmail.com> wrote:
> On Mon, May 25, 2009 at 2:16 AM, Grant Likely <grant.likely@secretlab.ca>=
 wrote:
>> On Sun, May 24, 2009 at 7:38 PM, Jon Smirl <jonsmirl@gmail.com> wrote:
>>> +static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned sh=
ort reg)
>>> +{
>>> + =A0 =A0 =A0 int timeout;
>>> + =A0 =A0 =A0 unsigned int val;
>>> +
>>> + =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>>> +
>>> + =A0 =A0 =A0 /* Wait for it to be ready */
>>> + =A0 =A0 =A0 timeout =3D 1000;
>>> + =A0 =A0 =A0 while ((--timeout) && (in_be16(&psc_dma->psc_regs->sr_csr=
.status) &
>>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 MPC52xx_PSC_SR_CMDSEND))
>>> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(10);
>>
>> Holy unbounded latency Batman! =A0This code waits up to 10ms for a regis=
ter read!
>>
>> I hate spinning, but if it must be done; I'd like to see it small.
>> What is the worst case latency? 125us for 8000Hz bus speed? =A0If you
>> must spin; can a cpu_relax() be used instead of the udelay() while
>> watch the timebase? =A0Timur recently posted a patch which makes this
>> easier.
>>
>> http://patchwork.ozlabs.org/patch/27414/
>>
>> They *should* be appearing in Ben's -next branch soon.
>
>
> The link always runs at 12.288Mhz. Each frame is 256 bits. Worst case
> you wait for two frames, 42us. If it doesn't respond in 42us the codec
> clock is not ticking ( a recurring problem I am running into). These
> codecs may be going into a sleep mode I don't understand, but this is
> not the right place to try and wake them up. I'll lower the retry
> counts to 10 instead of 1000.

That still leaves the problem of unecessarily burning time.  udelay
shouldn't be passed any value larger than 1.  In fact, I think udelay
itself is too coarse grained.  Plus, I'd rather see the timebase used
as the exit condition (as mentioned in previous email).

> I played around with implementing this on a kernel thread with
> interrupts. It can be done but the code is a lot more complex.

A kernel thread is definitely the wrong approach.  However, if this is
non-atomic context and IRQs are available, then a wait queue can be
used.  42us is about 16k processor clocks.  I'm not sure what the IRQ
and scheduling overhead is so I don't know whether it would be a net
gain or loss in performance.  However, it would be a net gain in worst
case latency.

> BTW, 8000Hz is implemented by slot stuffing. The link always runs at
> 12.288Mhz. The DACs are double buffered. When a sample is transfered
> between buffers it sets a bit on the link back to the host, and the
> host sends the next sample in the appropriate slot.

ok.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 2/4] AC97 driver for mpc5200
  2009-05-25 15:21     ` Jon Smirl
@ 2009-05-25 16:00       ` Grant Likely
  0 siblings, 0 replies; 22+ messages in thread
From: Grant Likely @ 2009-05-25 16:00 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, Mark Brown

On Mon, May 25, 2009 at 9:21 AM, Jon Smirl <jonsmirl@gmail.com> wrote:
> On Mon, May 25, 2009 at 6:26 AM, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
>>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_lock(&psc_dma->lock);
>>> + =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&psc_dma->psc_regs->ac97_slots, psc_=
dma->slots);
>>> + =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&psc_dma->lock);
>>> + =A0 =A0 =A0 =A0 =A0 =A0 break;
>>
>> This locking looks wrong - I'd expect it to also cover the modification
>> of psc_dma->slots? =A0Otherwise it's hard to see what it buys you.
>
> Grant, why are you spin locking around register access?

This lock/unlock is definitely bogus since a single register access is
already atomic.  Are there places in the code that I wrote where a
spin_lock/unlock is done around a single register access?

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika
  2009-05-25  1:38 ` [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika Jon Smirl
@ 2009-05-28 14:00   ` Peter Korsgaard
  2009-05-28 18:58     ` Jon Smirl
  0 siblings, 1 reply; 22+ messages in thread
From: Peter Korsgaard @ 2009-05-28 14:00 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linuxppc-dev, alsa-devel, broonie

>>>>> "Jon" == Jon Smirl <jonsmirl@gmail.com> writes:

Hi,

 Jon> Fabric bindings for STAC9766 AC97 codec on the Efika.
 Jon> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
 Jon> ---
 Jon>  sound/soc/fsl/Kconfig              |    8 +++
 Jon>  sound/soc/fsl/Makefile             |    1 
 Jon>  sound/soc/fsl/efika-audio-fabric.c |   95 ++++++++++++++++++++++++++++++++++++
 Jon>  3 files changed, 104 insertions(+), 0 deletions(-)
 Jon>  create mode 100644 sound/soc/fsl/efika-audio-fabric.c

 Jon> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
 Jon> index 79579ae..f571c6e 100644
 Jon> --- a/sound/soc/fsl/Kconfig
 Jon> +++ b/sound/soc/fsl/Kconfig
 Jon> @@ -47,3 +47,11 @@ config SND_MPC52xx_SOC_PCM030
 Jon>  	help
 Jon>  	  Say Y if you want to add support for sound on the Phytec pcm030 baseboard.
 
 Jon> +config SND_MPC52xx_SOC_EFIKA
 Jon> +	tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
 Jon> +	depends on PPC_EFIKA
 Jon> +	select SND_SOC_MPC5200_AC97
 Jon> +	select SND_SOC_STAC9766
 Jon> +	help
 Jon> +	  Say Y if you want to add support for sound on the Efika.
 Jon> +

Wouldn't it make more sense to make this default y when it has such
specific dependencies and is so deep down in the tree - Most efika
users probably want to enable this if they have enabled ALSA and
SND_SOC?

-- 
Bye, Peter Korsgaard

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika
  2009-05-28 14:00   ` Peter Korsgaard
@ 2009-05-28 18:58     ` Jon Smirl
  0 siblings, 0 replies; 22+ messages in thread
From: Jon Smirl @ 2009-05-28 18:58 UTC (permalink / raw)
  To: Peter Korsgaard; +Cc: linuxppc-dev, alsa-devel, broonie

On Thu, May 28, 2009 at 10:00 AM, Peter Korsgaard <jacmet@sunsite.dk> wrote=
:
>>>>>> "Jon" =3D=3D Jon Smirl <jonsmirl@gmail.com> writes:
>
> Hi,
>
> =A0Jon> Fabric bindings for STAC9766 AC97 codec on the Efika.
> =A0Jon> Signed-off-by: Jon Smirl <jonsmirl@gmail.com>
> =A0Jon> ---
> =A0Jon> =A0sound/soc/fsl/Kconfig =A0 =A0 =A0 =A0 =A0 =A0 =A0| =A0 =A08 ++=
+
> =A0Jon> =A0sound/soc/fsl/Makefile =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =A01
> =A0Jon> =A0sound/soc/fsl/efika-audio-fabric.c | =A0 95 ++++++++++++++++++=
++++++++++++++++++
> =A0Jon> =A03 files changed, 104 insertions(+), 0 deletions(-)
> =A0Jon> =A0create mode 100644 sound/soc/fsl/efika-audio-fabric.c
>
> =A0Jon> diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
> =A0Jon> index 79579ae..f571c6e 100644
> =A0Jon> --- a/sound/soc/fsl/Kconfig
> =A0Jon> +++ b/sound/soc/fsl/Kconfig
> =A0Jon> @@ -47,3 +47,11 @@ config SND_MPC52xx_SOC_PCM030
> =A0Jon> =A0 help
> =A0Jon> =A0 =A0 Say Y if you want to add support for sound on the Phytec =
pcm030 baseboard.
>
> =A0Jon> +config SND_MPC52xx_SOC_EFIKA
> =A0Jon> + tristate "SoC AC97 Audio support for bbplan Efika and STAC9766"
> =A0Jon> + depends on PPC_EFIKA
> =A0Jon> + select SND_SOC_MPC5200_AC97
> =A0Jon> + select SND_SOC_STAC9766
> =A0Jon> + help
> =A0Jon> + =A0 Say Y if you want to add support for sound on the Efika.
> =A0Jon> +
>
> Wouldn't it make more sense to make this default y when it has such
> specific dependencies and is so deep down in the tree - Most efika
> users probably want to enable this if they have enabled ALSA and
> SND_SOC?

I can change it in the next round of updates. Right now I'd like to
get some people testing it and maybe doing some patches to enhance it.

For example I know he code has a problem where about 5% of the time
the codec doesn't reset right on boot. Someone needs to put an
oscilloscope on the codec chip and tell me why it is failing.

>
> --
> Bye, Peter Korsgaard
>



--=20
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2009-05-28 18:58 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-25  1:38 [PATCH V3 0/4] mpc5200 audio rework for AC97 Jon Smirl
2009-05-25  1:38 ` [PATCH V3 1/4] Main rewite of the mpc5200 audio DMA code Jon Smirl
2009-05-25  6:26   ` Grant Likely
2009-05-25  9:34     ` Mark Brown
2009-05-25 13:22       ` Grant Likely
2009-05-25  1:38 ` [PATCH V3 2/4] AC97 driver for mpc5200 Jon Smirl
2009-05-25  6:16   ` Grant Likely
2009-05-25 15:15     ` Jon Smirl
2009-05-25 15:22       ` Mark Brown
2009-05-25 15:59       ` Grant Likely
2009-05-25 10:26   ` Mark Brown
2009-05-25 15:21     ` Jon Smirl
2009-05-25 16:00       ` Grant Likely
2009-05-25  1:38 ` [PATCH V3 3/4] Support for AC97 on Phytec pmc030 base board Jon Smirl
2009-05-25  6:34   ` Grant Likely
2009-05-25  9:46     ` Mark Brown
2009-05-25 14:39     ` Jon Smirl
2009-05-25  9:48   ` Mark Brown
2009-05-25  1:38 ` [PATCH V3 4/4] Fabric bindings for STAC9766 on the Efika Jon Smirl
2009-05-28 14:00   ` Peter Korsgaard
2009-05-28 18:58     ` Jon Smirl
2009-05-25 10:43 ` [PATCH V3 0/4] mpc5200 audio rework for AC97 Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).