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