1 /* 2 * Rockchip PDM ALSA SoC Digital Audio Interface(DAI) driver 3 * 4 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd 5 * 6 * This software is licensed under the terms of the GNU General Public 7 * License version 2, as published by the Free Software Foundation, and 8 * may be copied, distributed, and modified under those terms. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17 #include <linux/module.h> 18 #include <linux/clk.h> 19 #include <linux/of.h> 20 #include <linux/pm_runtime.h> 21 #include <linux/regmap.h> 22 #include <sound/dmaengine_pcm.h> 23 #include <sound/pcm_params.h> 24 25 #include "rockchip_pdm.h" 26 27 #define PDM_DMA_BURST_SIZE (16) /* size * width: 16*4 = 64 bytes */ 28 29 struct rk_pdm_dev { 30 struct device *dev; 31 struct clk *clk; 32 struct clk *hclk; 33 struct regmap *regmap; 34 struct snd_dmaengine_dai_dma_data capture_dma_data; 35 }; 36 37 struct rk_pdm_clkref { 38 unsigned int sr; 39 unsigned int clk; 40 }; 41 42 static struct rk_pdm_clkref clkref[] = { 43 { 8000, 40960000 }, 44 { 11025, 56448000 }, 45 { 12000, 61440000 }, 46 }; 47 48 static unsigned int get_pdm_clk(unsigned int sr) 49 { 50 unsigned int i, count, clk, div; 51 52 clk = 0; 53 if (!sr) 54 return clk; 55 56 count = ARRAY_SIZE(clkref); 57 for (i = 0; i < count; i++) { 58 if (sr % clkref[i].sr) 59 continue; 60 div = sr / clkref[i].sr; 61 if ((div & (div - 1)) == 0) { 62 clk = clkref[i].clk; 63 break; 64 } 65 } 66 67 return clk; 68 } 69 70 static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai) 71 { 72 return snd_soc_dai_get_drvdata(dai); 73 } 74 75 static void rockchip_pdm_rxctrl(struct rk_pdm_dev *pdm, int on) 76 { 77 if (on) { 78 regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, 79 PDM_DMA_RD_MSK, PDM_DMA_RD_EN); 80 regmap_update_bits(pdm->regmap, PDM_SYSCONFIG, 81 PDM_RX_MASK, PDM_RX_START); 82 } else { 83 regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, 84 PDM_DMA_RD_MSK, PDM_DMA_RD_DIS); 85 regmap_update_bits(pdm->regmap, PDM_SYSCONFIG, 86 PDM_RX_MASK | PDM_RX_CLR_MASK, 87 PDM_RX_STOP | PDM_RX_CLR_WR); 88 } 89 } 90 91 static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream, 92 struct snd_pcm_hw_params *params, 93 struct snd_soc_dai *dai) 94 { 95 struct rk_pdm_dev *pdm = to_info(dai); 96 unsigned int val = 0; 97 unsigned int clk_rate, clk_div, samplerate; 98 int ret; 99 100 samplerate = params_rate(params); 101 clk_rate = get_pdm_clk(samplerate); 102 if (!clk_rate) 103 return -EINVAL; 104 105 ret = clk_set_rate(pdm->clk, clk_rate); 106 if (ret) 107 return -EINVAL; 108 109 clk_div = DIV_ROUND_CLOSEST(clk_rate, samplerate); 110 111 switch (clk_div) { 112 case 320: 113 val = PDM_CLK_320FS; 114 break; 115 case 640: 116 val = PDM_CLK_640FS; 117 break; 118 case 1280: 119 val = PDM_CLK_1280FS; 120 break; 121 case 2560: 122 val = PDM_CLK_2560FS; 123 break; 124 case 5120: 125 val = PDM_CLK_5120FS; 126 break; 127 default: 128 dev_err(pdm->dev, "unsupported div: %d\n", clk_div); 129 return -EINVAL; 130 } 131 132 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val); 133 regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, 134 PDM_HPF_CF_MSK, PDM_HPF_60HZ); 135 regmap_update_bits(pdm->regmap, PDM_HPF_CTRL, 136 PDM_HPF_LE | PDM_HPF_RE, PDM_HPF_LE | PDM_HPF_RE); 137 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, PDM_CLK_EN, PDM_CLK_EN); 138 139 val = 0; 140 switch (params_format(params)) { 141 case SNDRV_PCM_FORMAT_S8: 142 val |= PDM_VDW(8); 143 break; 144 case SNDRV_PCM_FORMAT_S16_LE: 145 val |= PDM_VDW(16); 146 break; 147 case SNDRV_PCM_FORMAT_S20_3LE: 148 val |= PDM_VDW(20); 149 break; 150 case SNDRV_PCM_FORMAT_S24_LE: 151 val |= PDM_VDW(24); 152 break; 153 case SNDRV_PCM_FORMAT_S32_LE: 154 val |= PDM_VDW(32); 155 break; 156 default: 157 return -EINVAL; 158 } 159 160 switch (params_channels(params)) { 161 case 8: 162 val |= PDM_PATH3_EN; 163 /* fallthrough */ 164 case 6: 165 val |= PDM_PATH2_EN; 166 /* fallthrough */ 167 case 4: 168 val |= PDM_PATH1_EN; 169 /* fallthrough */ 170 case 2: 171 val |= PDM_PATH0_EN; 172 break; 173 default: 174 dev_err(pdm->dev, "invalid channel: %d\n", 175 params_channels(params)); 176 return -EINVAL; 177 } 178 179 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 180 regmap_update_bits(pdm->regmap, PDM_CTRL0, 181 PDM_PATH_MSK | PDM_VDW_MSK, 182 val); 183 regmap_update_bits(pdm->regmap, PDM_DMA_CTRL, PDM_DMA_RDL_MSK, 184 PDM_DMA_RDL(16)); 185 regmap_update_bits(pdm->regmap, PDM_SYSCONFIG, 186 PDM_RX_MASK | PDM_RX_CLR_MASK, 187 PDM_RX_STOP | PDM_RX_CLR_WR); 188 } 189 190 return 0; 191 } 192 193 static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai, 194 unsigned int fmt) 195 { 196 struct rk_pdm_dev *pdm = to_info(cpu_dai); 197 unsigned int mask = 0, val = 0; 198 199 mask = PDM_CKP_MSK; 200 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 201 case SND_SOC_DAIFMT_NB_NF: 202 val = PDM_CKP_NORMAL; 203 break; 204 case SND_SOC_DAIFMT_IB_NF: 205 val = PDM_CKP_INVERTED; 206 break; 207 default: 208 return -EINVAL; 209 } 210 211 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, mask, val); 212 213 return 0; 214 } 215 216 static int rockchip_pdm_trigger(struct snd_pcm_substream *substream, int cmd, 217 struct snd_soc_dai *dai) 218 { 219 struct rk_pdm_dev *pdm = to_info(dai); 220 int ret = 0; 221 222 switch (cmd) { 223 case SNDRV_PCM_TRIGGER_START: 224 case SNDRV_PCM_TRIGGER_RESUME: 225 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 226 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 227 rockchip_pdm_rxctrl(pdm, 1); 228 break; 229 case SNDRV_PCM_TRIGGER_SUSPEND: 230 case SNDRV_PCM_TRIGGER_STOP: 231 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 232 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 233 rockchip_pdm_rxctrl(pdm, 0); 234 break; 235 default: 236 ret = -EINVAL; 237 break; 238 } 239 240 return ret; 241 } 242 243 static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) 244 { 245 struct rk_pdm_dev *pdm = to_info(dai); 246 247 dai->capture_dma_data = &pdm->capture_dma_data; 248 249 return 0; 250 } 251 252 static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { 253 .set_fmt = rockchip_pdm_set_fmt, 254 .trigger = rockchip_pdm_trigger, 255 .hw_params = rockchip_pdm_hw_params, 256 }; 257 258 #define ROCKCHIP_PDM_RATES SNDRV_PCM_RATE_8000_192000 259 #define ROCKCHIP_PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 260 SNDRV_PCM_FMTBIT_S20_3LE | \ 261 SNDRV_PCM_FMTBIT_S24_LE | \ 262 SNDRV_PCM_FMTBIT_S32_LE) 263 264 static struct snd_soc_dai_driver rockchip_pdm_dai = { 265 .probe = rockchip_pdm_dai_probe, 266 .capture = { 267 .stream_name = "Capture", 268 .channels_min = 2, 269 .channels_max = 8, 270 .rates = ROCKCHIP_PDM_RATES, 271 .formats = ROCKCHIP_PDM_FORMATS, 272 }, 273 .ops = &rockchip_pdm_dai_ops, 274 .symmetric_rates = 1, 275 }; 276 277 static const struct snd_soc_component_driver rockchip_pdm_component = { 278 .name = "rockchip-pdm", 279 }; 280 281 static int rockchip_pdm_runtime_suspend(struct device *dev) 282 { 283 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 284 285 clk_disable_unprepare(pdm->clk); 286 clk_disable_unprepare(pdm->hclk); 287 288 return 0; 289 } 290 291 static int rockchip_pdm_runtime_resume(struct device *dev) 292 { 293 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 294 int ret; 295 296 ret = clk_prepare_enable(pdm->clk); 297 if (ret) { 298 dev_err(pdm->dev, "clock enable failed %d\n", ret); 299 return ret; 300 } 301 302 ret = clk_prepare_enable(pdm->hclk); 303 if (ret) { 304 dev_err(pdm->dev, "hclock enable failed %d\n", ret); 305 return ret; 306 } 307 308 return 0; 309 } 310 311 static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg) 312 { 313 switch (reg) { 314 case PDM_SYSCONFIG: 315 case PDM_CTRL0: 316 case PDM_CTRL1: 317 case PDM_CLK_CTRL: 318 case PDM_HPF_CTRL: 319 case PDM_FIFO_CTRL: 320 case PDM_DMA_CTRL: 321 case PDM_INT_EN: 322 case PDM_INT_CLR: 323 case PDM_DATA_VALID: 324 return true; 325 default: 326 return false; 327 } 328 } 329 330 static bool rockchip_pdm_rd_reg(struct device *dev, unsigned int reg) 331 { 332 switch (reg) { 333 case PDM_SYSCONFIG: 334 case PDM_CTRL0: 335 case PDM_CTRL1: 336 case PDM_CLK_CTRL: 337 case PDM_HPF_CTRL: 338 case PDM_FIFO_CTRL: 339 case PDM_DMA_CTRL: 340 case PDM_INT_EN: 341 case PDM_INT_CLR: 342 case PDM_INT_ST: 343 case PDM_DATA_VALID: 344 case PDM_VERSION: 345 return true; 346 default: 347 return false; 348 } 349 } 350 351 static bool rockchip_pdm_volatile_reg(struct device *dev, unsigned int reg) 352 { 353 switch (reg) { 354 case PDM_SYSCONFIG: 355 case PDM_INT_CLR: 356 case PDM_INT_ST: 357 return true; 358 default: 359 return false; 360 } 361 } 362 363 static const struct regmap_config rockchip_pdm_regmap_config = { 364 .reg_bits = 32, 365 .reg_stride = 4, 366 .val_bits = 32, 367 .max_register = PDM_VERSION, 368 .writeable_reg = rockchip_pdm_wr_reg, 369 .readable_reg = rockchip_pdm_rd_reg, 370 .volatile_reg = rockchip_pdm_volatile_reg, 371 .cache_type = REGCACHE_FLAT, 372 }; 373 374 static int rockchip_pdm_probe(struct platform_device *pdev) 375 { 376 struct rk_pdm_dev *pdm; 377 struct resource *res; 378 void __iomem *regs; 379 int ret; 380 381 pdm = devm_kzalloc(&pdev->dev, sizeof(*pdm), GFP_KERNEL); 382 if (!pdm) 383 return -ENOMEM; 384 385 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 386 regs = devm_ioremap_resource(&pdev->dev, res); 387 if (IS_ERR(regs)) 388 return PTR_ERR(regs); 389 390 pdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 391 &rockchip_pdm_regmap_config); 392 if (IS_ERR(pdm->regmap)) 393 return PTR_ERR(pdm->regmap); 394 395 pdm->capture_dma_data.addr = res->start + PDM_RXFIFO_DATA; 396 pdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 397 pdm->capture_dma_data.maxburst = PDM_DMA_BURST_SIZE; 398 399 pdm->dev = &pdev->dev; 400 dev_set_drvdata(&pdev->dev, pdm); 401 402 pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk"); 403 if (IS_ERR(pdm->clk)) 404 return PTR_ERR(pdm->clk); 405 406 pdm->hclk = devm_clk_get(&pdev->dev, "pdm_hclk"); 407 if (IS_ERR(pdm->hclk)) 408 return PTR_ERR(pdm->hclk); 409 410 ret = clk_prepare_enable(pdm->hclk); 411 if (ret) 412 return ret; 413 414 pm_runtime_enable(&pdev->dev); 415 if (!pm_runtime_enabled(&pdev->dev)) { 416 ret = rockchip_pdm_runtime_resume(&pdev->dev); 417 if (ret) 418 goto err_pm_disable; 419 } 420 421 ret = devm_snd_soc_register_component(&pdev->dev, 422 &rockchip_pdm_component, 423 &rockchip_pdm_dai, 1); 424 425 if (ret) { 426 dev_err(&pdev->dev, "could not register dai: %d\n", ret); 427 goto err_suspend; 428 } 429 430 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 431 if (ret) { 432 dev_err(&pdev->dev, "could not register pcm: %d\n", ret); 433 goto err_suspend; 434 } 435 436 return 0; 437 438 err_suspend: 439 if (!pm_runtime_status_suspended(&pdev->dev)) 440 rockchip_pdm_runtime_suspend(&pdev->dev); 441 err_pm_disable: 442 pm_runtime_disable(&pdev->dev); 443 444 clk_disable_unprepare(pdm->hclk); 445 446 return ret; 447 } 448 449 static int rockchip_pdm_remove(struct platform_device *pdev) 450 { 451 struct rk_pdm_dev *pdm = dev_get_drvdata(&pdev->dev); 452 453 pm_runtime_disable(&pdev->dev); 454 if (!pm_runtime_status_suspended(&pdev->dev)) 455 rockchip_pdm_runtime_suspend(&pdev->dev); 456 457 clk_disable_unprepare(pdm->clk); 458 clk_disable_unprepare(pdm->hclk); 459 460 return 0; 461 } 462 463 #ifdef CONFIG_PM_SLEEP 464 static int rockchip_pdm_suspend(struct device *dev) 465 { 466 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 467 468 regcache_mark_dirty(pdm->regmap); 469 470 return 0; 471 } 472 473 static int rockchip_pdm_resume(struct device *dev) 474 { 475 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 476 int ret; 477 478 ret = pm_runtime_get_sync(dev); 479 if (ret < 0) 480 return ret; 481 482 ret = regcache_sync(pdm->regmap); 483 484 pm_runtime_put(dev); 485 486 return ret; 487 } 488 #endif 489 490 static const struct dev_pm_ops rockchip_pdm_pm_ops = { 491 SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend, 492 rockchip_pdm_runtime_resume, NULL) 493 SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) 494 }; 495 496 static const struct of_device_id rockchip_pdm_match[] = { 497 { .compatible = "rockchip,pdm", }, 498 {}, 499 }; 500 MODULE_DEVICE_TABLE(of, rockchip_pdm_match); 501 502 static struct platform_driver rockchip_pdm_driver = { 503 .probe = rockchip_pdm_probe, 504 .remove = rockchip_pdm_remove, 505 .driver = { 506 .name = "rockchip-pdm", 507 .of_match_table = of_match_ptr(rockchip_pdm_match), 508 .pm = &rockchip_pdm_pm_ops, 509 }, 510 }; 511 512 module_platform_driver(rockchip_pdm_driver); 513 514 MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>"); 515 MODULE_DESCRIPTION("Rockchip PDM Controller Driver"); 516 MODULE_LICENSE("GPL v2"); 517