[alsa-devel] [PATCH v3 0/3] ALSA SoC: MPC5200 audio driver
Jon Smirl
jonsmirl at gmail.com
Tue Jul 22 23:38:11 EST 2008
On 7/22/08, Mark Brown <broonie at opensource.wolfsonmicro.com> wrote:
> On Tue, Jul 22, 2008 at 12:58:09AM -0600, Grant Likely wrote:
>
> > Here is the latest series for adding MPC5200 I2S and TI AIC26 codec
> > support to ALSA SoC. I believe all the comments are addressed and I
> > hope that this series is now ready to be merged. I would really like
> > to see these ones land in 2.6.27.
>
>
> That might be a bit of a push given how far into the merge window we
> are and Takashi's holiday this week, though as they are new drivers
> things could be a bit more relaxed.
These drivers are going to get hit with immediate patches. The DMA is
not broken out so that AC97 support can be fixed for the Efika.
I haven't touched these up for the driver that was just posted.
From: Jon Smirl <jonsmirl at gmail.com>
---
include/sound/soc-of.h | 2 +
sound/soc/fsl/mpc5200_psc_i2s.c | 93 ++++++++++++++++++++++++++++++++-------
sound/soc/fsl/mpc5200_psc_i2s.h | 13 +++++
sound/soc/soc-of.c | 26 +++++++++--
4 files changed, 112 insertions(+), 22 deletions(-)
create mode 100644 sound/soc/fsl/mpc5200_psc_i2s.h
diff --git a/include/sound/soc-of.h b/include/sound/soc-of.h
index a963032..15f0b8d 100644
--- a/include/sound/soc-of.h
+++ b/include/sound/soc-of.h
@@ -17,5 +17,7 @@ int of_snd_soc_register_codec(struct
snd_soc_codec_device *codec_dev,
int of_snd_soc_register_platform(struct snd_soc_platform *platform,
struct device_node *node,
struct snd_soc_cpu_dai *cpu_dai);
+
+void of_snd_soc_register_machine(char *name, struct snd_soc_ops *ops);
#endif /* _INCLUDE_SOC_OF_H_ */
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 81d0933..a34961a 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -5,6 +5,8 @@
* Copyright (C) 2008 Secret Lab Technologies Ltd.
*/
+#define DEBUG
+
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -23,8 +25,12 @@
#include <sysdev/bestcomm/bestcomm.h>
#include <sysdev/bestcomm/gen_bd.h>
+#include <asm/time.h>
+#include <asm/mpc52xx.h>
#include <asm/mpc52xx_psc.h>
+#include "mpc5200_psc_i2s.h"
+
MODULE_AUTHOR("Grant Likely <grant.likely at secretlab.ca>");
MODULE_DESCRIPTION("Freescale MPC5200 PSC in I2S mode ASoC Driver");
MODULE_LICENSE("GPL");
@@ -90,8 +96,10 @@ struct psc_i2s {
struct mpc52xx_psc_fifo __iomem *fifo_regs;
unsigned int irq;
struct device *dev;
+ u32 sicr;
struct snd_soc_cpu_dai dai;
spinlock_t lock;
+ uint sysclk;
/* per-stream data */
struct psc_i2s_stream playback_stream;
@@ -210,9 +218,7 @@ static int psc_i2s_startup(struct
snd_pcm_substream *substream)
out_8(®s->command, 4 << 4); /* reset error */
/* Default to CODEC8 mode */
- out_be32(®s->sicr,
- MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
- MPC52xx_PSC_SICR_CLKPOL | MPC52xx_PSC_SICR_SIM_CODEC_8);
+ out_be32(®s->sicr, psc_i2s->sicr | MPC52xx_PSC_SICR_SIM_CODEC_8);
/* First write: RxRdy (FIFO Alarm) generates receive FIFO interrupt */
/* Second write to mode: register Normal mode for non loopback */
@@ -249,7 +255,7 @@ static int psc_i2s_hw_params(struct
snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
- u32 sicr;
+ u32 sicr, bits, framesync, bitclk, value;
dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
" periods=%i buffer_size=%i buffer_bytes=%i\n",
@@ -257,26 +263,46 @@ static int psc_i2s_hw_params(struct
snd_pcm_substream *substream,
params_period_bytes(params), params_periods(params),
params_buffer_size(params), params_buffer_bytes(params));
- sicr = MPC52xx_PSC_SICR_DTS1 |
- MPC52xx_PSC_SICR_I2S | MPC52xx_PSC_SICR_CLKPOL;
+ sicr = psc_i2s->sicr;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
sicr |= MPC52xx_PSC_SICR_SIM_CODEC_8;
+ bits = 8;
break;
case SNDRV_PCM_FORMAT_S16_BE:
sicr |= MPC52xx_PSC_SICR_SIM_CODEC_16;
+ bits = 16;
break;
case SNDRV_PCM_FORMAT_S24_BE:
sicr |= MPC52xx_PSC_SICR_SIM_CODEC_24;
+ bits = 24;
break;
case SNDRV_PCM_FORMAT_S32_BE:
sicr |= MPC52xx_PSC_SICR_SIM_CODEC_32;
+ bits = 32;
break;
default:
dev_dbg(psc_i2s->dev, "invalid format\n");
return -EINVAL;
}
out_be32(&psc_i2s->psc_regs->sicr, sicr);
+
+ if (psc_i2s->sysclk) {
+ framesync = bits * 2;
+ bitclk = (psc_i2s->sysclk) / (params_rate(params) * framesync);
+
+ /* bitclk field is byte swapped due to mpc5200/b compatibility */
+ value = ((framesync - 1) << 24) |
+ (((bitclk - 1) & 0xFF) << 16) | ((bitclk - 1) & 0xFF00);
+
+ dev_dbg(psc_i2s->dev, "%s(substream=%p) rate=%i sysclk=%i"
+ " framesync=%i bitclk=%i reg=%X\n",
+ __FUNCTION__, substream, params_rate(params), psc_i2s->sysclk,
+ framesync, bitclk, value);
+
+ out_be32(&psc_i2s->psc_regs->ccr, value);
+ out_8(&psc_i2s->psc_regs->ctur, bits - 1);
+ }
//rc = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
//if (rc) {
@@ -463,9 +489,29 @@ static int psc_i2s_set_sysclk(struct
snd_soc_cpu_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
{
struct psc_i2s *psc_i2s = cpu_dai->private_data;
- dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
- cpu_dai, dir);
- return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
+ int clkdiv, err;
+ dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, freq=%u, dir=%i)\n",
+ cpu_dai, freq, dir);
+ if (dir == SND_SOC_CLOCK_OUT) {
+ psc_i2s->sysclk = freq;
+ if (clk_id == MPC52xx_CLK_CELLSLAVE) {
+ psc_i2s->sicr |= MPC52xx_PSC_SICR_CELLSLAVE | MPC52xx_PSC_SICR_GENCLK;
+ } else { /* MPC52xx_CLK_INTERNAL */
+ psc_i2s->sicr &= ~MPC52xx_PSC_SICR_CELLSLAVE;
+ psc_i2s->sicr |= MPC52xx_PSC_SICR_GENCLK;
+
+ clkdiv = ppc_proc_freq / freq;
+ err = ppc_proc_freq % freq;
+ if (err > freq / 2)
+ clkdiv++;
+
+ dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(clkdiv %d freq error=%ldHz)\n",
+ clkdiv, (ppc_proc_freq / clkdiv - freq));
+
+ return mpc52xx_set_psc_clkdiv(psc_i2s->dai.id + 1, clkdiv);
+ }
+ }
+ return 0;
}
/**
@@ -660,14 +706,15 @@ static int psc_i2s_pcm_new(struct snd_card
*card, struct snd_soc_codec_dai *dai,
return -ENOMEM;
}
- rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
- &pcm->streams[1].substream->dma_buffer);
- if (rc) {
- snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
- dev_err(card->dev, "Can't allocate capture DMA buffer\n");
- return -ENOMEM;
+ if (pcm->streams[1].substream != NULL) { /* only allocate if the is
a capture stream */
+ rc = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, pcm->dev, size,
+ &pcm->streams[1].substream->dma_buffer);
+ if (rc) {
+ snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
+ dev_err(card->dev, "Can't allocate capture DMA buffer\n");
+ return -ENOMEM;
+ }
}
-
return 0;
}
@@ -829,6 +876,18 @@ static int __devinit psc_i2s_of_probe(struct of_device *op,
return -ENODEV;
}
+ /* Disable all interrupts and reset the PSC */
+ out_be16(&psc_i2s->psc_regs->mpc52xx_psc_imr, 0);
+ out_8(&psc_i2s->psc_regs->command, 3 << 4); /* reset transmitter */
+ out_8(&psc_i2s->psc_regs->command, 2 << 4); /* reset receiver */
+ out_8(&psc_i2s->psc_regs->command, 1 << 4); /* reset mode */
+ out_8(&psc_i2s->psc_regs->command, 4 << 4); /* reset error */
+
+ /* Default to CODEC8 mode */
+ psc_i2s->sicr = MPC52xx_PSC_SICR_DTS1 | MPC52xx_PSC_SICR_I2S |
+ MPC52xx_PSC_SICR_CLKPOL;
+ out_be32(&psc_i2s->psc_regs->sicr, psc_i2s->sicr |
MPC52xx_PSC_SICR_SIM_CODEC_8);
+
/* Save what we've done so it can be found again later */
dev_set_drvdata(&op->dev, psc_i2s);
@@ -865,7 +924,7 @@ static int __devexit psc_i2s_of_remove(struct of_device *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);
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
new file mode 100644
index 0000000..0e0a84e
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_i2s.h
@@ -0,0 +1,13 @@
+/*
+ * 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__
+
+#define MPC52xx_CLK_INTERNAL 0
+#define MPC52xx_CLK_CELLSLAVE 1
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */
diff --git a/sound/soc/soc-of.c b/sound/soc/soc-of.c
index 9694979..3d21ed0 100644
--- a/sound/soc/soc-of.c
+++ b/sound/soc/soc-of.c
@@ -38,8 +38,8 @@ struct of_snd_soc_device {
struct device_node *codec_node;
};
-static struct snd_soc_ops of_snd_soc_ops = {
-};
+static struct snd_soc_ops *machine_ops = NULL;
+static char *machine_name = NULL;
static struct of_snd_soc_device *
of_snd_soc_get_device(struct device_node *codec_node)
@@ -61,7 +61,7 @@ of_snd_soc_get_device(struct device_node *codec_node)
of_soc->machine.dai_link = &of_soc->dai_link;
of_soc->machine.num_links = 1;
of_soc->device.machine = &of_soc->machine;
- of_soc->dai_link.ops = &of_snd_soc_ops;
+ of_soc->dai_link.ops = machine_ops;
list_add(&of_soc->list, &of_snd_soc_device_list);
return of_soc;
@@ -74,7 +74,7 @@ static void of_snd_soc_register_device(struct
of_snd_soc_device *of_soc)
/* Only register the device if both the codec and platform have
* been registered */
- if ((!of_soc->device.codec_data) || (!of_soc->platform_node))
+ if ((!of_soc->device.codec_data) || (!of_soc->platform_node) || !machine_name)
return;
pr_info("platform<-->codec match achieved; registering machine\n");
@@ -159,7 +159,7 @@ int of_snd_soc_register_platform(struct
snd_soc_platform *platform,
of_soc->platform_node = node;
of_soc->dai_link.cpu_dai = cpu_dai;
of_soc->device.platform = platform;
- of_soc->machine.name = of_soc->dai_link.cpu_dai->name;
+ of_soc->machine.name = machine_name;
/* Now try to register the SoC device */
of_snd_soc_register_device(of_soc);
@@ -169,3 +169,19 @@ int of_snd_soc_register_platform(struct
snd_soc_platform *platform,
return rc;
}
EXPORT_SYMBOL_GPL(of_snd_soc_register_platform);
+
+void of_snd_soc_register_machine(char *name, struct snd_soc_ops *ops)
+{
+ struct of_snd_soc_device *of_soc;
+
+ machine_name = name;
+ machine_ops = ops;
+
+ list_for_each_entry(of_soc, &of_snd_soc_device_list, list) {
+ of_soc->dai_link.ops = machine_ops;
+ of_soc->machine.name = machine_name;
+ of_snd_soc_register_device(of_soc);
+ }
+
+}
+EXPORT_SYMBOL_GPL(of_snd_soc_register_machine);
>
> Takashi, I'll queue these (and other ASoC patches) for submission in
> bulk once you return.
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
--
Jon Smirl
jonsmirl at gmail.com
More information about the Linuxppc-dev
mailing list