diff --git a/drivers/interrupt_controller/CMakeLists.txt b/drivers/interrupt_controller/CMakeLists.txt index 0e458d033f2..8f3b279eda6 100644 --- a/drivers/interrupt_controller/CMakeLists.txt +++ b/drivers/interrupt_controller/CMakeLists.txt @@ -41,6 +41,7 @@ zephyr_library_sources_ifdef(CONFIG_NXP_S32_WKPU intc_wkpu_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_XMC4XXX_INTC intc_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_NXP_PINT intc_nxp_pint.c) zephyr_library_sources_ifdef(CONFIG_RENESAS_RA_ICU intc_renesas_ra_icu.c) +zephyr_library_sources_ifdef(CONFIG_RENESAS_RZ_EXT_IRQ intc_renesas_rz_ext_irq.c) zephyr_library_sources_ifdef(CONFIG_NXP_IRQSTEER intc_nxp_irqsteer.c) zephyr_library_sources_ifdef(CONFIG_INTC_MTK_ADSP intc_mtk_adsp.c) zephyr_library_sources_ifdef(CONFIG_WCH_PFIC intc_wch_pfic.c) diff --git a/drivers/interrupt_controller/Kconfig b/drivers/interrupt_controller/Kconfig index caabfc57690..388bfd2eb9f 100644 --- a/drivers/interrupt_controller/Kconfig +++ b/drivers/interrupt_controller/Kconfig @@ -104,6 +104,8 @@ source "drivers/interrupt_controller/Kconfig.vim" source "drivers/interrupt_controller/Kconfig.renesas_ra" +source "drivers/interrupt_controller/Kconfig.renesas_rz" + source "drivers/interrupt_controller/Kconfig.nxp_irqsteer" source "drivers/interrupt_controller/Kconfig.mtk_adsp" diff --git a/drivers/interrupt_controller/Kconfig.renesas_rz b/drivers/interrupt_controller/Kconfig.renesas_rz new file mode 100644 index 00000000000..6fe45f73788 --- /dev/null +++ b/drivers/interrupt_controller/Kconfig.renesas_rz @@ -0,0 +1,11 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config RENESAS_RZ_EXT_IRQ + bool "Renesas RZ external interrupt controller driver" + default y + depends on DT_HAS_RENESAS_RZ_EXT_IRQ_ENABLED + select USE_RZ_FSP_EXT_IRQ + select PINCTRL + help + Renesas RZ external interrupt controller driver diff --git a/drivers/interrupt_controller/intc_renesas_rz_ext_irq.c b/drivers/interrupt_controller/intc_renesas_rz_ext_irq.c new file mode 100644 index 00000000000..7447441086c --- /dev/null +++ b/drivers/interrupt_controller/intc_renesas_rz_ext_irq.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rz_ext_irq + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(rz_ext_irq, CONFIG_INTC_LOG_LEVEL); + +struct intc_rz_ext_irq_config { + const struct pinctrl_dev_config *pin_config; + const external_irq_cfg_t *fsp_cfg; + const external_irq_api_t *fsp_api; +}; + +struct intc_rz_ext_irq_data { + external_irq_ctrl_t *fsp_ctrl; + intc_rz_ext_irq_callback_t callback; + void *callback_data; +}; + +/* FSP interruption handlers. */ +void r_intc_irq_isr(void); +void r_intc_nmi_isr(void); + +int intc_rz_ext_irq_enable(const struct device *dev) +{ + const struct intc_rz_ext_irq_config *config = dev->config; + struct intc_rz_ext_irq_data *data = dev->data; + fsp_err_t err = FSP_SUCCESS; + + err = config->fsp_api->enable(data->fsp_ctrl); + + if (err != FSP_SUCCESS) { + return -EIO; + } + + return 0; +} + +int intc_rz_ext_irq_disable(const struct device *dev) +{ + const struct intc_rz_ext_irq_config *config = dev->config; + struct intc_rz_ext_irq_data *data = dev->data; + fsp_err_t err = FSP_SUCCESS; + + err = config->fsp_api->disable(data->fsp_ctrl); + + if (err != FSP_SUCCESS) { + return -EIO; + } + + return 0; +} + +int intc_rz_ext_irq_set_callback(const struct device *dev, intc_rz_ext_irq_callback_t cb, void *arg) +{ + struct intc_rz_ext_irq_data *data = dev->data; + + data->callback = cb; + data->callback_data = arg; + + return 0; +} + +static int intc_rz_ext_irq_init(const struct device *dev) +{ + const struct intc_rz_ext_irq_config *config = dev->config; + struct intc_rz_ext_irq_data *data = dev->data; + fsp_err_t err = FSP_SUCCESS; + int ret = 0; + + if (config->pin_config) { + ret = pinctrl_apply_state(config->pin_config, PINCTRL_STATE_DEFAULT); + + if (ret < 0) { + LOG_ERR("%s: pinctrl config failed.", __func__); + return ret; + } + } + + err = config->fsp_api->open(data->fsp_ctrl, config->fsp_cfg); + + if (err != FSP_SUCCESS) { + return -EIO; + } + + return 0; +} + +static void intc_rz_ext_irq_callback(external_irq_callback_args_t *args) +{ + const struct device *dev = (const struct device *)args->p_context; + struct intc_rz_ext_irq_data *data = dev->data; + + if (data->callback) { + data->callback(data->callback_data); + } +} + +#define EXT_IRQ_RZG_IRQ_CONNECT(index, isr, isr_nmi) \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(index, 0, irq), DT_INST_IRQ_BY_IDX(index, 0, priority), \ + COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq), \ + (isr_nmi), (isr)), NULL, 0); + +#define INTC_RZG_EXT_IRQ_INIT(index) \ + static const external_irq_cfg_t g_external_irq##index##_cfg = { \ + .trigger = DT_INST_ENUM_IDX_OR(index, trigger_type, 0), \ + .filter_enable = true, \ + .pclk_div = EXTERNAL_IRQ_PCLK_DIV_BY_1, \ + .p_callback = intc_rz_ext_irq_callback, \ + .p_context = DEVICE_DT_INST_GET(index), \ + .p_extend = NULL, \ + .ipl = DT_INST_IRQ_BY_IDX(index, 0, priority), \ + .irq = DT_INST_IRQ_BY_IDX(index, 0, irq), \ + COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq), \ + (.channel = DT_INST_IRQ_BY_IDX(index, 0, irq)), \ + (.channel = DT_INST_IRQ_BY_IDX(index, 0, irq) - 1)), \ + }; \ + \ + PINCTRL_DT_INST_DEFINE(index); \ + \ + struct intc_rz_ext_irq_config intc_rz_ext_irq_config##index = { \ + .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \ + .fsp_cfg = (external_irq_cfg_t *)&g_external_irq##index##_cfg, \ + COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq), ( \ + .fsp_api = &g_external_irq_on_intc_nmi), ( \ + .fsp_api = &g_external_irq_on_intc_irq)), \ + }; \ + \ + COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq), \ + (static intc_nmi_instance_ctrl_t g_external_irq##index##_ctrl;), \ + (static intc_irq_instance_ctrl_t g_external_irq##index##_ctrl;)) \ + \ + static struct intc_rz_ext_irq_data intc_rz_ext_irq_data##index = { \ + .fsp_ctrl = (external_irq_ctrl_t *)&g_external_irq##index##_ctrl, \ + }; \ + \ + static int intc_rz_ext_irq_init_##index(const struct device *dev) \ + { \ + EXT_IRQ_RZG_IRQ_CONNECT(index, r_intc_irq_isr, r_intc_nmi_isr) \ + return intc_rz_ext_irq_init(dev); \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, intc_rz_ext_irq_init_##index, NULL, \ + &intc_rz_ext_irq_data##index, &intc_rz_ext_irq_config##index, \ + PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL); + +DT_INST_FOREACH_STATUS_OKAY(INTC_RZG_EXT_IRQ_INIT) diff --git a/dts/bindings/interrupt-controller/renesas,rz-ext-irq.yaml b/dts/bindings/interrupt-controller/renesas,rz-ext-irq.yaml new file mode 100644 index 00000000000..91c833cbef7 --- /dev/null +++ b/dts/bindings/interrupt-controller/renesas,rz-ext-irq.yaml @@ -0,0 +1,26 @@ +# Copyright (c) 2024 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RZG external interrupt controller + +compatible: "renesas,rz-ext-irq" + +include: [interrupt-controller.yaml, base.yaml, pinctrl-device.yaml] + +properties: + "#address-cells": + const: 0 + + "#interrupt-cells": + const: 2 + + trigger-type: + required: true + type: string + description: | + Indicates the condition that will trigger an interrupt when detected. + enum: + - "falling" + - "rising" + - "both_edges" + - "low_level" diff --git a/include/zephyr/drivers/interrupt_controller/intc_rz_ext_irq.h b/include/zephyr/drivers/interrupt_controller/intc_rz_ext_irq.h new file mode 100644 index 00000000000..4244a039dd5 --- /dev/null +++ b/include/zephyr/drivers/interrupt_controller/intc_rz_ext_irq.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RZ_EXT_IRQ_H_ +#define ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RZ_EXT_IRQ_H_ + +/** RZ external interrupt callback */ +typedef void (*intc_rz_ext_irq_callback_t)(void *arg); + +/** + * @brief Enable external interrupt for specified channel at NVIC. + * + * @param dev: pointer to interrupt controller instance + * @return 0 on success, or negative value on error + */ +int intc_rz_ext_irq_enable(const struct device *dev); + +/** + * @brief Disable external interrupt for specified channel at NVIC. + * + * @param dev: pointer to interrupt controller instance + * @return 0 on success, or negative value on error + */ +int intc_rz_ext_irq_disable(const struct device *dev); + +/** + * @brief Updates the user callback + * + * @param dev: pointer to interrupt controller instance + * @param cb: callback to set + * @param arg: user data passed to callback + * @return 0 on success, or negative value on error + */ +int intc_rz_ext_irq_set_callback(const struct device *dev, intc_rz_ext_irq_callback_t cb, + void *arg); + +#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_RZ_EXT_IRQ_H_ */ diff --git a/modules/Kconfig.renesas_fsp b/modules/Kconfig.renesas_fsp index 6caac534d9d..58c82eeace1 100644 --- a/modules/Kconfig.renesas_fsp +++ b/modules/Kconfig.renesas_fsp @@ -173,4 +173,9 @@ config USE_RZ_FSP_GPT help Enable RZ FSP GPT driver +config USE_RZ_FSP_EXT_IRQ + bool + help + Enable RZ FSP External IRQ driver + endif