07eee1bc79
The gd32_exti_isr function may be unused if the GPIO driver is not enabled but EXTI is (no IRQ will connect to it). This may be improved in the future by requiring explicit enablement of the exti DT node. Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>
195 lines
5.2 KiB
C
195 lines
5.2 KiB
C
/*
|
|
* Copyright (c) 2021 Teslabs Engineering S.L.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT gd_gd32_exti
|
|
|
|
#include <device.h>
|
|
#include <drivers/interrupt_controller/gd32_exti.h>
|
|
#include <soc.h>
|
|
#include <sys/__assert.h>
|
|
#include <sys/util_macro.h>
|
|
|
|
/** Unsupported line indicator */
|
|
#define EXTI_NOTSUP 0xFFU
|
|
|
|
/** Number of EXTI lines. */
|
|
#define NUM_EXTI_LINES DT_INST_PROP(0, num_lines)
|
|
|
|
/** @brief EXTI line ranges hold by a single ISR */
|
|
struct gd32_exti_range {
|
|
/** Start of the range */
|
|
uint8_t min;
|
|
/** End of the range */
|
|
uint8_t max;
|
|
};
|
|
|
|
/** @brief EXTI line interrupt callback. */
|
|
struct gd32_cb_data {
|
|
/** Callback function */
|
|
gd32_exti_cb_t cb;
|
|
/** User data. */
|
|
void *user;
|
|
};
|
|
|
|
/** EXTI driver data. */
|
|
struct gd32_exti_data {
|
|
/** Array of callbacks. */
|
|
struct gd32_cb_data cbs[NUM_EXTI_LINES];
|
|
};
|
|
|
|
#ifdef CONFIG_GPIO_GD32
|
|
static const struct gd32_exti_range line0_range = {0U, 0U};
|
|
static const struct gd32_exti_range line1_range = {1U, 1U};
|
|
static const struct gd32_exti_range line2_range = {2U, 2U};
|
|
static const struct gd32_exti_range line3_range = {3U, 3U};
|
|
static const struct gd32_exti_range line4_range = {4U, 4U};
|
|
static const struct gd32_exti_range line5_9_range = {5U, 9U};
|
|
static const struct gd32_exti_range line10_15_range = {10U, 15U};
|
|
#endif /* CONFIG_GPIO_GD32 */
|
|
|
|
/** @brief Obtain line IRQ number if enabled. */
|
|
#define EXTI_LINE_IRQ_COND(enabled, line) \
|
|
COND_CODE_1(enabled, (DT_INST_IRQ_BY_NAME(0, line, irq)), (EXTI_NOTSUP))
|
|
|
|
static const uint8_t line2irq[NUM_EXTI_LINES] = {
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line0),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line1),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line2),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line3),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line4),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
|
|
EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
|
|
EXTI_NOTSUP,
|
|
EXTI_NOTSUP,
|
|
EXTI_NOTSUP,
|
|
#ifdef CONFIG_SOC_SERIES_GD32F4XX
|
|
EXTI_NOTSUP,
|
|
EXTI_NOTSUP,
|
|
EXTI_NOTSUP,
|
|
EXTI_NOTSUP,
|
|
#endif /* CONFIG_SOC_SERIES_GD32F4XX */
|
|
};
|
|
|
|
__unused static void gd32_exti_isr(void *isr_data)
|
|
{
|
|
const struct device *dev = DEVICE_DT_INST_GET(0);
|
|
struct gd32_exti_data *data = dev->data;
|
|
const struct gd32_exti_range *range = isr_data;
|
|
|
|
for (uint8_t i = range->min; i <= range->max; i++) {
|
|
if ((EXTI_PD & BIT(i)) != 0U) {
|
|
EXTI_PD = BIT(i);
|
|
|
|
if (data->cbs[i].cb != NULL) {
|
|
data->cbs[i].cb(i, data->cbs[i].user);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void gd32_exti_enable(uint8_t line)
|
|
{
|
|
__ASSERT_NO_MSG(line < NUM_EXTI_LINES);
|
|
__ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
|
|
|
|
EXTI_INTEN |= BIT(line);
|
|
|
|
irq_enable(line2irq[line]);
|
|
}
|
|
|
|
void gd32_exti_disable(uint8_t line)
|
|
{
|
|
__ASSERT_NO_MSG(line < NUM_EXTI_LINES);
|
|
__ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
|
|
|
|
EXTI_INTEN &= ~BIT(line);
|
|
}
|
|
|
|
void gd32_exti_trigger(uint8_t line, uint8_t trigger)
|
|
{
|
|
__ASSERT_NO_MSG(line < NUM_EXTI_LINES);
|
|
__ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
|
|
|
|
if ((trigger & GD32_EXTI_TRIG_RISING) != 0U) {
|
|
EXTI_RTEN |= BIT(line);
|
|
} else {
|
|
EXTI_RTEN &= ~BIT(line);
|
|
}
|
|
|
|
if ((trigger & GD32_EXTI_TRIG_FALLING) != 0U) {
|
|
EXTI_FTEN |= BIT(line);
|
|
} else {
|
|
EXTI_FTEN &= ~BIT(line);
|
|
}
|
|
}
|
|
|
|
int gd32_exti_configure(uint8_t line, gd32_exti_cb_t cb, void *user)
|
|
{
|
|
const struct device *dev = DEVICE_DT_INST_GET(0);
|
|
struct gd32_exti_data *data = dev->data;
|
|
|
|
__ASSERT_NO_MSG(line < NUM_EXTI_LINES);
|
|
__ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
|
|
|
|
if ((data->cbs[line].cb != NULL) && (cb != NULL)) {
|
|
return -EALREADY;
|
|
}
|
|
|
|
data->cbs[line].cb = cb;
|
|
data->cbs[line].user = user;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gd32_exti_init(const struct device *dev)
|
|
{
|
|
#ifdef CONFIG_GPIO_GD32
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line0, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line0, priority),
|
|
gd32_exti_isr, &line0_range, 0);
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line1, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line1, priority),
|
|
gd32_exti_isr, &line1_range, 0);
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line2, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line2, priority),
|
|
gd32_exti_isr, &line2_range, 0);
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line3, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line3, priority),
|
|
gd32_exti_isr, &line3_range, 0);
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line4, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line4, priority),
|
|
gd32_exti_isr, &line4_range, 0);
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line5_9, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line5_9, priority),
|
|
gd32_exti_isr, &line5_9_range, 0);
|
|
|
|
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line10_15, irq),
|
|
DT_INST_IRQ_BY_NAME(0, line10_15, priority),
|
|
gd32_exti_isr, &line10_15_range, 0);
|
|
#endif /* CONFIG_GPIO_GD32 */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct gd32_exti_data data;
|
|
|
|
DEVICE_DT_INST_DEFINE(0, gd32_exti_init, NULL, &data, NULL, PRE_KERNEL_1,
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
|