Path: blob/master/sound/soc/davinci/davinci-vcif.c
10817 views
/*1* ALSA SoC Voice Codec Interface for TI DAVINCI processor2*3* Copyright (C) 2010 Texas Instruments.4*5* Author: Miguel Aguilar <[email protected]>6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License as published by9* the Free Software Foundation; either version 2 of the License, or10* (at your option) any later version.11*12* This program is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15* GNU General Public License for more details.16*17* You should have received a copy of the GNU General Public License18* along with this program; if not, write to the Free Software19* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA20*/2122#include <linux/init.h>23#include <linux/module.h>24#include <linux/device.h>25#include <linux/delay.h>26#include <linux/slab.h>27#include <linux/io.h>28#include <linux/mfd/davinci_voicecodec.h>2930#include <sound/core.h>31#include <sound/pcm.h>32#include <sound/pcm_params.h>33#include <sound/initval.h>34#include <sound/soc.h>3536#include "davinci-pcm.h"37#include "davinci-i2s.h"3839#define MOD_REG_BIT(val, mask, set) do { \40if (set) { \41val |= mask; \42} else { \43val &= ~mask; \44} \45} while (0)4647struct davinci_vcif_dev {48struct davinci_vc *davinci_vc;49struct davinci_pcm_dma_params dma_params[2];50};5152static void davinci_vcif_start(struct snd_pcm_substream *substream)53{54struct snd_soc_pcm_runtime *rtd = substream->private_data;55struct davinci_vcif_dev *davinci_vcif_dev =56snd_soc_dai_get_drvdata(rtd->cpu_dai);57struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;58u32 w;5960/* Start the sample generator and enable transmitter/receiver */61w = readl(davinci_vc->base + DAVINCI_VC_CTRL);6263if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)64MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1);65else66MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1);6768writel(w, davinci_vc->base + DAVINCI_VC_CTRL);69}7071static void davinci_vcif_stop(struct snd_pcm_substream *substream)72{73struct snd_soc_pcm_runtime *rtd = substream->private_data;74struct davinci_vcif_dev *davinci_vcif_dev =75snd_soc_dai_get_drvdata(rtd->cpu_dai);76struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;77u32 w;7879/* Reset transmitter/receiver and sample rate/frame sync generators */80w = readl(davinci_vc->base + DAVINCI_VC_CTRL);81if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)82MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0);83else84MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0);8586writel(w, davinci_vc->base + DAVINCI_VC_CTRL);87}8889static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,90struct snd_pcm_hw_params *params,91struct snd_soc_dai *dai)92{93struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);94struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;95struct davinci_pcm_dma_params *dma_params =96&davinci_vcif_dev->dma_params[substream->stream];97u32 w;9899/* Restart the codec before setup */100davinci_vcif_stop(substream);101davinci_vcif_start(substream);102103/* General line settings */104writel(DAVINCI_VC_CTRL_MASK, davinci_vc->base + DAVINCI_VC_CTRL);105106writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTCLR);107108writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTEN);109110w = readl(davinci_vc->base + DAVINCI_VC_CTRL);111112/* Determine xfer data type */113switch (params_format(params)) {114case SNDRV_PCM_FORMAT_U8:115dma_params->data_type = 0;116117MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |118DAVINCI_VC_CTRL_RD_UNSIGNED |119DAVINCI_VC_CTRL_WD_BITS_8 |120DAVINCI_VC_CTRL_WD_UNSIGNED, 1);121break;122case SNDRV_PCM_FORMAT_S8:123dma_params->data_type = 1;124125MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |126DAVINCI_VC_CTRL_WD_BITS_8, 1);127128MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_UNSIGNED |129DAVINCI_VC_CTRL_WD_UNSIGNED, 0);130break;131case SNDRV_PCM_FORMAT_S16_LE:132dma_params->data_type = 2;133134MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 |135DAVINCI_VC_CTRL_RD_UNSIGNED |136DAVINCI_VC_CTRL_WD_BITS_8 |137DAVINCI_VC_CTRL_WD_UNSIGNED, 0);138break;139default:140printk(KERN_WARNING "davinci-vcif: unsupported PCM format");141return -EINVAL;142}143144dma_params->acnt = dma_params->data_type;145146writel(w, davinci_vc->base + DAVINCI_VC_CTRL);147148return 0;149}150151static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,152struct snd_soc_dai *dai)153{154int ret = 0;155156switch (cmd) {157case SNDRV_PCM_TRIGGER_START:158case SNDRV_PCM_TRIGGER_RESUME:159case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:160davinci_vcif_start(substream);161case SNDRV_PCM_TRIGGER_STOP:162case SNDRV_PCM_TRIGGER_SUSPEND:163case SNDRV_PCM_TRIGGER_PAUSE_PUSH:164davinci_vcif_stop(substream);165break;166default:167ret = -EINVAL;168}169170return ret;171}172173static int davinci_vcif_startup(struct snd_pcm_substream *substream,174struct snd_soc_dai *dai)175{176struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);177178snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);179return 0;180}181182#define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000183184static struct snd_soc_dai_ops davinci_vcif_dai_ops = {185.startup = davinci_vcif_startup,186.trigger = davinci_vcif_trigger,187.hw_params = davinci_vcif_hw_params,188};189190static struct snd_soc_dai_driver davinci_vcif_dai = {191.playback = {192.channels_min = 1,193.channels_max = 2,194.rates = DAVINCI_VCIF_RATES,195.formats = SNDRV_PCM_FMTBIT_S16_LE,},196.capture = {197.channels_min = 1,198.channels_max = 2,199.rates = DAVINCI_VCIF_RATES,200.formats = SNDRV_PCM_FMTBIT_S16_LE,},201.ops = &davinci_vcif_dai_ops,202203};204205static int davinci_vcif_probe(struct platform_device *pdev)206{207struct davinci_vc *davinci_vc = pdev->dev.platform_data;208struct davinci_vcif_dev *davinci_vcif_dev;209int ret;210211davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL);212if (!davinci_vcif_dev) {213dev_dbg(&pdev->dev,214"could not allocate memory for private data\n");215return -ENOMEM;216}217218/* DMA tx params */219davinci_vcif_dev->davinci_vc = davinci_vc;220davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel =221davinci_vc->davinci_vcif.dma_tx_channel;222davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =223davinci_vc->davinci_vcif.dma_tx_addr;224225/* DMA rx params */226davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel =227davinci_vc->davinci_vcif.dma_rx_channel;228davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =229davinci_vc->davinci_vcif.dma_rx_addr;230231dev_set_drvdata(&pdev->dev, davinci_vcif_dev);232233ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);234if (ret != 0) {235dev_err(&pdev->dev, "could not register dai\n");236goto fail;237}238239return 0;240241fail:242kfree(davinci_vcif_dev);243244return ret;245}246247static int davinci_vcif_remove(struct platform_device *pdev)248{249struct davinci_vcif_dev *davinci_vcif_dev = dev_get_drvdata(&pdev->dev);250251snd_soc_unregister_dai(&pdev->dev);252kfree(davinci_vcif_dev);253254return 0;255}256257static struct platform_driver davinci_vcif_driver = {258.probe = davinci_vcif_probe,259.remove = davinci_vcif_remove,260.driver = {261.name = "davinci-vcif",262.owner = THIS_MODULE,263},264};265266static int __init davinci_vcif_init(void)267{268return platform_driver_probe(&davinci_vcif_driver, davinci_vcif_probe);269}270module_init(davinci_vcif_init);271272static void __exit davinci_vcif_exit(void)273{274platform_driver_unregister(&davinci_vcif_driver);275}276module_exit(davinci_vcif_exit);277278MODULE_AUTHOR("Miguel Aguilar");279MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface");280MODULE_LICENSE("GPL");281282283