[alsa-devel] [PATCH 2/4] ASoC: DaVinci: Voice Codec Interface
miguel.aguilar at ridgerun.com
miguel.aguilar at ridgerun.com
Tue Sep 22 21:29:20 CEST 2009
From: Miguel Aguilar <miguel.aguilar at ridgerun.com>
1) Adds an interface needed by the voice codec CQ0093.
2) Add an option to select internal or external codec in the DM365.
Signed-off-by: Miguel Aguilar <miguel.aguilar at ridgerun.com>
---
sound/soc/davinci/Kconfig | 26 +++-
sound/soc/davinci/Makefile | 2 +
sound/soc/davinci/davinci-vcif.c | 363 ++++++++++++++++++++++++++++++++++++++
sound/soc/davinci/davinci-vcif.h | 63 +++++++
4 files changed, 452 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/davinci/davinci-vcif.c
create mode 100644 sound/soc/davinci/davinci-vcif.h
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index 047ee39..051a10e 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -9,18 +9,40 @@ config SND_DAVINCI_SOC
config SND_DAVINCI_SOC_I2S
tristate
+config SND_DAVINCI_SOC_VCIF
+ tristate
+
config SND_DAVINCI_SOC_MCASP
tristate
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_DAVINCI_SOC
- depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
+ depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
select SND_DAVINCI_SOC_I2S
select SND_SOC_TLV320AIC3X
help
Say Y if you want to add support for SoC audio on TI
- DaVinci DM6446 or DM355 EVM platforms.
+ DaVinci DM6446, DM355 or DM365 EVM platforms.
+
+choice
+ prompt "DM365 codec select"
+ depends on SND_DAVINCI_SOC_EVM
+ depends on MACH_DAVINCI_DM365_EVM
+ default SND_DM365_EXTERNAL_CODEC
+
+config SND_DM365_INTERNAL_CODEC
+ bool "CQ93VC"
+ select SND_DAVINCI_SOC_VCIF
+ select SND_SOC_CQ0093VC
+ help
+ Say Y if you want to add support for SoC On-chip voice codec
+
+config SND_DM365_EXTERNAL_CODEC
+ bool "AIC3101"
+ help
+ Say Y if you want to add support for AIC3101 audio codec
+endchoice
config SND_DM6467_SOC_EVM
tristate "SoC Audio support for DaVinci DM6467 EVM"
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index a6939d7..a93679d 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -2,10 +2,12 @@
snd-soc-davinci-objs := davinci-pcm.o
snd-soc-davinci-i2s-objs := davinci-i2s.o
snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
+snd-soc-davinci-vcif-objs:= davinci-vcif.o
obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
+obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
# DAVINCI Machine Support
snd-soc-evm-objs := davinci-evm.o
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
new file mode 100644
index 0000000..83191f1
--- /dev/null
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -0,0 +1,363 @@
+/*
+ * ALSA SoC Voice Codec Interface for TI DAVINCI processor
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * Author: Miguel Aguilar <miguel.aguilar at ridgerun.com>
+ *
+ * Initial code: Hui Geng
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include "davinci-pcm.h"
+#include "davinci-i2s.h"
+#include "davinci-vcif.h"
+
+#define MOD_REG_BIT(val, mask, set) do { \
+ if (set) { \
+ val |= mask; \
+ } else { \
+ val &= ~mask; \
+ } \
+} while (0)
+
+static struct davinci_pcm_dma_params davinci_vcif_pcm_out = {
+ .name = "VCIF PCM Stereo out",
+};
+
+static struct davinci_pcm_dma_params davinci_vcif_pcm_in = {
+ .name = "VCIF PCM Stereo in",
+};
+
+struct davinci_vcif_dev {
+ void __iomem *base;
+ resource_size_t pbase;
+ size_t base_size;
+ int mode;
+ u32 pcr;
+ struct clk *clk;
+ struct davinci_pcm_dma_params *dma_params[2];
+};
+
+static inline void davinci_vcif_write_reg(struct davinci_vcif_dev *dev,
+ int reg, u32 val)
+{
+ __raw_writel(val, dev->base + reg);
+}
+
+static inline u32 davinci_vcif_read_reg(struct davinci_vcif_dev *dev, int reg)
+{
+ return __raw_readl(dev->base + reg);
+}
+
+static void davinci_vcif_start(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct davinci_vcif_dev *dev = rtd->dai->cpu_dai->private_data;
+ u32 w;
+
+ /* Start the sample generator and enable transmitter/receiver */
+ w = davinci_vcif_read_reg(dev, DAVINCI_VCIF_CTRL_REG);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RSTDAC, 1);
+ else
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RSTADC, 1);
+
+ davinci_vcif_write_reg(dev, DAVINCI_VCIF_CTRL_REG, w);
+}
+
+static void davinci_vcif_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct davinci_vcif_dev *dev = rtd->dai->cpu_dai->private_data;
+ u32 w;
+
+ /* Reset transmitter/receiver and sample rate/frame sync generators */
+ w = davinci_vcif_read_reg(dev, DAVINCI_VCIF_CTRL_REG);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RSTDAC, 0);
+ else
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RSTADC, 0);
+
+ davinci_vcif_write_reg(dev, DAVINCI_VCIF_CTRL_REG, w);
+}
+
+static int davinci_vcif_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct davinci_vcif_dev *dev = cpu_dai->private_data;
+
+ cpu_dai->dma_data = dev->dma_params[substream->stream];
+ return 0;
+}
+
+static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct davinci_pcm_dma_params *dma_params = dai->dma_data;
+ struct davinci_vcif_dev *dev = dai->private_data;
+ u32 w;
+
+ /* Restart the codec before setup */
+ davinci_vcif_stop(substream);
+ davinci_vcif_start(substream);
+
+ /* General line settings */
+ davinci_vcif_write_reg(dev,
+ DAVINCI_VCIF_CTRL_REG, DAVINCI_VCIF_CTRL_MASK);
+
+ davinci_vcif_write_reg(dev,
+ DAVINCI_VCIF_INTCLR_REG, DAVINCI_VCIF_INT_MASK);
+
+ davinci_vcif_write_reg(dev,
+ DAVINCI_VCIF_INTEN_REG, DAVINCI_VCIF_INT_MASK);
+
+ w = davinci_vcif_read_reg(dev, DAVINCI_VCIF_CTRL_REG);
+
+ /* Determine xfer data type */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U8:
+ dma_params->data_type = 0;
+
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RD_BITS_8 |
+ DAVINCI_VCIF_CTRL_RD_UNSIGNED |
+ DAVINCI_VCIF_CTRL_WD_BITS_8 |
+ DAVINCI_VCIF_CTRL_WD_UNSIGNED, 1);
+ break;
+ case SNDRV_PCM_FORMAT_S8:
+ dma_params->data_type = 1;
+
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RD_BITS_8 |
+ DAVINCI_VCIF_CTRL_WD_BITS_8, 1);
+
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RD_UNSIGNED |
+ DAVINCI_VCIF_CTRL_WD_UNSIGNED, 0);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ dma_params->data_type = 2;
+
+ MOD_REG_BIT(w, DAVINCI_VCIF_CTRL_RD_BITS_8 |
+ DAVINCI_VCIF_CTRL_RD_UNSIGNED |
+ DAVINCI_VCIF_CTRL_WD_BITS_8 |
+ DAVINCI_VCIF_CTRL_WD_UNSIGNED, 0);
+ break;
+ default:
+ printk(KERN_WARNING "davinci-vcif: unsupported PCM format");
+ return -EINVAL;
+ }
+
+ dma_params->acnt = dma_params->data_type;
+
+ davinci_vcif_write_reg(dev, DAVINCI_VCIF_CTRL_REG, w);
+
+ return 0;
+}
+
+static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ davinci_vcif_start(substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ davinci_vcif_stop(substream);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+#define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000
+
+static struct snd_soc_dai_ops davinci_vcif_dai_ops = {
+ .startup = davinci_vcif_startup,
+ .trigger = davinci_vcif_trigger,
+ .hw_params = davinci_vcif_hw_params,
+};
+
+struct snd_soc_dai davinci_vcif_dai = {
+ .name = "davinci-vcif",
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = DAVINCI_VCIF_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = DAVINCI_VCIF_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &davinci_vcif_dai_ops,
+
+};
+EXPORT_SYMBOL_GPL(davinci_vcif_dai);
+
+static int davinci_vcif_probe(struct platform_device *pdev)
+{
+ struct davinci_vcif_dev *dev;
+ struct resource *res, *mem;
+ int ret;
+
+ dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL);
+ if (!dev) {
+ dev_dbg(&pdev->dev, "could not allocate memory for private data\n");
+ return -ENOMEM;
+ }
+
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_dbg(&pdev->dev, "%s: could not get the clock for voice codec\n",
+ pdev->name);
+ ret = -ENODEV;
+ goto fail1;
+ }
+ clk_enable(dev->clk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ ret = -ENODEV;
+ goto fail2;
+ }
+
+ dev->pbase = res->start;
+ dev->base_size = resource_size(res);
+
+ mem = request_mem_region(dev->pbase, dev->base_size, pdev->name);
+ if (!mem) {
+ dev_err(&pdev->dev, "VCIF region already claimed\n");
+ ret = -EBUSY;
+ goto fail2;
+ }
+
+ dev->base = ioremap(dev->pbase, dev->base_size);
+ if (!dev->base) {
+ dev_err(&pdev->dev,"%s: can't ioremap mem resource.\n", pdev->name);
+ ret = -ENOMEM;
+ goto fail3;
+ }
+
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_vcif_pcm_out;
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr =
+ (dma_addr_t)(io_v2p(dev->base) + DAVINCI_VCIF_WFIFO_REG);
+
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_vcif_pcm_in;
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr =
+ (dma_addr_t)(io_v2p(dev->base) + DAVINCI_VCIF_RFIFO_REG);
+
+ /* first TX, then RX */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "%s: no DMA resource\n", pdev->name);
+ ret = -ENXIO;
+ goto fail4;
+ }
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "%s: no DMA resource\n", pdev->name);
+ ret = -ENXIO;
+ goto fail4;
+ }
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = res->start;
+
+ davinci_vcif_dai.private_data = dev;
+ ret = snd_soc_register_dai(&davinci_vcif_dai);
+ if (ret != 0)
+ goto fail4;
+
+ return 0;
+
+fail4:
+ iounmap(dev->base);
+fail3:
+ release_mem_region(dev->pbase, dev->base_size);
+fail2:
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+fail1:
+ kfree(dev);
+
+ return ret;
+}
+
+static int davinci_vcif_remove(struct platform_device *pdev)
+{
+ struct davinci_vcif_dev *dev = davinci_vcif_dai.private_data;
+
+ iounmap(dev->base);
+ release_mem_region(dev->pbase, dev->base_size);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+ dev->clk = NULL;
+
+ kfree(dev);
+
+ snd_soc_unregister_dai(&davinci_vcif_dai);
+
+ return 0;
+}
+
+static struct platform_driver davinci_vcif_driver = {
+ .probe = davinci_vcif_probe,
+ .remove = davinci_vcif_remove,
+ .driver = {
+ .name = "voice_codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init davinci_vcif_init(void)
+{
+ return platform_driver_probe(&davinci_vcif_driver, davinci_vcif_probe);
+}
+module_init(davinci_vcif_init);
+
+static void __exit davinci_vcif_exit(void)
+{
+ platform_driver_unregister(&davinci_vcif_driver);
+}
+module_exit(davinci_vcif_exit);
+
+MODULE_AUTHOR("Miguel Aguilar");
+MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/davinci/davinci-vcif.h b/sound/soc/davinci/davinci-vcif.h
new file mode 100644
index 0000000..30e441d
--- /dev/null
+++ b/sound/soc/davinci/davinci-vcif.h
@@ -0,0 +1,63 @@
+/*
+ * ALSA SoC Voice Codec Interface for TI DAVINCI processor
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * Author: Miguel Aguilar <miguel.aguilar at ridgerun.com>
+ *
+ * Initial code: Hui Geng
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _DAVINCI_VCIF_H
+#define _DAVINCI_VCIF_H
+
+#define DAVINCI_VCIF_PID_REG 0x00
+#define DAVINCI_VCIF_CTRL_REG 0x04
+#define DAVINCI_VCIF_INTEN_REG 0x08
+#define DAVINCI_VCIF_INTSTATUS_REG 0x0c
+#define DAVINCI_VCIF_INTCLR_REG 0x10
+#define DAVINCI_VCIF_EMUL_CTRL_REG 0x14
+#define DAVINCI_VCIF_RFIFO_REG 0x20
+#define DAVINCI_VCIF_WFIFO_REG 0x24
+#define DAVINCI_VCIF_FIFOSTAT_REG 0x28
+#define DAVINCI_VCIF_TST_CTRL_REG 0x2C
+
+#define DAVINCI_VCIF_CTRL_MASK 0x5500
+#define DAVINCI_VCIF_CTRL_RSTADC (1 << 0)
+#define DAVINCI_VCIF_CTRL_RSTDAC (1 << 1)
+#define DAVINCI_VCIF_CTRL_RD_BITS_8 (1 << 4)
+#define DAVINCI_VCIF_CTRL_RD_UNSIGNED (1 << 5)
+#define DAVINCI_VCIF_CTRL_WD_BITS_8 (1 << 6)
+#define DAVINCI_VCIF_CTRL_WD_UNSIGNED (1 << 7)
+#define DAVINCI_VCIF_CTRL_RFIFOEN (1 << 8)
+#define DAVINCI_VCIF_CTRL_RFIFOCL (1 << 9)
+#define DAVINCI_VCIF_CTRL_RFIFOMD_WORD_1 (1 << 10)
+#define DAVINCI_VCIF_CTRL_WFIFOEN (1 << 12)
+#define DAVINCI_VCIF_CTRL_WFIFOCL (1 << 13)
+#define DAVINCI_VCIF_CTRL_WFIFOMD_WORD_1 (1 << 14)
+
+#define DAVINCI_VCIF_INT_MASK 0x3F
+#define DAVINCI_VCIF_INT_RDRDY_MASK (1 << 0)
+#define DAVINCI_VCIF_INT_RERROVF_MASK (1 << 1)
+#define DAVINCI_VCIF_INT_RERRUDR_MASK (1 << 2)
+#define DAVINCI_VCIF_INT_WDREQ_MASK (1 << 3)
+#define DAVINCI_VCIF_INT_WERROVF_MASK (1 << 4)
+#define DAVINCI_VCIF_INT_WERRUDR_MASK (1 << 5)
+
+extern struct snd_soc_dai davinci_vcif_dai;
+
+#endif
--
1.6.0.4
More information about the Alsa-devel
mailing list