From: Miguel Aguilar miguel.aguilar@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@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@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@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