2 * Rockchip PDM ALSA SoC Digital Audio Interface(DAI) driver
4 * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd
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.
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.
17 #include <linux/module.h>
18 #include <linux/clk.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/regmap.h>
22 #include <sound/dmaengine_pcm.h>
23 #include <sound/pcm_params.h>
25 #include "rockchip_pdm.h"
27 #define PDM_DMA_BURST_SIZE (16) /* size * width: 16*4 = 64 bytes */
33 struct regmap
*regmap
;
34 struct snd_dmaengine_dai_dma_data capture_dma_data
;
37 struct rk_pdm_clkref
{
42 static struct rk_pdm_clkref clkref
[] = {
48 static unsigned int get_pdm_clk(unsigned int sr
)
50 unsigned int i
, count
, clk
, div
;
56 count
= ARRAY_SIZE(clkref
);
57 for (i
= 0; i
< count
; i
++) {
58 if (sr
% clkref
[i
].sr
)
60 div
= sr
/ clkref
[i
].sr
;
61 if ((div
& (div
- 1)) == 0) {
70 static inline struct rk_pdm_dev
*to_info(struct snd_soc_dai
*dai
)
72 return snd_soc_dai_get_drvdata(dai
);
75 static void rockchip_pdm_rxctrl(struct rk_pdm_dev
*pdm
, int 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
);
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
);
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
)
95 struct rk_pdm_dev
*pdm
= to_info(dai
);
97 unsigned int clk_rate
, clk_div
, samplerate
;
100 samplerate
= params_rate(params
);
101 clk_rate
= get_pdm_clk(samplerate
);
105 ret
= clk_set_rate(pdm
->clk
, clk_rate
);
109 clk_div
= DIV_ROUND_CLOSEST(clk_rate
, samplerate
);
119 val
= PDM_CLK_1280FS
;
122 val
= PDM_CLK_2560FS
;
125 val
= PDM_CLK_5120FS
;
128 dev_err(pdm
->dev
, "unsupported div: %d\n", clk_div
);
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
);
140 switch (params_format(params
)) {
141 case SNDRV_PCM_FORMAT_S8
:
144 case SNDRV_PCM_FORMAT_S16_LE
:
147 case SNDRV_PCM_FORMAT_S20_3LE
:
150 case SNDRV_PCM_FORMAT_S24_LE
:
153 case SNDRV_PCM_FORMAT_S32_LE
:
160 switch (params_channels(params
)) {
174 dev_err(pdm
->dev
, "invalid channel: %d\n",
175 params_channels(params
));
179 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
) {
180 regmap_update_bits(pdm
->regmap
, PDM_CTRL0
,
181 PDM_PATH_MSK
| PDM_VDW_MSK
,
183 regmap_update_bits(pdm
->regmap
, PDM_DMA_CTRL
, PDM_DMA_RDL_MSK
,
185 regmap_update_bits(pdm
->regmap
, PDM_SYSCONFIG
,
186 PDM_RX_MASK
| PDM_RX_CLR_MASK
,
187 PDM_RX_STOP
| PDM_RX_CLR_WR
);
193 static int rockchip_pdm_set_fmt(struct snd_soc_dai
*cpu_dai
,
196 struct rk_pdm_dev
*pdm
= to_info(cpu_dai
);
197 unsigned int mask
= 0, val
= 0;
200 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
201 case SND_SOC_DAIFMT_NB_NF
:
202 val
= PDM_CKP_NORMAL
;
204 case SND_SOC_DAIFMT_IB_NF
:
205 val
= PDM_CKP_INVERTED
;
211 regmap_update_bits(pdm
->regmap
, PDM_CLK_CTRL
, mask
, val
);
216 static int rockchip_pdm_trigger(struct snd_pcm_substream
*substream
, int cmd
,
217 struct snd_soc_dai
*dai
)
219 struct rk_pdm_dev
*pdm
= to_info(dai
);
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);
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);
243 static int rockchip_pdm_dai_probe(struct snd_soc_dai
*dai
)
245 struct rk_pdm_dev
*pdm
= to_info(dai
);
247 dai
->capture_dma_data
= &pdm
->capture_dma_data
;
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
,
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)
264 static struct snd_soc_dai_driver rockchip_pdm_dai
= {
265 .probe
= rockchip_pdm_dai_probe
,
267 .stream_name
= "Capture",
270 .rates
= ROCKCHIP_PDM_RATES
,
271 .formats
= ROCKCHIP_PDM_FORMATS
,
273 .ops
= &rockchip_pdm_dai_ops
,
274 .symmetric_rates
= 1,
277 static const struct snd_soc_component_driver rockchip_pdm_component
= {
278 .name
= "rockchip-pdm",
281 static int rockchip_pdm_runtime_suspend(struct device
*dev
)
283 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
285 clk_disable_unprepare(pdm
->clk
);
286 clk_disable_unprepare(pdm
->hclk
);
291 static int rockchip_pdm_runtime_resume(struct device
*dev
)
293 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
296 ret
= clk_prepare_enable(pdm
->clk
);
298 dev_err(pdm
->dev
, "clock enable failed %d\n", ret
);
302 ret
= clk_prepare_enable(pdm
->hclk
);
304 dev_err(pdm
->dev
, "hclock enable failed %d\n", ret
);
311 static bool rockchip_pdm_wr_reg(struct device
*dev
, unsigned int reg
)
330 static bool rockchip_pdm_rd_reg(struct device
*dev
, unsigned int reg
)
351 static bool rockchip_pdm_volatile_reg(struct device
*dev
, unsigned int reg
)
363 static const struct regmap_config rockchip_pdm_regmap_config
= {
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
,
374 static int rockchip_pdm_probe(struct platform_device
*pdev
)
376 struct rk_pdm_dev
*pdm
;
377 struct resource
*res
;
381 pdm
= devm_kzalloc(&pdev
->dev
, sizeof(*pdm
), GFP_KERNEL
);
385 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
386 regs
= devm_ioremap_resource(&pdev
->dev
, res
);
388 return PTR_ERR(regs
);
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
);
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
;
399 pdm
->dev
= &pdev
->dev
;
400 dev_set_drvdata(&pdev
->dev
, pdm
);
402 pdm
->clk
= devm_clk_get(&pdev
->dev
, "pdm_clk");
403 if (IS_ERR(pdm
->clk
))
404 return PTR_ERR(pdm
->clk
);
406 pdm
->hclk
= devm_clk_get(&pdev
->dev
, "pdm_hclk");
407 if (IS_ERR(pdm
->hclk
))
408 return PTR_ERR(pdm
->hclk
);
410 ret
= clk_prepare_enable(pdm
->hclk
);
414 pm_runtime_enable(&pdev
->dev
);
415 if (!pm_runtime_enabled(&pdev
->dev
)) {
416 ret
= rockchip_pdm_runtime_resume(&pdev
->dev
);
421 ret
= devm_snd_soc_register_component(&pdev
->dev
,
422 &rockchip_pdm_component
,
423 &rockchip_pdm_dai
, 1);
426 dev_err(&pdev
->dev
, "could not register dai: %d\n", ret
);
430 ret
= devm_snd_dmaengine_pcm_register(&pdev
->dev
, NULL
, 0);
432 dev_err(&pdev
->dev
, "could not register pcm: %d\n", ret
);
439 if (!pm_runtime_status_suspended(&pdev
->dev
))
440 rockchip_pdm_runtime_suspend(&pdev
->dev
);
442 pm_runtime_disable(&pdev
->dev
);
444 clk_disable_unprepare(pdm
->hclk
);
449 static int rockchip_pdm_remove(struct platform_device
*pdev
)
451 struct rk_pdm_dev
*pdm
= dev_get_drvdata(&pdev
->dev
);
453 pm_runtime_disable(&pdev
->dev
);
454 if (!pm_runtime_status_suspended(&pdev
->dev
))
455 rockchip_pdm_runtime_suspend(&pdev
->dev
);
457 clk_disable_unprepare(pdm
->clk
);
458 clk_disable_unprepare(pdm
->hclk
);
463 #ifdef CONFIG_PM_SLEEP
464 static int rockchip_pdm_suspend(struct device
*dev
)
466 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
468 regcache_mark_dirty(pdm
->regmap
);
473 static int rockchip_pdm_resume(struct device
*dev
)
475 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
478 ret
= pm_runtime_get_sync(dev
);
482 ret
= regcache_sync(pdm
->regmap
);
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
)
496 static const struct of_device_id rockchip_pdm_match
[] = {
497 { .compatible
= "rockchip,pdm", },
500 MODULE_DEVICE_TABLE(of
, rockchip_pdm_match
);
502 static struct platform_driver rockchip_pdm_driver
= {
503 .probe
= rockchip_pdm_probe
,
504 .remove
= rockchip_pdm_remove
,
506 .name
= "rockchip-pdm",
507 .of_match_table
= of_match_ptr(rockchip_pdm_match
),
508 .pm
= &rockchip_pdm_pm_ops
,
512 module_platform_driver(rockchip_pdm_driver
);
514 MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>");
515 MODULE_DESCRIPTION("Rockchip PDM Controller Driver");
516 MODULE_LICENSE("GPL v2");