1 /*
2  * Copyright (c) 2024-2025 Renesas Electronics Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT renesas_rz_ext_irq
8 
9 #include <zephyr/device.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/pinctrl.h>
13 #include <zephyr/irq.h>
14 #include <zephyr/logging/log.h>
15 #if defined(CONFIG_SOC_SERIES_RZG3S)
16 #include <instances/rzg/r_intc_irq.h>
17 #include <instances/rzg/r_intc_nmi.h>
18 #elif defined(CONFIG_SOC_SERIES_RZN2L) || defined(CONFIG_SOC_SERIES_RZT2L)
19 #include <instances/rzn/r_icu.h>
20 #endif /* CONFIG_SOC_SERIES_* */
21 #include <zephyr/drivers/interrupt_controller/intc_rz_ext_irq.h>
22 #include <zephyr/dt-bindings/interrupt-controller/arm-gic.h>
23 
24 LOG_MODULE_REGISTER(rz_ext_irq, CONFIG_INTC_LOG_LEVEL);
25 
26 struct intc_rz_ext_irq_config {
27 	const struct pinctrl_dev_config *pin_config;
28 	const external_irq_cfg_t *fsp_cfg;
29 	const external_irq_api_t *fsp_api;
30 };
31 
32 struct intc_rz_ext_irq_data {
33 	external_irq_ctrl_t *fsp_ctrl;
34 	intc_rz_ext_irq_callback_t callback;
35 	void *callback_data;
36 };
37 
38 /* FSP interruption handlers. */
39 #if defined(CONFIG_SOC_SERIES_RZG3S)
40 void r_intc_irq_isr(void);
41 void r_intc_nmi_isr(void);
42 #elif defined(CONFIG_SOC_SERIES_RZN2L) || defined(CONFIG_SOC_SERIES_RZT2L)
43 void r_icu_isr(void);
44 #endif /* CONFIG_SOC_SERIES_* */
45 
intc_rz_ext_irq_enable(const struct device * dev)46 int intc_rz_ext_irq_enable(const struct device *dev)
47 {
48 	const struct intc_rz_ext_irq_config *config = dev->config;
49 	struct intc_rz_ext_irq_data *data = dev->data;
50 	fsp_err_t err = FSP_SUCCESS;
51 
52 	err = config->fsp_api->enable(data->fsp_ctrl);
53 
54 	if (err != FSP_SUCCESS) {
55 		return -EIO;
56 	}
57 
58 	return 0;
59 }
60 
intc_rz_ext_irq_disable(const struct device * dev)61 int intc_rz_ext_irq_disable(const struct device *dev)
62 {
63 	const struct intc_rz_ext_irq_config *config = dev->config;
64 	struct intc_rz_ext_irq_data *data = dev->data;
65 	fsp_err_t err = FSP_SUCCESS;
66 
67 	err = config->fsp_api->disable(data->fsp_ctrl);
68 
69 	if (err != FSP_SUCCESS) {
70 		return -EIO;
71 	}
72 
73 	return 0;
74 }
75 
intc_rz_ext_irq_set_callback(const struct device * dev,intc_rz_ext_irq_callback_t cb,void * arg)76 int intc_rz_ext_irq_set_callback(const struct device *dev, intc_rz_ext_irq_callback_t cb, void *arg)
77 {
78 	struct intc_rz_ext_irq_data *data = dev->data;
79 
80 	data->callback = cb;
81 	data->callback_data = arg;
82 
83 	return 0;
84 }
85 
intc_rz_ext_irq_set_type(const struct device * dev,uint8_t trig)86 int intc_rz_ext_irq_set_type(const struct device *dev, uint8_t trig)
87 {
88 	const struct intc_rz_ext_irq_config *config = dev->config;
89 	struct intc_rz_ext_irq_data *data = dev->data;
90 	fsp_err_t err = FSP_SUCCESS;
91 	external_irq_cfg_t *p_cfg = (external_irq_cfg_t *)config->fsp_cfg;
92 
93 	p_cfg->trigger = (external_irq_trigger_t)trig;
94 	err = config->fsp_api->close(data->fsp_ctrl);
95 
96 	if (err != FSP_SUCCESS) {
97 		return -EIO;
98 	}
99 
100 	err = config->fsp_api->open(data->fsp_ctrl, config->fsp_cfg);
101 
102 	if (err != FSP_SUCCESS) {
103 		return -EIO;
104 	}
105 
106 	return 0;
107 }
108 
intc_rz_ext_irq_init(const struct device * dev)109 static int intc_rz_ext_irq_init(const struct device *dev)
110 {
111 	const struct intc_rz_ext_irq_config *config = dev->config;
112 	struct intc_rz_ext_irq_data *data = dev->data;
113 	fsp_err_t err = FSP_SUCCESS;
114 	int ret = 0;
115 
116 	if (config->pin_config) {
117 		ret = pinctrl_apply_state(config->pin_config, PINCTRL_STATE_DEFAULT);
118 
119 		if (ret < 0) {
120 			LOG_ERR("%s: pinctrl config failed.", __func__);
121 			return ret;
122 		}
123 	}
124 
125 	err = config->fsp_api->open(data->fsp_ctrl, config->fsp_cfg);
126 
127 	if (err != FSP_SUCCESS) {
128 		return -EIO;
129 	}
130 
131 	return 0;
132 }
133 
intc_rz_ext_irq_callback(external_irq_callback_args_t * args)134 static void intc_rz_ext_irq_callback(external_irq_callback_args_t *args)
135 {
136 	const struct device *dev = (const struct device *)args->p_context;
137 	struct intc_rz_ext_irq_data *data = dev->data;
138 
139 	if (data->callback) {
140 		data->callback(data->callback_data);
141 	}
142 }
143 
144 #ifdef CONFIG_CPU_CORTEX_M
145 #define GET_IRQ_FLAGS(index) 0
146 #else /* Cortex-A/R */
147 #define GET_IRQ_FLAGS(index) DT_INST_IRQ_BY_IDX(index, 0, flags)
148 #endif
149 
150 #define EXT_IRQ_RZ_IRQ_CONNECT(index, isr, isr_nmi)                                                \
151 	IRQ_CONNECT(DT_INST_IRQ_BY_IDX(index, 0, irq), DT_INST_IRQ_BY_IDX(index, 0, priority),     \
152 		    COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq),                                 \
153 		    (isr_nmi), (isr)), NULL, GET_IRQ_FLAGS(index));
154 
155 #define INTC_RZG_EXT_IRQ_INIT(index)                                                               \
156 	static const external_irq_cfg_t g_external_irq##index##_cfg = {                            \
157 		.trigger = DT_INST_ENUM_IDX_OR(index, trigger_type, 0),                            \
158 		.filter_enable = true,                                                             \
159 		.clock_source_div = EXTERNAL_IRQ_CLOCK_SOURCE_DIV_1,                               \
160 		.p_callback = intc_rz_ext_irq_callback,                                            \
161 		.p_context = DEVICE_DT_INST_GET(index),                                            \
162 		.p_extend = NULL,                                                                  \
163 		.ipl = DT_INST_IRQ_BY_IDX(index, 0, priority),                                     \
164 		.irq = DT_INST_IRQ_BY_IDX(index, 0, irq),                                          \
165 		COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq),                   \
166 			(.channel = DT_INST_IRQ_BY_IDX(index, 0, irq)),          \
167 			(.channel = DT_INST_IRQ_BY_IDX(index, 0, irq) - 1)),     \
168 	};                                                                                         \
169                                                                                                    \
170 	PINCTRL_DT_INST_DEFINE(index);                                                             \
171                                                                                                    \
172 	struct intc_rz_ext_irq_config intc_rz_ext_irq_config##index = {                            \
173 		.pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(index),                               \
174 		.fsp_cfg = (external_irq_cfg_t *)&g_external_irq##index##_cfg,                     \
175 		COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq), (            \
176 			.fsp_api = &g_external_irq_on_intc_nmi), (          \
177 			.fsp_api = &g_external_irq_on_intc_irq)),           \
178 	};                                                                                         \
179                                                                                                    \
180 	COND_CODE_0(DT_INST_IRQ_BY_IDX(index, 0, irq),                                     \
181 		    (static intc_nmi_instance_ctrl_t g_external_irq##index##_ctrl;),       \
182 		    (static intc_irq_instance_ctrl_t g_external_irq##index##_ctrl;))       \
183                                                                                                    \
184 	static struct intc_rz_ext_irq_data intc_rz_ext_irq_data##index = {                         \
185 		.fsp_ctrl = (external_irq_ctrl_t *)&g_external_irq##index##_ctrl,                  \
186 	};                                                                                         \
187                                                                                                    \
188 	static int intc_rz_ext_irq_init_##index(const struct device *dev)                          \
189 	{                                                                                          \
190 		EXT_IRQ_RZ_IRQ_CONNECT(index, r_intc_irq_isr, r_intc_nmi_isr)                      \
191 		return intc_rz_ext_irq_init(dev);                                                  \
192 	};                                                                                         \
193                                                                                                    \
194 	DEVICE_DT_INST_DEFINE(index, intc_rz_ext_irq_init_##index, NULL,                           \
195 			      &intc_rz_ext_irq_data##index, &intc_rz_ext_irq_config##index,        \
196 			      PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
197 
198 #define INTC_RZTN_EXT_IRQ_INIT(index)                                                              \
199 	static const external_irq_cfg_t g_external_irq##index##_cfg = {                            \
200 		.trigger = DT_INST_ENUM_IDX_OR(index, trigger_type, 0),                            \
201 		.filter_enable = true,                                                             \
202 		.clock_source_div = EXTERNAL_IRQ_CLOCK_SOURCE_DIV_1,                               \
203 		.p_callback = intc_rz_ext_irq_callback,                                            \
204 		.p_context = DEVICE_DT_INST_GET(index),                                            \
205 		.p_extend = NULL,                                                                  \
206 		.ipl = DT_INST_IRQ_BY_IDX(index, 0, priority),                                     \
207 		.irq = DT_INST_IRQ_BY_IDX(index, 0, irq),                                          \
208 		.channel = DT_INST_REG_ADDR(index),                                                \
209 	};                                                                                         \
210                                                                                                    \
211 	PINCTRL_DT_INST_DEFINE(index);                                                             \
212                                                                                                    \
213 	struct intc_rz_ext_irq_config intc_rz_ext_irq_config##index = {                            \
214 		.pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(index),                               \
215 		.fsp_cfg = (external_irq_cfg_t *)&g_external_irq##index##_cfg,                     \
216 		.fsp_api = &g_external_irq_on_icu,                                                 \
217 	};                                                                                         \
218                                                                                                    \
219 	icu_instance_ctrl_t g_external_irq##index##_ctrl;                                          \
220                                                                                                    \
221 	static struct intc_rz_ext_irq_data intc_rz_ext_irq_data##index = {                         \
222 		.fsp_ctrl = (icu_instance_ctrl_t *)&g_external_irq##index##_ctrl,                  \
223 	};                                                                                         \
224                                                                                                    \
225 	static int intc_rz_ext_irq_init_##index(const struct device *dev)                          \
226 	{                                                                                          \
227 		EXT_IRQ_RZ_IRQ_CONNECT(index, r_icu_isr, NULL);                                    \
228 		return intc_rz_ext_irq_init(dev);                                                  \
229 	};                                                                                         \
230                                                                                                    \
231 	DEVICE_DT_INST_DEFINE(index, intc_rz_ext_irq_init_##index, NULL,                           \
232 			      &intc_rz_ext_irq_data##index, &intc_rz_ext_irq_config##index,        \
233 			      PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
234 
235 #if defined(CONFIG_SOC_SERIES_RZG3S)
236 DT_INST_FOREACH_STATUS_OKAY(INTC_RZG_EXT_IRQ_INIT)
237 #elif defined(CONFIG_SOC_SERIES_RZN2L) || defined(CONFIG_SOC_SERIES_RZT2L)
238 DT_INST_FOREACH_STATUS_OKAY(INTC_RZTN_EXT_IRQ_INIT)
239 #endif
240