1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Rockchip PDM ALSA SoC Digital Audio Interface(DAI) driver |
4 | * |
5 | * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/clk.h> |
10 | #include <linux/of.h> |
11 | #include <linux/pm_runtime.h> |
12 | #include <linux/rational.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/reset.h> |
15 | #include <sound/dmaengine_pcm.h> |
16 | #include <sound/pcm_params.h> |
17 | |
18 | #include "rockchip_pdm.h" |
19 | |
20 | #define PDM_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */ |
21 | #define PDM_SIGNOFF_CLK_RATE (100000000) |
22 | #define PDM_PATH_MAX (4) |
23 | |
24 | enum rk_pdm_version { |
25 | RK_PDM_RK3229, |
26 | RK_PDM_RK3308, |
27 | RK_PDM_RV1126, |
28 | }; |
29 | |
30 | struct rk_pdm_dev { |
31 | struct device *dev; |
32 | struct clk *clk; |
33 | struct clk *hclk; |
34 | struct regmap *regmap; |
35 | struct snd_dmaengine_dai_dma_data capture_dma_data; |
36 | struct reset_control *reset; |
37 | enum rk_pdm_version version; |
38 | }; |
39 | |
40 | struct rk_pdm_clkref { |
41 | unsigned int sr; |
42 | unsigned int clk; |
43 | unsigned int clk_out; |
44 | }; |
45 | |
46 | struct rk_pdm_ds_ratio { |
47 | unsigned int ratio; |
48 | unsigned int sr; |
49 | }; |
50 | |
51 | static struct rk_pdm_clkref clkref[] = { |
52 | { 8000, 40960000, 2048000 }, |
53 | { 11025, 56448000, 2822400 }, |
54 | { 12000, 61440000, 3072000 }, |
55 | { 8000, 98304000, 2048000 }, |
56 | { 12000, 98304000, 3072000 }, |
57 | }; |
58 | |
59 | static struct rk_pdm_ds_ratio ds_ratio[] = { |
60 | { 0, 192000 }, |
61 | { 0, 176400 }, |
62 | { 0, 128000 }, |
63 | { 1, 96000 }, |
64 | { 1, 88200 }, |
65 | { 1, 64000 }, |
66 | { 2, 48000 }, |
67 | { 2, 44100 }, |
68 | { 2, 32000 }, |
69 | { 3, 24000 }, |
70 | { 3, 22050 }, |
71 | { 3, 16000 }, |
72 | { 4, 12000 }, |
73 | { 4, 11025 }, |
74 | { 4, 8000 }, |
75 | }; |
76 | |
77 | static unsigned int get_pdm_clk(struct rk_pdm_dev *pdm, unsigned int sr, |
78 | unsigned int *clk_src, unsigned int *clk_out) |
79 | { |
80 | unsigned int i, count, clk, div, rate; |
81 | |
82 | clk = 0; |
83 | if (!sr) |
84 | return clk; |
85 | |
86 | count = ARRAY_SIZE(clkref); |
87 | for (i = 0; i < count; i++) { |
88 | if (sr % clkref[i].sr) |
89 | continue; |
90 | div = sr / clkref[i].sr; |
91 | if ((div & (div - 1)) == 0) { |
92 | *clk_out = clkref[i].clk_out; |
93 | rate = clk_round_rate(clk: pdm->clk, rate: clkref[i].clk); |
94 | if (rate != clkref[i].clk) |
95 | continue; |
96 | clk = clkref[i].clk; |
97 | *clk_src = clkref[i].clk; |
98 | break; |
99 | } |
100 | } |
101 | |
102 | if (!clk) { |
103 | clk = clk_round_rate(clk: pdm->clk, PDM_SIGNOFF_CLK_RATE); |
104 | *clk_src = clk; |
105 | } |
106 | return clk; |
107 | } |
108 | |
109 | static unsigned int get_pdm_ds_ratio(unsigned int sr) |
110 | { |
111 | unsigned int i, count, ratio; |
112 | |
113 | ratio = 0; |
114 | if (!sr) |
115 | return ratio; |
116 | |
117 | count = ARRAY_SIZE(ds_ratio); |
118 | for (i = 0; i < count; i++) { |
119 | if (sr == ds_ratio[i].sr) |
120 | ratio = ds_ratio[i].ratio; |
121 | } |
122 | return ratio; |
123 | } |
124 | |
125 | static unsigned int get_pdm_cic_ratio(unsigned int clk) |
126 | { |
127 | switch (clk) { |
128 | case 4096000: |
129 | case 5644800: |
130 | case 6144000: |
131 | return 0; |
132 | case 2048000: |
133 | case 2822400: |
134 | case 3072000: |
135 | return 1; |
136 | case 1024000: |
137 | case 1411200: |
138 | case 1536000: |
139 | return 2; |
140 | default: |
141 | return 1; |
142 | } |
143 | } |
144 | |
145 | static unsigned int samplerate_to_bit(unsigned int samplerate) |
146 | { |
147 | switch (samplerate) { |
148 | case 8000: |
149 | case 11025: |
150 | case 12000: |
151 | return 0; |
152 | case 16000: |
153 | case 22050: |
154 | case 24000: |
155 | return 1; |
156 | case 32000: |
157 | return 2; |
158 | case 44100: |
159 | case 48000: |
160 | return 3; |
161 | case 64000: |
162 | case 88200: |
163 | case 96000: |
164 | return 4; |
165 | case 128000: |
166 | case 176400: |
167 | case 192000: |
168 | return 5; |
169 | default: |
170 | return 1; |
171 | } |
172 | } |
173 | |
174 | static inline struct rk_pdm_dev *to_info(struct snd_soc_dai *dai) |
175 | { |
176 | return snd_soc_dai_get_drvdata(dai); |
177 | } |
178 | |
179 | static void rockchip_pdm_rxctrl(struct rk_pdm_dev *pdm, int on) |
180 | { |
181 | if (on) { |
182 | regmap_update_bits(map: pdm->regmap, PDM_DMA_CTRL, |
183 | PDM_DMA_RD_MSK, PDM_DMA_RD_EN); |
184 | regmap_update_bits(map: pdm->regmap, PDM_SYSCONFIG, |
185 | PDM_RX_MASK, PDM_RX_START); |
186 | } else { |
187 | regmap_update_bits(map: pdm->regmap, PDM_DMA_CTRL, |
188 | PDM_DMA_RD_MSK, PDM_DMA_RD_DIS); |
189 | regmap_update_bits(map: pdm->regmap, PDM_SYSCONFIG, |
190 | PDM_RX_MASK | PDM_RX_CLR_MASK, |
191 | PDM_RX_STOP | PDM_RX_CLR_WR); |
192 | } |
193 | } |
194 | |
195 | static int rockchip_pdm_hw_params(struct snd_pcm_substream *substream, |
196 | struct snd_pcm_hw_params *params, |
197 | struct snd_soc_dai *dai) |
198 | { |
199 | struct rk_pdm_dev *pdm = to_info(dai); |
200 | unsigned int val = 0; |
201 | unsigned int clk_rate, clk_div, samplerate; |
202 | unsigned int clk_src, clk_out = 0; |
203 | unsigned long m, n; |
204 | bool change; |
205 | int ret; |
206 | |
207 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
208 | return 0; |
209 | |
210 | samplerate = params_rate(p: params); |
211 | clk_rate = get_pdm_clk(pdm, sr: samplerate, clk_src: &clk_src, clk_out: &clk_out); |
212 | if (!clk_rate) |
213 | return -EINVAL; |
214 | |
215 | ret = clk_set_rate(clk: pdm->clk, rate: clk_src); |
216 | if (ret) |
217 | return -EINVAL; |
218 | |
219 | if (pdm->version == RK_PDM_RK3308 || |
220 | pdm->version == RK_PDM_RV1126) { |
221 | rational_best_approximation(given_numerator: clk_out, given_denominator: clk_src, |
222 | GENMASK(16 - 1, 0), |
223 | GENMASK(16 - 1, 0), |
224 | best_numerator: &m, best_denominator: &n); |
225 | |
226 | val = (m << PDM_FD_NUMERATOR_SFT) | |
227 | (n << PDM_FD_DENOMINATOR_SFT); |
228 | regmap_update_bits_check(map: pdm->regmap, PDM_CTRL1, |
229 | PDM_FD_NUMERATOR_MSK | |
230 | PDM_FD_DENOMINATOR_MSK, |
231 | val, change: &change); |
232 | if (change) { |
233 | reset_control_assert(rstc: pdm->reset); |
234 | reset_control_deassert(rstc: pdm->reset); |
235 | rockchip_pdm_rxctrl(pdm, on: 0); |
236 | } |
237 | clk_div = n / m; |
238 | if (clk_div >= 40) |
239 | val = PDM_CLK_FD_RATIO_40; |
240 | else if (clk_div <= 35) |
241 | val = PDM_CLK_FD_RATIO_35; |
242 | else |
243 | return -EINVAL; |
244 | regmap_update_bits(map: pdm->regmap, PDM_CLK_CTRL, |
245 | PDM_CLK_FD_RATIO_MSK, |
246 | val); |
247 | } |
248 | |
249 | if (pdm->version == RK_PDM_RV1126) { |
250 | val = get_pdm_cic_ratio(clk: clk_out); |
251 | regmap_update_bits(map: pdm->regmap, PDM_CLK_CTRL, PDM_CIC_RATIO_MSK, val); |
252 | val = samplerate_to_bit(samplerate); |
253 | regmap_update_bits(map: pdm->regmap, PDM_CTRL0, |
254 | PDM_SAMPLERATE_MSK, PDM_SAMPLERATE(val)); |
255 | } else { |
256 | val = get_pdm_ds_ratio(sr: samplerate); |
257 | regmap_update_bits(map: pdm->regmap, PDM_CLK_CTRL, PDM_DS_RATIO_MSK, val); |
258 | } |
259 | |
260 | regmap_update_bits(map: pdm->regmap, PDM_HPF_CTRL, |
261 | PDM_HPF_CF_MSK, PDM_HPF_60HZ); |
262 | regmap_update_bits(map: pdm->regmap, PDM_HPF_CTRL, |
263 | PDM_HPF_LE | PDM_HPF_RE, PDM_HPF_LE | PDM_HPF_RE); |
264 | regmap_update_bits(map: pdm->regmap, PDM_CLK_CTRL, PDM_CLK_EN, PDM_CLK_EN); |
265 | if (pdm->version != RK_PDM_RK3229) |
266 | regmap_update_bits(map: pdm->regmap, PDM_CTRL0, |
267 | PDM_MODE_MSK, PDM_MODE_LJ); |
268 | |
269 | val = 0; |
270 | switch (params_format(p: params)) { |
271 | case SNDRV_PCM_FORMAT_S8: |
272 | val |= PDM_VDW(8); |
273 | break; |
274 | case SNDRV_PCM_FORMAT_S16_LE: |
275 | val |= PDM_VDW(16); |
276 | break; |
277 | case SNDRV_PCM_FORMAT_S20_3LE: |
278 | val |= PDM_VDW(20); |
279 | break; |
280 | case SNDRV_PCM_FORMAT_S24_LE: |
281 | val |= PDM_VDW(24); |
282 | break; |
283 | case SNDRV_PCM_FORMAT_S32_LE: |
284 | val |= PDM_VDW(32); |
285 | break; |
286 | default: |
287 | return -EINVAL; |
288 | } |
289 | |
290 | switch (params_channels(p: params)) { |
291 | case 8: |
292 | val |= PDM_PATH3_EN; |
293 | fallthrough; |
294 | case 6: |
295 | val |= PDM_PATH2_EN; |
296 | fallthrough; |
297 | case 4: |
298 | val |= PDM_PATH1_EN; |
299 | fallthrough; |
300 | case 2: |
301 | val |= PDM_PATH0_EN; |
302 | break; |
303 | default: |
304 | dev_err(pdm->dev, "invalid channel: %d\n" , |
305 | params_channels(params)); |
306 | return -EINVAL; |
307 | } |
308 | |
309 | regmap_update_bits(map: pdm->regmap, PDM_CTRL0, |
310 | PDM_PATH_MSK | PDM_VDW_MSK, |
311 | val); |
312 | /* all channels share the single FIFO */ |
313 | regmap_update_bits(map: pdm->regmap, PDM_DMA_CTRL, PDM_DMA_RDL_MSK, |
314 | PDM_DMA_RDL(8 * params_channels(params))); |
315 | |
316 | return 0; |
317 | } |
318 | |
319 | static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai, |
320 | unsigned int fmt) |
321 | { |
322 | struct rk_pdm_dev *pdm = to_info(dai: cpu_dai); |
323 | unsigned int mask = 0, val = 0; |
324 | |
325 | mask = PDM_CKP_MSK; |
326 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
327 | case SND_SOC_DAIFMT_NB_NF: |
328 | val = PDM_CKP_NORMAL; |
329 | break; |
330 | case SND_SOC_DAIFMT_IB_NF: |
331 | val = PDM_CKP_INVERTED; |
332 | break; |
333 | default: |
334 | return -EINVAL; |
335 | } |
336 | |
337 | pm_runtime_get_sync(dev: cpu_dai->dev); |
338 | regmap_update_bits(map: pdm->regmap, PDM_CLK_CTRL, mask, val); |
339 | pm_runtime_put(dev: cpu_dai->dev); |
340 | |
341 | return 0; |
342 | } |
343 | |
344 | static int rockchip_pdm_trigger(struct snd_pcm_substream *substream, int cmd, |
345 | struct snd_soc_dai *dai) |
346 | { |
347 | struct rk_pdm_dev *pdm = to_info(dai); |
348 | int ret = 0; |
349 | |
350 | switch (cmd) { |
351 | case SNDRV_PCM_TRIGGER_START: |
352 | case SNDRV_PCM_TRIGGER_RESUME: |
353 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
354 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
355 | rockchip_pdm_rxctrl(pdm, on: 1); |
356 | break; |
357 | case SNDRV_PCM_TRIGGER_SUSPEND: |
358 | case SNDRV_PCM_TRIGGER_STOP: |
359 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
360 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
361 | rockchip_pdm_rxctrl(pdm, on: 0); |
362 | break; |
363 | default: |
364 | ret = -EINVAL; |
365 | break; |
366 | } |
367 | |
368 | return ret; |
369 | } |
370 | |
371 | static int rockchip_pdm_dai_probe(struct snd_soc_dai *dai) |
372 | { |
373 | struct rk_pdm_dev *pdm = to_info(dai); |
374 | |
375 | snd_soc_dai_dma_data_set_capture(dai, &pdm->capture_dma_data); |
376 | |
377 | return 0; |
378 | } |
379 | |
380 | static const struct snd_soc_dai_ops rockchip_pdm_dai_ops = { |
381 | .probe = rockchip_pdm_dai_probe, |
382 | .set_fmt = rockchip_pdm_set_fmt, |
383 | .trigger = rockchip_pdm_trigger, |
384 | .hw_params = rockchip_pdm_hw_params, |
385 | }; |
386 | |
387 | #define ROCKCHIP_PDM_RATES SNDRV_PCM_RATE_8000_192000 |
388 | #define ROCKCHIP_PDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
389 | SNDRV_PCM_FMTBIT_S20_3LE | \ |
390 | SNDRV_PCM_FMTBIT_S24_LE | \ |
391 | SNDRV_PCM_FMTBIT_S32_LE) |
392 | |
393 | static struct snd_soc_dai_driver rockchip_pdm_dai = { |
394 | .capture = { |
395 | .stream_name = "Capture" , |
396 | .channels_min = 2, |
397 | .channels_max = 8, |
398 | .rates = ROCKCHIP_PDM_RATES, |
399 | .formats = ROCKCHIP_PDM_FORMATS, |
400 | }, |
401 | .ops = &rockchip_pdm_dai_ops, |
402 | .symmetric_rate = 1, |
403 | }; |
404 | |
405 | static const struct snd_soc_component_driver rockchip_pdm_component = { |
406 | .name = "rockchip-pdm" , |
407 | .legacy_dai_naming = 1, |
408 | }; |
409 | |
410 | static int rockchip_pdm_runtime_suspend(struct device *dev) |
411 | { |
412 | struct rk_pdm_dev *pdm = dev_get_drvdata(dev); |
413 | |
414 | clk_disable_unprepare(clk: pdm->clk); |
415 | clk_disable_unprepare(clk: pdm->hclk); |
416 | |
417 | return 0; |
418 | } |
419 | |
420 | static int rockchip_pdm_runtime_resume(struct device *dev) |
421 | { |
422 | struct rk_pdm_dev *pdm = dev_get_drvdata(dev); |
423 | int ret; |
424 | |
425 | ret = clk_prepare_enable(clk: pdm->clk); |
426 | if (ret) { |
427 | dev_err(pdm->dev, "clock enable failed %d\n" , ret); |
428 | return ret; |
429 | } |
430 | |
431 | ret = clk_prepare_enable(clk: pdm->hclk); |
432 | if (ret) { |
433 | clk_disable_unprepare(clk: pdm->clk); |
434 | dev_err(pdm->dev, "hclock enable failed %d\n" , ret); |
435 | return ret; |
436 | } |
437 | |
438 | return 0; |
439 | } |
440 | |
441 | static bool rockchip_pdm_wr_reg(struct device *dev, unsigned int reg) |
442 | { |
443 | switch (reg) { |
444 | case PDM_SYSCONFIG: |
445 | case PDM_CTRL0: |
446 | case PDM_CTRL1: |
447 | case PDM_CLK_CTRL: |
448 | case PDM_HPF_CTRL: |
449 | case PDM_FIFO_CTRL: |
450 | case PDM_DMA_CTRL: |
451 | case PDM_INT_EN: |
452 | case PDM_INT_CLR: |
453 | case PDM_DATA_VALID: |
454 | return true; |
455 | default: |
456 | return false; |
457 | } |
458 | } |
459 | |
460 | static bool rockchip_pdm_rd_reg(struct device *dev, unsigned int reg) |
461 | { |
462 | switch (reg) { |
463 | case PDM_SYSCONFIG: |
464 | case PDM_CTRL0: |
465 | case PDM_CTRL1: |
466 | case PDM_CLK_CTRL: |
467 | case PDM_HPF_CTRL: |
468 | case PDM_FIFO_CTRL: |
469 | case PDM_DMA_CTRL: |
470 | case PDM_INT_EN: |
471 | case PDM_INT_CLR: |
472 | case PDM_INT_ST: |
473 | case PDM_DATA_VALID: |
474 | case PDM_RXFIFO_DATA: |
475 | case PDM_VERSION: |
476 | return true; |
477 | default: |
478 | return false; |
479 | } |
480 | } |
481 | |
482 | static bool rockchip_pdm_volatile_reg(struct device *dev, unsigned int reg) |
483 | { |
484 | switch (reg) { |
485 | case PDM_SYSCONFIG: |
486 | case PDM_FIFO_CTRL: |
487 | case PDM_INT_CLR: |
488 | case PDM_INT_ST: |
489 | case PDM_RXFIFO_DATA: |
490 | return true; |
491 | default: |
492 | return false; |
493 | } |
494 | } |
495 | |
496 | static bool rockchip_pdm_precious_reg(struct device *dev, unsigned int reg) |
497 | { |
498 | switch (reg) { |
499 | case PDM_RXFIFO_DATA: |
500 | return true; |
501 | default: |
502 | return false; |
503 | } |
504 | } |
505 | |
506 | static const struct reg_default rockchip_pdm_reg_defaults[] = { |
507 | { PDM_CTRL0, 0x78000017 }, |
508 | { PDM_CTRL1, 0x0bb8ea60 }, |
509 | { PDM_CLK_CTRL, 0x0000e401 }, |
510 | { PDM_DMA_CTRL, 0x0000001f }, |
511 | }; |
512 | |
513 | static const struct regmap_config rockchip_pdm_regmap_config = { |
514 | .reg_bits = 32, |
515 | .reg_stride = 4, |
516 | .val_bits = 32, |
517 | .max_register = PDM_VERSION, |
518 | .reg_defaults = rockchip_pdm_reg_defaults, |
519 | .num_reg_defaults = ARRAY_SIZE(rockchip_pdm_reg_defaults), |
520 | .writeable_reg = rockchip_pdm_wr_reg, |
521 | .readable_reg = rockchip_pdm_rd_reg, |
522 | .volatile_reg = rockchip_pdm_volatile_reg, |
523 | .precious_reg = rockchip_pdm_precious_reg, |
524 | .cache_type = REGCACHE_FLAT, |
525 | }; |
526 | |
527 | static const struct of_device_id rockchip_pdm_match[] __maybe_unused = { |
528 | { .compatible = "rockchip,pdm" , |
529 | .data = (void *)RK_PDM_RK3229 }, |
530 | { .compatible = "rockchip,px30-pdm" , |
531 | .data = (void *)RK_PDM_RK3308 }, |
532 | { .compatible = "rockchip,rk1808-pdm" , |
533 | .data = (void *)RK_PDM_RK3308 }, |
534 | { .compatible = "rockchip,rk3308-pdm" , |
535 | .data = (void *)RK_PDM_RK3308 }, |
536 | { .compatible = "rockchip,rk3568-pdm" , |
537 | .data = (void *)RK_PDM_RV1126 }, |
538 | { .compatible = "rockchip,rv1126-pdm" , |
539 | .data = (void *)RK_PDM_RV1126 }, |
540 | {}, |
541 | }; |
542 | MODULE_DEVICE_TABLE(of, rockchip_pdm_match); |
543 | |
544 | static int rockchip_pdm_path_parse(struct rk_pdm_dev *pdm, struct device_node *node) |
545 | { |
546 | unsigned int path[PDM_PATH_MAX]; |
547 | int cnt = 0, ret = 0, i = 0, val = 0, msk = 0; |
548 | |
549 | cnt = of_count_phandle_with_args(np: node, list_name: "rockchip,path-map" , |
550 | NULL); |
551 | if (cnt != PDM_PATH_MAX) |
552 | return cnt; |
553 | |
554 | ret = of_property_read_u32_array(np: node, propname: "rockchip,path-map" , |
555 | out_values: path, sz: cnt); |
556 | if (ret) |
557 | return ret; |
558 | |
559 | for (i = 0; i < cnt; i++) { |
560 | if (path[i] >= PDM_PATH_MAX) |
561 | return -EINVAL; |
562 | msk |= PDM_PATH_MASK(i); |
563 | val |= PDM_PATH(i, path[i]); |
564 | } |
565 | |
566 | regmap_update_bits(map: pdm->regmap, PDM_CLK_CTRL, mask: msk, val); |
567 | |
568 | return 0; |
569 | } |
570 | |
571 | static int rockchip_pdm_probe(struct platform_device *pdev) |
572 | { |
573 | struct device_node *node = pdev->dev.of_node; |
574 | struct rk_pdm_dev *pdm; |
575 | struct resource *res; |
576 | void __iomem *regs; |
577 | int ret; |
578 | |
579 | pdm = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pdm), GFP_KERNEL); |
580 | if (!pdm) |
581 | return -ENOMEM; |
582 | |
583 | pdm->version = (enum rk_pdm_version)device_get_match_data(dev: &pdev->dev); |
584 | if (pdm->version == RK_PDM_RK3308) { |
585 | pdm->reset = devm_reset_control_get(dev: &pdev->dev, id: "pdm-m" ); |
586 | if (IS_ERR(ptr: pdm->reset)) |
587 | return PTR_ERR(ptr: pdm->reset); |
588 | } |
589 | |
590 | regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
591 | if (IS_ERR(ptr: regs)) |
592 | return PTR_ERR(ptr: regs); |
593 | |
594 | pdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs, |
595 | &rockchip_pdm_regmap_config); |
596 | if (IS_ERR(ptr: pdm->regmap)) |
597 | return PTR_ERR(ptr: pdm->regmap); |
598 | |
599 | pdm->capture_dma_data.addr = res->start + PDM_RXFIFO_DATA; |
600 | pdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
601 | pdm->capture_dma_data.maxburst = PDM_DMA_BURST_SIZE; |
602 | |
603 | pdm->dev = &pdev->dev; |
604 | dev_set_drvdata(dev: &pdev->dev, data: pdm); |
605 | |
606 | pdm->clk = devm_clk_get(dev: &pdev->dev, id: "pdm_clk" ); |
607 | if (IS_ERR(ptr: pdm->clk)) |
608 | return PTR_ERR(ptr: pdm->clk); |
609 | |
610 | pdm->hclk = devm_clk_get(dev: &pdev->dev, id: "pdm_hclk" ); |
611 | if (IS_ERR(ptr: pdm->hclk)) |
612 | return PTR_ERR(ptr: pdm->hclk); |
613 | |
614 | ret = clk_prepare_enable(clk: pdm->hclk); |
615 | if (ret) |
616 | return ret; |
617 | |
618 | pm_runtime_enable(dev: &pdev->dev); |
619 | if (!pm_runtime_enabled(dev: &pdev->dev)) { |
620 | ret = rockchip_pdm_runtime_resume(dev: &pdev->dev); |
621 | if (ret) |
622 | goto err_pm_disable; |
623 | } |
624 | |
625 | ret = devm_snd_soc_register_component(dev: &pdev->dev, |
626 | component_driver: &rockchip_pdm_component, |
627 | dai_drv: &rockchip_pdm_dai, num_dai: 1); |
628 | |
629 | if (ret) { |
630 | dev_err(&pdev->dev, "could not register dai: %d\n" , ret); |
631 | goto err_suspend; |
632 | } |
633 | |
634 | rockchip_pdm_rxctrl(pdm, on: 0); |
635 | |
636 | ret = rockchip_pdm_path_parse(pdm, node); |
637 | if (ret != 0 && ret != -ENOENT) |
638 | goto err_suspend; |
639 | |
640 | ret = devm_snd_dmaengine_pcm_register(dev: &pdev->dev, NULL, flags: 0); |
641 | if (ret) { |
642 | dev_err(&pdev->dev, "could not register pcm: %d\n" , ret); |
643 | goto err_suspend; |
644 | } |
645 | |
646 | return 0; |
647 | |
648 | err_suspend: |
649 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
650 | rockchip_pdm_runtime_suspend(dev: &pdev->dev); |
651 | err_pm_disable: |
652 | pm_runtime_disable(dev: &pdev->dev); |
653 | |
654 | clk_disable_unprepare(clk: pdm->hclk); |
655 | |
656 | return ret; |
657 | } |
658 | |
659 | static void rockchip_pdm_remove(struct platform_device *pdev) |
660 | { |
661 | struct rk_pdm_dev *pdm = dev_get_drvdata(dev: &pdev->dev); |
662 | |
663 | pm_runtime_disable(dev: &pdev->dev); |
664 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
665 | rockchip_pdm_runtime_suspend(dev: &pdev->dev); |
666 | |
667 | clk_disable_unprepare(clk: pdm->clk); |
668 | clk_disable_unprepare(clk: pdm->hclk); |
669 | } |
670 | |
671 | #ifdef CONFIG_PM_SLEEP |
672 | static int rockchip_pdm_suspend(struct device *dev) |
673 | { |
674 | struct rk_pdm_dev *pdm = dev_get_drvdata(dev); |
675 | |
676 | regcache_mark_dirty(map: pdm->regmap); |
677 | |
678 | return 0; |
679 | } |
680 | |
681 | static int rockchip_pdm_resume(struct device *dev) |
682 | { |
683 | struct rk_pdm_dev *pdm = dev_get_drvdata(dev); |
684 | int ret; |
685 | |
686 | ret = pm_runtime_resume_and_get(dev); |
687 | if (ret < 0) |
688 | return ret; |
689 | |
690 | ret = regcache_sync(map: pdm->regmap); |
691 | |
692 | pm_runtime_put(dev); |
693 | |
694 | return ret; |
695 | } |
696 | #endif |
697 | |
698 | static const struct dev_pm_ops rockchip_pdm_pm_ops = { |
699 | SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend, |
700 | rockchip_pdm_runtime_resume, NULL) |
701 | SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) |
702 | }; |
703 | |
704 | static struct platform_driver rockchip_pdm_driver = { |
705 | .probe = rockchip_pdm_probe, |
706 | .remove_new = rockchip_pdm_remove, |
707 | .driver = { |
708 | .name = "rockchip-pdm" , |
709 | .of_match_table = of_match_ptr(rockchip_pdm_match), |
710 | .pm = &rockchip_pdm_pm_ops, |
711 | }, |
712 | }; |
713 | |
714 | module_platform_driver(rockchip_pdm_driver); |
715 | |
716 | MODULE_AUTHOR("Sugar <sugar.zhang@rock-chips.com>" ); |
717 | MODULE_DESCRIPTION("Rockchip PDM Controller Driver" ); |
718 | MODULE_LICENSE("GPL v2" ); |
719 | |