diff options
Diffstat (limited to 'sound/soc/davinci/davinci-i2s.c')
| -rw-r--r-- | sound/soc/davinci/davinci-i2s.c | 153 |
1 files changed, 121 insertions, 32 deletions
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index abb5fedb0b1e..81ff5c37ab56 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) | 59 | #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) |
| 60 | #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) | 60 | #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) |
| 61 | #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) | 61 | #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) |
| 62 | #define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) | ||
| 62 | #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) | 63 | #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) |
| 63 | #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) | 64 | #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) |
| 64 | #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) | 65 | #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) |
| @@ -110,16 +111,59 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) | |||
| 110 | { | 111 | { |
| 111 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 112 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 112 | struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; | 113 | struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; |
| 114 | struct snd_soc_device *socdev = rtd->socdev; | ||
| 115 | struct snd_soc_platform *platform = socdev->card->platform; | ||
| 113 | u32 w; | 116 | u32 w; |
| 117 | int ret; | ||
| 114 | 118 | ||
| 115 | /* Start the sample generator and enable transmitter/receiver */ | 119 | /* Start the sample generator and enable transmitter/receiver */ |
| 116 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); | 120 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); |
| 117 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); | 121 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); |
| 118 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 122 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); |
| 123 | |||
| 124 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 125 | /* Stop the DMA to avoid data loss */ | ||
| 126 | /* while the transmitter is out of reset to handle XSYNCERR */ | ||
| 127 | if (platform->pcm_ops->trigger) { | ||
| 128 | ret = platform->pcm_ops->trigger(substream, | ||
| 129 | SNDRV_PCM_TRIGGER_STOP); | ||
| 130 | if (ret < 0) | ||
| 131 | printk(KERN_DEBUG "Playback DMA stop failed\n"); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* Enable the transmitter */ | ||
| 135 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); | ||
| 119 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); | 136 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); |
| 120 | else | 137 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); |
| 138 | |||
| 139 | /* wait for any unexpected frame sync error to occur */ | ||
| 140 | udelay(100); | ||
| 141 | |||
| 142 | /* Disable the transmitter to clear any outstanding XSYNCERR */ | ||
| 143 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); | ||
| 144 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); | ||
| 145 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); | ||
| 146 | |||
| 147 | /* Restart the DMA */ | ||
| 148 | if (platform->pcm_ops->trigger) { | ||
| 149 | ret = platform->pcm_ops->trigger(substream, | ||
| 150 | SNDRV_PCM_TRIGGER_START); | ||
| 151 | if (ret < 0) | ||
| 152 | printk(KERN_DEBUG "Playback DMA start failed\n"); | ||
| 153 | } | ||
| 154 | /* Enable the transmitter */ | ||
| 155 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); | ||
| 156 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); | ||
| 157 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); | ||
| 158 | |||
| 159 | } else { | ||
| 160 | |||
| 161 | /* Enable the reciever */ | ||
| 162 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); | ||
| 121 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); | 163 | MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); |
| 122 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); | 164 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); |
| 165 | } | ||
| 166 | |||
| 123 | 167 | ||
| 124 | /* Start frame sync */ | 168 | /* Start frame sync */ |
| 125 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); | 169 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); |
| @@ -144,7 +188,8 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) | |||
| 144 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); | 188 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); |
| 145 | } | 189 | } |
| 146 | 190 | ||
| 147 | static int davinci_i2s_startup(struct snd_pcm_substream *substream) | 191 | static int davinci_i2s_startup(struct snd_pcm_substream *substream, |
| 192 | struct snd_soc_dai *dai) | ||
| 148 | { | 193 | { |
| 149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 194 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 150 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 195 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
| @@ -171,6 +216,16 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
| 171 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, | 216 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, |
| 172 | DAVINCI_MCBSP_SRGR_FSGM); | 217 | DAVINCI_MCBSP_SRGR_FSGM); |
| 173 | break; | 218 | break; |
| 219 | case SND_SOC_DAIFMT_CBM_CFS: | ||
| 220 | /* McBSP CLKR pin is the input for the Sample Rate Generator. | ||
| 221 | * McBSP FSR and FSX are driven by the Sample Rate Generator. */ | ||
| 222 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, | ||
| 223 | DAVINCI_MCBSP_PCR_SCLKME | | ||
| 224 | DAVINCI_MCBSP_PCR_FSXM | | ||
| 225 | DAVINCI_MCBSP_PCR_FSRM); | ||
| 226 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, | ||
| 227 | DAVINCI_MCBSP_SRGR_FSGM); | ||
| 228 | break; | ||
| 174 | case SND_SOC_DAIFMT_CBM_CFM: | 229 | case SND_SOC_DAIFMT_CBM_CFM: |
| 175 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); | 230 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); |
| 176 | break; | 231 | break; |
| @@ -205,11 +260,34 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
| 205 | return -EINVAL; | 260 | return -EINVAL; |
| 206 | } | 261 | } |
| 207 | 262 | ||
| 263 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 264 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 265 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, | ||
| 266 | DAVINCI_MCBSP_RCR_RFRLEN1(1) | | ||
| 267 | DAVINCI_MCBSP_RCR_RDATDLY(0)); | ||
| 268 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, | ||
| 269 | DAVINCI_MCBSP_XCR_XFRLEN1(1) | | ||
| 270 | DAVINCI_MCBSP_XCR_XDATDLY(0) | | ||
| 271 | DAVINCI_MCBSP_XCR_XFIG); | ||
| 272 | break; | ||
| 273 | case SND_SOC_DAIFMT_I2S: | ||
| 274 | default: | ||
| 275 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, | ||
| 276 | DAVINCI_MCBSP_RCR_RFRLEN1(1) | | ||
| 277 | DAVINCI_MCBSP_RCR_RDATDLY(1)); | ||
| 278 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, | ||
| 279 | DAVINCI_MCBSP_XCR_XFRLEN1(1) | | ||
| 280 | DAVINCI_MCBSP_XCR_XDATDLY(1) | | ||
| 281 | DAVINCI_MCBSP_XCR_XFIG); | ||
| 282 | break; | ||
| 283 | } | ||
| 284 | |||
| 208 | return 0; | 285 | return 0; |
| 209 | } | 286 | } |
| 210 | 287 | ||
| 211 | static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | 288 | static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, |
| 212 | struct snd_pcm_hw_params *params) | 289 | struct snd_pcm_hw_params *params, |
| 290 | struct snd_soc_dai *dai) | ||
| 213 | { | 291 | { |
| 214 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 292 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 215 | struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; | 293 | struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; |
| @@ -219,17 +297,14 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 219 | u32 w; | 297 | u32 w; |
| 220 | 298 | ||
| 221 | /* general line settings */ | 299 | /* general line settings */ |
| 222 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, | 300 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); |
| 223 | DAVINCI_MCBSP_SPCR_RINTM(3) | | 301 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
| 224 | DAVINCI_MCBSP_SPCR_XINTM(3) | | 302 | w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; |
| 225 | DAVINCI_MCBSP_SPCR_FREE); | 303 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); |
| 226 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, | 304 | } else { |
| 227 | DAVINCI_MCBSP_RCR_RFRLEN1(1) | | 305 | w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; |
| 228 | DAVINCI_MCBSP_RCR_RDATDLY(1)); | 306 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); |
| 229 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, | 307 | } |
| 230 | DAVINCI_MCBSP_XCR_XFRLEN1(1) | | ||
| 231 | DAVINCI_MCBSP_XCR_XDATDLY(1) | | ||
| 232 | DAVINCI_MCBSP_XCR_XFIG); | ||
| 233 | 308 | ||
| 234 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | 309 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); |
| 235 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); | 310 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); |
| @@ -260,20 +335,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 260 | return -EINVAL; | 335 | return -EINVAL; |
| 261 | } | 336 | } |
| 262 | 337 | ||
| 263 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); | 338 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
| 264 | MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | | 339 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); |
| 265 | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); | 340 | MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | |
| 266 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); | 341 | DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); |
| 342 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); | ||
| 267 | 343 | ||
| 268 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); | 344 | } else { |
| 269 | MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | | 345 | w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); |
| 270 | DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); | 346 | MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | |
| 271 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); | 347 | DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); |
| 348 | davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); | ||
| 272 | 349 | ||
| 350 | } | ||
| 273 | return 0; | 351 | return 0; |
| 274 | } | 352 | } |
| 275 | 353 | ||
| 276 | static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) | 354 | static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, |
| 355 | struct snd_soc_dai *dai) | ||
| 277 | { | 356 | { |
| 278 | int ret = 0; | 357 | int ret = 0; |
| 279 | 358 | ||
| @@ -299,8 +378,8 @@ static int davinci_i2s_probe(struct platform_device *pdev, | |||
| 299 | struct snd_soc_dai *dai) | 378 | struct snd_soc_dai *dai) |
| 300 | { | 379 | { |
| 301 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 380 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 302 | struct snd_soc_machine *machine = socdev->machine; | 381 | struct snd_soc_card *card = socdev->card; |
| 303 | struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; | 382 | struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; |
| 304 | struct davinci_mcbsp_dev *dev; | 383 | struct davinci_mcbsp_dev *dev; |
| 305 | struct resource *mem, *ioarea; | 384 | struct resource *mem, *ioarea; |
| 306 | struct evm_snd_platform_data *pdata; | 385 | struct evm_snd_platform_data *pdata; |
| @@ -361,8 +440,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, | |||
| 361 | struct snd_soc_dai *dai) | 440 | struct snd_soc_dai *dai) |
| 362 | { | 441 | { |
| 363 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 442 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
| 364 | struct snd_soc_machine *machine = socdev->machine; | 443 | struct snd_soc_card *card = socdev->card; |
| 365 | struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; | 444 | struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; |
| 366 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; | 445 | struct davinci_mcbsp_dev *dev = cpu_dai->private_data; |
| 367 | struct resource *mem; | 446 | struct resource *mem; |
| 368 | 447 | ||
| @@ -381,7 +460,6 @@ static void davinci_i2s_remove(struct platform_device *pdev, | |||
| 381 | struct snd_soc_dai davinci_i2s_dai = { | 460 | struct snd_soc_dai davinci_i2s_dai = { |
| 382 | .name = "davinci-i2s", | 461 | .name = "davinci-i2s", |
| 383 | .id = 0, | 462 | .id = 0, |
| 384 | .type = SND_SOC_DAI_I2S, | ||
| 385 | .probe = davinci_i2s_probe, | 463 | .probe = davinci_i2s_probe, |
| 386 | .remove = davinci_i2s_remove, | 464 | .remove = davinci_i2s_remove, |
| 387 | .playback = { | 465 | .playback = { |
| @@ -397,13 +475,24 @@ struct snd_soc_dai davinci_i2s_dai = { | |||
| 397 | .ops = { | 475 | .ops = { |
| 398 | .startup = davinci_i2s_startup, | 476 | .startup = davinci_i2s_startup, |
| 399 | .trigger = davinci_i2s_trigger, | 477 | .trigger = davinci_i2s_trigger, |
| 400 | .hw_params = davinci_i2s_hw_params,}, | 478 | .hw_params = davinci_i2s_hw_params, |
| 401 | .dai_ops = { | ||
| 402 | .set_fmt = davinci_i2s_set_dai_fmt, | 479 | .set_fmt = davinci_i2s_set_dai_fmt, |
| 403 | }, | 480 | }, |
| 404 | }; | 481 | }; |
| 405 | EXPORT_SYMBOL_GPL(davinci_i2s_dai); | 482 | EXPORT_SYMBOL_GPL(davinci_i2s_dai); |
| 406 | 483 | ||
| 484 | static int __init davinci_i2s_init(void) | ||
| 485 | { | ||
| 486 | return snd_soc_register_dai(&davinci_i2s_dai); | ||
| 487 | } | ||
| 488 | module_init(davinci_i2s_init); | ||
| 489 | |||
| 490 | static void __exit davinci_i2s_exit(void) | ||
| 491 | { | ||
| 492 | snd_soc_unregister_dai(&davinci_i2s_dai); | ||
| 493 | } | ||
| 494 | module_exit(davinci_i2s_exit); | ||
| 495 | |||
| 407 | MODULE_AUTHOR("Vladimir Barinov"); | 496 | MODULE_AUTHOR("Vladimir Barinov"); |
| 408 | MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); | 497 | MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); |
| 409 | MODULE_LICENSE("GPL"); | 498 | MODULE_LICENSE("GPL"); |
