From: Jon Smirl <jonsmirl@gmail.com>
To: grant.likely@secretlab.ca, broonie@sirena.org.uk
Cc: alsa-devel@alsa-project.org
Subject: [PATCH V1 11/13] AC97 driver for mpc5200
Date: Wed, 13 May 2009 21:59:22 -0400 [thread overview]
Message-ID: <20090514015922.28145.58560.stgit@terra> (raw)
In-Reply-To: <20090514015729.28145.30483.stgit@terra>
AC97 driver for mpc5200
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 | 379 ++++++++++++++++++++++++++++++++++++++
sound/soc/fsl/mpc5200_psc_ac97.h | 13 +
4 files changed, 404 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 8060b95..d8f63f5 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -30,3 +30,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 SND_SOC_OF_SIMPLE
+ 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..aa37c8d
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -0,0 +1,379 @@
+/*
+ * linux/sound/mpc5200-ac97.c -- AC97 support for the Freescale MPC52xx chip.
+ *
+ * Copyright 2008 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/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/time.h>
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#include "mpc5200_dma.h"
+#include "mpc5200_psc_ac97.h"
+
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_DESCRIPTION("mpc5200 AC97 module");
+MODULE_LICENSE("GPL");
+
+#define DRV_NAME "mpc5200-psc-ac97"
+
+static unsigned short psc_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
+{
+ struct psc_dma *psc_dma = ac97->private_data;
+ 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)
+{
+ struct psc_dma *psc_dma = ac97->private_data;
+ 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_cold_reset(struct snd_ac97 *ac97)
+{
+ struct psc_dma *psc_dma = ac97->private_data;
+
+ /* Do a cold reset */
+ out_8(&psc_dma->psc_regs->op1, MPC52xx_PSC_OP_RES);
+ udelay(10);
+ out_8(&psc_dma->psc_regs->op0, MPC52xx_PSC_OP_RES);
+ udelay(50);
+
+ /* PSC recover from cold reset (cfr user manual, not sure if useful) */
+ out_be32(&psc_dma->psc_regs->sicr, in_be32(&psc_dma->psc_regs->sicr));
+}
+
+static void psc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ pr_info("psc_ac97_warm_reset\n");
+}
+
+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);
+
+#ifdef CONFIG_PM
+static int psc_ac97_suspend(struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+static int psc_ac97_resume(struct snd_soc_dai *dai)
+{
+ return 0;
+}
+
+#else
+#define psc_ac97_suspend NULL
+#define psc_ac97_resume NULL
+#endif
+
+static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ 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, "%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 *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct psc_dma *psc_dma = rtd->dai->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;
+}
+
+/**
+ * psc_ac97_set_fmt: set the serial format.
+ *
+ * This function is called by the machine driver to tell us what serial
+ * format to use.
+ *
+ * This driver only supports AC97 mode. Return an error if the format is
+ * not SND_SOC_DAIFMT_AC97.
+ *
+ * @format: one of SND_SOC_DAIFMT_xxx
+ */
+static int psc_ac97_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
+{
+ struct psc_dma *psc_dma = cpu_dai->private_data;
+ dev_dbg(psc_dma->dev, "psc_ac97_set_fmt(cpu_dai=%p, format=%i)\n",
+ cpu_dai, format);
+
+ return (format == SND_SOC_DAIFMT_AC97) ? 0 : -EINVAL;
+}
+
+/* ---------------------------------------------------------------------
+ * 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,
+ .set_fmt = psc_ac97_set_fmt,
+ .trigger = psc_ac97_trigger,
+};
+
+static struct snd_soc_dai_ops psc_ac97_digital_ops = {
+ .hw_params = psc_ac97_hw_digital_params,
+ .set_fmt = psc_ac97_set_fmt,
+};
+
+static struct snd_soc_dai psc_ac97_dai_template[] = {
+{
+ .name = "%s analog",
+ .suspend = psc_ac97_suspend,
+ .resume = psc_ac97_resume,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 6,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE,
+ },
+ .ops = &psc_ac97_analog_ops,
+},
+{
+ .name = "%s digital",
+ .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,
+}};
+
+
+/* ---------------------------------------------------------------------
+ * 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;
+ struct psc_dma *psc_dma;
+
+ rc = mpc5200_audio_dma_create(op, psc_ac97_dai_template, ARRAY_SIZE(psc_ac97_dai_template));
+ if (rc != 0)
+ return rc;
+
+ psc_dma = dev_get_drvdata(&op->dev);
+
+ psc_dma->imr = 0;
+ out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
+
+ out_8(&psc_dma->psc_regs->op1, MPC52xx_PSC_OP_RES);
+ udelay(10);
+ out_8(&psc_dma->psc_regs->op0, MPC52xx_PSC_OP_RES);
+ udelay(50);
+
+ /* Configure the serial interface mode to AC97 */
+ psc_dma->sicr = MPC52xx_PSC_SICR_SIM_AC97 | MPC52xx_PSC_SICR_ENAC97;
+ out_be32(&psc_dma->psc_regs->sicr, psc_dma->sicr);
+
+ /* No slots active */
+ out_be32(&psc_dma->psc_regs->ac97_slots, 0x00000000);
+
+ /* Go */
+ out_8(&psc_dma->psc_regs->command, MPC52xx_PSC_TX_ENABLE);
+ out_8(&psc_dma->psc_regs->command, 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);
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.h b/sound/soc/fsl/mpc5200_psc_ac97.h
new file mode 100644
index 0000000..d028c55
--- /dev/null
+++ b/sound/soc/fsl/mpc5200_psc_ac97.h
@@ -0,0 +1,13 @@
+/*
+ * 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__
+
+#define MPC5200_AC97_ANALOG 0
+#define MPC5200_AC97_DIGITAL 1
+
+#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_AC97_H__ */
next prev parent reply other threads:[~2009-05-14 1:59 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-14 1:58 [PATCH V1 00/13] mpc5200 audio rework for AC97 Jon Smirl
2009-05-14 1:59 ` [PATCH V1 01/13] Temporarily undo 2008f137e92220b98120c4803499cdddb2b0fb06 Jon Smirl
2009-05-14 10:13 ` Mark Brown
2009-05-14 14:37 ` Jon Smirl
2009-05-14 16:25 ` Mark Brown
2009-05-14 20:21 ` Jon Smirl
2009-05-14 1:59 ` [PATCH V1 02/13] Basic split of mpc5200 DMA code out from mpc5200_psc_i2s Jon Smirl
2009-05-14 1:59 ` [PATCH V1 03/13] Rename the PSC functions to DMA Jon Smirl
2009-05-14 10:14 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 04/13] redo 2008f137e92220b98120c4803499cdddb2b0fb06 Jon Smirl
2009-05-14 1:59 ` [PATCH V1 05/13] Add a few more mpc5200 PSC defines Jon Smirl
2009-05-14 10:15 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 06/13] Allow a custom ASOC fabric driver with soc-of-simple Jon Smirl
2009-05-14 10:41 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 07/13] Add SNDRV_PCM_FMTBIT_S32_BE as a valid AC97 format Jon Smirl
2009-05-14 11:53 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 08/13] Have the WM9712 driver self register itself Jon Smirl
2009-05-14 10:45 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 09/13] Main rewite of the mpc5200 audio DMA code Jon Smirl
2009-05-14 10:51 ` Mark Brown
2009-05-14 14:50 ` Jon Smirl
2009-05-14 19:14 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 10/13] Codec for STAC9766 used on the Efika Jon Smirl
2009-05-14 11:03 ` Mark Brown
2009-05-14 1:59 ` Jon Smirl [this message]
2009-05-14 2:17 ` [PATCH V1 11/13] AC97 driver for mpc5200 Jon Smirl
2009-05-14 11:39 ` Mark Brown
2009-05-14 1:59 ` [PATCH V1 12/13] Fabric bindings for STAC9766 on the Efika Jon Smirl
2009-05-14 1:59 ` [PATCH V1 13/13] Support for AC97 on Phytec pmc030 base board Jon Smirl
2009-05-14 2:03 ` [PATCH V1 00/13] mpc5200 audio rework for AC97 Jon Smirl
2009-05-14 3:34 ` Grant Likely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090514015922.28145.58560.stgit@terra \
--to=jonsmirl@gmail.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@sirena.org.uk \
--cc=grant.likely@secretlab.ca \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.