Skip to content

Commit ff23285

Browse files
bogdanovsnashif
authored andcommitted
drivers: pwm: Add support for cc23x0 LGPT PWM
Add PWM support for LGPT0, LGPT1, LGPT2 and LGPT3 for cc23x0 SoC. Signed-off-by: Stoyan Bogdanov <[email protected]>
1 parent bc07843 commit ff23285

File tree

5 files changed

+210
-0
lines changed

5 files changed

+210
-0
lines changed

drivers/pwm/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ zephyr_library()
66

77
zephyr_library_sources_ifdef(CONFIG_PWM_TELINK_B91 pwm_b91.c)
88
zephyr_library_sources_ifdef(CONFIG_PWM_CC13XX_CC26XX_TIMER pwm_cc13xx_cc26xx_timer.c)
9+
zephyr_library_sources_ifdef(CONFIG_PWM_CC23X0_TIMER pwm_cc23x0_timer.c)
910
zephyr_library_sources_ifdef(CONFIG_PWM_STM32 pwm_stm32.c)
1011
zephyr_library_sources_ifdef(CONFIG_PWM_SIFIVE pwm_sifive.c)
1112
zephyr_library_sources_ifdef(CONFIG_PWM_NRF_SW pwm_nrf_sw.c)

drivers/pwm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ source "drivers/pwm/Kconfig.b91"
3636

3737
source "drivers/pwm/Kconfig.cc13xx_cc26xx_timer"
3838

39+
source "drivers/pwm/Kconfig.cc23x0_timer"
40+
3941
source "drivers/pwm/Kconfig.stm32"
4042

4143
source "drivers/pwm/Kconfig.sifive"

drivers/pwm/Kconfig.cc23x0_timer

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2024 BayLibre, SAS
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config PWM_CC23X0_TIMER
5+
bool "TI SimpleLink CC23x0 LGPT PWM driver"
6+
default y
7+
depends on DT_HAS_TI_CC23X0_LGPT_PWM_ENABLED
8+
select PINCTRL
9+
help
10+
Enables TI SimpleLink CC23x0 LGPT PWM driver.

drivers/pwm/pwm_cc23x0_timer.c

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright (c) 2024 BayLibre, SAS
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ti_cc23x0_lgpt_pwm
8+
9+
#include <zephyr/drivers/pinctrl.h>
10+
#include <zephyr/drivers/pwm.h>
11+
12+
#include <driverlib/gpio.h>
13+
#include <driverlib/clkctl.h>
14+
#include <inc/hw_lgpt.h>
15+
#include <inc/hw_lgpt1.h>
16+
#include <inc/hw_lgpt3.h>
17+
#include <inc/hw_types.h>
18+
#include <inc/hw_evtsvt.h>
19+
#include <inc/hw_memmap.h>
20+
21+
#include <zephyr/logging/log.h>
22+
#define LOG_MODULE_NAME pwm_cc23x0_lgpt
23+
LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_PWM_LOG_LEVEL);
24+
25+
#define LGPT_CLK_PRESCALE(pres) ((pres + 1) << 8)
26+
27+
struct pwm_cc23x0_data {
28+
uint32_t prescale;
29+
uint32_t base_clk;
30+
};
31+
32+
struct pwm_cc23x0_config {
33+
const uint32_t base; /* LGPT register base address */
34+
const struct pinctrl_dev_config *pcfg;
35+
};
36+
37+
static int pwm_cc23x0_set_cycles(const struct device *dev, uint32_t channel, uint32_t period,
38+
uint32_t pulse, pwm_flags_t flags)
39+
{
40+
const struct pwm_cc23x0_config *config = dev->config;
41+
42+
LOG_DBG("set cycles period[%x] pulse[%x]", period, pulse);
43+
44+
if ((config->base != LGPT3_BASE) && (pulse > 0xffff || period > 0xffff || pulse > period)) {
45+
/* LGPT0, LGPT1, LGPT2 - 16bit counters */
46+
LOG_ERR("Period of pulse out of range");
47+
return -EINVAL;
48+
} else if (pulse > 0xffffff || period > 0xffffff || pulse > period) {
49+
/* LGPT3 - 24bit counter */
50+
LOG_ERR("Period of pulse out of range");
51+
return -EINVAL;
52+
}
53+
54+
if (channel == 0) {
55+
HWREG(config->base + LGPT_O_C0CC) = pulse;
56+
HWREG(config->base + LGPT_O_C0CFG) = 0x100 | 0xB;
57+
} else if (channel == 1) {
58+
HWREG(config->base + LGPT_O_C1CC) = pulse;
59+
HWREG(config->base + LGPT_O_C1CFG) = 0x200 | 0xB;
60+
} else if (channel == 2) {
61+
HWREG(config->base + LGPT_O_C2CC) = pulse;
62+
HWREG(config->base + LGPT_O_C2CFG) = 0x400 | 0xB;
63+
} else {
64+
LOG_ERR("Invalid chan ID");
65+
return -ENOTSUP;
66+
}
67+
68+
/* get it from flags */
69+
HWREG(config->base + LGPT_O_CTL) = LGPT_CTL_MODE_UPDWN_PER;
70+
HWREG(config->base + LGPT_O_TGT) = period;
71+
72+
/* Activate LGPT */
73+
HWREG(config->base + LGPT_O_STARTCFG) = 0x1;
74+
75+
return 0;
76+
}
77+
78+
static int pwm_cc23x0_get_cycles_per_sec(const struct device *dev, uint32_t channel,
79+
uint64_t *cycles)
80+
{
81+
struct pwm_cc23x0_data *data = dev->data;
82+
83+
*cycles = data->base_clk / (data->prescale + 1);
84+
85+
return 0;
86+
}
87+
88+
static const struct pwm_driver_api pwm_cc23x0_driver_api = {
89+
.set_cycles = pwm_cc23x0_set_cycles,
90+
.get_cycles_per_sec = pwm_cc23x0_get_cycles_per_sec,
91+
};
92+
93+
static int pwm_cc23x0_activate_clock(const struct device *dev)
94+
{
95+
const struct pwm_cc23x0_config *config = dev->config;
96+
struct pwm_cc23x0_data *data = dev->data;
97+
uint32_t lgpt_clk_id = 0;
98+
99+
switch (config->base) {
100+
case LGPT0_BASE:
101+
lgpt_clk_id = CLKCTL_LGPT0;
102+
break;
103+
case LGPT1_BASE:
104+
lgpt_clk_id = CLKCTL_LGPT1;
105+
break;
106+
case LGPT2_BASE:
107+
lgpt_clk_id = CLKCTL_LGPT2;
108+
break;
109+
case LGPT3_BASE:
110+
lgpt_clk_id = CLKCTL_LGPT3;
111+
break;
112+
default:
113+
return -EINVAL;
114+
}
115+
116+
CLKCTLEnable(CLKCTL_BASE, lgpt_clk_id);
117+
HWREG(config->base + LGPT_O_PRECFG) = LGPT_CLK_PRESCALE(data->prescale);
118+
HWREG(EVTSVT_BASE + EVTSVT_O_LGPTSYNCSEL) = EVTSVT_LGPTSYNCSEL_PUBID_SYSTIM0;
119+
120+
return 0;
121+
}
122+
123+
#define DT_TIMER(idx) DT_INST_PARENT(idx)
124+
#define DT_TIMER_BASE_ADDR(idx) (DT_REG_ADDR(DT_TIMER(idx)))
125+
126+
static int pwm_cc23x0_init(const struct device *dev)
127+
{
128+
const struct pwm_cc23x0_config *config = dev->config;
129+
130+
int ret;
131+
132+
LOG_DBG("PWM cc23x0 base=[%x]", config->base);
133+
134+
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
135+
if (ret < 0) {
136+
LOG_ERR("[ERR] failed to setup PWM pinctrl");
137+
return ret;
138+
}
139+
140+
pwm_cc23x0_activate_clock(dev);
141+
142+
return 0;
143+
}
144+
145+
#define PWM_DEVICE_INIT(idx) \
146+
PINCTRL_DT_INST_DEFINE(idx); \
147+
LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, CONFIG_PWM_LOG_LEVEL); \
148+
\
149+
static const struct pwm_cc23x0_config pwm_cc23x0_##idx##_config = { \
150+
.base = DT_TIMER_BASE_ADDR(idx), \
151+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
152+
}; \
153+
\
154+
static struct pwm_cc23x0_data pwm_cc23x0_##idx##_data = { \
155+
.prescale = DT_PROP(DT_INST_PARENT(idx), clk_prescale), \
156+
.base_clk = DT_PROP(DT_PATH(cpus, cpu_0), clock_frequency), \
157+
}; \
158+
\
159+
DEVICE_DT_INST_DEFINE(idx, pwm_cc23x0_init, NULL, &pwm_cc23x0_##idx##_data, \
160+
&pwm_cc23x0_##idx##_config, POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \
161+
&pwm_cc23x0_driver_api)
162+
163+
DT_INST_FOREACH_STATUS_OKAY(PWM_DEVICE_INIT);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright (c) 2024 BayLibre, SAS
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
TI CC23x0 LGPT PWM Controller Node
6+
7+
&lgpt0 {
8+
status = "okay";
9+
};
10+
11+
&pwm0 {
12+
status = "okay";
13+
pinctrl-0 = <&pwm0_default>;
14+
pinctrl-names = "default";
15+
};
16+
17+
Note: PWM0-PWM8 are 16bit without prescale, max timeout is 1365100 ns
18+
PWM9-PWM11 are 24bit without prescale, max timeout is 349519750 ns
19+
20+
compatible: "ti,cc23x0-lgpt-pwm"
21+
22+
include: [base.yaml, pwm-controller.yaml, pinctrl-device.yaml]
23+
24+
properties:
25+
pinctrl-0:
26+
required: true
27+
28+
pinctrl-names:
29+
required: true
30+
31+
pwm-cells:
32+
- channel
33+
- period
34+
- flags

0 commit comments

Comments
 (0)