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