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 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
);
218 static int rockchip_pdm_trigger(struct snd_pcm_substream
*substream
, int cmd
,
219 struct snd_soc_dai
*dai
)
221 struct rk_pdm_dev
*pdm
= to_info(dai
);
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);
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);
245 static int rockchip_pdm_dai_probe(struct snd_soc_dai
*dai
)
247 struct rk_pdm_dev
*pdm
= to_info(dai
);
249 dai
->capture_dma_data
= &pdm
->capture_dma_data
;
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
,
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)
266 static struct snd_soc_dai_driver rockchip_pdm_dai
= {
267 .probe
= rockchip_pdm_dai_probe
,
269 .stream_name
= "Capture",
272 .rates
= ROCKCHIP_PDM_RATES
,
273 .formats
= ROCKCHIP_PDM_FORMATS
,
275 .ops
= &rockchip_pdm_dai_ops
,
276 .symmetric_rates
= 1,
279 static const struct snd_soc_component_driver rockchip_pdm_component
= {
280 .name
= "rockchip-pdm",
283 static int rockchip_pdm_runtime_suspend(struct device
*dev
)
285 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
287 clk_disable_unprepare(pdm
->clk
);
288 clk_disable_unprepare(pdm
->hclk
);
293 static int rockchip_pdm_runtime_resume(struct device
*dev
)
295 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
298 ret
= clk_prepare_enable(pdm
->clk
);
300 dev_err(pdm
->dev
, "clock enable failed %d\n", ret
);
304 ret
= clk_prepare_enable(pdm
->hclk
);
306 dev_err(pdm
->dev
, "hclock enable failed %d\n", ret
);
313 static bool rockchip_pdm_wr_reg(struct device
*dev
, unsigned int reg
)
332 static bool rockchip_pdm_rd_reg(struct device
*dev
, unsigned int reg
)
353 static bool rockchip_pdm_volatile_reg(struct device
*dev
, unsigned int reg
)
365 static const struct regmap_config rockchip_pdm_regmap_config
= {
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
,
376 static int rockchip_pdm_probe(struct platform_device
*pdev
)
378 struct rk_pdm_dev
*pdm
;
379 struct resource
*res
;
383 pdm
= devm_kzalloc(&pdev
->dev
, sizeof(*pdm
), GFP_KERNEL
);
387 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
388 regs
= devm_ioremap_resource(&pdev
->dev
, res
);
390 return PTR_ERR(regs
);
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
);
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
;
401 pdm
->dev
= &pdev
->dev
;
402 dev_set_drvdata(&pdev
->dev
, pdm
);
404 pdm
->clk
= devm_clk_get(&pdev
->dev
, "pdm_clk");
405 if (IS_ERR(pdm
->clk
))
406 return PTR_ERR(pdm
->clk
);
408 pdm
->hclk
= devm_clk_get(&pdev
->dev
, "pdm_hclk");
409 if (IS_ERR(pdm
->hclk
))
410 return PTR_ERR(pdm
->hclk
);
412 ret
= clk_prepare_enable(pdm
->hclk
);
416 pm_runtime_enable(&pdev
->dev
);
417 if (!pm_runtime_enabled(&pdev
->dev
)) {
418 ret
= rockchip_pdm_runtime_resume(&pdev
->dev
);
423 ret
= devm_snd_soc_register_component(&pdev
->dev
,
424 &rockchip_pdm_component
,
425 &rockchip_pdm_dai
, 1);
428 dev_err(&pdev
->dev
, "could not register dai: %d\n", ret
);
432 ret
= devm_snd_dmaengine_pcm_register(&pdev
->dev
, NULL
, 0);
434 dev_err(&pdev
->dev
, "could not register pcm: %d\n", ret
);
441 if (!pm_runtime_status_suspended(&pdev
->dev
))
442 rockchip_pdm_runtime_suspend(&pdev
->dev
);
444 pm_runtime_disable(&pdev
->dev
);
446 clk_disable_unprepare(pdm
->hclk
);
451 static int rockchip_pdm_remove(struct platform_device
*pdev
)
453 struct rk_pdm_dev
*pdm
= dev_get_drvdata(&pdev
->dev
);
455 pm_runtime_disable(&pdev
->dev
);
456 if (!pm_runtime_status_suspended(&pdev
->dev
))
457 rockchip_pdm_runtime_suspend(&pdev
->dev
);
459 clk_disable_unprepare(pdm
->clk
);
460 clk_disable_unprepare(pdm
->hclk
);
465 #ifdef CONFIG_PM_SLEEP
466 static int rockchip_pdm_suspend(struct device
*dev
)
468 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
470 regcache_mark_dirty(pdm
->regmap
);
475 static int rockchip_pdm_resume(struct device
*dev
)
477 struct rk_pdm_dev
*pdm
= dev_get_drvdata(dev
);
480 ret
= pm_runtime_get_sync(dev
);
484 ret
= regcache_sync(pdm
->regmap
);
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
)
498 static const struct of_device_id rockchip_pdm_match
[] = {
499 { .compatible
= "rockchip,pdm", },
502 MODULE_DEVICE_TABLE(of
, rockchip_pdm_match
);
504 static struct platform_driver rockchip_pdm_driver
= {
505 .probe
= rockchip_pdm_probe
,
506 .remove
= rockchip_pdm_remove
,
508 .name
= "rockchip-pdm",
509 .of_match_table
= of_match_ptr(rockchip_pdm_match
),
510 .pm
= &rockchip_pdm_pm_ops
,
514 module_platform_driver(rockchip_pdm_driver
);
516 MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>");
517 MODULE_DESCRIPTION("Rockchip PDM Controller Driver");
518 MODULE_LICENSE("GPL v2");