1 /* 2 * IMG I2S input controller driver 3 * 4 * Copyright (C) 2015 Imagination Technologies Ltd. 5 * 6 * Author: Damien Horsley <Damien.Horsley@imgtec.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms and conditions of the GNU General Public License, 10 * version 2, as published by the Free Software Foundation. 11 */ 12 13 #include <linux/clk.h> 14 #include <linux/init.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/reset.h> 20 21 #include <sound/core.h> 22 #include <sound/dmaengine_pcm.h> 23 #include <sound/initval.h> 24 #include <sound/pcm.h> 25 #include <sound/pcm_params.h> 26 #include <sound/soc.h> 27 28 #define IMG_I2S_IN_RX_FIFO 0x0 29 30 #define IMG_I2S_IN_CTL 0x4 31 #define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK 0xfffffffc 32 #define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT 2 33 #define IMG_I2S_IN_CTL_16PACK_MASK BIT(1) 34 #define IMG_I2S_IN_CTL_ME_MASK BIT(0) 35 36 #define IMG_I2S_IN_CH_CTL 0x4 37 #define IMG_I2S_IN_CH_CTL_CCDEL_MASK 0x38000 38 #define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT 15 39 #define IMG_I2S_IN_CH_CTL_FEN_MASK BIT(14) 40 #define IMG_I2S_IN_CH_CTL_FMODE_MASK BIT(13) 41 #define IMG_I2S_IN_CH_CTL_16PACK_MASK BIT(12) 42 #define IMG_I2S_IN_CH_CTL_JUST_MASK BIT(10) 43 #define IMG_I2S_IN_CH_CTL_PACKH_MASK BIT(9) 44 #define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK BIT(8) 45 #define IMG_I2S_IN_CH_CTL_BLKP_MASK BIT(7) 46 #define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK BIT(6) 47 #define IMG_I2S_IN_CH_CTL_LRD_MASK BIT(3) 48 #define IMG_I2S_IN_CH_CTL_FW_MASK BIT(2) 49 #define IMG_I2S_IN_CH_CTL_SW_MASK BIT(1) 50 #define IMG_I2S_IN_CH_CTL_ME_MASK BIT(0) 51 52 #define IMG_I2S_IN_CH_STRIDE 0x20 53 54 struct img_i2s_in { 55 void __iomem *base; 56 struct clk *clk_sys; 57 struct snd_dmaengine_dai_dma_data dma_data; 58 struct device *dev; 59 unsigned int max_i2s_chan; 60 void __iomem *channel_base; 61 unsigned int active_channels; 62 struct snd_soc_dai_driver dai_driver; 63 }; 64 65 static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg) 66 { 67 writel(val, i2s->base + reg); 68 } 69 70 static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg) 71 { 72 return readl(i2s->base + reg); 73 } 74 75 static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan, 76 u32 val, u32 reg) 77 { 78 writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg); 79 } 80 81 static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan, 82 u32 reg) 83 { 84 return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg); 85 } 86 87 static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan) 88 { 89 u32 reg; 90 91 reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL); 92 reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK; 93 img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL); 94 } 95 96 static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan) 97 { 98 u32 reg; 99 100 reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL); 101 reg |= IMG_I2S_IN_CH_CTL_ME_MASK; 102 img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL); 103 } 104 105 static inline void img_i2s_in_disable(struct img_i2s_in *i2s) 106 { 107 u32 reg; 108 109 reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); 110 reg &= ~IMG_I2S_IN_CTL_ME_MASK; 111 img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); 112 } 113 114 static inline void img_i2s_in_enable(struct img_i2s_in *i2s) 115 { 116 u32 reg; 117 118 reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); 119 reg |= IMG_I2S_IN_CTL_ME_MASK; 120 img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); 121 } 122 123 static inline void img_i2s_in_flush(struct img_i2s_in *i2s) 124 { 125 int i; 126 u32 reg; 127 128 for (i = 0; i < i2s->active_channels; i++) { 129 reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); 130 reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK; 131 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); 132 reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK; 133 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); 134 } 135 } 136 137 static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd, 138 struct snd_soc_dai *dai) 139 { 140 struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); 141 142 switch (cmd) { 143 case SNDRV_PCM_TRIGGER_START: 144 case SNDRV_PCM_TRIGGER_RESUME: 145 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 146 img_i2s_in_enable(i2s); 147 break; 148 149 case SNDRV_PCM_TRIGGER_STOP: 150 case SNDRV_PCM_TRIGGER_SUSPEND: 151 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 152 img_i2s_in_disable(i2s); 153 break; 154 default: 155 return -EINVAL; 156 } 157 158 return 0; 159 } 160 161 static int img_i2s_in_check_rate(struct img_i2s_in *i2s, 162 unsigned int sample_rate, unsigned int frame_size, 163 unsigned int *bclk_filter_enable, 164 unsigned int *bclk_filter_value) 165 { 166 unsigned int bclk_freq, cur_freq; 167 168 bclk_freq = sample_rate * frame_size; 169 170 cur_freq = clk_get_rate(i2s->clk_sys); 171 172 if (cur_freq >= bclk_freq * 8) { 173 *bclk_filter_enable = 1; 174 *bclk_filter_value = 0; 175 } else if (cur_freq >= bclk_freq * 7) { 176 *bclk_filter_enable = 1; 177 *bclk_filter_value = 1; 178 } else if (cur_freq >= bclk_freq * 6) { 179 *bclk_filter_enable = 0; 180 *bclk_filter_value = 0; 181 } else { 182 dev_err(i2s->dev, 183 "Sys clock rate %u insufficient for sample rate %u\n", 184 cur_freq, sample_rate); 185 return -EINVAL; 186 } 187 188 return 0; 189 } 190 191 static int img_i2s_in_hw_params(struct snd_pcm_substream *substream, 192 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 193 { 194 struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); 195 unsigned int rate, channels, i2s_channels, frame_size; 196 unsigned int bclk_filter_enable, bclk_filter_value; 197 int i, ret = 0; 198 u32 reg, control_mask, chan_control_mask; 199 u32 control_set = 0, chan_control_set = 0; 200 snd_pcm_format_t format; 201 202 rate = params_rate(params); 203 format = params_format(params); 204 channels = params_channels(params); 205 i2s_channels = channels / 2; 206 207 switch (format) { 208 case SNDRV_PCM_FORMAT_S32_LE: 209 frame_size = 64; 210 chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK; 211 chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK; 212 chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK; 213 break; 214 case SNDRV_PCM_FORMAT_S24_LE: 215 frame_size = 64; 216 chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK; 217 chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK; 218 break; 219 case SNDRV_PCM_FORMAT_S16_LE: 220 frame_size = 32; 221 control_set |= IMG_I2S_IN_CTL_16PACK_MASK; 222 chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK; 223 break; 224 default: 225 return -EINVAL; 226 } 227 228 if ((channels < 2) || 229 (channels > (i2s->max_i2s_chan * 2)) || 230 (channels % 2)) 231 return -EINVAL; 232 233 control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT); 234 235 ret = img_i2s_in_check_rate(i2s, rate, frame_size, 236 &bclk_filter_enable, &bclk_filter_value); 237 if (ret < 0) 238 return ret; 239 240 if (bclk_filter_enable) 241 chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK; 242 243 if (bclk_filter_value) 244 chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK; 245 246 control_mask = IMG_I2S_IN_CTL_16PACK_MASK | 247 IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK; 248 249 chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK | 250 IMG_I2S_IN_CH_CTL_FEN_MASK | 251 IMG_I2S_IN_CH_CTL_FMODE_MASK | 252 IMG_I2S_IN_CH_CTL_SW_MASK | 253 IMG_I2S_IN_CH_CTL_FW_MASK | 254 IMG_I2S_IN_CH_CTL_PACKH_MASK; 255 256 reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); 257 reg = (reg & ~control_mask) | control_set; 258 img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); 259 260 for (i = 0; i < i2s->active_channels; i++) 261 img_i2s_in_ch_disable(i2s, i); 262 263 for (i = 0; i < i2s->max_i2s_chan; i++) { 264 reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); 265 reg = (reg & ~chan_control_mask) | chan_control_set; 266 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); 267 } 268 269 i2s->active_channels = i2s_channels; 270 271 img_i2s_in_flush(i2s); 272 273 for (i = 0; i < i2s->active_channels; i++) 274 img_i2s_in_ch_enable(i2s, i); 275 276 return 0; 277 } 278 279 static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 280 { 281 struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); 282 int i; 283 u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0; 284 u32 reg; 285 286 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 287 case SND_SOC_DAIFMT_NB_NF: 288 lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK; 289 break; 290 case SND_SOC_DAIFMT_NB_IF: 291 break; 292 case SND_SOC_DAIFMT_IB_NF: 293 lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK; 294 blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK; 295 break; 296 case SND_SOC_DAIFMT_IB_IF: 297 blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK; 298 break; 299 default: 300 return -EINVAL; 301 } 302 303 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 304 case SND_SOC_DAIFMT_I2S: 305 chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; 306 break; 307 case SND_SOC_DAIFMT_LEFT_J: 308 break; 309 default: 310 return -EINVAL; 311 } 312 313 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 314 case SND_SOC_DAIFMT_CBM_CFM: 315 break; 316 default: 317 return -EINVAL; 318 } 319 320 chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; 321 322 for (i = 0; i < i2s->active_channels; i++) 323 img_i2s_in_ch_disable(i2s, i); 324 325 /* 326 * BLKP and LRD must be set during separate register writes 327 */ 328 for (i = 0; i < i2s->max_i2s_chan; i++) { 329 reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); 330 reg = (reg & ~chan_control_mask) | chan_control_set; 331 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); 332 reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set; 333 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); 334 reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set; 335 img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); 336 } 337 338 for (i = 0; i < i2s->active_channels; i++) 339 img_i2s_in_ch_enable(i2s, i); 340 341 return 0; 342 } 343 344 static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { 345 .trigger = img_i2s_in_trigger, 346 .hw_params = img_i2s_in_hw_params, 347 .set_fmt = img_i2s_in_set_fmt 348 }; 349 350 static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) 351 { 352 struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); 353 354 snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data); 355 356 return 0; 357 } 358 359 static const struct snd_soc_component_driver img_i2s_in_component = { 360 .name = "img-i2s-in" 361 }; 362 363 static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st, 364 struct snd_pcm_hw_params *params, struct dma_slave_config *sc) 365 { 366 unsigned int i2s_channels = params_channels(params) / 2; 367 struct snd_soc_pcm_runtime *rtd = st->private_data; 368 struct snd_dmaengine_dai_dma_data *dma_data; 369 int ret; 370 371 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); 372 373 ret = snd_hwparams_to_dma_slave_config(st, params, sc); 374 if (ret) 375 return ret; 376 377 sc->src_addr = dma_data->addr; 378 sc->src_addr_width = dma_data->addr_width; 379 sc->src_maxburst = 4 * i2s_channels; 380 381 return 0; 382 } 383 384 static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = { 385 .prepare_slave_config = img_i2s_in_dma_prepare_slave_config 386 }; 387 388 static int img_i2s_in_probe(struct platform_device *pdev) 389 { 390 struct img_i2s_in *i2s; 391 struct resource *res; 392 void __iomem *base; 393 int ret, i; 394 struct reset_control *rst; 395 unsigned int max_i2s_chan_pow_2; 396 struct device *dev = &pdev->dev; 397 398 i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); 399 if (!i2s) 400 return -ENOMEM; 401 402 platform_set_drvdata(pdev, i2s); 403 404 i2s->dev = dev; 405 406 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 407 base = devm_ioremap_resource(dev, res); 408 if (IS_ERR(base)) 409 return PTR_ERR(base); 410 411 i2s->base = base; 412 413 if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", 414 &i2s->max_i2s_chan)) { 415 dev_err(dev, "No img,i2s-channels property\n"); 416 return -EINVAL; 417 } 418 419 max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); 420 421 i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); 422 423 i2s->clk_sys = devm_clk_get(dev, "sys"); 424 if (IS_ERR(i2s->clk_sys)) { 425 if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) 426 dev_err(dev, "Failed to acquire clock 'sys'\n"); 427 return PTR_ERR(i2s->clk_sys); 428 } 429 430 ret = clk_prepare_enable(i2s->clk_sys); 431 if (ret) 432 return ret; 433 434 i2s->active_channels = 1; 435 i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; 436 i2s->dma_data.addr_width = 4; 437 438 i2s->dai_driver.probe = img_i2s_in_dai_probe; 439 i2s->dai_driver.capture.channels_min = 2; 440 i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; 441 i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; 442 i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE | 443 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE; 444 i2s->dai_driver.ops = &img_i2s_in_dai_ops; 445 446 rst = devm_reset_control_get(dev, "rst"); 447 if (IS_ERR(rst)) { 448 if (PTR_ERR(rst) == -EPROBE_DEFER) { 449 ret = -EPROBE_DEFER; 450 goto err_clk_disable; 451 } 452 453 dev_dbg(dev, "No top level reset found\n"); 454 455 img_i2s_in_disable(i2s); 456 457 for (i = 0; i < i2s->max_i2s_chan; i++) 458 img_i2s_in_ch_disable(i2s, i); 459 } else { 460 reset_control_assert(rst); 461 reset_control_deassert(rst); 462 } 463 464 img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL); 465 466 for (i = 0; i < i2s->max_i2s_chan; i++) 467 img_i2s_in_ch_writel(i2s, i, 468 (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) | 469 IMG_I2S_IN_CH_CTL_JUST_MASK | 470 IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL); 471 472 ret = devm_snd_soc_register_component(dev, &img_i2s_in_component, 473 &i2s->dai_driver, 1); 474 if (ret) 475 goto err_clk_disable; 476 477 ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0); 478 if (ret) 479 goto err_clk_disable; 480 481 return 0; 482 483 err_clk_disable: 484 clk_disable_unprepare(i2s->clk_sys); 485 486 return ret; 487 } 488 489 static int img_i2s_in_dev_remove(struct platform_device *pdev) 490 { 491 struct img_i2s_in *i2s = platform_get_drvdata(pdev); 492 493 clk_disable_unprepare(i2s->clk_sys); 494 495 return 0; 496 } 497 498 static const struct of_device_id img_i2s_in_of_match[] = { 499 { .compatible = "img,i2s-in" }, 500 {} 501 }; 502 MODULE_DEVICE_TABLE(of, img_i2s_in_of_match); 503 504 static struct platform_driver img_i2s_in_driver = { 505 .driver = { 506 .name = "img-i2s-in", 507 .of_match_table = img_i2s_in_of_match 508 }, 509 .probe = img_i2s_in_probe, 510 .remove = img_i2s_in_dev_remove 511 }; 512 module_platform_driver(img_i2s_in_driver); 513 514 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 515 MODULE_DESCRIPTION("IMG I2S Input Driver"); 516 MODULE_LICENSE("GPL v2"); 517