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/initval.h> 32 #include <sound/dmaengine_pcm.h> 33 34 #include "jz4740-i2s.h" 35 36 #define JZ4740_DMA_TYPE_AIC_TRANSMIT 24 37 #define JZ4740_DMA_TYPE_AIC_RECEIVE 25 38 39 #define JZ_REG_AIC_CONF 0x00 40 #define JZ_REG_AIC_CTRL 0x04 41 #define JZ_REG_AIC_I2S_FMT 0x10 42 #define JZ_REG_AIC_FIFO_STATUS 0x14 43 #define JZ_REG_AIC_I2S_STATUS 0x1c 44 #define JZ_REG_AIC_CLK_DIV 0x30 45 #define JZ_REG_AIC_FIFO 0x34 46 47 #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12) 48 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8) 49 #define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6) 50 #define JZ_AIC_CONF_INTERNAL_CODEC BIT(5) 51 #define JZ_AIC_CONF_I2S BIT(4) 52 #define JZ_AIC_CONF_RESET BIT(3) 53 #define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2) 54 #define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1) 55 #define JZ_AIC_CONF_ENABLE BIT(0) 56 57 #define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12 58 #define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8 59 60 #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19) 61 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16) 62 #define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15) 63 #define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14) 64 #define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11) 65 #define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10) 66 #define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9) 67 #define JZ_AIC_CTRL_FLUSH BIT(8) 68 #define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6) 69 #define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5) 70 #define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4) 71 #define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3) 72 #define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2) 73 #define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1) 74 #define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0) 75 76 #define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19 77 #define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16 78 79 #define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12) 80 #define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4) 81 #define JZ_AIC_I2S_FMT_MSB BIT(0) 82 83 #define JZ_AIC_I2S_STATUS_BUSY BIT(2) 84 85 #define JZ_AIC_CLK_DIV_MASK 0xf 86 87 struct jz4740_i2s { 88 struct resource *mem; 89 void __iomem *base; 90 dma_addr_t phys_base; 91 92 struct clk *clk_aic; 93 struct clk *clk_i2s; 94 95 struct snd_dmaengine_dai_dma_data playback_dma_data; 96 struct snd_dmaengine_dai_dma_data capture_dma_data; 97 }; 98 99 static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, 100 unsigned int reg) 101 { 102 return readl(i2s->base + reg); 103 } 104 105 static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s, 106 unsigned int reg, uint32_t value) 107 { 108 writel(value, i2s->base + reg); 109 } 110 111 static int jz4740_i2s_startup(struct snd_pcm_substream *substream, 112 struct snd_soc_dai *dai) 113 { 114 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 115 uint32_t conf, ctrl; 116 117 if (dai->active) 118 return 0; 119 120 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 121 ctrl |= JZ_AIC_CTRL_FLUSH; 122 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 123 124 clk_prepare_enable(i2s->clk_i2s); 125 126 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 127 conf |= JZ_AIC_CONF_ENABLE; 128 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 129 130 return 0; 131 } 132 133 static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, 134 struct snd_soc_dai *dai) 135 { 136 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 137 uint32_t conf; 138 139 if (dai->active) 140 return; 141 142 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 143 conf &= ~JZ_AIC_CONF_ENABLE; 144 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 145 146 clk_disable_unprepare(i2s->clk_i2s); 147 } 148 149 static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 150 struct snd_soc_dai *dai) 151 { 152 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 153 154 uint32_t ctrl; 155 uint32_t mask; 156 157 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 158 mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA; 159 else 160 mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA; 161 162 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL); 163 164 switch (cmd) { 165 case SNDRV_PCM_TRIGGER_START: 166 case SNDRV_PCM_TRIGGER_RESUME: 167 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 168 ctrl |= mask; 169 break; 170 case SNDRV_PCM_TRIGGER_STOP: 171 case SNDRV_PCM_TRIGGER_SUSPEND: 172 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 173 ctrl &= ~mask; 174 break; 175 default: 176 return -EINVAL; 177 } 178 179 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 180 181 return 0; 182 } 183 184 static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 185 { 186 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 187 188 uint32_t format = 0; 189 uint32_t conf; 190 191 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 192 193 conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER); 194 195 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 196 case SND_SOC_DAIFMT_CBS_CFS: 197 conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER; 198 format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK; 199 break; 200 case SND_SOC_DAIFMT_CBM_CFS: 201 conf |= JZ_AIC_CONF_SYNC_CLK_MASTER; 202 break; 203 case SND_SOC_DAIFMT_CBS_CFM: 204 conf |= JZ_AIC_CONF_BIT_CLK_MASTER; 205 break; 206 case SND_SOC_DAIFMT_CBM_CFM: 207 break; 208 default: 209 return -EINVAL; 210 } 211 212 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 213 case SND_SOC_DAIFMT_MSB: 214 format |= JZ_AIC_I2S_FMT_MSB; 215 break; 216 case SND_SOC_DAIFMT_I2S: 217 break; 218 default: 219 return -EINVAL; 220 } 221 222 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 223 case SND_SOC_DAIFMT_NB_NF: 224 break; 225 default: 226 return -EINVAL; 227 } 228 229 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 230 jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format); 231 232 return 0; 233 } 234 235 static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, 236 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 237 { 238 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 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 break; 248 case SNDRV_PCM_FORMAT_S16: 249 sample_size = 1; 250 break; 251 default: 252 return -EINVAL; 253 } 254 255 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 256 ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK; 257 ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET; 258 if (params_channels(params) == 1) 259 ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; 260 else 261 ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; 262 } else { 263 ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; 264 ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; 265 } 266 267 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); 268 269 return 0; 270 } 271 272 static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, 273 unsigned int freq, int dir) 274 { 275 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 276 struct clk *parent; 277 int ret = 0; 278 279 switch (clk_id) { 280 case JZ4740_I2S_CLKSRC_EXT: 281 parent = clk_get(NULL, "ext"); 282 clk_set_parent(i2s->clk_i2s, parent); 283 break; 284 case JZ4740_I2S_CLKSRC_PLL: 285 parent = clk_get(NULL, "pll half"); 286 clk_set_parent(i2s->clk_i2s, parent); 287 ret = clk_set_rate(i2s->clk_i2s, freq); 288 break; 289 default: 290 return -EINVAL; 291 } 292 clk_put(parent); 293 294 return ret; 295 } 296 297 static int jz4740_i2s_suspend(struct snd_soc_dai *dai) 298 { 299 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 300 uint32_t conf; 301 302 if (dai->active) { 303 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 304 conf &= ~JZ_AIC_CONF_ENABLE; 305 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 306 307 clk_disable_unprepare(i2s->clk_i2s); 308 } 309 310 clk_disable_unprepare(i2s->clk_aic); 311 312 return 0; 313 } 314 315 static int jz4740_i2s_resume(struct snd_soc_dai *dai) 316 { 317 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 318 uint32_t conf; 319 320 clk_prepare_enable(i2s->clk_aic); 321 322 if (dai->active) { 323 clk_prepare_enable(i2s->clk_i2s); 324 325 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF); 326 conf |= JZ_AIC_CONF_ENABLE; 327 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 328 } 329 330 return 0; 331 } 332 333 static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) 334 { 335 struct snd_dmaengine_dai_dma_data *dma_data; 336 337 /* Playback */ 338 dma_data = &i2s->playback_dma_data; 339 dma_data->maxburst = 16; 340 dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT; 341 dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; 342 343 /* Capture */ 344 dma_data = &i2s->capture_dma_data; 345 dma_data->maxburst = 16; 346 dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE; 347 dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; 348 } 349 350 static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) 351 { 352 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 353 uint32_t conf; 354 355 clk_prepare_enable(i2s->clk_aic); 356 357 jz4740_i2c_init_pcm_config(i2s); 358 snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, 359 &i2s->capture_dma_data); 360 361 conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | 362 (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | 363 JZ_AIC_CONF_OVERFLOW_PLAY_LAST | 364 JZ_AIC_CONF_I2S | 365 JZ_AIC_CONF_INTERNAL_CODEC; 366 367 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET); 368 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf); 369 370 return 0; 371 } 372 373 static int jz4740_i2s_dai_remove(struct snd_soc_dai *dai) 374 { 375 struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); 376 377 clk_disable_unprepare(i2s->clk_aic); 378 return 0; 379 } 380 381 static const struct snd_soc_dai_ops jz4740_i2s_dai_ops = { 382 .startup = jz4740_i2s_startup, 383 .shutdown = jz4740_i2s_shutdown, 384 .trigger = jz4740_i2s_trigger, 385 .hw_params = jz4740_i2s_hw_params, 386 .set_fmt = jz4740_i2s_set_fmt, 387 .set_sysclk = jz4740_i2s_set_sysclk, 388 }; 389 390 #define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \ 391 SNDRV_PCM_FMTBIT_S16_LE) 392 393 static struct snd_soc_dai_driver jz4740_i2s_dai = { 394 .probe = jz4740_i2s_dai_probe, 395 .remove = jz4740_i2s_dai_remove, 396 .playback = { 397 .channels_min = 1, 398 .channels_max = 2, 399 .rates = SNDRV_PCM_RATE_8000_48000, 400 .formats = JZ4740_I2S_FMTS, 401 }, 402 .capture = { 403 .channels_min = 2, 404 .channels_max = 2, 405 .rates = SNDRV_PCM_RATE_8000_48000, 406 .formats = JZ4740_I2S_FMTS, 407 }, 408 .symmetric_rates = 1, 409 .ops = &jz4740_i2s_dai_ops, 410 .suspend = jz4740_i2s_suspend, 411 .resume = jz4740_i2s_resume, 412 }; 413 414 static const struct snd_soc_component_driver jz4740_i2s_component = { 415 .name = "jz4740-i2s", 416 }; 417 418 static int jz4740_i2s_dev_probe(struct platform_device *pdev) 419 { 420 struct jz4740_i2s *i2s; 421 struct resource *mem; 422 int ret; 423 424 i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 425 if (!i2s) 426 return -ENOMEM; 427 428 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 429 i2s->base = devm_ioremap_resource(&pdev->dev, mem); 430 if (IS_ERR(i2s->base)) 431 return PTR_ERR(i2s->base); 432 433 i2s->phys_base = mem->start; 434 435 i2s->clk_aic = devm_clk_get(&pdev->dev, "aic"); 436 if (IS_ERR(i2s->clk_aic)) 437 return PTR_ERR(i2s->clk_aic); 438 439 i2s->clk_i2s = devm_clk_get(&pdev->dev, "i2s"); 440 if (IS_ERR(i2s->clk_i2s)) 441 return PTR_ERR(i2s->clk_i2s); 442 443 platform_set_drvdata(pdev, i2s); 444 445 ret = devm_snd_soc_register_component(&pdev->dev, 446 &jz4740_i2s_component, &jz4740_i2s_dai, 1); 447 if (ret) 448 return ret; 449 450 return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 451 SND_DMAENGINE_PCM_FLAG_COMPAT); 452 } 453 454 static struct platform_driver jz4740_i2s_driver = { 455 .probe = jz4740_i2s_dev_probe, 456 .driver = { 457 .name = "jz4740-i2s", 458 }, 459 }; 460 461 module_platform_driver(jz4740_i2s_driver); 462 463 MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>"); 464 MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver"); 465 MODULE_LICENSE("GPL"); 466 MODULE_ALIAS("platform:jz4740-i2s"); 467