1 /* 2 * kirkwood-i2s.c 3 * 4 * (c) 2010 Arnaud Patard <apatard@mandriva.com> 5 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 */ 12 13 #include <linux/init.h> 14 #include <linux/module.h> 15 #include <linux/platform_device.h> 16 #include <linux/io.h> 17 #include <linux/slab.h> 18 #include <linux/mbus.h> 19 #include <linux/delay.h> 20 #include <sound/pcm.h> 21 #include <sound/pcm_params.h> 22 #include <sound/soc.h> 23 #include <plat/audio.h> 24 #include "kirkwood.h" 25 26 #define DRV_NAME "kirkwood-i2s" 27 28 #define KIRKWOOD_I2S_RATES \ 29 (SNDRV_PCM_RATE_44100 | \ 30 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 31 #define KIRKWOOD_I2S_FORMATS \ 32 (SNDRV_PCM_FMTBIT_S16_LE | \ 33 SNDRV_PCM_FMTBIT_S24_LE | \ 34 SNDRV_PCM_FMTBIT_S32_LE) 35 36 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai, 37 unsigned int fmt) 38 { 39 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai); 40 unsigned long mask; 41 unsigned long value; 42 43 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 44 case SND_SOC_DAIFMT_RIGHT_J: 45 mask = KIRKWOOD_I2S_CTL_RJ; 46 break; 47 case SND_SOC_DAIFMT_LEFT_J: 48 mask = KIRKWOOD_I2S_CTL_LJ; 49 break; 50 case SND_SOC_DAIFMT_I2S: 51 mask = KIRKWOOD_I2S_CTL_I2S; 52 break; 53 default: 54 return -EINVAL; 55 } 56 57 /* 58 * Set same format for playback and record 59 * This avoids some troubles. 60 */ 61 value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL); 62 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK; 63 value |= mask; 64 writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL); 65 66 value = readl(priv->io+KIRKWOOD_I2S_RECCTL); 67 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK; 68 value |= mask; 69 writel(value, priv->io+KIRKWOOD_I2S_RECCTL); 70 71 return 0; 72 } 73 74 static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) 75 { 76 unsigned long value; 77 78 value = KIRKWOOD_DCO_CTL_OFFSET_0; 79 switch (rate) { 80 default: 81 case 44100: 82 value |= KIRKWOOD_DCO_CTL_FREQ_11; 83 break; 84 case 48000: 85 value |= KIRKWOOD_DCO_CTL_FREQ_12; 86 break; 87 case 96000: 88 value |= KIRKWOOD_DCO_CTL_FREQ_24; 89 break; 90 } 91 writel(value, io + KIRKWOOD_DCO_CTL); 92 93 /* wait for dco locked */ 94 do { 95 cpu_relax(); 96 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS); 97 value &= KIRKWOOD_DCO_SPCR_STATUS; 98 } while (value == 0); 99 } 100 101 static int kirkwood_i2s_startup(struct snd_pcm_substream *substream, 102 struct snd_soc_dai *dai) 103 { 104 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 105 106 snd_soc_dai_set_dma_data(dai, substream, priv); 107 return 0; 108 } 109 110 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, 111 struct snd_pcm_hw_params *params, 112 struct snd_soc_dai *dai) 113 { 114 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 115 unsigned int i2s_reg, reg; 116 unsigned long i2s_value, value; 117 118 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 119 i2s_reg = KIRKWOOD_I2S_PLAYCTL; 120 reg = KIRKWOOD_PLAYCTL; 121 } else { 122 i2s_reg = KIRKWOOD_I2S_RECCTL; 123 reg = KIRKWOOD_RECCTL; 124 } 125 126 /* set dco conf */ 127 kirkwood_set_dco(priv->io, params_rate(params)); 128 129 i2s_value = readl(priv->io+i2s_reg); 130 i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; 131 132 value = readl(priv->io+reg); 133 value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK; 134 135 /* 136 * Size settings in play/rec i2s control regs and play/rec control 137 * regs must be the same. 138 */ 139 switch (params_format(params)) { 140 case SNDRV_PCM_FORMAT_S16_LE: 141 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; 142 value |= KIRKWOOD_PLAYCTL_SIZE_16_C; 143 break; 144 /* 145 * doesn't work... S20_3LE != kirkwood 20bit format ? 146 * 147 case SNDRV_PCM_FORMAT_S20_3LE: 148 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; 149 value |= KIRKWOOD_PLAYCTL_SIZE_20; 150 break; 151 */ 152 case SNDRV_PCM_FORMAT_S24_LE: 153 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; 154 value |= KIRKWOOD_PLAYCTL_SIZE_24; 155 break; 156 case SNDRV_PCM_FORMAT_S32_LE: 157 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; 158 value |= KIRKWOOD_PLAYCTL_SIZE_32; 159 break; 160 default: 161 return -EINVAL; 162 } 163 164 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 165 value &= ~KIRKWOOD_PLAYCTL_MONO_MASK; 166 if (params_channels(params) == 1) 167 value |= KIRKWOOD_PLAYCTL_MONO_BOTH; 168 else 169 value |= KIRKWOOD_PLAYCTL_MONO_OFF; 170 } 171 172 writel(i2s_value, priv->io+i2s_reg); 173 writel(value, priv->io+reg); 174 175 return 0; 176 } 177 178 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, 179 int cmd, struct snd_soc_dai *dai) 180 { 181 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 182 unsigned long value; 183 184 /* 185 * specs says KIRKWOOD_PLAYCTL must be read 2 times before 186 * changing it. So read 1 time here and 1 later. 187 */ 188 value = readl(priv->io + KIRKWOOD_PLAYCTL); 189 190 switch (cmd) { 191 case SNDRV_PCM_TRIGGER_START: 192 /* stop audio, enable interrupts */ 193 value = readl(priv->io + KIRKWOOD_PLAYCTL); 194 value |= KIRKWOOD_PLAYCTL_PAUSE; 195 writel(value, priv->io + KIRKWOOD_PLAYCTL); 196 197 value = readl(priv->io + KIRKWOOD_INT_MASK); 198 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; 199 writel(value, priv->io + KIRKWOOD_INT_MASK); 200 201 /* configure audio & enable i2s playback */ 202 value = readl(priv->io + KIRKWOOD_PLAYCTL); 203 value &= ~KIRKWOOD_PLAYCTL_BURST_MASK; 204 value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE 205 | KIRKWOOD_PLAYCTL_SPDIF_EN); 206 207 if (priv->burst == 32) 208 value |= KIRKWOOD_PLAYCTL_BURST_32; 209 else 210 value |= KIRKWOOD_PLAYCTL_BURST_128; 211 value |= KIRKWOOD_PLAYCTL_I2S_EN; 212 writel(value, priv->io + KIRKWOOD_PLAYCTL); 213 break; 214 215 case SNDRV_PCM_TRIGGER_STOP: 216 /* stop audio, disable interrupts */ 217 value = readl(priv->io + KIRKWOOD_PLAYCTL); 218 value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; 219 writel(value, priv->io + KIRKWOOD_PLAYCTL); 220 221 value = readl(priv->io + KIRKWOOD_INT_MASK); 222 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES; 223 writel(value, priv->io + KIRKWOOD_INT_MASK); 224 225 /* disable all playbacks */ 226 value = readl(priv->io + KIRKWOOD_PLAYCTL); 227 value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); 228 writel(value, priv->io + KIRKWOOD_PLAYCTL); 229 break; 230 231 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 232 case SNDRV_PCM_TRIGGER_SUSPEND: 233 value = readl(priv->io + KIRKWOOD_PLAYCTL); 234 value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; 235 writel(value, priv->io + KIRKWOOD_PLAYCTL); 236 break; 237 238 case SNDRV_PCM_TRIGGER_RESUME: 239 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 240 value = readl(priv->io + KIRKWOOD_PLAYCTL); 241 value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); 242 writel(value, priv->io + KIRKWOOD_PLAYCTL); 243 break; 244 245 default: 246 return -EINVAL; 247 } 248 249 return 0; 250 } 251 252 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, 253 int cmd, struct snd_soc_dai *dai) 254 { 255 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 256 unsigned long value; 257 258 value = readl(priv->io + KIRKWOOD_RECCTL); 259 260 switch (cmd) { 261 case SNDRV_PCM_TRIGGER_START: 262 /* stop audio, enable interrupts */ 263 value = readl(priv->io + KIRKWOOD_RECCTL); 264 value |= KIRKWOOD_RECCTL_PAUSE; 265 writel(value, priv->io + KIRKWOOD_RECCTL); 266 267 value = readl(priv->io + KIRKWOOD_INT_MASK); 268 value |= KIRKWOOD_INT_CAUSE_REC_BYTES; 269 writel(value, priv->io + KIRKWOOD_INT_MASK); 270 271 /* configure audio & enable i2s record */ 272 value = readl(priv->io + KIRKWOOD_RECCTL); 273 value &= ~KIRKWOOD_RECCTL_BURST_MASK; 274 value &= ~KIRKWOOD_RECCTL_MONO; 275 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE 276 | KIRKWOOD_RECCTL_SPDIF_EN); 277 278 if (priv->burst == 32) 279 value |= KIRKWOOD_RECCTL_BURST_32; 280 else 281 value |= KIRKWOOD_RECCTL_BURST_128; 282 value |= KIRKWOOD_RECCTL_I2S_EN; 283 284 writel(value, priv->io + KIRKWOOD_RECCTL); 285 break; 286 287 case SNDRV_PCM_TRIGGER_STOP: 288 /* stop audio, disable interrupts */ 289 value = readl(priv->io + KIRKWOOD_RECCTL); 290 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE; 291 writel(value, priv->io + KIRKWOOD_RECCTL); 292 293 value = readl(priv->io + KIRKWOOD_INT_MASK); 294 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES; 295 writel(value, priv->io + KIRKWOOD_INT_MASK); 296 297 /* disable all records */ 298 value = readl(priv->io + KIRKWOOD_RECCTL); 299 value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); 300 writel(value, priv->io + KIRKWOOD_RECCTL); 301 break; 302 303 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 304 case SNDRV_PCM_TRIGGER_SUSPEND: 305 value = readl(priv->io + KIRKWOOD_RECCTL); 306 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE; 307 writel(value, priv->io + KIRKWOOD_RECCTL); 308 break; 309 310 case SNDRV_PCM_TRIGGER_RESUME: 311 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 312 value = readl(priv->io + KIRKWOOD_RECCTL); 313 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE); 314 writel(value, priv->io + KIRKWOOD_RECCTL); 315 break; 316 317 default: 318 return -EINVAL; 319 } 320 321 return 0; 322 } 323 324 static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 325 struct snd_soc_dai *dai) 326 { 327 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 328 return kirkwood_i2s_play_trigger(substream, cmd, dai); 329 else 330 return kirkwood_i2s_rec_trigger(substream, cmd, dai); 331 332 return 0; 333 } 334 335 static int kirkwood_i2s_probe(struct snd_soc_dai *dai) 336 { 337 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 338 unsigned long value; 339 unsigned int reg_data; 340 341 /* put system in a "safe" state : */ 342 /* disable audio interrupts */ 343 writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE); 344 writel(0, priv->io + KIRKWOOD_INT_MASK); 345 346 reg_data = readl(priv->io + 0x1200); 347 reg_data &= (~(0x333FF8)); 348 reg_data |= 0x111D18; 349 writel(reg_data, priv->io + 0x1200); 350 351 msleep(500); 352 353 reg_data = readl(priv->io + 0x1200); 354 reg_data &= (~(0x333FF8)); 355 reg_data |= 0x111D18; 356 writel(reg_data, priv->io + 0x1200); 357 358 /* disable playback/record */ 359 value = readl(priv->io + KIRKWOOD_PLAYCTL); 360 value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN); 361 writel(value, priv->io + KIRKWOOD_PLAYCTL); 362 363 value = readl(priv->io + KIRKWOOD_RECCTL); 364 value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); 365 writel(value, priv->io + KIRKWOOD_RECCTL); 366 367 return 0; 368 369 } 370 371 static int kirkwood_i2s_remove(struct snd_soc_dai *dai) 372 { 373 return 0; 374 } 375 376 static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { 377 .startup = kirkwood_i2s_startup, 378 .trigger = kirkwood_i2s_trigger, 379 .hw_params = kirkwood_i2s_hw_params, 380 .set_fmt = kirkwood_i2s_set_fmt, 381 }; 382 383 384 static struct snd_soc_dai_driver kirkwood_i2s_dai = { 385 .probe = kirkwood_i2s_probe, 386 .remove = kirkwood_i2s_remove, 387 .playback = { 388 .channels_min = 1, 389 .channels_max = 2, 390 .rates = KIRKWOOD_I2S_RATES, 391 .formats = KIRKWOOD_I2S_FORMATS,}, 392 .capture = { 393 .channels_min = 1, 394 .channels_max = 2, 395 .rates = KIRKWOOD_I2S_RATES, 396 .formats = KIRKWOOD_I2S_FORMATS,}, 397 .ops = &kirkwood_i2s_dai_ops, 398 }; 399 400 static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) 401 { 402 struct resource *mem; 403 struct kirkwood_asoc_platform_data *data = 404 pdev->dev.platform_data; 405 struct kirkwood_dma_data *priv; 406 int err; 407 408 priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL); 409 if (!priv) { 410 dev_err(&pdev->dev, "allocation failed\n"); 411 err = -ENOMEM; 412 goto error; 413 } 414 dev_set_drvdata(&pdev->dev, priv); 415 416 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 417 if (!mem) { 418 dev_err(&pdev->dev, "platform_get_resource failed\n"); 419 err = -ENXIO; 420 goto err_alloc; 421 } 422 423 priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME); 424 if (!priv->mem) { 425 dev_err(&pdev->dev, "request_mem_region failed\n"); 426 err = -EBUSY; 427 goto error_alloc; 428 } 429 430 priv->io = ioremap(priv->mem->start, SZ_16K); 431 if (!priv->io) { 432 dev_err(&pdev->dev, "ioremap failed\n"); 433 err = -ENOMEM; 434 goto err_iomem; 435 } 436 437 priv->irq = platform_get_irq(pdev, 0); 438 if (priv->irq <= 0) { 439 dev_err(&pdev->dev, "platform_get_irq failed\n"); 440 err = -ENXIO; 441 goto err_ioremap; 442 } 443 444 if (!data || !data->dram) { 445 dev_err(&pdev->dev, "no platform data ?!\n"); 446 err = -EINVAL; 447 goto err_ioremap; 448 } 449 450 priv->dram = data->dram; 451 priv->burst = data->burst; 452 453 return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); 454 455 err_ioremap: 456 iounmap(priv->io); 457 err_iomem: 458 release_mem_region(priv->mem->start, SZ_16K); 459 err_alloc: 460 kfree(priv); 461 error: 462 return err; 463 } 464 465 static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev) 466 { 467 struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); 468 469 snd_soc_unregister_dai(&pdev->dev); 470 iounmap(priv->io); 471 release_mem_region(priv->mem->start, SZ_16K); 472 kfree(priv); 473 474 return 0; 475 } 476 477 static struct platform_driver kirkwood_i2s_driver = { 478 .probe = kirkwood_i2s_dev_probe, 479 .remove = kirkwood_i2s_dev_remove, 480 .driver = { 481 .name = DRV_NAME, 482 .owner = THIS_MODULE, 483 }, 484 }; 485 486 static int __init kirkwood_i2s_init(void) 487 { 488 return platform_driver_register(&kirkwood_i2s_driver); 489 } 490 module_init(kirkwood_i2s_init); 491 492 static void __exit kirkwood_i2s_exit(void) 493 { 494 platform_driver_unregister(&kirkwood_i2s_driver); 495 } 496 module_exit(kirkwood_i2s_exit); 497 498 /* Module information */ 499 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>"); 500 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); 501 MODULE_LICENSE("GPL"); 502 MODULE_ALIAS("platform:kirkwood-i2s"); 503