From ea08227dd07b3e60635c2c8ef4837f795b791cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Arg=C3=BCelles?= Date: Mon, 11 Sep 2023 13:47:26 +0700 Subject: [PATCH] gpio: nxp_s32: prepare to support multiple interrupt controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor external interrupts infrastructure to prepare supporting multiple interrupt controllers. Signed-off-by: Manuel Argüelles --- drivers/gpio/gpio_nxp_s32.c | 165 +++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 77 deletions(-) diff --git a/drivers/gpio/gpio_nxp_s32.c b/drivers/gpio/gpio_nxp_s32.c index de5dbd39dd7..c40b5691931 100644 --- a/drivers/gpio/gpio_nxp_s32.c +++ b/drivers/gpio/gpio_nxp_s32.c @@ -9,20 +9,27 @@ #include #include #include +#include #include #include +LOG_MODULE_REGISTER(nxp_s32_gpio, CONFIG_GPIO_LOG_LEVEL); + #ifdef CONFIG_NXP_S32_EIRQ #include -struct eirq_nxp_s32_info { - const struct device *eirq_dev; - uint8_t num_lines; - struct gpio_pin_line { - uint8_t pin; - uint8_t line; - } gpio_pin_lines[]; +#define NXP_S32_GPIO_LINE_NOT_FOUND 0xff + +struct gpio_nxp_s32_irq_map { + uint8_t pin; + uint8_t line; +} __packed; + +struct gpio_nxp_s32_irq_config { + const struct device *ctrl; + uint8_t map_cnt; + struct gpio_nxp_s32_irq_map *map; }; #endif @@ -34,7 +41,7 @@ struct gpio_nxp_s32_config { Siul2_Port_Ip_PortType *port_base; #ifdef CONFIG_NXP_S32_EIRQ - struct eirq_nxp_s32_info *eirq_info; + struct gpio_nxp_s32_irq_config *eirq_info; #endif }; @@ -155,17 +162,26 @@ static int nxp_s32_gpio_port_toggle_bits(const struct device *port, #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; - for (i = 0; i < eirq_info->num_lines; i++) { - if (eirq_info->gpio_pin_lines[i].pin == pin) { - return eirq_info->gpio_pin_lines[i].line; + for (i = 0; i < irq_cfg->map_cnt; i++) { + if (irq_cfg->map[i].pin == pin) { + 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, @@ -198,12 +214,48 @@ static int nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType *edge_type, 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; - struct gpio_nxp_s32_data *data = dev->data; + const struct gpio_nxp_s32_config *config = dev->config; + 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, @@ -211,48 +263,7 @@ static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev, enum gpio_int_mode mode, enum gpio_int_trig trig) { - const struct gpio_nxp_s32_config *config = dev->config; - 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; + return nxp_s32_gpio_config_eirq(dev, pin, mode, trig); } 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) { 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) { /* @@ -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 * 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 */ @@ -424,30 +435,30 @@ static const struct gpio_driver_api gpio_nxp_s32_driver_api = { DT_INST_PHANDLE(n, interrupt_parent) #define GPIO_NXP_S32_EIRQ_PIN_LINE(idx, n) \ - { \ - .pin = DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \ - .line = DT_INST_IRQ_BY_IDX(n, idx, eirq_line), \ - } + DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \ + DT_INST_IRQ_BY_IDX(n, idx, eirq_line) \ #define GPIO_NXP_S32_SET_EIRQ_INFO(n) \ BUILD_ASSERT((DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupt_parent) == \ DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupts)), \ - "interrupts and interrupt-parent must be set when" \ - " using external interrupts"); \ - IF_ENABLED(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay), \ - (static struct eirq_nxp_s32_info eirq_nxp_s32_info_##n = { \ - .eirq_dev = DEVICE_DT_GET(GPIO_NXP_S32_EIRQ_NODE(n)), \ - .gpio_pin_lines = { \ - LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \ - GPIO_NXP_S32_EIRQ_PIN_LINE, (,), n) \ - }, \ - .num_lines = DT_NUM_IRQS(DT_DRV_INST(n)) \ + "interrupts and interrupt-parent must be set when " \ + "using external interrupts"); \ + IF_ENABLED(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay), ( \ + static uint8_t gpio_nxp_s32_eirq_data_##n[] = { \ + LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \ + GPIO_NXP_S32_EIRQ_PIN_LINE, (,), 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) \ .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 #define GPIO_NXP_S32_SET_EIRQ_INFO(n) #define GPIO_NXP_S32_GET_EIRQ_INFO(n)