Skip to content

Commit 7ce78aa

Browse files
ene-stevenkartben
authored andcommitted
drivers: pwm: pwm driver
Add pwm driver for ENE KB106X Signed-off-by: Steven Chang <[email protected]>
1 parent bffb153 commit 7ce78aa

File tree

7 files changed

+323
-0
lines changed

7 files changed

+323
-0
lines changed

drivers/pwm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_MSPM0 pwm_mspm0.c)
5050
zephyr_library_sources_ifdef(CONFIG_PWM_NUMAKER pwm_numaker.c)
5151
zephyr_library_sources_ifdef(CONFIG_PWM_NXP_FLEXIO pwm_nxp_flexio.c)
5252
zephyr_library_sources_ifdef(CONFIG_PWM_NXP_S32_EMIOS pwm_nxp_s32_emios.c)
53+
zephyr_library_sources_ifdef(CONFIG_PWM_ENE_KB106X pwm_ene_kb106x.c)
5354
zephyr_library_sources_ifdef(CONFIG_PWM_ENE_KB1200 pwm_ene_kb1200.c)
5455
zephyr_library_sources_ifdef(CONFIG_PWM_RENESAS_RA pwm_renesas_ra.c)
5556
zephyr_library_sources_ifdef(CONFIG_PWM_RENESAS_RX_MTU pwm_renesas_rx_mtu.c)

drivers/pwm/Kconfig.ene

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ config PWM_ENE_KB1200
88
select PINCTRL
99
help
1010
This option enables the PWM driver for KB1200 processors.
11+
12+
config PWM_ENE_KB106X
13+
bool "ENE KB106X PWM driver"
14+
default y
15+
depends on DT_HAS_ENE_KB106X_PWM_ENABLED
16+
select PINCTRL
17+
help
18+
This option enables the PWM driver for KB106X processors.

drivers/pwm/pwm_ene_kb106x.c

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) 2025 ENE Technology Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ene_kb106x_pwm
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/drivers/pwm.h>
10+
#include <zephyr/drivers/pinctrl.h>
11+
#include <reg/pwm.h>
12+
13+
/* Device config */
14+
struct pwm_kb106x_config {
15+
/* pwm controller base address */
16+
struct pwm_regs *pwm;
17+
const struct pinctrl_dev_config *pcfg;
18+
};
19+
20+
/* Driver data */
21+
struct pwm_kb106x_data {
22+
/* PWM cycles per second */
23+
uint32_t cycles_per_sec;
24+
};
25+
26+
/* PWM api functions */
27+
static int pwm_kb106x_set_cycles(const struct device *dev, uint32_t channel, uint32_t period_cycles,
28+
uint32_t pulse_cycles, pwm_flags_t flags)
29+
{
30+
/* Single channel for each pwm device */
31+
ARG_UNUSED(channel);
32+
const struct pwm_kb106x_config *config = dev->config;
33+
int prescaler;
34+
uint32_t high_len;
35+
uint32_t cycle_len;
36+
37+
/*
38+
* Calculate PWM prescaler that let period_cycles map to
39+
* maximum pwm period cycles and won't exceed it.
40+
* Then prescaler = ceil (period_cycles / pwm_max_period_cycles)
41+
*/
42+
prescaler = DIV_ROUND_UP(period_cycles, PWM_MAX_CYCLES);
43+
if (prescaler > PWM_MAX_PRESCALER) {
44+
return -EINVAL;
45+
}
46+
47+
high_len = (pulse_cycles / prescaler);
48+
cycle_len = (period_cycles / prescaler);
49+
50+
/* Select PWM inverted polarity (ie. active-low pulse). */
51+
if (flags & PWM_POLARITY_INVERTED) {
52+
high_len = cycle_len - high_len;
53+
}
54+
55+
/* Set PWM prescaler. */
56+
config->pwm->PWMCFG = (config->pwm->PWMCFG & ~GENMASK(13, 8)) | ((prescaler - 1) << 8);
57+
58+
/*
59+
* period_cycles: PWM Cycle Length
60+
* pulse_cycles : PWM High Length
61+
*/
62+
config->pwm->PWMHIGH = high_len;
63+
config->pwm->PWMCYC = cycle_len;
64+
65+
/* Start pwm */
66+
config->pwm->PWMCFG |= PWM_ENABLE;
67+
68+
return 0;
69+
}
70+
71+
static int pwm_kb106x_get_cycles_per_sec(const struct device *dev, uint32_t channel,
72+
uint64_t *cycles)
73+
{
74+
/* Single channel for each pwm device */
75+
ARG_UNUSED(channel);
76+
ARG_UNUSED(dev);
77+
78+
if (cycles) {
79+
/* User does not have to know about lowest clock,
80+
* the driver will select the most relevant one.
81+
*/
82+
*cycles = PWM_INPUT_FREQ_HI; /*32Mhz*/
83+
}
84+
return 0;
85+
}
86+
87+
static DEVICE_API(pwm, pwm_kb106x_driver_api) = {
88+
.set_cycles = pwm_kb106x_set_cycles,
89+
.get_cycles_per_sec = pwm_kb106x_get_cycles_per_sec,
90+
};
91+
92+
static int pwm_kb106x_init(const struct device *dev)
93+
{
94+
int ret;
95+
const struct pwm_kb106x_config *config = dev->config;
96+
97+
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
98+
if (ret != 0) {
99+
return ret;
100+
}
101+
config->pwm->PWMCFG = PWM_SOURCE_CLK_32M | PWM_RULE1 | PWM_PUSHPULL;
102+
103+
return 0;
104+
}
105+
106+
#define KB106X_PWM_INIT(inst) \
107+
PINCTRL_DT_INST_DEFINE(inst); \
108+
static const struct pwm_kb106x_config pwm_kb106x_cfg_##inst = { \
109+
.pwm = (struct pwm_regs *)DT_INST_REG_ADDR(inst), \
110+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
111+
}; \
112+
static struct pwm_kb106x_data pwm_kb106x_data_##inst; \
113+
DEVICE_DT_INST_DEFINE(inst, &pwm_kb106x_init, NULL, &pwm_kb106x_data_##inst, \
114+
&pwm_kb106x_cfg_##inst, PRE_KERNEL_1, CONFIG_PWM_INIT_PRIORITY, \
115+
&pwm_kb106x_driver_api);
116+
117+
DT_INST_FOREACH_STATUS_OKAY(KB106X_PWM_INIT)

dts/arm/ene/kb106x/kb1064.dtsi

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,101 @@
55
*/
66

77
#include <arm/ene/kb106x/kb106x.dtsi>
8+
9+
&soc {
10+
pwm4: pwm@40210040 {
11+
compatible = "ene,kb106x-pwm";
12+
reg = <0x40210040 0x10>;
13+
pwm-channel = <4>;
14+
#pwm-cells = <3>;
15+
status = "disabled";
16+
};
17+
18+
pwm5: pwm@40210050 {
19+
compatible = "ene,kb106x-pwm";
20+
reg = <0x40210050 0x10>;
21+
pwm-channel = <5>;
22+
#pwm-cells = <3>;
23+
status = "disabled";
24+
};
25+
26+
pwm6: pwm@40210060 {
27+
compatible = "ene,kb106x-pwm";
28+
reg = <0x40210060 0x10>;
29+
pwm-channel = <6>;
30+
#pwm-cells = <3>;
31+
status = "disabled";
32+
};
33+
34+
pwm7: pwm@40210070 {
35+
compatible = "ene,kb106x-pwm";
36+
reg = <0x40210070 0x10>;
37+
pwm-channel = <7>;
38+
#pwm-cells = <3>;
39+
status = "disabled";
40+
};
41+
42+
pwm8: pwm@40210080 {
43+
compatible = "ene,kb106x-pwm";
44+
reg = <0x40210080 0x10>;
45+
pwm-channel = <8>;
46+
#pwm-cells = <3>;
47+
status = "disabled";
48+
};
49+
50+
pwm9: pwm@40210090 {
51+
compatible = "ene,kb106x-pwm";
52+
reg = <0x40210090 0x10>;
53+
pwm-channel = <9>;
54+
#pwm-cells = <3>;
55+
status = "disabled";
56+
};
57+
58+
pwm10: pwm@402100a0 {
59+
compatible = "ene,kb106x-pwm";
60+
reg = <0x402100A0 0x10>;
61+
pwm-channel = <10>;
62+
#pwm-cells = <3>;
63+
status = "disabled";
64+
};
65+
66+
pwm11: pwm@402100b0 {
67+
compatible = "ene,kb106x-pwm";
68+
reg = <0x402100B0 0x10>;
69+
pwm-channel = <11>;
70+
#pwm-cells = <3>;
71+
status = "disabled";
72+
};
73+
74+
pwm12: pwm@402100c0 {
75+
compatible = "ene,kb106x-pwm";
76+
reg = <0x402100C0 0x10>;
77+
pwm-channel = <12>;
78+
#pwm-cells = <3>;
79+
status = "disabled";
80+
};
81+
82+
pwm13: pwm@402100d0 {
83+
compatible = "ene,kb106x-pwm";
84+
reg = <0x402100D0 0x10>;
85+
pwm-channel = <13>;
86+
#pwm-cells = <3>;
87+
status = "disabled";
88+
};
89+
90+
pwm14: pwm@402100e0 {
91+
compatible = "ene,kb106x-pwm";
92+
reg = <0x402100E0 0x10>;
93+
pwm-channel = <14>;
94+
#pwm-cells = <3>;
95+
status = "disabled";
96+
};
97+
98+
pwm15: pwm@402100f0 {
99+
compatible = "ene,kb106x-pwm";
100+
reg = <0x402100F0 0x10>;
101+
pwm-channel = <15>;
102+
#pwm-cells = <3>;
103+
status = "disabled";
104+
};
105+
};

dts/arm/ene/kb106x/kb106x.dtsi

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,38 @@
125125
status = "disabled";
126126
#io-channel-cells = <1>;
127127
};
128+
129+
pwm0: pwm@40210000 {
130+
compatible = "ene,kb106x-pwm";
131+
reg = <0x40210000 0x10>;
132+
pwm-channel = <0>;
133+
#pwm-cells = <3>;
134+
status = "disabled";
135+
};
136+
137+
pwm1: pwm@40210010 {
138+
compatible = "ene,kb106x-pwm";
139+
reg = <0x40210010 0x10>;
140+
pwm-channel = <1>;
141+
#pwm-cells = <3>;
142+
status = "disabled";
143+
};
144+
145+
pwm2: pwm@40210020 {
146+
compatible = "ene,kb106x-pwm";
147+
reg = <0x40210020 0x10>;
148+
pwm-channel = <2>;
149+
#pwm-cells = <3>;
150+
status = "disabled";
151+
};
152+
153+
pwm3: pwm@40210030 {
154+
compatible = "ene,kb106x-pwm";
155+
reg = <0x40210030 0x10>;
156+
pwm-channel = <3>;
157+
#pwm-cells = <3>;
158+
status = "disabled";
159+
};
128160
};
129161
};
130162

dts/bindings/pwm/ene,kb106x-pwm.yaml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2025 ENE Technology Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ENE, Pulse Width Modulator (PWM) node
5+
6+
compatible: "ene,kb106x-pwm"
7+
8+
include: [pwm-controller.yaml, base.yaml, pinctrl-device.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
pwm-channel:
14+
type: int
15+
description: |
16+
A index to indicate PWM module that generates a single PWM signal.
17+
Please don't overwrite it in the board-level DT driver.
18+
pinctrl-0:
19+
required: true
20+
21+
pinctrl-names:
22+
required: true
23+
24+
pwm-cells:
25+
- channel
26+
- period
27+
- flags

soc/ene/kb106x/common/reg/pwm.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2025 ENE Technology Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ENE_KB106X_PWM_H
8+
#define ENE_KB106X_PWM_H
9+
10+
/**
11+
* Structure type to access Pulse Width Modulation (PWM).
12+
*/
13+
struct pwm_regs {
14+
volatile uint16_t PWMCFG; /*Configuration Register */
15+
volatile uint16_t Reserved0; /*Reserved */
16+
volatile uint16_t PWMHIGH; /*High Length Register */
17+
volatile uint16_t Reserved1; /*Reserved */
18+
volatile uint16_t PWMCYC; /*Cycle Length Register */
19+
volatile uint16_t Reserved2; /*Reserved */
20+
volatile uint32_t PWMCHC; /*Current High/Cycle Length Register */
21+
};
22+
23+
#define PWM_SOURCE_CLK_32M 0x0000
24+
#define PWM_SOURCE_CLK_1M 0x4000
25+
#define PWM_SOURCE_CLK_32_768K 0x8000
26+
27+
#define PWM_PRESCALER_BIT_S 8
28+
29+
#define PWM_RULE0 0x0000
30+
#define PWM_RULE1 0x0080
31+
32+
#define PWM_PUSHPULL 0x0000
33+
#define PWM_OPENDRAIN 0x0002
34+
#define PWM_ENABLE 0x0001
35+
36+
#define PWM_INPUT_FREQ_HI 32000000u
37+
#define PWM_MAX_PRESCALER (1UL << (6))
38+
#define PWM_MAX_CYCLES (1UL << (14))
39+
40+
#endif /* ENE_KB106X_PWM_H */

0 commit comments

Comments
 (0)