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 (8) /* size * width: 8*4 = 32 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 pm_runtime_get_sync(cpu_dai->dev); 212 regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, mask, val); 213 pm_runtime_put(cpu_dai->dev); 214 215 return 0; 216 } 217 218 static int rockchip_pdm_trigger(struct snd_pcm_substream *substream, int cmd, 219 struct snd_soc_dai *dai) 220 { 221 struct rk_pdm_dev *pdm = to_info(dai); 222 int ret = 0; 223 224 switch (cmd) { 225 case SNDRV_PCM_TRIGGER_START: 226 case SNDRV_PCM_TRIGGER_RESUME: 227 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 228 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 229 rockchip_pdm_rxctrl(pdm, 1); 230 break; 231 case SNDRV_PCM_TRIGGER_SUSPEND: 232 case SNDRV_PCM_TRIGGER_STOP: 233 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 234 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 235 rockchip_pdm_rxctrl(pdm, 0); 236 break; 237 default: 238 ret = -EINVAL; 239 break; 240 } 241 242 return ret; 243 } 244 245 static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) 246 { 247 struct rk_pdm_dev *pdm = to_info(dai); 248 249 dai->capture_dma_data = &pdm->capture_dma_data; 250 251 return 0; 252 } 253 254 static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { 255 .set_fmt = rockchip_pdm_set_fmt, 256 .trigger = rockchip_pdm_trigger, 257 .hw_params = rockchip_pdm_hw_params, 258 }; 259 260 #define ROCKCHIP_PDM_RATES SNDRV_PCM_RATE_8000_192000 261 #define ROCKCHIP_PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 262 SNDRV_PCM_FMTBIT_S20_3LE | \ 263 SNDRV_PCM_FMTBIT_S24_LE | \ 264 SNDRV_PCM_FMTBIT_S32_LE) 265 266 static struct snd_soc_dai_driver rockchip_pdm_dai = { 267 .probe = rockchip_pdm_dai_probe, 268 .capture = { 269 .stream_name = "Capture", 270 .channels_min = 2, 271 .channels_max = 8, 272 .rates = ROCKCHIP_PDM_RATES, 273 .formats = ROCKCHIP_PDM_FORMATS, 274 }, 275 .ops = &rockchip_pdm_dai_ops, 276 .symmetric_rates = 1, 277 }; 278 279 static const struct snd_soc_component_driver rockchip_pdm_component = { 280 .name = "rockchip-pdm", 281 }; 282 283 static int rockchip_pdm_runtime_suspend(struct device *dev) 284 { 285 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 286 287 clk_disable_unprepare(pdm->clk); 288 clk_disable_unprepare(pdm->hclk); 289 290 return 0; 291 } 292 293 static int rockchip_pdm_runtime_resume(struct device *dev) 294 { 295 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 296 int ret; 297 298 ret = clk_prepare_enable(pdm->clk); 299 if (ret) { 300 dev_err(pdm->dev, "clock enable failed %d\n", ret); 301 return ret; 302 } 303 304 ret = clk_prepare_enable(pdm->hclk); 305 if (ret) { 306 dev_err(pdm->dev, "hclock enable failed %d\n", ret); 307 return ret; 308 } 309 310 return 0; 311 } 312 313 static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg) 314 { 315 switch (reg) { 316 case PDM_SYSCONFIG: 317 case PDM_CTRL0: 318 case PDM_CTRL1: 319 case PDM_CLK_CTRL: 320 case PDM_HPF_CTRL: 321 case PDM_FIFO_CTRL: 322 case PDM_DMA_CTRL: 323 case PDM_INT_EN: 324 case PDM_INT_CLR: 325 case PDM_DATA_VALID: 326 return true; 327 default: 328 return false; 329 } 330 } 331 332 static bool rockchip_pdm_rd_reg(struct device *dev, unsigned int reg) 333 { 334 switch (reg) { 335 case PDM_SYSCONFIG: 336 case PDM_CTRL0: 337 case PDM_CTRL1: 338 case PDM_CLK_CTRL: 339 case PDM_HPF_CTRL: 340 case PDM_FIFO_CTRL: 341 case PDM_DMA_CTRL: 342 case PDM_INT_EN: 343 case PDM_INT_CLR: 344 case PDM_INT_ST: 345 case PDM_DATA_VALID: 346 case PDM_VERSION: 347 return true; 348 default: 349 return false; 350 } 351 } 352 353 static bool rockchip_pdm_volatile_reg(struct device *dev, unsigned int reg) 354 { 355 switch (reg) { 356 case PDM_SYSCONFIG: 357 case PDM_INT_CLR: 358 case PDM_INT_ST: 359 return true; 360 default: 361 return false; 362 } 363 } 364 365 static const struct regmap_config rockchip_pdm_regmap_config = { 366 .reg_bits = 32, 367 .reg_stride = 4, 368 .val_bits = 32, 369 .max_register = PDM_VERSION, 370 .writeable_reg = rockchip_pdm_wr_reg, 371 .readable_reg = rockchip_pdm_rd_reg, 372 .volatile_reg = rockchip_pdm_volatile_reg, 373 .cache_type = REGCACHE_FLAT, 374 }; 375 376 static int rockchip_pdm_probe(struct platform_device *pdev) 377 { 378 struct rk_pdm_dev *pdm; 379 struct resource *res; 380 void __iomem *regs; 381 int ret; 382 383 pdm = devm_kzalloc(&pdev->dev, sizeof(*pdm), GFP_KERNEL); 384 if (!pdm) 385 return -ENOMEM; 386 387 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 388 regs = devm_ioremap_resource(&pdev->dev, res); 389 if (IS_ERR(regs)) 390 return PTR_ERR(regs); 391 392 pdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 393 &rockchip_pdm_regmap_config); 394 if (IS_ERR(pdm->regmap)) 395 return PTR_ERR(pdm->regmap); 396 397 pdm->capture_dma_data.addr = res->start + PDM_RXFIFO_DATA; 398 pdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 399 pdm->capture_dma_data.maxburst = PDM_DMA_BURST_SIZE; 400 401 pdm->dev = &pdev->dev; 402 dev_set_drvdata(&pdev->dev, pdm); 403 404 pdm->clk = devm_clk_get(&pdev->dev, "pdm_clk"); 405 if (IS_ERR(pdm->clk)) 406 return PTR_ERR(pdm->clk); 407 408 pdm->hclk = devm_clk_get(&pdev->dev, "pdm_hclk"); 409 if (IS_ERR(pdm->hclk)) 410 return PTR_ERR(pdm->hclk); 411 412 ret = clk_prepare_enable(pdm->hclk); 413 if (ret) 414 return ret; 415 416 pm_runtime_enable(&pdev->dev); 417 if (!pm_runtime_enabled(&pdev->dev)) { 418 ret = rockchip_pdm_runtime_resume(&pdev->dev); 419 if (ret) 420 goto err_pm_disable; 421 } 422 423 ret = devm_snd_soc_register_component(&pdev->dev, 424 &rockchip_pdm_component, 425 &rockchip_pdm_dai, 1); 426 427 if (ret) { 428 dev_err(&pdev->dev, "could not register dai: %d\n", ret); 429 goto err_suspend; 430 } 431 432 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 433 if (ret) { 434 dev_err(&pdev->dev, "could not register pcm: %d\n", ret); 435 goto err_suspend; 436 } 437 438 return 0; 439 440 err_suspend: 441 if (!pm_runtime_status_suspended(&pdev->dev)) 442 rockchip_pdm_runtime_suspend(&pdev->dev); 443 err_pm_disable: 444 pm_runtime_disable(&pdev->dev); 445 446 clk_disable_unprepare(pdm->hclk); 447 448 return ret; 449 } 450 451 static int rockchip_pdm_remove(struct platform_device *pdev) 452 { 453 struct rk_pdm_dev *pdm = dev_get_drvdata(&pdev->dev); 454 455 pm_runtime_disable(&pdev->dev); 456 if (!pm_runtime_status_suspended(&pdev->dev)) 457 rockchip_pdm_runtime_suspend(&pdev->dev); 458 459 clk_disable_unprepare(pdm->clk); 460 clk_disable_unprepare(pdm->hclk); 461 462 return 0; 463 } 464 465 #ifdef CONFIG_PM_SLEEP 466 static int rockchip_pdm_suspend(struct device *dev) 467 { 468 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 469 470 regcache_mark_dirty(pdm->regmap); 471 472 return 0; 473 } 474 475 static int rockchip_pdm_resume(struct device *dev) 476 { 477 struct rk_pdm_dev *pdm = dev_get_drvdata(dev); 478 int ret; 479 480 ret = pm_runtime_get_sync(dev); 481 if (ret < 0) 482 return ret; 483 484 ret = regcache_sync(pdm->regmap); 485 486 pm_runtime_put(dev); 487 488 return ret; 489 } 490 #endif 491 492 static const struct dev_pm_ops rockchip_pdm_pm_ops = { 493 SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend, 494 rockchip_pdm_runtime_resume, NULL) 495 SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) 496 }; 497 498 static const struct of_device_id rockchip_pdm_match[] = { 499 { .compatible = "rockchip,pdm", }, 500 {}, 501 }; 502 MODULE_DEVICE_TABLE(of, rockchip_pdm_match); 503 504 static struct platform_driver rockchip_pdm_driver = { 505 .probe = rockchip_pdm_probe, 506 .remove = rockchip_pdm_remove, 507 .driver = { 508 .name = "rockchip-pdm", 509 .of_match_table = of_match_ptr(rockchip_pdm_match), 510 .pm = &rockchip_pdm_pm_ops, 511 }, 512 }; 513 514 module_platform_driver(rockchip_pdm_driver); 515 516 MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>"); 517 MODULE_DESCRIPTION("Rockchip PDM Controller Driver"); 518 MODULE_LICENSE("GPL v2"); 519