1 // SPDX-License-Identifier: GPL-2.0
3 * jh7110_pwmdac.c -- StarFive JH7110 PWM-DAC driver
5 * Copyright (C) 2021-2023 StarFive Technology Co., Ltd.
9 * Xingyu Wu <xingyu.wu@starfivetech.com>
10 * Hal Feng <hal.feng@starfivetech.com>
13 #include <linux/clk.h>
14 #include <linux/device.h>
15 #include <linux/init.h>
16 #include <linux/interrupt.h>
18 #include <linux/module.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/reset.h>
21 #include <linux/slab.h>
22 #include <linux/types.h>
23 #include <sound/dmaengine_pcm.h>
24 #include <sound/pcm.h>
25 #include <sound/pcm_params.h>
26 #include <sound/soc.h>
28 #define JH7110_PWMDAC_WDATA 0x00
29 #define JH7110_PWMDAC_CTRL 0x04
30 #define JH7110_PWMDAC_ENABLE BIT(0)
31 #define JH7110_PWMDAC_SHIFT BIT(1)
32 #define JH7110_PWMDAC_DUTY_CYCLE_SHIFT 2
33 #define JH7110_PWMDAC_DUTY_CYCLE_MASK GENMASK(3, 2)
34 #define JH7110_PWMDAC_CNT_N_SHIFT 4
35 #define JH7110_PWMDAC_CNT_N_MASK GENMASK(12, 4)
36 #define JH7110_PWMDAC_DATA_CHANGE BIT(13)
37 #define JH7110_PWMDAC_DATA_MODE BIT(14)
38 #define JH7110_PWMDAC_DATA_SHIFT_SHIFT 15
39 #define JH7110_PWMDAC_DATA_SHIFT_MASK GENMASK(17, 15)
41 enum JH7110_PWMDAC_SHIFT_VAL
{
46 enum JH7110_PWMDAC_DUTY_CYCLE_VAL
{
47 PWMDAC_CYCLE_LEFT
= 0,
52 enum JH7110_PWMDAC_CNT_N_VAL
{
53 PWMDAC_SAMPLE_CNT_1
= 1,
56 PWMDAC_SAMPLE_CNT_512
= 512, /* max */
59 enum JH7110_PWMDAC_DATA_CHANGE_VAL
{
64 enum JH7110_PWMDAC_DATA_MODE_VAL
{
69 enum JH7110_PWMDAC_DATA_SHIFT_VAL
{
70 PWMDAC_DATA_LEFT_SHIFT_BIT_0
= 0,
71 PWMDAC_DATA_LEFT_SHIFT_BIT_1
,
72 PWMDAC_DATA_LEFT_SHIFT_BIT_2
,
73 PWMDAC_DATA_LEFT_SHIFT_BIT_3
,
74 PWMDAC_DATA_LEFT_SHIFT_BIT_4
,
75 PWMDAC_DATA_LEFT_SHIFT_BIT_5
,
76 PWMDAC_DATA_LEFT_SHIFT_BIT_6
,
77 PWMDAC_DATA_LEFT_SHIFT_BIT_7
,
80 struct jh7110_pwmdac_cfg
{
81 enum JH7110_PWMDAC_SHIFT_VAL shift
;
82 enum JH7110_PWMDAC_DUTY_CYCLE_VAL duty_cycle
;
84 enum JH7110_PWMDAC_DATA_CHANGE_VAL data_change
;
85 enum JH7110_PWMDAC_DATA_MODE_VAL data_mode
;
86 enum JH7110_PWMDAC_DATA_SHIFT_VAL data_shift
;
89 struct jh7110_pwmdac_dev
{
91 resource_size_t mapbase
;
92 struct jh7110_pwmdac_cfg cfg
;
94 struct clk_bulk_data clks
[2];
95 struct reset_control
*rst_apb
;
97 struct snd_dmaengine_dai_dma_data play_dma_data
;
101 static inline void jh7110_pwmdac_write_reg(void __iomem
*io_base
, int reg
, u32 val
)
103 writel(val
, io_base
+ reg
);
106 static inline u32
jh7110_pwmdac_read_reg(void __iomem
*io_base
, int reg
)
108 return readl(io_base
+ reg
);
111 static void jh7110_pwmdac_set_enable(struct jh7110_pwmdac_dev
*dev
, bool enable
)
115 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
117 value
|= JH7110_PWMDAC_ENABLE
;
119 value
&= ~JH7110_PWMDAC_ENABLE
;
121 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
124 static void jh7110_pwmdac_set_shift(struct jh7110_pwmdac_dev
*dev
)
128 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
129 if (dev
->cfg
.shift
== PWMDAC_SHIFT_8
)
130 value
&= ~JH7110_PWMDAC_SHIFT
;
131 else if (dev
->cfg
.shift
== PWMDAC_SHIFT_10
)
132 value
|= JH7110_PWMDAC_SHIFT
;
134 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
137 static void jh7110_pwmdac_set_duty_cycle(struct jh7110_pwmdac_dev
*dev
)
141 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
142 value
&= ~JH7110_PWMDAC_DUTY_CYCLE_MASK
;
143 value
|= (dev
->cfg
.duty_cycle
& 0x3) << JH7110_PWMDAC_DUTY_CYCLE_SHIFT
;
145 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
148 static void jh7110_pwmdac_set_cnt_n(struct jh7110_pwmdac_dev
*dev
)
152 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
153 value
&= ~JH7110_PWMDAC_CNT_N_MASK
;
154 value
|= ((dev
->cfg
.cnt_n
- 1) & 0x1ff) << JH7110_PWMDAC_CNT_N_SHIFT
;
156 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
159 static void jh7110_pwmdac_set_data_change(struct jh7110_pwmdac_dev
*dev
)
163 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
164 if (dev
->cfg
.data_change
== NO_CHANGE
)
165 value
&= ~JH7110_PWMDAC_DATA_CHANGE
;
166 else if (dev
->cfg
.data_change
== CHANGE
)
167 value
|= JH7110_PWMDAC_DATA_CHANGE
;
169 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
172 static void jh7110_pwmdac_set_data_mode(struct jh7110_pwmdac_dev
*dev
)
176 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
177 if (dev
->cfg
.data_mode
== UNSIGNED_DATA
)
178 value
&= ~JH7110_PWMDAC_DATA_MODE
;
179 else if (dev
->cfg
.data_mode
== INVERTER_DATA_MSB
)
180 value
|= JH7110_PWMDAC_DATA_MODE
;
182 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
185 static void jh7110_pwmdac_set_data_shift(struct jh7110_pwmdac_dev
*dev
)
189 value
= jh7110_pwmdac_read_reg(dev
->base
, JH7110_PWMDAC_CTRL
);
190 value
&= ~JH7110_PWMDAC_DATA_SHIFT_MASK
;
191 value
|= (dev
->cfg
.data_shift
& 0x7) << JH7110_PWMDAC_DATA_SHIFT_SHIFT
;
193 jh7110_pwmdac_write_reg(dev
->base
, JH7110_PWMDAC_CTRL
, value
);
196 static void jh7110_pwmdac_set(struct jh7110_pwmdac_dev
*dev
)
198 jh7110_pwmdac_set_shift(dev
);
199 jh7110_pwmdac_set_duty_cycle(dev
);
200 jh7110_pwmdac_set_cnt_n(dev
);
201 jh7110_pwmdac_set_enable(dev
, true);
203 jh7110_pwmdac_set_data_change(dev
);
204 jh7110_pwmdac_set_data_mode(dev
);
205 jh7110_pwmdac_set_data_shift(dev
);
208 static void jh7110_pwmdac_stop(struct jh7110_pwmdac_dev
*dev
)
210 jh7110_pwmdac_set_enable(dev
, false);
213 static int jh7110_pwmdac_startup(struct snd_pcm_substream
*substream
,
214 struct snd_soc_dai
*dai
)
216 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
217 struct snd_soc_dai_link
*dai_link
= rtd
->dai_link
;
219 dai_link
->trigger_stop
= SND_SOC_TRIGGER_ORDER_LDC
;
224 static int jh7110_pwmdac_hw_params(struct snd_pcm_substream
*substream
,
225 struct snd_pcm_hw_params
*params
,
226 struct snd_soc_dai
*dai
)
228 struct jh7110_pwmdac_dev
*dev
= dev_get_drvdata(dai
->dev
);
229 unsigned long core_clk_rate
;
232 switch (params_rate(params
)) {
234 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_3
;
235 core_clk_rate
= 6144000;
238 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_2
;
239 core_clk_rate
= 5644800;
242 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_3
;
243 core_clk_rate
= 12288000;
246 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_1
;
247 core_clk_rate
= 5644800;
250 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_1
;
251 core_clk_rate
= 8192000;
254 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_1
;
255 core_clk_rate
= 11289600;
258 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_1
;
259 core_clk_rate
= 12288000;
262 dev_err(dai
->dev
, "%d rate not supported\n",
263 params_rate(params
));
267 switch (params_channels(params
)) {
269 dev
->play_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_2_BYTES
;
272 dev
->play_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
275 dev_err(dai
->dev
, "%d channels not supported\n",
276 params_channels(params
));
281 * The clock rate always rounds down when using clk_set_rate()
282 * so increase the rate a bit
285 jh7110_pwmdac_set(dev
);
287 ret
= clk_set_rate(dev
->clks
[1].clk
, core_clk_rate
);
289 return dev_err_probe(dai
->dev
, ret
,
290 "failed to set rate %lu for core clock\n",
296 static int jh7110_pwmdac_trigger(struct snd_pcm_substream
*substream
, int cmd
,
297 struct snd_soc_dai
*dai
)
299 struct jh7110_pwmdac_dev
*dev
= snd_soc_dai_get_drvdata(dai
);
303 case SNDRV_PCM_TRIGGER_START
:
304 case SNDRV_PCM_TRIGGER_RESUME
:
305 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
306 jh7110_pwmdac_set(dev
);
309 case SNDRV_PCM_TRIGGER_STOP
:
310 case SNDRV_PCM_TRIGGER_SUSPEND
:
311 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
312 jh7110_pwmdac_stop(dev
);
322 static int jh7110_pwmdac_crg_enable(struct jh7110_pwmdac_dev
*dev
, bool enable
)
327 ret
= clk_bulk_prepare_enable(ARRAY_SIZE(dev
->clks
), dev
->clks
);
329 return dev_err_probe(dev
->dev
, ret
,
330 "failed to enable pwmdac clocks\n");
332 ret
= reset_control_deassert(dev
->rst_apb
);
334 dev_err(dev
->dev
, "failed to deassert pwmdac apb reset\n");
338 clk_bulk_disable_unprepare(ARRAY_SIZE(dev
->clks
), dev
->clks
);
344 clk_bulk_disable_unprepare(ARRAY_SIZE(dev
->clks
), dev
->clks
);
349 static int jh7110_pwmdac_dai_probe(struct snd_soc_dai
*dai
)
351 struct jh7110_pwmdac_dev
*dev
= dev_get_drvdata(dai
->dev
);
353 snd_soc_dai_init_dma_data(dai
, &dev
->play_dma_data
, NULL
);
354 snd_soc_dai_set_drvdata(dai
, dev
);
359 static const struct snd_soc_dai_ops jh7110_pwmdac_dai_ops
= {
360 .probe
= jh7110_pwmdac_dai_probe
,
361 .startup
= jh7110_pwmdac_startup
,
362 .hw_params
= jh7110_pwmdac_hw_params
,
363 .trigger
= jh7110_pwmdac_trigger
,
366 static const struct snd_soc_component_driver jh7110_pwmdac_component
= {
367 .name
= "jh7110-pwmdac",
370 static struct snd_soc_dai_driver jh7110_pwmdac_dai
= {
371 .name
= "jh7110-pwmdac",
376 .rates
= SNDRV_PCM_RATE_8000_48000
,
377 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
379 .ops
= &jh7110_pwmdac_dai_ops
,
382 static int jh7110_pwmdac_runtime_suspend(struct device
*dev
)
384 struct jh7110_pwmdac_dev
*pwmdac
= dev_get_drvdata(dev
);
386 return jh7110_pwmdac_crg_enable(pwmdac
, false);
389 static int jh7110_pwmdac_runtime_resume(struct device
*dev
)
391 struct jh7110_pwmdac_dev
*pwmdac
= dev_get_drvdata(dev
);
393 return jh7110_pwmdac_crg_enable(pwmdac
, true);
396 static int jh7110_pwmdac_system_suspend(struct device
*dev
)
398 struct jh7110_pwmdac_dev
*pwmdac
= dev_get_drvdata(dev
);
400 /* save the CTRL register value */
401 pwmdac
->saved_ctrl
= jh7110_pwmdac_read_reg(pwmdac
->base
,
403 return pm_runtime_force_suspend(dev
);
406 static int jh7110_pwmdac_system_resume(struct device
*dev
)
408 struct jh7110_pwmdac_dev
*pwmdac
= dev_get_drvdata(dev
);
411 ret
= pm_runtime_force_resume(dev
);
415 /* restore the CTRL register value */
416 jh7110_pwmdac_write_reg(pwmdac
->base
, JH7110_PWMDAC_CTRL
,
421 static const struct dev_pm_ops jh7110_pwmdac_pm_ops
= {
422 RUNTIME_PM_OPS(jh7110_pwmdac_runtime_suspend
,
423 jh7110_pwmdac_runtime_resume
, NULL
)
424 SYSTEM_SLEEP_PM_OPS(jh7110_pwmdac_system_suspend
,
425 jh7110_pwmdac_system_resume
)
428 static void jh7110_pwmdac_init_params(struct jh7110_pwmdac_dev
*dev
)
430 dev
->cfg
.shift
= PWMDAC_SHIFT_8
;
431 dev
->cfg
.duty_cycle
= PWMDAC_CYCLE_CENTER
;
432 dev
->cfg
.cnt_n
= PWMDAC_SAMPLE_CNT_1
;
433 dev
->cfg
.data_change
= NO_CHANGE
;
434 dev
->cfg
.data_mode
= INVERTER_DATA_MSB
;
435 dev
->cfg
.data_shift
= PWMDAC_DATA_LEFT_SHIFT_BIT_0
;
437 dev
->play_dma_data
.addr
= dev
->mapbase
+ JH7110_PWMDAC_WDATA
;
438 dev
->play_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
439 dev
->play_dma_data
.fifo_size
= 1;
440 dev
->play_dma_data
.maxburst
= 16;
443 static int jh7110_pwmdac_probe(struct platform_device
*pdev
)
445 struct jh7110_pwmdac_dev
*dev
;
446 struct resource
*res
;
449 dev
= devm_kzalloc(&pdev
->dev
, sizeof(*dev
), GFP_KERNEL
);
453 dev
->base
= devm_platform_get_and_ioremap_resource(pdev
, 0, &res
);
454 if (IS_ERR(dev
->base
))
455 return PTR_ERR(dev
->base
);
457 dev
->mapbase
= res
->start
;
459 dev
->clks
[0].id
= "apb";
460 dev
->clks
[1].id
= "core";
462 ret
= devm_clk_bulk_get(&pdev
->dev
, ARRAY_SIZE(dev
->clks
), dev
->clks
);
464 return dev_err_probe(&pdev
->dev
, ret
,
465 "failed to get pwmdac clocks\n");
467 dev
->rst_apb
= devm_reset_control_get_exclusive(&pdev
->dev
, NULL
);
468 if (IS_ERR(dev
->rst_apb
))
469 return dev_err_probe(&pdev
->dev
, PTR_ERR(dev
->rst_apb
),
470 "failed to get pwmdac apb reset\n");
472 jh7110_pwmdac_init_params(dev
);
474 dev
->dev
= &pdev
->dev
;
475 dev_set_drvdata(&pdev
->dev
, dev
);
476 ret
= devm_snd_soc_register_component(&pdev
->dev
,
477 &jh7110_pwmdac_component
,
478 &jh7110_pwmdac_dai
, 1);
480 return dev_err_probe(&pdev
->dev
, ret
, "failed to register dai\n");
482 ret
= devm_snd_dmaengine_pcm_register(&pdev
->dev
, NULL
, 0);
484 return dev_err_probe(&pdev
->dev
, ret
, "failed to register pcm\n");
486 pm_runtime_enable(dev
->dev
);
487 if (!pm_runtime_enabled(&pdev
->dev
)) {
488 ret
= jh7110_pwmdac_runtime_resume(&pdev
->dev
);
496 pm_runtime_disable(&pdev
->dev
);
501 static void jh7110_pwmdac_remove(struct platform_device
*pdev
)
503 pm_runtime_disable(&pdev
->dev
);
506 static const struct of_device_id jh7110_pwmdac_of_match
[] = {
507 { .compatible
= "starfive,jh7110-pwmdac" },
510 MODULE_DEVICE_TABLE(of
, jh7110_pwmdac_of_match
);
512 static struct platform_driver jh7110_pwmdac_driver
= {
514 .name
= "jh7110-pwmdac",
515 .of_match_table
= jh7110_pwmdac_of_match
,
516 .pm
= pm_ptr(&jh7110_pwmdac_pm_ops
),
518 .probe
= jh7110_pwmdac_probe
,
519 .remove
= jh7110_pwmdac_remove
,
521 module_platform_driver(jh7110_pwmdac_driver
);
523 MODULE_AUTHOR("Jenny Zhang");
524 MODULE_AUTHOR("Curry Zhang");
525 MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
526 MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>");
527 MODULE_DESCRIPTION("StarFive JH7110 PWM-DAC driver");
528 MODULE_LICENSE("GPL");