1 /* 2 * IMG I2S output 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/pm_runtime.h> 20 #include <linux/reset.h> 21 22 #include <sound/core.h> 23 #include <sound/dmaengine_pcm.h> 24 #include <sound/initval.h> 25 #include <sound/pcm.h> 26 #include <sound/pcm_params.h> 27 #include <sound/soc.h> 28 29 #define IMG_I2S_OUT_TX_FIFO 0x0 30 31 #define IMG_I2S_OUT_CTL 0x4 32 #define IMG_I2S_OUT_CTL_DATA_EN_MASK BIT(24) 33 #define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK 0xffe000 34 #define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT 13 35 #define IMG_I2S_OUT_CTL_FRM_SIZE_MASK BIT(8) 36 #define IMG_I2S_OUT_CTL_MASTER_MASK BIT(6) 37 #define IMG_I2S_OUT_CTL_CLK_MASK BIT(5) 38 #define IMG_I2S_OUT_CTL_CLK_EN_MASK BIT(4) 39 #define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK BIT(3) 40 #define IMG_I2S_OUT_CTL_BCLK_POL_MASK BIT(2) 41 #define IMG_I2S_OUT_CTL_ME_MASK BIT(0) 42 43 #define IMG_I2S_OUT_CH_CTL 0x4 44 #define IMG_I2S_OUT_CHAN_CTL_CH_MASK BIT(11) 45 #define IMG_I2S_OUT_CHAN_CTL_LT_MASK BIT(10) 46 #define IMG_I2S_OUT_CHAN_CTL_FMT_MASK 0xf0 47 #define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT 4 48 #define IMG_I2S_OUT_CHAN_CTL_JUST_MASK BIT(3) 49 #define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK BIT(1) 50 #define IMG_I2S_OUT_CHAN_CTL_ME_MASK BIT(0) 51 52 #define IMG_I2S_OUT_CH_STRIDE 0x20 53 54 struct img_i2s_out { 55 void __iomem *base; 56 struct clk *clk_sys; 57 struct clk *clk_ref; 58 struct snd_dmaengine_dai_dma_data dma_data; 59 struct device *dev; 60 unsigned int max_i2s_chan; 61 void __iomem *channel_base; 62 bool force_clk_active; 63 unsigned int active_channels; 64 struct reset_control *rst; 65 struct snd_soc_dai_driver dai_driver; 66 }; 67 68 static int img_i2s_out_suspend(struct device *dev) 69 { 70 struct img_i2s_out *i2s = dev_get_drvdata(dev); 71 72 if (!i2s->force_clk_active) 73 clk_disable_unprepare(i2s->clk_ref); 74 75 return 0; 76 } 77 78 static int img_i2s_out_resume(struct device *dev) 79 { 80 struct img_i2s_out *i2s = dev_get_drvdata(dev); 81 int ret; 82 83 if (!i2s->force_clk_active) { 84 ret = clk_prepare_enable(i2s->clk_ref); 85 if (ret) { 86 dev_err(dev, "clk_enable failed: %d\n", ret); 87 return ret; 88 } 89 } 90 91 return 0; 92 } 93 94 static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val, 95 u32 reg) 96 { 97 writel(val, i2s->base + reg); 98 } 99 100 static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg) 101 { 102 return readl(i2s->base + reg); 103 } 104 105 static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s, 106 u32 chan, u32 val, u32 reg) 107 { 108 writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); 109 } 110 111 static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan, 112 u32 reg) 113 { 114 return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); 115 } 116 117 static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan) 118 { 119 u32 reg; 120 121 reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); 122 reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; 123 img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); 124 } 125 126 static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan) 127 { 128 u32 reg; 129 130 reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); 131 reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK; 132 img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); 133 } 134 135 static inline void img_i2s_out_disable(struct img_i2s_out *i2s) 136 { 137 u32 reg; 138 139 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 140 reg &= ~IMG_I2S_OUT_CTL_ME_MASK; 141 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 142 } 143 144 static inline void img_i2s_out_enable(struct img_i2s_out *i2s) 145 { 146 u32 reg; 147 148 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 149 reg |= IMG_I2S_OUT_CTL_ME_MASK; 150 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 151 } 152 153 static void img_i2s_out_reset(struct img_i2s_out *i2s) 154 { 155 int i; 156 u32 core_ctl, chan_ctl; 157 158 core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) & 159 ~IMG_I2S_OUT_CTL_ME_MASK & 160 ~IMG_I2S_OUT_CTL_DATA_EN_MASK; 161 162 if (!i2s->force_clk_active) 163 core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK; 164 165 chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) & 166 ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; 167 168 reset_control_assert(i2s->rst); 169 reset_control_deassert(i2s->rst); 170 171 for (i = 0; i < i2s->max_i2s_chan; i++) 172 img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL); 173 174 for (i = 0; i < i2s->active_channels; i++) 175 img_i2s_out_ch_enable(i2s, i); 176 177 img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL); 178 img_i2s_out_enable(i2s); 179 } 180 181 static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd, 182 struct snd_soc_dai *dai) 183 { 184 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 185 u32 reg; 186 187 switch (cmd) { 188 case SNDRV_PCM_TRIGGER_START: 189 case SNDRV_PCM_TRIGGER_RESUME: 190 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 191 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 192 if (!i2s->force_clk_active) 193 reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK; 194 reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK; 195 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 196 break; 197 case SNDRV_PCM_TRIGGER_STOP: 198 case SNDRV_PCM_TRIGGER_SUSPEND: 199 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 200 img_i2s_out_reset(i2s); 201 break; 202 default: 203 return -EINVAL; 204 } 205 206 return 0; 207 } 208 209 static int img_i2s_out_hw_params(struct snd_pcm_substream *substream, 210 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 211 { 212 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 213 unsigned int channels, i2s_channels; 214 long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate; 215 int i; 216 u32 reg, control_mask, control_set = 0; 217 snd_pcm_format_t format; 218 219 rate = params_rate(params); 220 format = params_format(params); 221 channels = params_channels(params); 222 i2s_channels = channels / 2; 223 224 if (format != SNDRV_PCM_FORMAT_S32_LE) 225 return -EINVAL; 226 227 if ((channels < 2) || 228 (channels > (i2s->max_i2s_chan * 2)) || 229 (channels % 2)) 230 return -EINVAL; 231 232 pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256); 233 if (pre_div_a < 0) 234 return pre_div_a; 235 pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384); 236 if (pre_div_b < 0) 237 return pre_div_b; 238 239 diff_a = abs((pre_div_a / 256) - rate); 240 diff_b = abs((pre_div_b / 384) - rate); 241 242 /* If diffs are equal, use lower clock rate */ 243 if (diff_a > diff_b) 244 clk_set_rate(i2s->clk_ref, pre_div_b); 245 else 246 clk_set_rate(i2s->clk_ref, pre_div_a); 247 248 /* 249 * Another driver (eg alsa machine driver) may have rejected the above 250 * change. Get the current rate and set the register bit according to 251 * the new minimum diff 252 */ 253 clk_rate = clk_get_rate(i2s->clk_ref); 254 255 diff_a = abs((clk_rate / 256) - rate); 256 diff_b = abs((clk_rate / 384) - rate); 257 258 if (diff_a > diff_b) 259 control_set |= IMG_I2S_OUT_CTL_CLK_MASK; 260 261 control_set |= ((i2s_channels - 1) << 262 IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) & 263 IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; 264 265 control_mask = IMG_I2S_OUT_CTL_CLK_MASK | 266 IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; 267 268 img_i2s_out_disable(i2s); 269 270 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 271 reg = (reg & ~control_mask) | control_set; 272 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 273 274 for (i = 0; i < i2s_channels; i++) 275 img_i2s_out_ch_enable(i2s, i); 276 277 for (; i < i2s->max_i2s_chan; i++) 278 img_i2s_out_ch_disable(i2s, i); 279 280 img_i2s_out_enable(i2s); 281 282 i2s->active_channels = i2s_channels; 283 284 return 0; 285 } 286 287 static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 288 { 289 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 290 int i; 291 bool force_clk_active; 292 u32 chan_control_mask, control_mask, chan_control_set = 0; 293 u32 reg, control_set = 0; 294 295 force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) == 296 SND_SOC_DAIFMT_CONT); 297 298 if (force_clk_active) 299 control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK; 300 301 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 302 case SND_SOC_DAIFMT_CBM_CFM: 303 break; 304 case SND_SOC_DAIFMT_CBS_CFS: 305 control_set |= IMG_I2S_OUT_CTL_MASTER_MASK; 306 break; 307 default: 308 return -EINVAL; 309 } 310 311 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 312 case SND_SOC_DAIFMT_NB_NF: 313 control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; 314 break; 315 case SND_SOC_DAIFMT_NB_IF: 316 control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; 317 control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; 318 break; 319 case SND_SOC_DAIFMT_IB_NF: 320 break; 321 case SND_SOC_DAIFMT_IB_IF: 322 control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; 323 break; 324 default: 325 return -EINVAL; 326 } 327 328 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 329 case SND_SOC_DAIFMT_I2S: 330 chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; 331 break; 332 case SND_SOC_DAIFMT_LEFT_J: 333 break; 334 default: 335 return -EINVAL; 336 } 337 338 control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK | 339 IMG_I2S_OUT_CTL_MASTER_MASK | 340 IMG_I2S_OUT_CTL_BCLK_POL_MASK | 341 IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; 342 343 chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; 344 345 img_i2s_out_disable(i2s); 346 347 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 348 reg = (reg & ~control_mask) | control_set; 349 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 350 351 for (i = 0; i < i2s->active_channels; i++) 352 img_i2s_out_ch_disable(i2s, i); 353 354 for (i = 0; i < i2s->max_i2s_chan; i++) { 355 reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); 356 reg = (reg & ~chan_control_mask) | chan_control_set; 357 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); 358 } 359 360 for (i = 0; i < i2s->active_channels; i++) 361 img_i2s_out_ch_enable(i2s, i); 362 363 img_i2s_out_enable(i2s); 364 365 i2s->force_clk_active = force_clk_active; 366 367 return 0; 368 } 369 370 static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { 371 .trigger = img_i2s_out_trigger, 372 .hw_params = img_i2s_out_hw_params, 373 .set_fmt = img_i2s_out_set_fmt 374 }; 375 376 static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) 377 { 378 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 379 380 snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL); 381 382 return 0; 383 } 384 385 static const struct snd_soc_component_driver img_i2s_out_component = { 386 .name = "img-i2s-out" 387 }; 388 389 static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st, 390 struct snd_pcm_hw_params *params, struct dma_slave_config *sc) 391 { 392 unsigned int i2s_channels = params_channels(params) / 2; 393 struct snd_soc_pcm_runtime *rtd = st->private_data; 394 struct snd_dmaengine_dai_dma_data *dma_data; 395 int ret; 396 397 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); 398 399 ret = snd_hwparams_to_dma_slave_config(st, params, sc); 400 if (ret) 401 return ret; 402 403 sc->dst_addr = dma_data->addr; 404 sc->dst_addr_width = dma_data->addr_width; 405 sc->dst_maxburst = 4 * i2s_channels; 406 407 return 0; 408 } 409 410 static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = { 411 .prepare_slave_config = img_i2s_out_dma_prepare_slave_config 412 }; 413 414 static int img_i2s_out_probe(struct platform_device *pdev) 415 { 416 struct img_i2s_out *i2s; 417 struct resource *res; 418 void __iomem *base; 419 int i, ret; 420 unsigned int max_i2s_chan_pow_2; 421 u32 reg; 422 struct device *dev = &pdev->dev; 423 424 i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 425 if (!i2s) 426 return -ENOMEM; 427 428 platform_set_drvdata(pdev, i2s); 429 430 i2s->dev = &pdev->dev; 431 432 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 433 base = devm_ioremap_resource(&pdev->dev, res); 434 if (IS_ERR(base)) 435 return PTR_ERR(base); 436 437 i2s->base = base; 438 439 if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", 440 &i2s->max_i2s_chan)) { 441 dev_err(&pdev->dev, "No img,i2s-channels property\n"); 442 return -EINVAL; 443 } 444 445 max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); 446 447 i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); 448 449 i2s->rst = devm_reset_control_get(&pdev->dev, "rst"); 450 if (IS_ERR(i2s->rst)) { 451 if (PTR_ERR(i2s->rst) != -EPROBE_DEFER) 452 dev_err(&pdev->dev, "No top level reset found\n"); 453 return PTR_ERR(i2s->rst); 454 } 455 456 i2s->clk_sys = devm_clk_get(&pdev->dev, "sys"); 457 if (IS_ERR(i2s->clk_sys)) { 458 if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) 459 dev_err(dev, "Failed to acquire clock 'sys'\n"); 460 return PTR_ERR(i2s->clk_sys); 461 } 462 463 i2s->clk_ref = devm_clk_get(&pdev->dev, "ref"); 464 if (IS_ERR(i2s->clk_ref)) { 465 if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER) 466 dev_err(dev, "Failed to acquire clock 'ref'\n"); 467 return PTR_ERR(i2s->clk_ref); 468 } 469 470 ret = clk_prepare_enable(i2s->clk_sys); 471 if (ret) 472 return ret; 473 474 reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK; 475 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 476 477 reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK | 478 IMG_I2S_OUT_CHAN_CTL_LT_MASK | 479 IMG_I2S_OUT_CHAN_CTL_CH_MASK | 480 (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT); 481 482 for (i = 0; i < i2s->max_i2s_chan; i++) 483 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); 484 485 img_i2s_out_reset(i2s); 486 487 pm_runtime_enable(&pdev->dev); 488 if (!pm_runtime_enabled(&pdev->dev)) { 489 ret = img_i2s_out_resume(&pdev->dev); 490 if (ret) 491 goto err_pm_disable; 492 } 493 494 i2s->active_channels = 1; 495 i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO; 496 i2s->dma_data.addr_width = 4; 497 i2s->dma_data.maxburst = 4; 498 499 i2s->dai_driver.probe = img_i2s_out_dai_probe; 500 i2s->dai_driver.playback.channels_min = 2; 501 i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; 502 i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; 503 i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE; 504 i2s->dai_driver.ops = &img_i2s_out_dai_ops; 505 506 ret = devm_snd_soc_register_component(&pdev->dev, 507 &img_i2s_out_component, &i2s->dai_driver, 1); 508 if (ret) 509 goto err_suspend; 510 511 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, 512 &img_i2s_out_dma_config, 0); 513 if (ret) 514 goto err_suspend; 515 516 return 0; 517 518 err_suspend: 519 if (!pm_runtime_status_suspended(&pdev->dev)) 520 img_i2s_out_suspend(&pdev->dev); 521 err_pm_disable: 522 pm_runtime_disable(&pdev->dev); 523 clk_disable_unprepare(i2s->clk_sys); 524 525 return ret; 526 } 527 528 static int img_i2s_out_dev_remove(struct platform_device *pdev) 529 { 530 struct img_i2s_out *i2s = platform_get_drvdata(pdev); 531 532 pm_runtime_disable(&pdev->dev); 533 if (!pm_runtime_status_suspended(&pdev->dev)) 534 img_i2s_out_suspend(&pdev->dev); 535 536 clk_disable_unprepare(i2s->clk_sys); 537 538 return 0; 539 } 540 541 static const struct of_device_id img_i2s_out_of_match[] = { 542 { .compatible = "img,i2s-out" }, 543 {} 544 }; 545 MODULE_DEVICE_TABLE(of, img_i2s_out_of_match); 546 547 static const struct dev_pm_ops img_i2s_out_pm_ops = { 548 SET_RUNTIME_PM_OPS(img_i2s_out_suspend, 549 img_i2s_out_resume, NULL) 550 }; 551 552 static struct platform_driver img_i2s_out_driver = { 553 .driver = { 554 .name = "img-i2s-out", 555 .of_match_table = img_i2s_out_of_match, 556 .pm = &img_i2s_out_pm_ops 557 }, 558 .probe = img_i2s_out_probe, 559 .remove = img_i2s_out_dev_remove 560 }; 561 module_platform_driver(img_i2s_out_driver); 562 563 MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 564 MODULE_DESCRIPTION("IMG I2S Output Driver"); 565 MODULE_LICENSE("GPL v2"); 566