Skip to content

Commit c6fe84c

Browse files
Yunshao-Chiangkartben
authored andcommitted
drivers: counter: add ite it8xxx2 timer driver
The IT8xxx2 timer driver uses timer 7 and timer 8 to implement the alarm timer and the top timer, respectively. Signed-off-by: Yunshao Chiang <[email protected]>
1 parent 54d8c80 commit c6fe84c

File tree

9 files changed

+394
-0
lines changed

9 files changed

+394
-0
lines changed

drivers/counter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ zephyr_library_sources_ifdef(CONFIG_COUNTER_AMBIQ counter_ambiq_ti
1515
zephyr_library_sources_ifdef(CONFIG_COUNTER_GECKO_RTCC counter_gecko_rtcc.c)
1616
zephyr_library_sources_ifdef(CONFIG_COUNTER_GECKO_STIMER counter_gecko_stimer.c)
1717
zephyr_library_sources_ifdef(CONFIG_COUNTER_IMX_EPIT counter_imx_epit.c)
18+
zephyr_library_sources_ifdef(CONFIG_COUNTER_ITE_IT8XXX2 counter_ite_it8xxx2.c)
1819
zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_CTIMER counter_mcux_ctimer.c)
1920
zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_RTC counter_mcux_rtc.c)
2021
zephyr_library_sources_ifdef(CONFIG_COUNTER_MCUX_LPC_RTC counter_mcux_lpc_rtc.c)

drivers/counter/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ source "drivers/counter/Kconfig.nrfx"
4242

4343
source "drivers/counter/Kconfig.imx_epit"
4444

45+
source "drivers/counter/Kconfig.ite_it8xxx2"
46+
4547
source "drivers/counter/Kconfig.stm32_rtc"
4648

4749
source "drivers/counter/Kconfig.stm32_timer"

drivers/counter/Kconfig.ite_it8xxx2

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2025 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config COUNTER_ITE_IT8XXX2
5+
bool "ITE IT8XXX2 Timer driver"
6+
default y
7+
depends on DT_HAS_ITE_IT8XXX2_COUNTER_ENABLED
8+
help
9+
Enable counter support for the ITE IT8XXX2.

drivers/counter/counter_ite_it8xxx2.c

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
/*
2+
* Copyright (c) 2025 ITE Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ite_it8xxx2_counter
8+
9+
#include <soc.h>
10+
#include <zephyr/drivers/counter.h>
11+
#include <zephyr/logging/log.h>
12+
LOG_MODULE_REGISTER(counter_it8xxx2, CONFIG_COUNTER_LOG_LEVEL);
13+
14+
/* IT8XXX2 Timer registers offsets */
15+
#define ET7CTRL 0x00
16+
#define ET7PSR 0x01
17+
#define ET7CNTLLR 0x04
18+
#define ET8CTRL 0x08
19+
#define ET8PSR 0x09
20+
#define ET8CNTLLR 0x0C
21+
#define ET7CNTOLR 0x28
22+
#define ET8CNTOLR 0x2C
23+
24+
/* ETnCTLR bit definitions (for n = 7 ~ 8) */
25+
#define ET_COMB BIT(3) /* only defined in ET7CTRL */
26+
#define ET_TC BIT(2)
27+
#define ET_RST BIT(1)
28+
#define ET_EN BIT(0)
29+
30+
/* ETnPSR bit definitions (for n = 7 ~ 8) */
31+
#define ETnPSR_32768HZ 0x00
32+
33+
struct counter_it8xxx2_config {
34+
struct counter_config_info info;
35+
mm_reg_t base;
36+
/* alarm timer irq */
37+
int alarm_irq;
38+
/* top timer irq */
39+
int top_irq;
40+
void (*irq_config_func)(const struct device *dev);
41+
};
42+
43+
struct counter_it8xxx2_data {
44+
counter_top_callback_t top_callback;
45+
void *top_user_data;
46+
counter_alarm_callback_t alarm_callback;
47+
void *alarm_user_data;
48+
};
49+
50+
static inline uint32_t counter_it8xxx2_read8(const struct device *dev, mm_reg_t offset)
51+
{
52+
const struct counter_it8xxx2_config *config = dev->config;
53+
54+
return sys_read8(config->base + offset);
55+
}
56+
57+
static inline uint32_t counter_it8xxx2_read32(const struct device *dev, mm_reg_t offset)
58+
{
59+
const struct counter_it8xxx2_config *config = dev->config;
60+
61+
return sys_read32(config->base + offset);
62+
}
63+
64+
static inline void counter_it8xxx2_write8(const struct device *dev, uint32_t value, mm_reg_t offset)
65+
{
66+
const struct counter_it8xxx2_config *config = dev->config;
67+
68+
sys_write8(value, config->base + offset);
69+
}
70+
71+
static inline void counter_it8xxx2_write32(const struct device *dev, uint32_t value,
72+
mm_reg_t offset)
73+
{
74+
const struct counter_it8xxx2_config *config = dev->config;
75+
76+
sys_write32(value, config->base + offset);
77+
}
78+
79+
static inline void counter_it8xxx2_alarm_timer_disable(const struct device *dev)
80+
{
81+
const struct counter_it8xxx2_config *config = dev->config;
82+
83+
irq_disable(config->alarm_irq);
84+
counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET7CTRL) & ~ET_EN, ET7CTRL);
85+
ite_intc_isr_clear(config->alarm_irq);
86+
}
87+
88+
static int counter_it8xxx2_start(const struct device *dev)
89+
{
90+
LOG_DBG("starting top timer");
91+
92+
counter_it8xxx2_write8(dev, ET_EN | ET_RST, ET8CTRL);
93+
94+
return 0;
95+
}
96+
97+
static int counter_it8xxx2_stop(const struct device *dev)
98+
{
99+
LOG_DBG("stopping timer");
100+
101+
counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET8CTRL) & ~ET_EN, ET8CTRL);
102+
103+
return 0;
104+
}
105+
106+
static int counter_it8xxx2_get_value(const struct device *dev, uint32_t *ticks)
107+
{
108+
*ticks = counter_it8xxx2_read32(dev, ET8CNTOLR);
109+
110+
return 0;
111+
}
112+
113+
static int counter_it8xxx2_set_alarm(const struct device *dev, uint8_t chan_id,
114+
const struct counter_alarm_cfg *alarm_cfg)
115+
{
116+
const struct counter_it8xxx2_config *config = dev->config;
117+
struct counter_it8xxx2_data *data = dev->data;
118+
119+
ARG_UNUSED(chan_id);
120+
121+
/* Interrupts are only triggered when the counter reaches 0.
122+
* So only relative alarms are supported.
123+
*/
124+
if (alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) {
125+
return -ENOTSUP;
126+
}
127+
128+
if (data->alarm_callback != NULL) {
129+
return -EBUSY;
130+
}
131+
132+
if (alarm_cfg->callback == NULL) {
133+
return -EINVAL;
134+
}
135+
136+
if (alarm_cfg->ticks > counter_it8xxx2_read32(dev, ET8CNTLLR)) {
137+
return -EINVAL;
138+
}
139+
140+
LOG_DBG("triggering alarm in 0x%08x ticks", alarm_cfg->ticks);
141+
142+
irq_disable(config->alarm_irq);
143+
144+
counter_it8xxx2_write32(dev, alarm_cfg->ticks, ET7CNTLLR);
145+
146+
data->alarm_callback = alarm_cfg->callback;
147+
data->alarm_user_data = alarm_cfg->user_data;
148+
149+
LOG_DBG("%p Counter alarm set to %u ticks", dev, alarm_cfg->ticks);
150+
151+
counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET7CTRL) | ET_EN | ET_RST, ET7CTRL);
152+
153+
ite_intc_isr_clear(config->alarm_irq);
154+
155+
irq_enable(config->alarm_irq);
156+
157+
return 0;
158+
}
159+
160+
static int counter_it8xxx2_cancel_alarm(const struct device *dev, uint8_t chan_id)
161+
{
162+
struct counter_it8xxx2_data *data = dev->data;
163+
164+
if (chan_id != 0) {
165+
LOG_ERR("Invalid channel id %u", chan_id);
166+
return -ENOTSUP;
167+
}
168+
169+
counter_it8xxx2_alarm_timer_disable(dev);
170+
171+
data->alarm_callback = NULL;
172+
data->alarm_user_data = NULL;
173+
174+
LOG_DBG("%p Counter alarm canceled", dev);
175+
176+
return 0;
177+
}
178+
179+
static int counter_it8xxx2_set_top_value(const struct device *dev,
180+
const struct counter_top_cfg *top_cfg)
181+
{
182+
const struct counter_it8xxx2_config *config = dev->config;
183+
struct counter_it8xxx2_data *data = dev->data;
184+
185+
if (top_cfg == NULL) {
186+
LOG_ERR("Invalid top value configuration");
187+
return -EINVAL;
188+
}
189+
190+
if (top_cfg->ticks == 0) {
191+
return -EINVAL;
192+
}
193+
194+
if (top_cfg->ticks > config->info.max_top_value) {
195+
return -ENOTSUP;
196+
}
197+
198+
if (data->alarm_callback) {
199+
return -EBUSY;
200+
}
201+
202+
/* top value cannot be updated without reset */
203+
if (top_cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
204+
LOG_ERR("Updating top value without reset is not supported");
205+
return -ENOTSUP;
206+
}
207+
208+
LOG_DBG("setting top value to 0x%08x", top_cfg->ticks);
209+
210+
data->top_callback = top_cfg->callback;
211+
data->top_user_data = top_cfg->user_data;
212+
213+
irq_disable(config->top_irq);
214+
215+
/* set new top value */
216+
counter_it8xxx2_write32(dev, top_cfg->ticks, ET8CNTLLR);
217+
218+
/* re-enable and reset timer */
219+
counter_it8xxx2_write8(dev, counter_it8xxx2_read8(dev, ET8CTRL) | ET_EN | ET_RST, ET8CTRL);
220+
221+
ite_intc_isr_clear(config->top_irq);
222+
223+
irq_enable(config->top_irq);
224+
225+
return 0;
226+
}
227+
228+
static uint32_t counter_it8xxx2_get_top_value(const struct device *dev)
229+
{
230+
return counter_it8xxx2_read32(dev, ET8CNTLLR);
231+
}
232+
233+
static void counter_it8xxx2_alarm_isr(const struct device *dev)
234+
{
235+
struct counter_it8xxx2_data *data = dev->data;
236+
counter_alarm_callback_t alarm_cb;
237+
void *user_data;
238+
uint32_t ticks;
239+
240+
LOG_DBG("%p alarm timer ISR", dev);
241+
242+
/* Alarm is one-shot, so disable interrupt and callback */
243+
if (data->alarm_callback) {
244+
alarm_cb = data->alarm_callback;
245+
data->alarm_callback = NULL;
246+
user_data = data->alarm_user_data;
247+
248+
ticks = counter_it8xxx2_read32(dev, ET8CNTOLR);
249+
250+
alarm_cb(dev, 0, ticks, user_data);
251+
}
252+
253+
counter_it8xxx2_alarm_timer_disable(dev);
254+
}
255+
256+
static void counter_it8xxx2_top_isr(const struct device *dev)
257+
{
258+
const struct counter_it8xxx2_config *config = dev->config;
259+
struct counter_it8xxx2_data *data = dev->data;
260+
261+
LOG_DBG("%p top timer ISR", dev);
262+
263+
if (data->top_callback) {
264+
data->top_callback(dev, data->top_user_data);
265+
}
266+
267+
/* read clear timer 8 terminal count */
268+
counter_it8xxx2_read8(dev, ET8CTRL);
269+
270+
ite_intc_isr_clear(config->top_irq);
271+
}
272+
273+
static int counter_it8xxx2_init(const struct device *dev)
274+
{
275+
const struct counter_it8xxx2_config *config = dev->config;
276+
277+
LOG_DBG("max top value = 0x%08x", config->info.max_top_value);
278+
LOG_DBG("frequency = %d", config->info.freq);
279+
LOG_DBG("channels = %d", config->info.channels);
280+
281+
/* set the top value of top timer */
282+
counter_it8xxx2_write32(dev, config->info.max_top_value, ET8CNTLLR);
283+
284+
/* set the frequencies of alarm timer and top timer */
285+
counter_it8xxx2_write8(dev, ETnPSR_32768HZ, ET7PSR);
286+
counter_it8xxx2_write8(dev, ETnPSR_32768HZ, ET8PSR);
287+
288+
config->irq_config_func(dev);
289+
290+
return 0;
291+
}
292+
293+
static DEVICE_API(counter, counter_it8xxx2_driver_api) = {
294+
.start = counter_it8xxx2_start,
295+
.stop = counter_it8xxx2_stop,
296+
.get_value = counter_it8xxx2_get_value,
297+
.set_alarm = counter_it8xxx2_set_alarm,
298+
.cancel_alarm = counter_it8xxx2_cancel_alarm,
299+
.set_top_value = counter_it8xxx2_set_top_value,
300+
.get_top_value = counter_it8xxx2_get_top_value,
301+
};
302+
303+
#define COUNTER_IT8XXX2_INIT(n) \
304+
static void counter_it8xxx2_cfg_func_##n(const struct device *dev) \
305+
{ \
306+
IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, 0), 0, counter_it8xxx2_alarm_isr, \
307+
DEVICE_DT_INST_GET(n), 0); \
308+
IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, 1), 0, counter_it8xxx2_top_isr, \
309+
DEVICE_DT_INST_GET(n), 0); \
310+
} \
311+
\
312+
static struct counter_it8xxx2_config counter_it8xxx2_config_##n = { \
313+
.info = \
314+
{ \
315+
.max_top_value = UINT32_MAX, \
316+
.freq = 32768, \
317+
.flags = 0, \
318+
.channels = 1, \
319+
}, \
320+
.base = DT_INST_REG_ADDR(n), \
321+
.alarm_irq = DT_INST_IRQN_BY_IDX(n, 0), \
322+
.top_irq = DT_INST_IRQN_BY_IDX(n, 1), \
323+
.irq_config_func = counter_it8xxx2_cfg_func_##n, \
324+
}; \
325+
\
326+
static struct counter_it8xxx2_data counter_it8xxx2_data_##n; \
327+
\
328+
DEVICE_DT_INST_DEFINE(n, &counter_it8xxx2_init, NULL, &counter_it8xxx2_data_##n, \
329+
&counter_it8xxx2_config_##n, POST_KERNEL, \
330+
CONFIG_COUNTER_INIT_PRIORITY, &counter_it8xxx2_driver_api);
331+
332+
DT_INST_FOREACH_STATUS_OKAY(COUNTER_IT8XXX2_INIT)
333+
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
334+
"only one ite,it8xxx2-counter compatible node can be supported");
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#
2+
# Copyright (c) 2025 ITE Corporation.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
description: ITE IT8XXX2 counter
8+
9+
compatible: "ite,it8xxx2-counter"
10+
11+
include: base.yaml
12+
13+
properties:
14+
reg:
15+
required: true
16+
17+
interrupts:
18+
required: true

dts/riscv/ite/it8xxx2.dtsi

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@
153153
interrupt-parent = <&intc>;
154154
};
155155

156+
counter0: counter@f01f30 {
157+
compatible = "ite,it8xxx2-counter";
158+
reg = <0xf01f30 0x10>;
159+
interrupts = <IT8XXX2_IRQ_TIMER7 IRQ_TYPE_EDGE_RISING /* Alarm timer */
160+
IT8XXX2_IRQ_TIMER8 IRQ_TYPE_EDGE_RISING>; /* Top timer */
161+
interrupt-parent = <&intc>;
162+
status = "disabled";
163+
};
164+
156165
gpioa: gpio@f01601 {
157166
compatible = "ite,it8xxx2-gpio";
158167
reg = <0x00f01601 1 /* GPDR (set) */

0 commit comments

Comments
 (0)