2016-03-14 16:29:46 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016 Open-RnD Sp. z o.o.
|
2017-08-09 11:22:33 +02:00
|
|
|
* Copyright (c) 2017 RnDity Sp. z o.o.
|
2023-01-16 09:41:40 +01:00
|
|
|
* Copyright (c) 2019-23 Linaro Limited
|
2016-03-14 16:29:46 +01:00
|
|
|
*
|
2017-01-19 02:01:01 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
2016-03-14 16:29:46 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Driver for External interrupt/event controller in STM32 MCUs
|
|
|
|
*/
|
2021-02-15 17:20:57 +01:00
|
|
|
|
|
|
|
#define EXTI_NODE DT_INST(0, st_stm32_exti)
|
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/device.h>
|
2016-03-14 16:29:46 +01:00
|
|
|
#include <soc.h>
|
2020-11-20 20:35:06 +01:00
|
|
|
#include <stm32_ll_exti.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/sys/__assert.h>
|
2023-05-23 15:47:29 +02:00
|
|
|
#include <zephyr/sys/util.h>
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/drivers/interrupt_controller/exti_stm32.h>
|
2022-10-17 10:24:11 +02:00
|
|
|
#include <zephyr/irq.h>
|
2016-03-14 16:29:46 +01:00
|
|
|
|
2020-06-23 09:48:07 +02:00
|
|
|
#include "stm32_hsem.h"
|
|
|
|
|
2023-01-16 09:41:40 +01:00
|
|
|
/** @brief EXTI line ranges hold by a single ISR */
|
|
|
|
struct stm32_exti_range {
|
|
|
|
/** Start of the range */
|
|
|
|
uint8_t start;
|
|
|
|
/** Range length */
|
|
|
|
uint8_t len;
|
2019-02-26 18:58:24 +01:00
|
|
|
};
|
2023-01-16 09:41:40 +01:00
|
|
|
|
|
|
|
#define NUM_EXTI_LINES DT_PROP(DT_NODELABEL(exti), num_lines)
|
|
|
|
|
|
|
|
static IRQn_Type exti_irq_table[NUM_EXTI_LINES] = {[0 ... NUM_EXTI_LINES - 1] = 0xFF};
|
2016-03-14 16:29:46 +01:00
|
|
|
|
|
|
|
/* wrapper for user callback */
|
|
|
|
struct __exti_cb {
|
|
|
|
stm32_exti_callback_t cb;
|
|
|
|
void *data;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* driver data */
|
|
|
|
struct stm32_exti_data {
|
|
|
|
/* per-line callbacks */
|
2023-01-16 09:41:40 +01:00
|
|
|
struct __exti_cb cb[NUM_EXTI_LINES];
|
2016-03-14 16:29:46 +01:00
|
|
|
};
|
|
|
|
|
2019-10-09 13:54:29 +02:00
|
|
|
void stm32_exti_enable(int line)
|
2016-03-14 16:29:46 +01:00
|
|
|
{
|
2016-10-28 12:27:22 +02:00
|
|
|
int irqnum = 0;
|
2016-03-14 16:29:46 +01:00
|
|
|
|
2023-01-16 09:41:40 +01:00
|
|
|
if (line >= NUM_EXTI_LINES) {
|
2019-02-26 18:58:24 +01:00
|
|
|
__ASSERT_NO_MSG(line);
|
2019-01-29 21:09:04 +01:00
|
|
|
}
|
2016-03-14 16:29:46 +01:00
|
|
|
|
2019-10-09 13:54:29 +02:00
|
|
|
/* Get matching exti irq provided line thanks to irq_table */
|
|
|
|
irqnum = exti_irq_table[line];
|
|
|
|
if (irqnum == 0xFF) {
|
|
|
|
__ASSERT_NO_MSG(line);
|
2019-02-26 18:58:24 +01:00
|
|
|
}
|
2016-03-14 16:29:46 +01:00
|
|
|
|
2019-10-09 13:54:29 +02:00
|
|
|
/* Enable requested line interrupt */
|
2020-04-22 13:43:37 +02:00
|
|
|
#if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4)
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_C2_EXTI_EnableIT_0_31(BIT((uint32_t)line));
|
2020-04-22 13:43:37 +02:00
|
|
|
#else
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_EnableIT_0_31(BIT((uint32_t)line));
|
2020-04-22 13:43:37 +02:00
|
|
|
#endif
|
2019-10-09 13:54:29 +02:00
|
|
|
|
2019-06-04 13:37:14 +02:00
|
|
|
/* Enable exti irq interrupt */
|
2016-03-14 16:29:46 +01:00
|
|
|
irq_enable(irqnum);
|
|
|
|
}
|
|
|
|
|
2016-08-13 07:06:32 +02:00
|
|
|
void stm32_exti_disable(int line)
|
2016-03-14 16:29:46 +01:00
|
|
|
{
|
2019-01-29 21:09:04 +01:00
|
|
|
if (line < 32) {
|
2020-04-22 13:43:37 +02:00
|
|
|
#if defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4)
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_C2_EXTI_DisableIT_0_31(BIT((uint32_t)line));
|
2020-04-22 13:43:37 +02:00
|
|
|
#else
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_DisableIT_0_31(BIT((uint32_t)line));
|
2020-04-22 13:43:37 +02:00
|
|
|
#endif
|
2019-02-26 18:58:24 +01:00
|
|
|
} else {
|
|
|
|
__ASSERT_NO_MSG(line);
|
2019-01-29 21:09:04 +01:00
|
|
|
}
|
2016-03-14 16:29:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief check if interrupt is pending
|
|
|
|
*
|
|
|
|
* @param line line number
|
|
|
|
*/
|
|
|
|
static inline int stm32_exti_is_pending(int line)
|
|
|
|
{
|
2019-01-29 21:09:04 +01:00
|
|
|
if (line < 32) {
|
2023-03-10 14:08:18 +01:00
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32g0_exti)
|
2023-05-26 20:20:13 +02:00
|
|
|
return (LL_EXTI_IsActiveRisingFlag_0_31(BIT((uint32_t)line)) ||
|
|
|
|
LL_EXTI_IsActiveFallingFlag_0_31(BIT((uint32_t)line)));
|
2020-04-22 13:43:37 +02:00
|
|
|
#elif defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4)
|
2023-05-26 20:20:13 +02:00
|
|
|
return LL_C2_EXTI_IsActiveFlag_0_31(BIT((uint32_t)line));
|
2019-02-26 18:58:24 +01:00
|
|
|
#else
|
2023-05-26 20:20:13 +02:00
|
|
|
return LL_EXTI_IsActiveFlag_0_31(BIT((uint32_t)line));
|
2019-02-26 18:58:24 +01:00
|
|
|
#endif
|
|
|
|
} else {
|
2019-01-29 21:09:04 +01:00
|
|
|
__ASSERT_NO_MSG(line);
|
|
|
|
return 0;
|
|
|
|
}
|
2016-03-14 16:29:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief clear pending interrupt bit
|
|
|
|
*
|
|
|
|
* @param line line number
|
|
|
|
*/
|
|
|
|
static inline void stm32_exti_clear_pending(int line)
|
|
|
|
{
|
2019-01-29 21:09:04 +01:00
|
|
|
if (line < 32) {
|
2023-03-10 14:08:18 +01:00
|
|
|
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32g0_exti)
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_ClearRisingFlag_0_31(BIT((uint32_t)line));
|
|
|
|
LL_EXTI_ClearFallingFlag_0_31(BIT((uint32_t)line));
|
2020-04-22 13:43:37 +02:00
|
|
|
#elif defined(CONFIG_SOC_SERIES_STM32H7X) && defined(CONFIG_CPU_CORTEX_M4)
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_C2_EXTI_ClearFlag_0_31(BIT((uint32_t)line));
|
2019-02-26 18:58:24 +01:00
|
|
|
#else
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_ClearFlag_0_31(BIT((uint32_t)line));
|
2019-02-26 18:58:24 +01:00
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
__ASSERT_NO_MSG(line);
|
2019-01-29 21:09:04 +01:00
|
|
|
}
|
2016-03-14 16:29:46 +01:00
|
|
|
}
|
|
|
|
|
2016-08-13 07:06:32 +02:00
|
|
|
void stm32_exti_trigger(int line, int trigger)
|
2016-03-14 16:29:46 +01:00
|
|
|
{
|
2019-10-08 16:39:01 +02:00
|
|
|
|
|
|
|
if (line >= 32) {
|
|
|
|
__ASSERT_NO_MSG(line);
|
2016-03-14 16:29:46 +01:00
|
|
|
}
|
|
|
|
|
2020-06-23 09:48:07 +02:00
|
|
|
z_stm32_hsem_lock(CFG_HW_EXTI_SEMID, HSEM_LOCK_DEFAULT_RETRY);
|
|
|
|
|
2019-10-08 16:39:01 +02:00
|
|
|
switch (trigger) {
|
|
|
|
case STM32_EXTI_TRIG_NONE:
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_DisableRisingTrig_0_31(BIT((uint32_t)line));
|
|
|
|
LL_EXTI_DisableFallingTrig_0_31(BIT((uint32_t)line));
|
2019-10-08 16:39:01 +02:00
|
|
|
break;
|
|
|
|
case STM32_EXTI_TRIG_RISING:
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_EnableRisingTrig_0_31(BIT((uint32_t)line));
|
|
|
|
LL_EXTI_DisableFallingTrig_0_31(BIT((uint32_t)line));
|
2019-10-08 16:39:01 +02:00
|
|
|
break;
|
|
|
|
case STM32_EXTI_TRIG_FALLING:
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_EnableFallingTrig_0_31(BIT((uint32_t)line));
|
|
|
|
LL_EXTI_DisableRisingTrig_0_31(BIT((uint32_t)line));
|
2019-10-08 16:39:01 +02:00
|
|
|
break;
|
|
|
|
case STM32_EXTI_TRIG_BOTH:
|
2023-05-26 20:20:13 +02:00
|
|
|
LL_EXTI_EnableRisingTrig_0_31(BIT((uint32_t)line));
|
|
|
|
LL_EXTI_EnableFallingTrig_0_31(BIT((uint32_t)line));
|
2020-02-12 12:15:31 +01:00
|
|
|
break;
|
2019-10-08 16:39:01 +02:00
|
|
|
default:
|
|
|
|
__ASSERT_NO_MSG(trigger);
|
2023-05-26 20:35:01 +02:00
|
|
|
break;
|
2016-03-14 16:29:46 +01:00
|
|
|
}
|
2020-06-23 09:48:07 +02:00
|
|
|
z_stm32_hsem_unlock(CFG_HW_EXTI_SEMID);
|
2016-03-14 16:29:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief EXTI ISR handler
|
|
|
|
*
|
2023-01-16 09:41:40 +01:00
|
|
|
* Check EXTI lines in exti_range for pending interrupts
|
2016-03-14 16:29:46 +01:00
|
|
|
*
|
2023-07-13 14:18:49 +02:00
|
|
|
* @param exti_range Pointer to a exti_range structure
|
2016-03-14 16:29:46 +01:00
|
|
|
*/
|
2023-01-16 09:41:40 +01:00
|
|
|
static void stm32_exti_isr(const void *exti_range)
|
2016-03-14 16:29:46 +01:00
|
|
|
{
|
2023-01-16 09:41:40 +01:00
|
|
|
const struct device *dev = DEVICE_DT_GET(EXTI_NODE);
|
2020-05-28 21:23:02 +02:00
|
|
|
struct stm32_exti_data *data = dev->data;
|
2023-01-16 09:41:40 +01:00
|
|
|
const struct stm32_exti_range *range = exti_range;
|
2016-03-14 16:29:46 +01:00
|
|
|
int line;
|
|
|
|
|
|
|
|
/* see which bits are set */
|
2023-05-26 20:55:15 +02:00
|
|
|
for (uint8_t i = 0; i <= range->len; i++) {
|
2023-01-16 09:41:40 +01:00
|
|
|
line = range->start + i;
|
2016-03-14 16:29:46 +01:00
|
|
|
/* check if interrupt is pending */
|
2023-05-26 21:20:23 +02:00
|
|
|
if (stm32_exti_is_pending(line) != 0) {
|
2016-03-14 16:29:46 +01:00
|
|
|
/* clear pending interrupt */
|
|
|
|
stm32_exti_clear_pending(line);
|
|
|
|
|
|
|
|
/* run callback only if one is registered */
|
|
|
|
if (!data->cb[line].cb) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
data->cb[line].cb(line, data->cb[line].data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 09:41:40 +01:00
|
|
|
static void stm32_fill_irq_table(int8_t start, int8_t len, int32_t irqn)
|
2016-10-28 12:27:22 +02:00
|
|
|
{
|
2023-01-16 09:41:40 +01:00
|
|
|
for (int i = 0; i < len; i++) {
|
|
|
|
exti_irq_table[start + i] = irqn;
|
|
|
|
}
|
2018-06-14 08:24:39 +02:00
|
|
|
}
|
2016-10-28 12:27:22 +02:00
|
|
|
|
2023-01-16 09:41:40 +01:00
|
|
|
/* This macro:
|
|
|
|
* - populates line_range_x from line_range dt property
|
|
|
|
* - fill exti_irq_table through stm32_fill_irq_table()
|
|
|
|
* - calls IRQ_CONNECT for each irq & matching line_range
|
|
|
|
*/
|
2023-05-23 15:47:29 +02:00
|
|
|
|
2023-01-16 09:41:40 +01:00
|
|
|
#define STM32_EXTI_INIT(node_id, interrupts, idx) \
|
|
|
|
static const struct stm32_exti_range line_range_##idx = { \
|
2023-05-23 15:47:29 +02:00
|
|
|
DT_PROP_BY_IDX(node_id, line_ranges, UTIL_X2(idx)), \
|
|
|
|
DT_PROP_BY_IDX(node_id, line_ranges, UTIL_INC(UTIL_X2(idx))) \
|
2023-01-16 09:41:40 +01:00
|
|
|
}; \
|
|
|
|
stm32_fill_irq_table(line_range_##idx.start, \
|
|
|
|
line_range_##idx.len, \
|
|
|
|
DT_IRQ_BY_IDX(node_id, idx, irq)); \
|
|
|
|
IRQ_CONNECT(DT_IRQ_BY_IDX(node_id, idx, irq), \
|
|
|
|
DT_IRQ_BY_IDX(node_id, idx, priority), \
|
|
|
|
stm32_exti_isr, &line_range_##idx, \
|
|
|
|
0);
|
2016-03-14 16:29:46 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief initialize EXTI device driver
|
|
|
|
*/
|
2020-04-30 20:33:38 +02:00
|
|
|
static int stm32_exti_init(const struct device *dev)
|
2016-03-14 16:29:46 +01:00
|
|
|
{
|
2023-01-16 09:41:40 +01:00
|
|
|
ARG_UNUSED(dev);
|
2023-05-23 15:47:29 +02:00
|
|
|
|
2023-01-16 09:41:40 +01:00
|
|
|
DT_FOREACH_PROP_ELEM(DT_NODELABEL(exti),
|
|
|
|
interrupt_names,
|
|
|
|
STM32_EXTI_INIT);
|
2016-03-14 16:29:46 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct stm32_exti_data exti_data;
|
2021-02-15 17:20:57 +01:00
|
|
|
DEVICE_DT_DEFINE(EXTI_NODE, &stm32_exti_init,
|
2021-04-28 11:06:54 +02:00
|
|
|
NULL,
|
2021-02-15 17:20:57 +01:00
|
|
|
&exti_data, NULL,
|
2022-03-11 23:25:41 +01:00
|
|
|
PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY,
|
2021-02-15 17:20:57 +01:00
|
|
|
NULL);
|
2016-03-14 16:29:46 +01:00
|
|
|
|
2016-08-13 07:06:32 +02:00
|
|
|
/**
|
|
|
|
* @brief set & unset for the interrupt callbacks
|
|
|
|
*/
|
2019-10-09 11:20:02 +02:00
|
|
|
int stm32_exti_set_callback(int line, stm32_exti_callback_t cb, void *arg)
|
2016-08-13 07:06:32 +02:00
|
|
|
{
|
2022-08-22 10:36:10 +02:00
|
|
|
const struct device *const dev = DEVICE_DT_GET(EXTI_NODE);
|
2020-05-28 21:23:02 +02:00
|
|
|
struct stm32_exti_data *data = dev->data;
|
2016-08-13 07:06:32 +02:00
|
|
|
|
2023-05-26 21:39:24 +02:00
|
|
|
if ((data->cb[line].cb == cb) && (data->cb[line].data == arg)) {
|
2023-04-03 13:43:33 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-05-26 21:50:06 +02:00
|
|
|
/* if callback already exists/maybe-running return busy */
|
|
|
|
if (data->cb[line].cb != NULL) {
|
2018-12-05 09:25:39 +01:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
2016-08-13 07:06:32 +02:00
|
|
|
|
|
|
|
data->cb[line].cb = cb;
|
|
|
|
data->cb[line].data = arg;
|
2018-12-05 09:25:39 +01:00
|
|
|
|
|
|
|
return 0;
|
2016-08-13 07:06:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void stm32_exti_unset_callback(int line)
|
|
|
|
{
|
2022-08-22 10:36:10 +02:00
|
|
|
const struct device *const dev = DEVICE_DT_GET(EXTI_NODE);
|
2020-05-28 21:23:02 +02:00
|
|
|
struct stm32_exti_data *data = dev->data;
|
2016-08-13 07:06:32 +02:00
|
|
|
|
|
|
|
data->cb[line].cb = NULL;
|
|
|
|
data->cb[line].data = NULL;
|
|
|
|
}
|