Skip to content

Commit 34255cb

Browse files
committed
drivers: pwm: Add PWM driver for SOPHGO CVI series
This commit adds PWM driver for CVI series SoCs. Signed-off-by: Chen Xingyu <[email protected]>
1 parent 5f0b7a7 commit 34255cb

File tree

7 files changed

+246
-0
lines changed

7 files changed

+246
-0
lines changed

drivers/pwm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_FAKE pwm_fake.c)
5454
zephyr_library_sources_ifdef(CONFIG_PWM_RENESAS_RZ_GPT pwm_renesas_rz_gpt.c)
5555
zephyr_library_sources_ifdef(CONFIG_PWM_NEORV32 pwm_neorv32.c)
5656
zephyr_library_sources_ifdef(CONFIG_PWM_WCH_GPTM pwm_wch_gptm.c)
57+
zephyr_library_sources_ifdef(CONFIG_PWM_SOPHGO_CVI pwm_sophgo_cvi.c)
5758

5859
zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c)
5960
zephyr_library_sources_ifdef(CONFIG_PWM_CAPTURE pwm_capture.c)

drivers/pwm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,6 @@ source "drivers/pwm/Kconfig.neorv32"
130130

131131
source "drivers/pwm/Kconfig.wch"
132132

133+
source "drivers/pwm/Kconfig.sophgo"
134+
133135
endif # PWM

drivers/pwm/Kconfig.sophgo

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2023-2024 Chen Xingyu <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config PWM_SOPHGO_CVI
5+
bool "SOPHGO CVI series PWM driver"
6+
default y
7+
depends on DT_HAS_SOPHGO_CVI_PWM_ENABLED
8+
help
9+
Enables support for the SOPHGO CVI series PWM.

drivers/pwm/pwm_sophgo_cvi.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright (c) 2023-2024 Chen Xingyu <[email protected]>
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT sophgo_cvi_pwm
7+
8+
#include <zephyr/arch/cpu.h>
9+
#include <zephyr/device.h>
10+
#include <zephyr/drivers/pwm.h>
11+
#if defined(CONFIG_PINCTRL)
12+
#include <zephyr/drivers/pinctrl.h>
13+
#endif /* CONFIG_PINCTRL */
14+
15+
#define HLPERIOD(base, n) (base + 0x000 + (n) * 8)
16+
#define PERIOD(base, n) (base + 0x004 + (n) * 8)
17+
#define PWMCONFIG(base) (base + 0x040)
18+
#define PWMSTART(base) (base + 0x044)
19+
#define PWMDONE(base) (base + 0x048)
20+
#define PWMUPDATE(base) (base + 0x04c)
21+
#define PCOUNT(base, n) (base + 0x050 + (n) * 4)
22+
#define PULSECOUNT(base, n) (base + 0x060 + (n) * 4)
23+
#define SHIFTCOUNT(base, n) (base + 0x080 + (n) * 4)
24+
#define SHIFTSTART(base) (base + 0x090)
25+
#define PWM_OE(base) (base + 0x0d0)
26+
27+
/* PWMCONFIG */
28+
#define CFG_POLARITY(n) BIT(n + 0)
29+
#define CFG_PWMMODE(n) BIT(n + 8)
30+
#define CFG_SHIFTMODE BIT(16)
31+
32+
#define PWM_CH_MAX 4
33+
34+
struct pwm_cvi_config {
35+
mm_reg_t base;
36+
uint32_t clk_pwm;
37+
#if defined(CONFIG_PINCTRL)
38+
const struct pinctrl_dev_config *pcfg;
39+
#endif /* CONFIG_PINCTRL */
40+
};
41+
42+
static int pwm_cvi_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles,
43+
uint32_t pulse_cycles, pwm_flags_t flags)
44+
{
45+
const struct pwm_cvi_config *cfg = dev->config;
46+
uint32_t regval;
47+
48+
if (channel > PWM_CH_MAX) {
49+
return -EINVAL;
50+
}
51+
52+
if (period_cycles > cfg->clk_pwm) {
53+
return -EINVAL;
54+
}
55+
56+
if (pulse_cycles >= period_cycles) {
57+
pulse_cycles = period_cycles - 1;
58+
}
59+
60+
/* Configure output */
61+
regval = sys_read32(PWM_OE(cfg->base));
62+
regval |= BIT(channel);
63+
sys_write32(regval, PWM_OE(cfg->base));
64+
65+
/* Set polarity and mode */
66+
regval = sys_read32(PWMCONFIG(cfg->base));
67+
if (flags & PWM_POLARITY_INVERTED) {
68+
regval &= ~CFG_POLARITY(channel); /* active low */
69+
} else {
70+
regval |= CFG_POLARITY(channel); /* active high */
71+
}
72+
regval &= ~CFG_PWMMODE(channel); /* continuous mode */
73+
sys_write32(regval, PWMCONFIG(cfg->base));
74+
75+
/* Set period and pulse */
76+
sys_write32(period_cycles, PERIOD(cfg->base, channel));
77+
sys_write32(pulse_cycles, HLPERIOD(cfg->base, channel));
78+
79+
if (sys_read32(PWMSTART(cfg->base)) & BIT(channel)) {
80+
/* Update channel */
81+
regval = sys_read32(PWMUPDATE(cfg->base));
82+
regval |= BIT(channel);
83+
sys_write32(regval, PWMUPDATE(cfg->base));
84+
regval &= ~BIT(channel);
85+
sys_write32(regval, PWMUPDATE(cfg->base));
86+
} else {
87+
/* Start channel */
88+
regval = sys_read32(PWMSTART(cfg->base));
89+
regval &= ~BIT(channel);
90+
sys_write32(regval, PWMSTART(cfg->base));
91+
regval |= BIT(channel);
92+
sys_write32(regval, PWMSTART(cfg->base));
93+
}
94+
95+
return 0;
96+
}
97+
98+
static int pwm_cvi_get_cycles_per_sec(const struct device *dev, uint32_t channel, uint64_t *cycles)
99+
{
100+
const struct pwm_cvi_config *cfg = dev->config;
101+
102+
if (channel > PWM_CH_MAX) {
103+
return -EINVAL;
104+
}
105+
106+
*cycles = cfg->clk_pwm;
107+
108+
return 0;
109+
}
110+
111+
static int pwm_cvi_init(const struct device *dev)
112+
{
113+
#if defined(CONFIG_PINCTRL)
114+
const struct pwm_cvi_config *cfg = dev->config;
115+
int ret;
116+
117+
ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
118+
if (ret < 0) {
119+
return ret;
120+
}
121+
#endif /* CONFIG_PINCTRL */
122+
123+
return 0;
124+
}
125+
126+
static DEVICE_API(pwm, pwm_cvi_api) = {
127+
.set_cycles = pwm_cvi_set_cycles,
128+
.get_cycles_per_sec = pwm_cvi_get_cycles_per_sec,
129+
};
130+
131+
#define PWM_CVI_INST(n) \
132+
IF_ENABLED(CONFIG_PINCTRL, (PINCTRL_DT_INST_DEFINE(n);)) \
133+
\
134+
static const struct pwm_cvi_config pwm_cvi_cfg_##n = { \
135+
.base = DT_INST_REG_ADDR(n), \
136+
.clk_pwm = DT_INST_PROP(n, clock_frequency), \
137+
IF_ENABLED(CONFIG_PINCTRL, (.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),)) \
138+
}; \
139+
\
140+
DEVICE_DT_INST_DEFINE(n, &pwm_cvi_init, NULL, NULL, &pwm_cvi_cfg_##n, PRE_KERNEL_1, \
141+
CONFIG_PWM_INIT_PRIORITY, &pwm_cvi_api);
142+
143+
DT_INST_FOREACH_STATUS_OKAY(PWM_CVI_INST)

dts/bindings/pwm/sophgo,cvi-pwm.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2023-2024 Chen Xingyu <[email protected]>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: SOPHGO CVI series PWM
5+
6+
compatible: "sophgo,cvi-pwm"
7+
8+
include: [pwm-controller.yaml, pinctrl-device.yaml, base.yaml]
9+
10+
properties:
11+
clock-frequency:
12+
type: int
13+
required: true
14+
15+
pinctrl-0:
16+
required: true
17+
18+
pinctrl-names:
19+
required: true
20+
21+
"#pwm-cells":
22+
const: 3
23+
24+
pwm-cells:
25+
- channel
26+
- period
27+
- flags

dts/riscv/sophgo/cv180x.dtsi

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,38 @@
5454
status = "disabled";
5555
};
5656

57+
pwm0: pwm@3060000 {
58+
compatible = "sophgo,cvi-pwm";
59+
reg = <0x3060000 DT_SIZE_K(4)>;
60+
clock-frequency = <DT_FREQ_M(100)>;
61+
#pwm-cells = <3>;
62+
status = "disabled";
63+
};
64+
65+
pwm1: pwm@3061000 {
66+
compatible = "sophgo,cvi-pwm";
67+
reg = <0x3061000 DT_SIZE_K(4)>;
68+
clock-frequency = <DT_FREQ_M(100)>;
69+
#pwm-cells = <3>;
70+
status = "disabled";
71+
};
72+
73+
pwm2: pwm@3062000 {
74+
compatible = "sophgo,cvi-pwm";
75+
reg = <0x3062000 DT_SIZE_K(4)>;
76+
clock-frequency = <DT_FREQ_M(100)>;
77+
#pwm-cells = <3>;
78+
status = "disabled";
79+
};
80+
81+
pwm3: pwm@3063000 {
82+
compatible = "sophgo,cvi-pwm";
83+
reg = <0x3063000 DT_SIZE_K(4)>;
84+
clock-frequency = <DT_FREQ_M(100)>;
85+
#pwm-cells = <3>;
86+
status = "disabled";
87+
};
88+
5789
uart0: uart@4140000 {
5890
compatible = "ns16550";
5991
reg = <0x4140000 DT_SIZE_K(64)>;

dts/riscv/sophgo/cv181x.dtsi

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,38 @@
5454
status = "disabled";
5555
};
5656

57+
pwm0: pwm@3060000 {
58+
compatible = "sophgo,cvi-pwm";
59+
reg = <0x3060000 DT_SIZE_K(4)>;
60+
clock-frequency = <DT_FREQ_M(100)>;
61+
#pwm-cells = <3>;
62+
status = "disabled";
63+
};
64+
65+
pwm1: pwm@3061000 {
66+
compatible = "sophgo,cvi-pwm";
67+
reg = <0x3061000 DT_SIZE_K(4)>;
68+
clock-frequency = <DT_FREQ_M(100)>;
69+
#pwm-cells = <3>;
70+
status = "disabled";
71+
};
72+
73+
pwm2: pwm@3062000 {
74+
compatible = "sophgo,cvi-pwm";
75+
reg = <0x3062000 DT_SIZE_K(4)>;
76+
clock-frequency = <DT_FREQ_M(100)>;
77+
#pwm-cells = <3>;
78+
status = "disabled";
79+
};
80+
81+
pwm3: pwm@3063000 {
82+
compatible = "sophgo,cvi-pwm";
83+
reg = <0x3063000 DT_SIZE_K(4)>;
84+
clock-frequency = <DT_FREQ_M(100)>;
85+
#pwm-cells = <3>;
86+
status = "disabled";
87+
};
88+
5789
uart0: uart@4140000 {
5890
compatible = "ns16550";
5991
reg = <0x4140000 DT_SIZE_K(64)>;

0 commit comments

Comments
 (0)