Skip to content

Commit 36ef800

Browse files
KozhinovAlexandermathieuchopstm
authored andcommitted
drivers: interrupt_controller: introduce STM32 EXTI driver
add peripheral lines support add EXTI interface Co-authored-by: Mathieu CHOPLAIN <[email protected]> Signed-off-by: Alexander Kozhinov <[email protected]>
1 parent 5e727d7 commit 36ef800

File tree

5 files changed

+678
-3
lines changed

5 files changed

+678
-3
lines changed

drivers/interrupt_controller/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ zephyr_library_sources_ifdef(CONFIG_CAVS_ICTL intc_cavs.c)
77
zephyr_library_sources_ifdef(CONFIG_DW_ICTL intc_dw.c)
88
zephyr_library_sources_ifdef(CONFIG_DW_ICTL_ACE intc_dw_ace.c)
99
zephyr_library_sources_ifdef(CONFIG_GPIO_INTC_STM32 intc_gpio_stm32.c)
10+
zephyr_library_sources_ifdef(CONFIG_EXTI_STM32 intc_exti_stm32.c)
1011
zephyr_library_sources_ifdef(CONFIG_GD32_EXTI intc_gd32_exti.c)
1112
zephyr_library_sources_ifdef(CONFIG_GIC_V1 intc_gic.c)
1213
zephyr_library_sources_ifdef(CONFIG_GIC_V2 intc_gic.c)

drivers/interrupt_controller/Kconfig.stm32

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
# STM32 EXTI configuration
22

33
# Copyright (c) 2016 Open-RnD Sp. z o.o.
4+
# Copyright (c) 2025 Alexander Kozhinov <[email protected]>
45
# SPDX-License-Identifier: Apache-2.0
56

67
if SOC_FAMILY_STM32
78

8-
config GPIO_INTC_STM32
9-
bool "GPIO Interrupt/Event Controller (EXTI) Driver for STM32 family of MCUs"
9+
config EXTI_STM32
10+
bool "STM32 External Interrupt/Event Controller (EXTI) Driver"
1011
default y
1112
depends on DT_HAS_ST_STM32_EXTI_ENABLED
1213
help
13-
Enable GPIO interrupt controller driver for STM32 family of MCUs
14+
Enable STM32 EXTI driver
15+
16+
config GPIO_INTC_STM32
17+
bool "STM32 GPIO Interrupt/Event Controller (EXTI) Driver"
18+
default y
19+
depends on EXTI_STM32
20+
help
21+
Enable STM32 GPIO interrupt controller driver
1422

1523
config GPIO_INTC_STM32WB0
1624
bool "GPIO Interrupt Controller Driver for STM32WB0 series"
Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
/*
2+
* Copyright (c) 2016 Open-RnD Sp. z o.o.
3+
* Copyright (c) 2017 RnDity Sp. z o.o.
4+
* Copyright (c) 2019-23 Linaro Limited
5+
* Copyright (C) 2025 Savoir-faire Linux, Inc.
6+
* Copyright (c) 2025 Alexander Kozhinov <[email protected]>
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*/
10+
11+
/**
12+
* @brief STM32 External Interrupt/Event Controller (EXTI) Driver
13+
*/
14+
15+
#include <soc.h>
16+
#include <zephyr/device.h>
17+
#include <zephyr/sys/util.h>
18+
#include <zephyr/logging/log.h>
19+
#include <zephyr/drivers/interrupt_controller/intc_exti_stm32.h>
20+
#include <zephyr/drivers/clock_control/stm32_clock_control.h>
21+
22+
#include "stm32_hsem.h"
23+
#include "intc_exti_stm32_priv.h"
24+
25+
LOG_MODULE_REGISTER(exti_stm32, CONFIG_INTC_LOG_LEVEL);
26+
27+
#define IS_VALID_EXTI_LINE_NUM(line_num) ((line_num) < STM32_EXTI_TOTAL_LINES_NUM)
28+
29+
/*
30+
* The boilerplate for COND_CODE_x is needed because the values are not 0/1
31+
*/
32+
#if STM32_EXTI_TOTAL_LINES_NUM > 32
33+
#define HAS_LINES_32_63 1
34+
#if STM32_EXTI_TOTAL_LINES_NUM > 64
35+
#define HAS_LINES_64_95 1
36+
#endif /* STM32_EXTI_TOTAL_LINES_NUM > 64 */
37+
#endif /* STM32_EXTI_TOTAL_LINES_NUM > 32 */
38+
39+
#define EXTI_FN_HANDLER(_fn, line_num, line) \
40+
if (line_num < 32U) { \
41+
_fn(0_31, line); \
42+
IF_ENABLED(HAS_LINES_32_63, ( \
43+
} else if (line_num < 64U) { \
44+
_fn(32_63, line); \
45+
)) \
46+
IF_ENABLED(HAS_LINES_64_95, ( \
47+
} else if (line_num < 96U) { \
48+
_fn(64_95, line); \
49+
)) \
50+
} else { \
51+
LOG_ERR("Invalid line number %u", line_num); \
52+
__ASSERT_NO_MSG(0); \
53+
}
54+
55+
#define EXTI_FN_RET_HANDLER(_fn, ret, line_num, line) \
56+
if (line_num < 32U) { \
57+
*ret = _fn(0_31, line); \
58+
IF_ENABLED(HAS_LINES_32_63, ( \
59+
} else if (line_num < 64U) { \
60+
*ret = _fn(32_63, line); \
61+
)) \
62+
IF_ENABLED(HAS_LINES_64_95, ( \
63+
} else if (line_num < 96U) { \
64+
*ret = _fn(64_95, line); \
65+
)) \
66+
} else { \
67+
LOG_ERR("Invalid line number %u", line_num); \
68+
__ASSERT_NO_MSG(0); \
69+
}
70+
71+
72+
bool stm32_exti_is_pending(uint32_t line_num)
73+
{
74+
bool ret = false;
75+
const uint32_t line = exti_linenum_to_ll_exti_line(line_num);
76+
77+
if (!IS_VALID_EXTI_LINE_NUM(line_num)) {
78+
LOG_ERR("Invalid line number %u", line_num);
79+
return false;
80+
}
81+
82+
z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
83+
84+
/*
85+
* Note: we can't use EXTI_FN_HANDLER here because we care
86+
* about the return value of EXTI_IS_ACTIVE_FLAG.
87+
*/
88+
EXTI_FN_RET_HANDLER(EXTI_IS_ACTIVE_FLAG, &ret, line_num, line);
89+
90+
z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
91+
92+
return ret;
93+
}
94+
95+
int stm32_exti_clear_pending(uint32_t line_num)
96+
{
97+
const uint32_t line = exti_linenum_to_ll_exti_line(line_num);
98+
99+
if (!IS_VALID_EXTI_LINE_NUM(line_num)) {
100+
LOG_ERR("Invalid line number %u", line_num);
101+
return -EINVAL;
102+
}
103+
104+
z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
105+
106+
EXTI_FN_HANDLER(EXTI_CLEAR_FLAG, line_num, line);
107+
108+
z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
109+
110+
return 0;
111+
}
112+
113+
int stm32_exti_sw_interrupt(uint32_t line_num)
114+
{
115+
const uint32_t line = exti_linenum_to_ll_exti_line(line_num);
116+
117+
if (!IS_VALID_EXTI_LINE_NUM(line_num)) {
118+
LOG_ERR("Invalid line number %u", line_num);
119+
return -EINVAL;
120+
}
121+
122+
z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
123+
124+
EXTI_FN_HANDLER(EXTI_GENERATE_SWI, line_num, line);
125+
126+
z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
127+
128+
return 0;
129+
}
130+
131+
/** Enables the peripheral clock required to access EXTI registers */
132+
static int stm32_exti_enable_clocks(void)
133+
{
134+
/* Initialize to 0 for series where there is nothing to do. */
135+
int ret = 0;
136+
137+
#if DT_NODE_HAS_PROP(EXTI_NODE, clocks)
138+
const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE);
139+
140+
if (!device_is_ready(clk)) {
141+
LOG_ERR("Clock control device not ready");
142+
return -ENODEV;
143+
}
144+
145+
const struct stm32_pclken pclken = {
146+
.bus = DT_CLOCKS_CELL(EXTI_NODE, bus),
147+
.enr = DT_CLOCKS_CELL(EXTI_NODE, bits)
148+
};
149+
150+
ret = clock_control_on(clk, (clock_control_subsys_t) &pclken);
151+
#endif
152+
return ret;
153+
}
154+
155+
/**
156+
* @brief Initializes the EXTI interrupt controller driver
157+
*/
158+
static int stm32_exti_init(const struct device *dev)
159+
{
160+
ARG_UNUSED(dev);
161+
162+
return stm32_exti_enable_clocks();
163+
}
164+
165+
/**
166+
* @brief Enable EXTI interrupts.
167+
*
168+
* @param line_num EXTI line number
169+
* @param line LL EXTI line
170+
*/
171+
static void stm32_exti_enable_it(uint32_t line_num, uint32_t line)
172+
{
173+
EXTI_FN_HANDLER(EXTI_ENABLE_IT, line_num, line);
174+
}
175+
176+
/**
177+
* @brief Disable EXTI interrupts.
178+
*
179+
* @param line_num EXTI line number
180+
* @param line LL EXTI line
181+
*/
182+
static void stm32_exti_disable_it(uint32_t line_num, uint32_t line)
183+
{
184+
EXTI_FN_HANDLER(EXTI_DISABLE_IT, line_num, line);
185+
}
186+
187+
/**
188+
* @brief Enables rising trigger for specified EXTI line
189+
*
190+
* @param line_num EXTI line number
191+
* @param line LL EXTI line
192+
*/
193+
static void stm32_exti_enable_rising_trig(uint32_t line_num, uint32_t line)
194+
{
195+
EXTI_FN_HANDLER(EXTI_ENABLE_RISING_TRIG, line_num, line);
196+
}
197+
198+
/**
199+
* @brief Disables rising trigger for specified EXTI line
200+
*
201+
* @param line_num EXTI line number
202+
* @param line LL EXTI line
203+
*/
204+
static void stm32_exti_disable_rising_trig(uint32_t line_num, uint32_t line)
205+
{
206+
EXTI_FN_HANDLER(EXTI_DISABLE_RISING_TRIG, line_num, line);
207+
}
208+
209+
/**
210+
* @brief Enables falling trigger for specified EXTI line
211+
*
212+
* @param line_num EXTI line number
213+
* @param line LL EXTI line
214+
*/
215+
static void stm32_exti_enable_falling_trig(uint32_t line_num, uint32_t line)
216+
{
217+
EXTI_FN_HANDLER(EXTI_ENABLE_FALLING_TRIG, line_num, line);
218+
}
219+
220+
/**
221+
* @brief Disables falling trigger for specified EXTI line
222+
*
223+
* @param line_num EXTI line number
224+
* @param line LL EXTI line
225+
*/
226+
static void stm32_exti_disable_falling_trig(uint32_t line_num, uint32_t line)
227+
{
228+
EXTI_FN_HANDLER(EXTI_DISABLE_FALLING_TRIG, line_num, line);
229+
}
230+
231+
/**
232+
* @brief Selects EXTI trigger mode
233+
*
234+
* @param line_num EXTI line number
235+
* @param line LL EXTI line
236+
* @param mode EXTI mode
237+
*/
238+
static void stm32_exti_select_line_trigger(uint32_t line_num, uint32_t line,
239+
uint32_t trg)
240+
{
241+
switch (trg) {
242+
case STM32_EXTI_TRIG_NONE:
243+
stm32_exti_disable_rising_trig(line_num, line);
244+
stm32_exti_disable_falling_trig(line_num, line);
245+
break;
246+
case STM32_EXTI_TRIG_RISING:
247+
stm32_exti_enable_rising_trig(line_num, line);
248+
stm32_exti_disable_falling_trig(line_num, line);
249+
break;
250+
case STM32_EXTI_TRIG_FALLING:
251+
stm32_exti_enable_falling_trig(line_num, line);
252+
stm32_exti_disable_rising_trig(line_num, line);
253+
break;
254+
case STM32_EXTI_TRIG_BOTH:
255+
stm32_exti_enable_rising_trig(line_num, line);
256+
stm32_exti_enable_falling_trig(line_num, line);
257+
break;
258+
default:
259+
LOG_ERR("Unsupported EXTI trigger 0x%X", trg);
260+
break;
261+
}
262+
}
263+
264+
/**
265+
* @brief Enable EXTI event.
266+
*
267+
* @param line_num EXTI line number
268+
* @param line LL EXTI line
269+
*/
270+
static void stm32_exti_enable_event(uint32_t line_num, uint32_t line)
271+
{
272+
EXTI_FN_HANDLER(EXTI_ENABLE_EVENT, line_num, line);
273+
}
274+
275+
/**
276+
* @brief Disable EXTI interrupts.
277+
*
278+
* @param line_num EXTI line number
279+
* @param line LL EXTI line
280+
*/
281+
static void stm32_exti_disable_event(uint32_t line_num, uint32_t line)
282+
{
283+
EXTI_FN_HANDLER(EXTI_DISABLE_EVENT, line_num, line);
284+
}
285+
286+
/**
287+
* @brief Enables external interrupt/event for specified EXTI line
288+
*
289+
* @param line_num EXTI line number
290+
* @param line LL EXTI line
291+
* @param mode EXTI mode
292+
*/
293+
static void stm32_exti_set_mode(uint32_t line_num, uint32_t line,
294+
stm32_exti_mode mode)
295+
{
296+
switch (mode) {
297+
case STM32_EXTI_MODE_NONE:
298+
stm32_exti_disable_event(line_num, line);
299+
stm32_exti_disable_it(line_num, line);
300+
break;
301+
case STM32_EXTI_MODE_IT:
302+
stm32_exti_disable_event(line_num, line);
303+
stm32_exti_enable_it(line_num, line);
304+
break;
305+
case STM32_EXTI_MODE_EVENT:
306+
stm32_exti_disable_it(line_num, line);
307+
stm32_exti_enable_event(line_num, line);
308+
break;
309+
case STM32_EXTI_MODE_BOTH:
310+
stm32_exti_enable_it(line_num, line);
311+
stm32_exti_enable_event(line_num, line);
312+
break;
313+
default:
314+
LOG_ERR("Unsupported EXTI mode %u", mode);
315+
break;
316+
}
317+
}
318+
319+
int stm32_exti_enable(uint32_t line_num, stm32_exti_trigger_type trigger,
320+
stm32_exti_mode mode)
321+
{
322+
const uint32_t line = exti_linenum_to_ll_exti_line(line_num);
323+
324+
if (!IS_VALID_EXTI_LINE_NUM(line_num)) {
325+
LOG_ERR("Invalid line number %u", line_num);
326+
return -EINVAL;
327+
}
328+
329+
z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
330+
331+
stm32_exti_select_line_trigger(line_num, line, trigger);
332+
stm32_exti_set_mode(line_num, line, mode);
333+
334+
z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
335+
336+
return 0;
337+
}
338+
339+
int stm32_exti_disable(uint32_t line_num)
340+
{
341+
const uint32_t line = exti_linenum_to_ll_exti_line(line_num);
342+
343+
if (!IS_VALID_EXTI_LINE_NUM(line_num)) {
344+
LOG_ERR("Invalid line number %u", line_num);
345+
return -EINVAL;
346+
}
347+
348+
z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
349+
350+
stm32_exti_set_mode(line_num, line, STM32_EXTI_MODE_NONE);
351+
stm32_exti_select_line_trigger(line_num, line, STM32_EXTI_TRIG_NONE);
352+
353+
z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
354+
355+
return 0;
356+
}
357+
358+
DEVICE_DT_DEFINE(EXTI_NODE, &stm32_exti_init,
359+
NULL, NULL, NULL,
360+
PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY,
361+
NULL);

0 commit comments

Comments
 (0)