Skip to content

Commit 1147c39

Browse files
ene-stevenfabiobaltieri
authored andcommitted
drivers: pwm: initial device driver for ENE KB1200
Add pwm driver for ENE KB1200 Signed-off-by: Steven Chang <[email protected]>
1 parent 14c6468 commit 1147c39

File tree

4 files changed

+136
-0
lines changed

4 files changed

+136
-0
lines changed

drivers/pwm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_PWM_XMC4XXX_CCU8 pwm_xmc4xxx_ccu8.c)
4040
zephyr_library_sources_ifdef(CONFIG_PWM_MCUX_CTIMER pwm_mcux_ctimer.c)
4141
zephyr_library_sources_ifdef(CONFIG_PWM_NUMAKER pwm_numaker.c)
4242
zephyr_library_sources_ifdef(CONFIG_PWM_NXP_S32_EMIOS pwm_nxp_s32_emios.c)
43+
zephyr_library_sources_ifdef(CONFIG_PWM_ENE_KB1200 pwm_ene_kb1200.c)
4344

4445
zephyr_library_sources_ifdef(CONFIG_USERSPACE pwm_handlers.c)
4546
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
@@ -100,4 +100,6 @@ source "drivers/pwm/Kconfig.numaker"
100100

101101
source "drivers/pwm/Kconfig.nxp_s32_emios"
102102

103+
source "drivers/pwm/Kconfig.ene"
104+
103105
endif # PWM

drivers/pwm/Kconfig.ene

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2024 ENE Technology Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config PWM_ENE_KB1200
5+
bool "ENE KB1200 PWM driver"
6+
default y
7+
depends on DT_HAS_ENE_KB1200_PWM_ENABLED
8+
select PINCTRL
9+
help
10+
This option enables the PWM driver for KB1200 processors.

drivers/pwm/pwm_ene_kb1200.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright (c) 2024 ENE Technology Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ene_kb1200_pwm
8+
9+
#include <zephyr/drivers/pwm.h>
10+
#include <zephyr/drivers/pinctrl.h>
11+
#include <reg/pwm.h>
12+
13+
/* Device config */
14+
struct pwm_kb1200_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_kb1200_data {
22+
/* PWM cycles per second */
23+
uint32_t cycles_per_sec;
24+
};
25+
26+
/* PWM api functions */
27+
static int pwm_kb1200_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_kb1200_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+
/* If pulse_cycles is 0, switch PWM off and return. */
48+
if (pulse_cycles == 0) {
49+
config->pwm->PWMCFG &= ~PWM_ENABLE;
50+
return 0;
51+
}
52+
53+
high_len = (pulse_cycles / prescaler);
54+
cycle_len = (period_cycles / prescaler);
55+
56+
/* Select PWM inverted polarity (ie. active-low pulse). */
57+
if (flags & PWM_POLARITY_INVERTED) {
58+
high_len = cycle_len - high_len;
59+
}
60+
61+
/* Set PWM prescaler. */
62+
config->pwm->PWMCFG = (config->pwm->PWMCFG & ~GENMASK(13, 8)) | ((prescaler - 1) << 8);
63+
64+
/*
65+
* period_cycles: PWM Cycle Length
66+
* pulse_cycles : PWM High Length
67+
*/
68+
config->pwm->PWMHIGH = high_len;
69+
config->pwm->PWMCYC = cycle_len;
70+
71+
/* Start pwm */
72+
config->pwm->PWMCFG |= PWM_ENABLE;
73+
74+
return 0;
75+
}
76+
77+
static int pwm_kb1200_get_cycles_per_sec(const struct device *dev, uint32_t channel,
78+
uint64_t *cycles)
79+
{
80+
/* Single channel for each pwm device */
81+
ARG_UNUSED(channel);
82+
ARG_UNUSED(dev);
83+
84+
if (cycles) {
85+
/* User does not have to know about lowest clock,
86+
* the driver will select the most relevant one.
87+
*/
88+
*cycles = PWM_INPUT_FREQ_HI; /*32Mhz*/
89+
}
90+
return 0;
91+
}
92+
93+
static const struct pwm_driver_api pwm_kb1200_driver_api = {
94+
.set_cycles = pwm_kb1200_set_cycles,
95+
.get_cycles_per_sec = pwm_kb1200_get_cycles_per_sec,
96+
};
97+
98+
static int pwm_kb1200_init(const struct device *dev)
99+
{
100+
int ret;
101+
const struct pwm_kb1200_config *config = dev->config;
102+
103+
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
104+
if (ret != 0) {
105+
return ret;
106+
}
107+
config->pwm->PWMCFG = PWM_SOURCE_CLK_32M | PWM_RULE1 | PWM_PUSHPULL;
108+
109+
return 0;
110+
}
111+
112+
#define KB1200_PWM_INIT(inst) \
113+
PINCTRL_DT_INST_DEFINE(inst); \
114+
static const struct pwm_kb1200_config pwm_kb1200_cfg_##inst = { \
115+
.pwm = (struct pwm_regs *)DT_INST_REG_ADDR(inst), \
116+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
117+
}; \
118+
static struct pwm_kb1200_data pwm_kb1200_data_##inst; \
119+
DEVICE_DT_INST_DEFINE(inst, &pwm_kb1200_init, NULL, &pwm_kb1200_data_##inst, \
120+
&pwm_kb1200_cfg_##inst, PRE_KERNEL_1, CONFIG_PWM_INIT_PRIORITY, \
121+
&pwm_kb1200_driver_api);
122+
123+
DT_INST_FOREACH_STATUS_OKAY(KB1200_PWM_INIT)

0 commit comments

Comments
 (0)