|
12 | 12 | #include <Siul2_Port_Ip.h>
|
13 | 13 | #include <Siul2_Dio_Ip.h>
|
14 | 14 |
|
| 15 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 16 | +#include <zephyr/drivers/interrupt_controller/intc_eirq_nxp_s32.h> |
| 17 | + |
| 18 | +struct eirq_nxp_s32_info { |
| 19 | + const struct device *eirq_dev; |
| 20 | + uint8_t num_lines; |
| 21 | + struct gpio_pin_line { |
| 22 | + uint8_t pin; |
| 23 | + uint8_t line; |
| 24 | + } gpio_pin_lines[]; |
| 25 | +}; |
| 26 | +#endif |
| 27 | + |
15 | 28 | struct gpio_s32_config {
|
16 | 29 | /* gpio_driver_config needs to be first */
|
17 | 30 | struct gpio_driver_config common;
|
18 | 31 |
|
19 | 32 | Siul2_Dio_Ip_GpioType *gpio_base;
|
20 | 33 | Siul2_Port_Ip_PortType *port_base;
|
| 34 | + |
| 35 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 36 | + struct eirq_nxp_s32_info *eirq_info; |
| 37 | +#endif |
21 | 38 | };
|
22 | 39 |
|
23 | 40 | struct gpio_s32_data {
|
24 | 41 | /* gpio_driver_data needs to be first */
|
25 | 42 | struct gpio_driver_data common;
|
| 43 | + |
| 44 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 45 | + sys_slist_t callbacks; |
| 46 | +#endif |
26 | 47 | };
|
27 | 48 |
|
28 | 49 | static int s32_gpio_configure(const struct device *dev, gpio_pin_t pin,
|
@@ -131,34 +152,159 @@ static int s32_gpio_port_toggle_bits(const struct device *port,
|
131 | 152 | return 0;
|
132 | 153 | }
|
133 | 154 |
|
| 155 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 156 | + |
| 157 | +static uint8_t s32_gpio_pin_to_line(const struct eirq_nxp_s32_info *eirq_info, uint8_t pin) |
| 158 | +{ |
| 159 | + uint8_t i; |
| 160 | + |
| 161 | + for (i = 0; i < eirq_info->num_lines; i++) { |
| 162 | + if (eirq_info->gpio_pin_lines[i].pin == pin) { |
| 163 | + return eirq_info->gpio_pin_lines[i].line; |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + return SIUL2_ICU_IP_NUM_OF_CHANNELS; |
| 168 | +} |
| 169 | + |
| 170 | +static int s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType *edge_type, |
| 171 | + enum gpio_int_mode mode, |
| 172 | + enum gpio_int_trig trigger) |
| 173 | +{ |
| 174 | + if (mode == GPIO_INT_MODE_DISABLED) { |
| 175 | + *edge_type = SIUL2_ICU_DISABLE; |
| 176 | + return 0; |
| 177 | + } |
| 178 | + |
| 179 | + if (mode == GPIO_INT_MODE_LEVEL) { |
| 180 | + return -ENOTSUP; |
| 181 | + } |
| 182 | + |
| 183 | + switch (trigger) { |
| 184 | + case GPIO_INT_TRIG_LOW: |
| 185 | + *edge_type = SIUL2_ICU_FALLING_EDGE; |
| 186 | + break; |
| 187 | + case GPIO_INT_TRIG_HIGH: |
| 188 | + *edge_type = SIUL2_ICU_RISING_EDGE; |
| 189 | + break; |
| 190 | + case GPIO_INT_TRIG_BOTH: |
| 191 | + *edge_type = SIUL2_ICU_BOTH_EDGES; |
| 192 | + break; |
| 193 | + default: |
| 194 | + return -ENOTSUP; |
| 195 | + } |
| 196 | + |
| 197 | + return 0; |
| 198 | +} |
| 199 | + |
| 200 | +static void s32_gpio_isr(uint8_t pin, void *arg) |
| 201 | +{ |
| 202 | + const struct device *dev = (struct device *)arg; |
| 203 | + struct gpio_s32_data *data = dev->data; |
| 204 | + |
| 205 | + gpio_fire_callbacks(&data->callbacks, dev, BIT(pin)); |
| 206 | +} |
| 207 | +#endif /* CONFIG_NXP_S32_EIRQ */ |
| 208 | + |
134 | 209 | static int s32_gpio_pin_interrupt_configure(const struct device *dev,
|
135 | 210 | gpio_pin_t pin,
|
136 | 211 | enum gpio_int_mode mode,
|
137 | 212 | enum gpio_int_trig trig)
|
138 | 213 | {
|
| 214 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 215 | + const struct gpio_s32_config *config = dev->config; |
| 216 | + const struct eirq_nxp_s32_info *eirq_info = config->eirq_info; |
| 217 | + |
| 218 | + uint8_t eirq_line; |
| 219 | + |
| 220 | + Siul2_Icu_Ip_EdgeType edge_type; |
| 221 | + |
| 222 | + if (eirq_info == NULL) { |
| 223 | + /* |
| 224 | + * There is no external interrupt device for |
| 225 | + * the GPIO port or exists but is not enabled |
| 226 | + */ |
| 227 | + return -ENOTSUP; |
| 228 | + } |
| 229 | + |
| 230 | + eirq_line = s32_gpio_pin_to_line(eirq_info, pin); |
| 231 | + |
| 232 | + if (eirq_line == SIUL2_ICU_IP_NUM_OF_CHANNELS) { |
| 233 | + /* |
| 234 | + * GPIO pin cannot be used for processing |
| 235 | + * external interrupt signal |
| 236 | + */ |
| 237 | + return -ENOTSUP; |
| 238 | + } |
| 239 | + |
| 240 | + if (s32_gpio_eirq_get_trigger(&edge_type, mode, trig)) { |
| 241 | + return -ENOTSUP; |
| 242 | + } |
| 243 | + |
| 244 | + if (edge_type == SIUL2_ICU_DISABLE) { |
| 245 | + eirq_nxp_s32_disable_interrupt(eirq_info->eirq_dev, eirq_line); |
| 246 | + eirq_nxp_s32_unset_callback(eirq_info->eirq_dev, eirq_line); |
| 247 | + } else { |
| 248 | + if (eirq_nxp_s32_set_callback(eirq_info->eirq_dev, eirq_line, |
| 249 | + s32_gpio_isr, pin, (void *)dev)) { |
| 250 | + return -EBUSY; |
| 251 | + } |
| 252 | + |
| 253 | + eirq_nxp_s32_enable_interrupt(eirq_info->eirq_dev, eirq_line, edge_type); |
| 254 | + } |
| 255 | + |
| 256 | + return 0; |
| 257 | +#else |
139 | 258 | ARG_UNUSED(dev);
|
140 | 259 | ARG_UNUSED(pin);
|
141 | 260 | ARG_UNUSED(mode);
|
142 | 261 | ARG_UNUSED(trig);
|
143 | 262 |
|
144 | 263 | return -ENOTSUP;
|
| 264 | +#endif |
145 | 265 | }
|
146 | 266 |
|
147 | 267 | static int s32_gpio_manage_callback(const struct device *dev,
|
148 | 268 | struct gpio_callback *cb, bool set)
|
149 | 269 | {
|
| 270 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 271 | + struct gpio_s32_data *data = dev->data; |
| 272 | + |
| 273 | + return gpio_manage_callback(&data->callbacks, cb, set); |
| 274 | +#else |
150 | 275 | ARG_UNUSED(dev);
|
151 | 276 | ARG_UNUSED(cb);
|
152 | 277 | ARG_UNUSED(set);
|
153 | 278 |
|
154 | 279 | return -ENOTSUP;
|
| 280 | +#endif |
155 | 281 | }
|
156 | 282 |
|
157 | 283 | static uint32_t s32_gpio_get_pending_int(const struct device *dev)
|
158 | 284 | {
|
| 285 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 286 | + const struct gpio_s32_config *config = dev->config; |
| 287 | + const struct eirq_nxp_s32_info *eirq_info = config->eirq_info; |
| 288 | + |
| 289 | + if (eirq_info == NULL) { |
| 290 | + /* |
| 291 | + * There is no external interrupt device for |
| 292 | + * the GPIO port or exists but is not enabled |
| 293 | + */ |
| 294 | + return 0; |
| 295 | + } |
| 296 | + |
| 297 | + /* |
| 298 | + * Return all pending lines of the interrupt controller |
| 299 | + * that GPIO port belongs to |
| 300 | + */ |
| 301 | + return eirq_nxp_s32_get_pending(eirq_info->eirq_dev); |
| 302 | + |
| 303 | +#else |
159 | 304 | ARG_UNUSED(dev);
|
160 | 305 |
|
161 | 306 | return -ENOTSUP;
|
| 307 | +#endif |
162 | 308 | }
|
163 | 309 |
|
164 | 310 | static const struct gpio_driver_api gpio_s32_driver_api = {
|
@@ -204,13 +350,49 @@ static const struct gpio_driver_api gpio_s32_driver_api = {
|
204 | 350 | #define GPIO_S32_PORT_REG_ADDR(n) \
|
205 | 351 | ((Siul2_Port_Ip_PortType *)DT_INST_REG_ADDR_BY_NAME(n, mscr))
|
206 | 352 |
|
| 353 | +#ifdef CONFIG_NXP_S32_EIRQ |
| 354 | +#define GPIO_S32_EIRQ_NODE(n) \ |
| 355 | + DT_INST_PHANDLE(n, interrupt_parent) |
| 356 | + |
| 357 | +#define GPIO_S32_EIRQ_PIN_LINE(idx, n) \ |
| 358 | + { \ |
| 359 | + .pin = DT_INST_IRQ_BY_IDX(n, idx, gpio_pin), \ |
| 360 | + .line = DT_INST_IRQ_BY_IDX(n, idx, eirq_line), \ |
| 361 | + } |
| 362 | + |
| 363 | +#define GPIO_S32_SET_EIRQ_INFO(n) \ |
| 364 | + BUILD_ASSERT((DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupt_parent) == \ |
| 365 | + DT_NODE_HAS_PROP(DT_DRV_INST(n), interrupts)), \ |
| 366 | + "interrupts and interrupt-parent must be set when" \ |
| 367 | + " using external interrupts"); \ |
| 368 | + IF_ENABLED(DT_NODE_HAS_STATUS(GPIO_S32_EIRQ_NODE(n), okay), \ |
| 369 | + (static struct eirq_nxp_s32_info eirq_nxp_s32_info_##n = { \ |
| 370 | + .eirq_dev = DEVICE_DT_GET(GPIO_S32_EIRQ_NODE(n)), \ |
| 371 | + .gpio_pin_lines = { \ |
| 372 | + LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), \ |
| 373 | + GPIO_S32_EIRQ_PIN_LINE, (,), n) \ |
| 374 | + }, \ |
| 375 | + .num_lines = DT_NUM_IRQS(DT_DRV_INST(n)) \ |
| 376 | + }; \ |
| 377 | + )) |
| 378 | + |
| 379 | +#define GPIO_S32_GET_EIRQ_INFO(n) \ |
| 380 | + .eirq_info = UTIL_AND(DT_NODE_HAS_STATUS(GPIO_S32_EIRQ_NODE(n), okay), \ |
| 381 | + &eirq_nxp_s32_info_##n) |
| 382 | +#else |
| 383 | +#define GPIO_S32_SET_EIRQ_INFO(n) |
| 384 | +#define GPIO_S32_GET_EIRQ_INFO(n) |
| 385 | +#endif /* CONFIG_NXP_S32_EIRQ */ |
| 386 | + |
207 | 387 | #define GPIO_S32_DEVICE_INIT(n) \
|
| 388 | + GPIO_S32_SET_EIRQ_INFO(n) \ |
208 | 389 | static const struct gpio_s32_config gpio_s32_config_##n = { \
|
209 | 390 | .common = { \
|
210 | 391 | .port_pin_mask = GPIO_S32_PORT_PIN_MASK(n), \
|
211 | 392 | }, \
|
212 | 393 | .gpio_base = GPIO_S32_REG_ADDR(n), \
|
213 | 394 | .port_base = GPIO_S32_PORT_REG_ADDR(n), \
|
| 395 | + GPIO_S32_GET_EIRQ_INFO(n) \ |
214 | 396 | }; \
|
215 | 397 | static struct gpio_s32_data gpio_s32_data_##n; \
|
216 | 398 | static int gpio_s32_init_##n(const struct device *dev) \
|
|
0 commit comments