gpio: nxp_s32: prepare to support multiple interrupt controllers
Refactor external interrupts infrastructure to prepare supporting multiple interrupt controllers. Signed-off-by: Manuel Argüelles <manuel.arguelles@nxp.com>
This commit is contained in:
parent
c8a5cf6728
commit
ea08227dd0
1 changed files with 88 additions and 77 deletions
|
@ -9,20 +9,27 @@
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <zephyr/drivers/gpio.h>
|
#include <zephyr/drivers/gpio.h>
|
||||||
#include <zephyr/drivers/gpio/gpio_utils.h>
|
#include <zephyr/drivers/gpio/gpio_utils.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
|
||||||
#include <Siul2_Port_Ip.h>
|
#include <Siul2_Port_Ip.h>
|
||||||
#include <Siul2_Dio_Ip.h>
|
#include <Siul2_Dio_Ip.h>
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(nxp_s32_gpio, CONFIG_GPIO_LOG_LEVEL);
|
||||||
|
|
||||||
#ifdef CONFIG_NXP_S32_EIRQ
|
#ifdef CONFIG_NXP_S32_EIRQ
|
||||||
#include <zephyr/drivers/interrupt_controller/intc_eirq_nxp_s32.h>
|
#include <zephyr/drivers/interrupt_controller/intc_eirq_nxp_s32.h>
|
||||||
|
|
||||||
struct eirq_nxp_s32_info {
|
#define NXP_S32_GPIO_LINE_NOT_FOUND 0xff
|
||||||
const struct device *eirq_dev;
|
|
||||||
uint8_t num_lines;
|
struct gpio_nxp_s32_irq_map {
|
||||||
struct gpio_pin_line {
|
uint8_t pin;
|
||||||
uint8_t pin;
|
uint8_t line;
|
||||||
uint8_t line;
|
} __packed;
|
||||||
} gpio_pin_lines[];
|
|
||||||
|
struct gpio_nxp_s32_irq_config {
|
||||||
|
const struct device *ctrl;
|
||||||
|
uint8_t map_cnt;
|
||||||
|
struct gpio_nxp_s32_irq_map *map;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -34,7 +41,7 @@ struct gpio_nxp_s32_config {
|
||||||
Siul2_Port_Ip_PortType *port_base;
|
Siul2_Port_Ip_PortType *port_base;
|
||||||
|
|
||||||
#ifdef CONFIG_NXP_S32_EIRQ
|
#ifdef CONFIG_NXP_S32_EIRQ
|
||||||
struct eirq_nxp_s32_info *eirq_info;
|
struct gpio_nxp_s32_irq_config *eirq_info;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -155,17 +162,26 @@ static int nxp_s32_gpio_port_toggle_bits(const struct device *port,
|
||||||
|
|
||||||
#ifdef CONFIG_NXP_S32_EIRQ
|
#ifdef CONFIG_NXP_S32_EIRQ
|
||||||
|
|
||||||
static uint8_t nxp_s32_gpio_pin_to_line(const struct eirq_nxp_s32_info *eirq_info, uint8_t pin)
|
static uint8_t nxp_s32_gpio_pin_to_line(const struct gpio_nxp_s32_irq_config *irq_cfg,
|
||||||
|
uint8_t pin)
|
||||||
{
|
{
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
for (i = 0; i < eirq_info->num_lines; i++) {
|
for (i = 0; i < irq_cfg->map_cnt; i++) {
|
||||||
if (eirq_info->gpio_pin_lines[i].pin == pin) {
|
if (irq_cfg->map[i].pin == pin) {
|
||||||
return eirq_info->gpio_pin_lines[i].line;
|
return irq_cfg->map[i].line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return SIUL2_ICU_IP_NUM_OF_CHANNELS;
|
return NXP_S32_GPIO_LINE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nxp_s32_gpio_isr(uint8_t pin, void *arg)
|
||||||
|
{
|
||||||
|
const struct device *dev = (struct device *)arg;
|
||||||
|
struct gpio_nxp_s32_data *data = dev->data;
|
||||||
|
|
||||||
|
gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType *edge_type,
|
static int nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType *edge_type,
|
||||||
|
@ -198,12 +214,48 @@ static int nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType *edge_type,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nxp_s32_gpio_isr(uint8_t pin, void *arg)
|
static int nxp_s32_gpio_config_eirq(const struct device *dev,
|
||||||
|
gpio_pin_t pin,
|
||||||
|
enum gpio_int_mode mode,
|
||||||
|
enum gpio_int_trig trig)
|
||||||
{
|
{
|
||||||
const struct device *dev = (struct device *)arg;
|
const struct gpio_nxp_s32_config *config = dev->config;
|
||||||
struct gpio_nxp_s32_data *data = dev->data;
|
const struct gpio_nxp_s32_irq_config *irq_cfg = config->eirq_info;
|
||||||
|
uint8_t irq_line;
|
||||||
|
Siul2_Icu_Ip_EdgeType edge_type;
|
||||||
|
|
||||||
gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
|
if (irq_cfg == NULL) {
|
||||||
|
LOG_ERR("external interrupt controller not available or enabled");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nxp_s32_gpio_eirq_get_trigger(&edge_type, mode, trig)) {
|
||||||
|
LOG_ERR("trigger or mode not supported");
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq_line = nxp_s32_gpio_pin_to_line(irq_cfg, pin);
|
||||||
|
if (irq_line == NXP_S32_GPIO_LINE_NOT_FOUND) {
|
||||||
|
if (edge_type == SIUL2_ICU_DISABLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
LOG_ERR("pin %d cannot be used for external interrupt", pin);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edge_type == SIUL2_ICU_DISABLE) {
|
||||||
|
eirq_nxp_s32_disable_interrupt(irq_cfg->ctrl, irq_line);
|
||||||
|
eirq_nxp_s32_unset_callback(irq_cfg->ctrl, irq_line);
|
||||||
|
} else {
|
||||||
|
if (eirq_nxp_s32_set_callback(irq_cfg->ctrl, irq_line,
|
||||||
|
nxp_s32_gpio_isr, pin, (void *)dev)) {
|
||||||
|
LOG_ERR("pin %d is already in use", pin);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
eirq_nxp_s32_enable_interrupt(irq_cfg->ctrl, irq_line, edge_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev,
|
static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev,
|
||||||
|
@ -211,48 +263,7 @@ static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev,
|
||||||
enum gpio_int_mode mode,
|
enum gpio_int_mode mode,
|
||||||
enum gpio_int_trig trig)
|
enum gpio_int_trig trig)
|
||||||
{
|
{
|
||||||
const struct gpio_nxp_s32_config *config = dev->config;
|
return nxp_s32_gpio_config_eirq(dev, pin, mode, trig);
|
||||||
const struct eirq_nxp_s32_info *eirq_info = config->eirq_info;
|
|
||||||
|
|
||||||
uint8_t eirq_line;
|
|
||||||
|
|
||||||
Siul2_Icu_Ip_EdgeType edge_type;
|
|
||||||
|
|
||||||
if (eirq_info == NULL) {
|
|
||||||
/*
|
|
||||||
* There is no external interrupt device for
|
|
||||||
* the GPIO port or exists but is not enabled
|
|
||||||
*/
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
eirq_line = nxp_s32_gpio_pin_to_line(eirq_info, pin);
|
|
||||||
|
|
||||||
if (eirq_line == SIUL2_ICU_IP_NUM_OF_CHANNELS) {
|
|
||||||
/*
|
|
||||||
* GPIO pin cannot be used for processing
|
|
||||||
* external interrupt signal
|
|
||||||
*/
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nxp_s32_gpio_eirq_get_trigger(&edge_type, mode, trig)) {
|
|
||||||
return -ENOTSUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edge_type == SIUL2_ICU_DISABLE) {
|
|
||||||
eirq_nxp_s32_disable_interrupt(eirq_info->eirq_dev, eirq_line);
|
|
||||||
eirq_nxp_s32_unset_callback(eirq_info->eirq_dev, eirq_line);
|
|
||||||
} else {
|
|
||||||
if (eirq_nxp_s32_set_callback(eirq_info->eirq_dev, eirq_line,
|
|
||||||
nxp_s32_gpio_isr, pin, (void *)dev)) {
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
eirq_nxp_s32_enable_interrupt(eirq_info->eirq_dev, eirq_line, edge_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nxp_s32_gpio_manage_callback(const struct device *dev,
|
static int nxp_s32_gpio_manage_callback(const struct device *dev,
|
||||||
|
@ -266,7 +277,7 @@ static int nxp_s32_gpio_manage_callback(const struct device *dev,
|
||||||
static uint32_t nxp_s32_gpio_get_pending_int(const struct device *dev)
|
static uint32_t nxp_s32_gpio_get_pending_int(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct gpio_nxp_s32_config *config = dev->config;
|
const struct gpio_nxp_s32_config *config = dev->config;
|
||||||
const struct eirq_nxp_s32_info *eirq_info = config->eirq_info;
|
const struct gpio_nxp_s32_irq_config *eirq_info = config->eirq_info;
|
||||||
|
|
||||||
if (eirq_info == NULL) {
|
if (eirq_info == NULL) {
|
||||||
/*
|
/*
|
||||||
|
@ -280,7 +291,7 @@ static uint32_t nxp_s32_gpio_get_pending_int(const struct device *dev)
|
||||||
* Return all pending lines of the interrupt controller
|
* Return all pending lines of the interrupt controller
|
||||||
* that GPIO port belongs to
|
* that GPIO port belongs to
|
||||||
*/
|
*/
|
||||||
return eirq_nxp_s32_get_pending(eirq_info->eirq_dev);
|
return eirq_nxp_s32_get_pending(eirq_info->ctrl);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NXP_S32_EIRQ */
|
#endif /* CONFIG_NXP_S32_EIRQ */
|
||||||
|
|
||||||
|
@ -424,30 +435,30 @@ static const struct gpio_driver_api gpio_nxp_s32_driver_api = {
|
||||||
DT_INST_PHANDLE(n, interrupt_parent)
|
DT_INST_PHANDLE(n, interrupt_parent)
|
||||||
|
|
||||||
#define GPIO_NXP_S32_EIRQ_PIN_LINE(idx, n) \
|
#define GPIO_NXP_S32_EIRQ_PIN_LINE(idx, n) \
|
||||||
{ \
|
DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \
|
||||||
.pin = DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \
|
DT_INST_IRQ_BY_IDX(n, idx, eirq_line) \
|
||||||
.line = DT_INST_IRQ_BY_IDX(n, idx, eirq_line), \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GPIO_NXP_S32_SET_EIRQ_INFO(n) \
|
#define GPIO_NXP_S32_SET_EIRQ_INFO(n) \
|
||||||
BUILD_ASSERT((DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupt_parent) == \
|
BUILD_ASSERT((DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupt_parent) == \
|
||||||
DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupts)), \
|
DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupts)), \
|
||||||
"interrupts and interrupt-parent must be set when" \
|
"interrupts and interrupt-parent must be set when " \
|
||||||
" using external interrupts"); \
|
"using external interrupts"); \
|
||||||
IF_ENABLED(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay), \
|
IF_ENABLED(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay), ( \
|
||||||
(static struct eirq_nxp_s32_info eirq_nxp_s32_info_##n = { \
|
static uint8_t gpio_nxp_s32_eirq_data_##n[] = { \
|
||||||
.eirq_dev = DEVICE_DT_GET(GPIO_NXP_S32_EIRQ_NODE(n)), \
|
LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \
|
||||||
.gpio_pin_lines = { \
|
GPIO_NXP_S32_EIRQ_PIN_LINE, (,), n) \
|
||||||
LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \
|
|
||||||
GPIO_NXP_S32_EIRQ_PIN_LINE, (,), n) \
|
|
||||||
}, \
|
|
||||||
.num_lines = DT_NUM_IRQS(DT_DRV_INST(n)) \
|
|
||||||
}; \
|
}; \
|
||||||
))
|
static struct gpio_nxp_s32_irq_config gpio_nxp_s32_eirq_##n = { \
|
||||||
|
.ctrl = DEVICE_DT_GET(GPIO_NXP_S32_EIRQ_NODE(n)), \
|
||||||
|
.map_cnt = DT_NUM_IRQS(DT_DRV_INST(n)), \
|
||||||
|
.map = (struct gpio_nxp_s32_irq_map *) \
|
||||||
|
gpio_nxp_s32_eirq_data_##n, \
|
||||||
|
}; \
|
||||||
|
))
|
||||||
|
|
||||||
#define GPIO_NXP_S32_GET_EIRQ_INFO(n) \
|
#define GPIO_NXP_S32_GET_EIRQ_INFO(n) \
|
||||||
.eirq_info = UTIL_AND(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay),\
|
.eirq_info = UTIL_AND(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay),\
|
||||||
&eirq_nxp_s32_info_##n)
|
&gpio_nxp_s32_eirq_##n),
|
||||||
#else
|
#else
|
||||||
#define GPIO_NXP_S32_SET_EIRQ_INFO(n)
|
#define GPIO_NXP_S32_SET_EIRQ_INFO(n)
|
||||||
#define GPIO_NXP_S32_GET_EIRQ_INFO(n)
|
#define GPIO_NXP_S32_GET_EIRQ_INFO(n)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue