Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5 266 lines 7.3 kB view raw
1/* 2 * ALSA SoC Voice Codec Interface for TI DAVINCI processor 3 * 4 * Copyright (C) 2010 Texas Instruments. 5 * 6 * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23#include <linux/init.h> 24#include <linux/module.h> 25#include <linux/device.h> 26#include <linux/delay.h> 27#include <linux/slab.h> 28#include <linux/io.h> 29#include <linux/mfd/davinci_voicecodec.h> 30 31#include <sound/core.h> 32#include <sound/pcm.h> 33#include <sound/pcm_params.h> 34#include <sound/initval.h> 35#include <sound/soc.h> 36 37#include "davinci-pcm.h" 38#include "davinci-i2s.h" 39 40#define MOD_REG_BIT(val, mask, set) do { \ 41 if (set) { \ 42 val |= mask; \ 43 } else { \ 44 val &= ~mask; \ 45 } \ 46} while (0) 47 48struct davinci_vcif_dev { 49 struct davinci_vc *davinci_vc; 50 struct davinci_pcm_dma_params dma_params[2]; 51}; 52 53static void davinci_vcif_start(struct snd_pcm_substream *substream) 54{ 55 struct snd_soc_pcm_runtime *rtd = substream->private_data; 56 struct davinci_vcif_dev *davinci_vcif_dev = 57 snd_soc_dai_get_drvdata(rtd->cpu_dai); 58 struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc; 59 u32 w; 60 61 /* Start the sample generator and enable transmitter/receiver */ 62 w = readl(davinci_vc->base + DAVINCI_VC_CTRL); 63 64 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 65 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0); 66 else 67 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0); 68 69 writel(w, davinci_vc->base + DAVINCI_VC_CTRL); 70} 71 72static void davinci_vcif_stop(struct snd_pcm_substream *substream) 73{ 74 struct snd_soc_pcm_runtime *rtd = substream->private_data; 75 struct davinci_vcif_dev *davinci_vcif_dev = 76 snd_soc_dai_get_drvdata(rtd->cpu_dai); 77 struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc; 78 u32 w; 79 80 /* Reset transmitter/receiver and sample rate/frame sync generators */ 81 w = readl(davinci_vc->base + DAVINCI_VC_CTRL); 82 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 83 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1); 84 else 85 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1); 86 87 writel(w, davinci_vc->base + DAVINCI_VC_CTRL); 88} 89 90static int davinci_vcif_hw_params(struct snd_pcm_substream *substream, 91 struct snd_pcm_hw_params *params, 92 struct snd_soc_dai *dai) 93{ 94 struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai); 95 struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc; 96 struct davinci_pcm_dma_params *dma_params = 97 &davinci_vcif_dev->dma_params[substream->stream]; 98 u32 w; 99 100 /* Restart the codec before setup */ 101 davinci_vcif_stop(substream); 102 davinci_vcif_start(substream); 103 104 /* General line settings */ 105 writel(DAVINCI_VC_CTRL_MASK, davinci_vc->base + DAVINCI_VC_CTRL); 106 107 writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTCLR); 108 109 writel(DAVINCI_VC_INT_MASK, davinci_vc->base + DAVINCI_VC_INTEN); 110 111 w = readl(davinci_vc->base + DAVINCI_VC_CTRL); 112 113 /* Determine xfer data type */ 114 switch (params_format(params)) { 115 case SNDRV_PCM_FORMAT_U8: 116 dma_params->data_type = 0; 117 118 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | 119 DAVINCI_VC_CTRL_RD_UNSIGNED | 120 DAVINCI_VC_CTRL_WD_BITS_8 | 121 DAVINCI_VC_CTRL_WD_UNSIGNED, 1); 122 break; 123 case SNDRV_PCM_FORMAT_S8: 124 dma_params->data_type = 1; 125 126 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | 127 DAVINCI_VC_CTRL_WD_BITS_8, 1); 128 129 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_UNSIGNED | 130 DAVINCI_VC_CTRL_WD_UNSIGNED, 0); 131 break; 132 case SNDRV_PCM_FORMAT_S16_LE: 133 dma_params->data_type = 2; 134 135 MOD_REG_BIT(w, DAVINCI_VC_CTRL_RD_BITS_8 | 136 DAVINCI_VC_CTRL_RD_UNSIGNED | 137 DAVINCI_VC_CTRL_WD_BITS_8 | 138 DAVINCI_VC_CTRL_WD_UNSIGNED, 0); 139 break; 140 default: 141 printk(KERN_WARNING "davinci-vcif: unsupported PCM format"); 142 return -EINVAL; 143 } 144 145 dma_params->acnt = dma_params->data_type; 146 147 writel(w, davinci_vc->base + DAVINCI_VC_CTRL); 148 149 return 0; 150} 151 152static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, 153 struct snd_soc_dai *dai) 154{ 155 int ret = 0; 156 157 switch (cmd) { 158 case SNDRV_PCM_TRIGGER_START: 159 case SNDRV_PCM_TRIGGER_RESUME: 160 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 161 davinci_vcif_start(substream); 162 break; 163 case SNDRV_PCM_TRIGGER_STOP: 164 case SNDRV_PCM_TRIGGER_SUSPEND: 165 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 166 davinci_vcif_stop(substream); 167 break; 168 default: 169 ret = -EINVAL; 170 } 171 172 return ret; 173} 174 175static int davinci_vcif_startup(struct snd_pcm_substream *substream, 176 struct snd_soc_dai *dai) 177{ 178 struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai); 179 180 snd_soc_dai_set_dma_data(dai, substream, dev->dma_params); 181 return 0; 182} 183 184#define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000 185 186static const struct snd_soc_dai_ops davinci_vcif_dai_ops = { 187 .startup = davinci_vcif_startup, 188 .trigger = davinci_vcif_trigger, 189 .hw_params = davinci_vcif_hw_params, 190}; 191 192static struct snd_soc_dai_driver davinci_vcif_dai = { 193 .playback = { 194 .channels_min = 1, 195 .channels_max = 2, 196 .rates = DAVINCI_VCIF_RATES, 197 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 198 .capture = { 199 .channels_min = 1, 200 .channels_max = 2, 201 .rates = DAVINCI_VCIF_RATES, 202 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 203 .ops = &davinci_vcif_dai_ops, 204 205}; 206 207static int davinci_vcif_probe(struct platform_device *pdev) 208{ 209 struct davinci_vc *davinci_vc = pdev->dev.platform_data; 210 struct davinci_vcif_dev *davinci_vcif_dev; 211 int ret; 212 213 davinci_vcif_dev = devm_kzalloc(&pdev->dev, 214 sizeof(struct davinci_vcif_dev), 215 GFP_KERNEL); 216 if (!davinci_vcif_dev) { 217 dev_dbg(&pdev->dev, 218 "could not allocate memory for private data\n"); 219 return -ENOMEM; 220 } 221 222 /* DMA tx params */ 223 davinci_vcif_dev->davinci_vc = davinci_vc; 224 davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = 225 davinci_vc->davinci_vcif.dma_tx_channel; 226 davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = 227 davinci_vc->davinci_vcif.dma_tx_addr; 228 229 /* DMA rx params */ 230 davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = 231 davinci_vc->davinci_vcif.dma_rx_channel; 232 davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = 233 davinci_vc->davinci_vcif.dma_rx_addr; 234 235 dev_set_drvdata(&pdev->dev, davinci_vcif_dev); 236 237 ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai); 238 if (ret != 0) { 239 dev_err(&pdev->dev, "could not register dai\n"); 240 return ret; 241 } 242 243 return 0; 244} 245 246static int davinci_vcif_remove(struct platform_device *pdev) 247{ 248 snd_soc_unregister_dai(&pdev->dev); 249 250 return 0; 251} 252 253static struct platform_driver davinci_vcif_driver = { 254 .probe = davinci_vcif_probe, 255 .remove = davinci_vcif_remove, 256 .driver = { 257 .name = "davinci-vcif", 258 .owner = THIS_MODULE, 259 }, 260}; 261 262module_platform_driver(davinci_vcif_driver); 263 264MODULE_AUTHOR("Miguel Aguilar"); 265MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface"); 266MODULE_LICENSE("GPL");