1 /* 2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation; either version 2 of the License, or (at your 7 * option) any later version. 8 * 9 * You should have received a copy of the GNU General Public License along 10 * with this program; if not, write to the Free Software Foundation, Inc., 11 * 675 Mass Ave, Cambridge, MA 02139, USA. 12 * 13 */ 14 15 #include <linux/init.h> 16 #include <linux/io.h> 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/platform_device.h> 20 #include <linux/slab.h> 21 22 #include <linux/clk.h> 23 #include <linux/delay.h> 24 25 #include <linux/dma-mapping.h> 26 27 #include <sound/core.h> 28 #include <sound/pcm.h> 29 #include <sound/pcm_params.h> 30 #include <sound/soc.h> 31 #include <sound/soc-dapm.h> 32 #include <sound/initval.h> 33 34 #include "jz4740-i2s.h" 35 #include "jz4740-pcm.h" 36 37 #define JZ_REG_AIC_CONF 0x00 38 #define JZ_REG_AIC_CTRL 0x04 39 #define JZ_REG_AIC_I2S_FMT 0x10 40 #define JZ_REG_AIC_FIFO_STATUS 0x14 41 #define JZ_REG_AIC_I2S_STATUS 0x1c 42 #define JZ_REG_AIC_CLK_DIV 0x30 43 #define JZ_REG_AIC_FIFO 0x34 44 45 #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12) 46 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8) 47 #define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6) 48 #define JZ_AIC_CONF_INTERNAL_CODEC BIT(5) 49 #define JZ_AIC_CONF_I2S BIT(4) 50 #define JZ_AIC_CONF_RESET BIT(3) 51 #define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2) 52 #define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1) 53 #define JZ_AIC_CONF_ENABLE BIT(0) 54 55 #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12 56 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8 57 58 #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19) 59 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16) 60 #define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15) 61 #define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14) 62 #define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11) 63 #define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10) 64 #define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9) 65 #define JZ_AIC_CTRL_FLUSH BIT(8) 66 #define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6) 67 #define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5) 68 #define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4) 69 #define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3) 70 #define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2) 71 #define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1) 72 #define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0) 73 74 #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19 75 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16 76 77 #define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12) 78 #define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4) 79 #define JZ_AIC_I2S_FMT_MSB BIT(0) 80 81 #define JZ_AIC_I2S_STATUS_BUSY BIT(2) 82 83 #define JZ_AIC_CLK_DIV_MASK 0xf 84 85 struct jz4740_i2s { 86 struct resource *mem; 87 void __iomem *base; 88 dma_addr_t phys_base; 89 90 struct clk *clk_aic; 91 struct clk *clk_i2s; 92 93 struct jz4740_pcm_config pcm_config_playback; 94 struct jz4740_pcm_config pcm_config_capture; 95 }; 96 97 static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, 98 unsigned int reg) 99 { 100 return readl(i2s->base + reg); 101 } 102 103 static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s, 104 unsigned int reg, uint32_t value) 105 { 106 writel(value, i2s->base + reg); 107 } 108 109 static int jz4740_i2s_startup(struct snd_pcm_substream *substream, 110 struct snd_soc_dai *dai) 111 { 112 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 113 uint32_t conf, ctrl; 114 115 if (dai->active) 116 return 0; 117 118 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 119 ctrl |= JZ_AIC_CTRL_FLUSH; 120 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 121 122 clk_enable(i2s->clk_i2s); 123 124 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 125 conf |= JZ_AIC_CONF_ENABLE; 126 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 127 128 return 0; 129 } 130 131 static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, 132 struct snd_soc_dai *dai) 133 { 134 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 135 uint32_t conf; 136 137 if (!dai->active) 138 return; 139 140 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 141 conf &= ~JZ_AIC_CONF_ENABLE; 142 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 143 144 clk_disable(i2s->clk_i2s); 145 } 146 147 static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 148 struct snd_soc_dai *dai) 149 { 150 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 151 152 uint32_t ctrl; 153 uint32_t mask; 154 155 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 156 mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA; 157 else 158 mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA; 159 160 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 161 162 switch (cmd) { 163 case SNDRV_PCM_TRIGGER_START: 164 case SNDRV_PCM_TRIGGER_RESUME: 165 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 166 ctrl |= mask; 167 break; 168 case SNDRV_PCM_TRIGGER_STOP: 169 case SNDRV_PCM_TRIGGER_SUSPEND: 170 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 171 ctrl &= ~mask; 172 break; 173 default: 174 return -EINVAL; 175 } 176 177 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 178 179 return 0; 180 } 181 182 static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 183 { 184 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 185 186 uint32_t format = 0; 187 uint32_t conf; 188 189 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 190 191 conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER); 192 193 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 194 case SND_SOC_DAIFMT_CBS_CFS: 195 conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER; 196 format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK; 197 break; 198 case SND_SOC_DAIFMT_CBM_CFS: 199 conf |= JZ_AIC_CONF_SYNC_CLK_MASTER; 200 break; 201 case SND_SOC_DAIFMT_CBS_CFM: 202 conf |= JZ_AIC_CONF_BIT_CLK_MASTER; 203 break; 204 case SND_SOC_DAIFMT_CBM_CFM: 205 break; 206 default: 207 return -EINVAL; 208 } 209 210 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 211 case SND_SOC_DAIFMT_MSB: 212 format |= JZ_AIC_I2S_FMT_MSB; 213 break; 214 case SND_SOC_DAIFMT_I2S: 215 break; 216 default: 217 return -EINVAL; 218 } 219 220 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 221 case SND_SOC_DAIFMT_NB_NF: 222 break; 223 default: 224 return -EINVAL; 225 } 226 227 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 228 jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format); 229 230 return 0; 231 } 232 233 static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, 234 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 235 { 236 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 237 enum jz4740_dma_width dma_width; 238 struct jz4740_pcm_config *pcm_config; 239 unsigned int sample_size; 240 uint32_t ctrl; 241 242 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 243 244 switch (params_format(params)) { 245 case SNDRV_PCM_FORMAT_S8: 246 sample_size = 0; 247 dma_width = JZ4740_DMA_WIDTH_8BIT; 248 break; 249 case SNDRV_PCM_FORMAT_S16: 250 sample_size = 1; 251 dma_width = JZ4740_DMA_WIDTH_16BIT; 252 break; 253 default: 254 return -EINVAL; 255 } 256 257 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 258 ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK; 259 ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET; 260 if (params_channels(params) == 1) 261 ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; 262 else 263 ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; 264 265 pcm_config = &i2s->pcm_config_playback; 266 pcm_config->dma_config.dst_width = dma_width; 267 268 } else { 269 ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; 270 ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; 271 272 pcm_config = &i2s->pcm_config_capture; 273 pcm_config->dma_config.src_width = dma_width; 274 } 275 276 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 277 278 snd_soc_dai_set_dma_data(dai, substream, pcm_config); 279 280 return 0; 281 } 282 283 static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, 284 unsigned int freq, int dir) 285 { 286 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 287 struct clk *parent; 288 int ret = 0; 289 290 switch (clk_id) { 291 case JZ4740_I2S_CLKSRC_EXT: 292 parent = clk_get(NULL, "ext"); 293 clk_set_parent(i2s->clk_i2s, parent); 294 break; 295 case JZ4740_I2S_CLKSRC_PLL: 296 parent = clk_get(NULL, "pll half"); 297 clk_set_parent(i2s->clk_i2s, parent); 298 ret = clk_set_rate(i2s->clk_i2s, freq); 299 break; 300 default: 301 return -EINVAL; 302 } 303 clk_put(parent); 304 305 return ret; 306 } 307 308 static int jz4740_i2s_suspend(struct snd_soc_dai *dai) 309 { 310 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 311 uint32_t conf; 312 313 if (dai->active) { 314 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 315 conf &= ~JZ_AIC_CONF_ENABLE; 316 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 317 318 clk_disable(i2s->clk_i2s); 319 } 320 321 clk_disable(i2s->clk_aic); 322 323 return 0; 324 } 325 326 static int jz4740_i2s_resume(struct snd_soc_dai *dai) 327 { 328 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 329 uint32_t conf; 330 331 clk_enable(i2s->clk_aic); 332 333 if (dai->active) { 334 clk_enable(i2s->clk_i2s); 335 336 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 337 conf |= JZ_AIC_CONF_ENABLE; 338 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 339 } 340 341 return 0; 342 } 343 344 static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) 345 { 346 struct jz4740_dma_config *dma_config; 347 348 /* Playback */ 349 dma_config = &i2s->pcm_config_playback.dma_config; 350 dma_config->src_width = JZ4740_DMA_WIDTH_32BIT, 351 dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; 352 dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT; 353 dma_config->flags = JZ4740_DMA_SRC_AUTOINC; 354 dma_config->mode = JZ4740_DMA_MODE_SINGLE; 355 i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; 356 357 /* Capture */ 358 dma_config = &i2s->pcm_config_capture.dma_config; 359 dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT, 360 dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; 361 dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE; 362 dma_config->flags = JZ4740_DMA_DST_AUTOINC; 363 dma_config->mode = JZ4740_DMA_MODE_SINGLE; 364 i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; 365 } 366 367 static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) 368 { 369 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 370 uint32_t conf; 371 372 clk_enable(i2s->clk_aic); 373 374 jz4740_i2c_init_pcm_config(i2s); 375 376 conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | 377 (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | 378 JZ_AIC_CONF_OVERFLOW_PLAY_LAST | 379 JZ_AIC_CONF_I2S | 380 JZ_AIC_CONF_INTERNAL_CODEC; 381 382 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET); 383 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 384 385 return 0; 386 } 387 388 static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai) 389 { 390 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 391 392 clk_disable(i2s->clk_aic); 393 return 0; 394 } 395 396 static struct snd_soc_dai_ops jz4740_i2s_dai_ops = { 397 .startup = jz4740_i2s_startup, 398 .shutdown = jz4740_i2s_shutdown, 399 .trigger = jz4740_i2s_trigger, 400 .hw_params = jz4740_i2s_hw_params, 401 .set_fmt = jz4740_i2s_set_fmt, 402 .set_sysclk = jz4740_i2s_set_sysclk, 403 }; 404 405 #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ 406 SNDRV_PCM_FMTBIT_S16_LE) 407 408 static struct snd_soc_dai_driver jz4740_i2s_dai = { 409 .probe = jz4740_i2s_dai_probe, 410 .remove = jz4740_i2s_dai_remove, 411 .playback = { 412 .channels_min = 1, 413 .channels_max = 2, 414 .rates = SNDRV_PCM_RATE_8000_48000, 415 .formats = JZ4740_I2S_FMTS, 416 }, 417 .capture = { 418 .channels_min = 2, 419 .channels_max = 2, 420 .rates = SNDRV_PCM_RATE_8000_48000, 421 .formats = JZ4740_I2S_FMTS, 422 }, 423 .symmetric_rates = 1, 424 .ops = &jz4740_i2s_dai_ops, 425 .suspend = jz4740_i2s_suspend, 426 .resume = jz4740_i2s_resume, 427 }; 428 429 static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev) 430 { 431 struct jz4740_i2s *i2s; 432 int ret; 433 434 i2s = kzalloc(sizeof(*i2s), GFP_KERNEL); 435 436 if (!i2s) 437 return -ENOMEM; 438 439 i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 440 if (!i2s->mem) { 441 ret = -ENOENT; 442 goto err_free; 443 } 444 445 i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem), 446 pdev->name); 447 if (!i2s->mem) { 448 ret = -EBUSY; 449 goto err_free; 450 } 451 452 i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem)); 453 if (!i2s->base) { 454 ret = -EBUSY; 455 goto err_release_mem_region; 456 } 457 458 i2s->phys_base = i2s->mem->start; 459 460 i2s->clk_aic = clk_get(&pdev->dev, "aic"); 461 if (IS_ERR(i2s->clk_aic)) { 462 ret = PTR_ERR(i2s->clk_aic); 463 goto err_iounmap; 464 } 465 466 i2s->clk_i2s = clk_get(&pdev->dev, "i2s"); 467 if (IS_ERR(i2s->clk_i2s)) { 468 ret = PTR_ERR(i2s->clk_i2s); 469 goto err_clk_put_aic; 470 } 471 472 platform_set_drvdata(pdev, i2s); 473 ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai); 474 475 if (ret) { 476 dev_err(&pdev->dev, "Failed to register DAI\n"); 477 goto err_clk_put_i2s; 478 } 479 480 return 0; 481 482 err_clk_put_i2s: 483 clk_put(i2s->clk_i2s); 484 err_clk_put_aic: 485 clk_put(i2s->clk_aic); 486 err_iounmap: 487 iounmap(i2s->base); 488 err_release_mem_region: 489 release_mem_region(i2s->mem->start, resource_size(i2s->mem)); 490 err_free: 491 kfree(i2s); 492 493 return ret; 494 } 495 496 static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev) 497 { 498 struct jz4740_i2s *i2s = platform_get_drvdata(pdev); 499 500 snd_soc_unregister_dai(&pdev->dev); 501 502 clk_put(i2s->clk_i2s); 503 clk_put(i2s->clk_aic); 504 505 iounmap(i2s->base); 506 release_mem_region(i2s->mem->start, resource_size(i2s->mem)); 507 508 platform_set_drvdata(pdev, NULL); 509 kfree(i2s); 510 511 return 0; 512 } 513 514 static struct platform_driver jz4740_i2s_driver = { 515 .probe = jz4740_i2s_dev_probe, 516 .remove = __devexit_p(jz4740_i2s_dev_remove), 517 .driver = { 518 .name = "jz4740-i2s", 519 .owner = THIS_MODULE, 520 }, 521 }; 522 523 static int __init jz4740_i2s_init(void) 524 { 525 return platform_driver_register(&jz4740_i2s_driver); 526 } 527 module_init(jz4740_i2s_init); 528 529 static void __exit jz4740_i2s_exit(void) 530 { 531 platform_driver_unregister(&jz4740_i2s_driver); 532 } 533 module_exit(jz4740_i2s_exit); 534 535 MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>"); 536 MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver"); 537 MODULE_LICENSE("GPL"); 538 MODULE_ALIAS("platform:jz4740-i2s"); 539