1 /*
2  * Xilinx Processor System MIO / EMIO GPIO controller driver
3  * Parent (IRQ handler) module
4  *
5  * Copyright (c) 2022, Weidmueller Interface GmbH & Co. KG
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/drivers/gpio/gpio_utils.h>
13 #include "gpio_xlnx_ps.h"
14 #include "gpio_xlnx_ps_bank.h"
15 
16 #define LOG_MODULE_NAME gpio_xlnx_ps
17 #define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
20 
21 #define DT_DRV_COMPAT xlnx_ps_gpio
22 
23 /*
24  * An API is required for this driver, but as no pin access is provided at
25  * this level, use the default API contents provided by the driver subsystem.
26  */
27 static const struct gpio_driver_api gpio_xlnx_ps_default_apis;
28 
29 /**
30  * @brief Initialize a Xilinx PS GPIO controller parent device
31  *
32  * Initialize a Xilinx PS GPIO controller parent device, whose task it is
33  * to handle the IRQ line of each controller instance, while the configuration,
34  * status and data acquisition of each MIO / EMIO GPIO pin associated with
35  * the parent controller instance is handled via the respective GPIO pin
36  * bank's child device.
37  *
38  * @param dev Pointer to the PS GPIO controller's device.
39  *
40  * @retval Always 0.
41  */
gpio_xlnx_ps_init(const struct device * dev)42 static int gpio_xlnx_ps_init(const struct device *dev)
43 {
44 	const struct gpio_xlnx_ps_dev_cfg *dev_conf = dev->config;
45 
46 	/* Initialize the device's interrupt */
47 	dev_conf->config_func(dev);
48 
49 	return 0;
50 }
51 
52 /**
53  * @brief Xilinx PS GPIO controller parent device ISR
54  *
55  * Interrupt service routine for the Xilinx PS GPIO controller's
56  * IRQ. The ISR iterates all associated MIO / EMIO GPIO pink bank
57  * child device instances and checks each bank's interrupt status.
58  * If any pending interrupt is detected within a GPIO pin bank,
59  * the callbacks registered for the respective bank are triggered
60  * using the functionality provided by the GPIO sub-system.
61  *
62  * @param dev Pointer to the PS GPIO controller's device.
63  */
gpio_xlnx_ps_isr(const struct device * dev)64 static void gpio_xlnx_ps_isr(const struct device *dev)
65 {
66 	const struct gpio_xlnx_ps_dev_cfg *dev_conf = dev->config;
67 
68 	const struct gpio_driver_api *api;
69 	struct gpio_xlnx_ps_bank_dev_data *bank_data;
70 
71 	uint32_t bank;
72 	uint32_t int_mask;
73 
74 	for (bank = 0; bank < dev_conf->num_banks; bank++) {
75 		api = dev_conf->bank_devices[bank]->api;
76 		int_mask = 0;
77 
78 		if (api != NULL) {
79 			int_mask = api->get_pending_int(dev_conf->bank_devices[bank]);
80 		}
81 		if (int_mask) {
82 			bank_data = (struct gpio_xlnx_ps_bank_dev_data *)
83 				dev_conf->bank_devices[bank]->data;
84 			gpio_fire_callbacks(&bank_data->callbacks,
85 				dev_conf->bank_devices[bank], int_mask);
86 		}
87 	}
88 }
89 
90 /* Device definition macros */
91 
92 /*
93  * Macros generating a list of all associated GPIO pin bank child
94  * devices for the parent controller device's config data struct
95  * specified in the device tree.
96  */
97 
98 #define GPIO_XLNX_PS_GEN_BANK_ARRAY(idx)\
99 static const struct device *const gpio_xlnx_ps##idx##_banks[] = {\
100 	DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(idx, DEVICE_DT_GET, (,))\
101 };
102 
103 /* Device config & run-time data struct creation macros */
104 #define GPIO_XLNX_PS_DEV_DATA(idx)\
105 static struct gpio_xlnx_ps_dev_data gpio_xlnx_ps##idx##_data;
106 
107 #define GPIO_XLNX_PS_DEV_CONFIG(idx)\
108 static const struct gpio_xlnx_ps_dev_cfg gpio_xlnx_ps##idx##_cfg = {\
109 	.base_addr = DT_INST_REG_ADDR(idx),\
110 	.bank_devices = gpio_xlnx_ps##idx##_banks,\
111 	.num_banks = ARRAY_SIZE(gpio_xlnx_ps##idx##_banks),\
112 	.config_func = gpio_xlnx_ps##idx##_irq_config\
113 };
114 
115 /*
116  * Macro used to generate each parent controller device's IRQ attach
117  * function.
118  */
119 #define GPIO_XLNX_PS_DEV_CONFIG_IRQ_FUNC(idx)\
120 static void gpio_xlnx_ps##idx##_irq_config(const struct device *dev)\
121 {\
122 	ARG_UNUSED(dev);\
123 	IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority),\
124 		    gpio_xlnx_ps_isr, DEVICE_DT_INST_GET(idx), 0);\
125 	irq_enable(DT_INST_IRQN(idx));\
126 }
127 
128 /* Device definition macro */
129 #define GPIO_XLNX_PS_DEV_DEFINE(idx)\
130 DEVICE_DT_INST_DEFINE(idx, gpio_xlnx_ps_init, NULL,\
131 	&gpio_xlnx_ps##idx##_data, &gpio_xlnx_ps##idx##_cfg,\
132 	PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_xlnx_ps_default_apis);
133 
134 /*
135  * Top-level device initialization macro, executed for each PS GPIO
136  * parent device entry contained in the device tree which has status
137  * "okay".
138  */
139 #define GPIO_XLNX_PS_DEV_INITITALIZE(idx)\
140 GPIO_XLNX_PS_GEN_BANK_ARRAY(idx)\
141 GPIO_XLNX_PS_DEV_CONFIG_IRQ_FUNC(idx)\
142 GPIO_XLNX_PS_DEV_DATA(idx)\
143 GPIO_XLNX_PS_DEV_CONFIG(idx)\
144 GPIO_XLNX_PS_DEV_DEFINE(idx)
145 
146 /*
147  * Register & initialize all instances of the Processor System's MIO / EMIO GPIO
148  * controller specified in the device tree.
149  */
150 DT_INST_FOREACH_STATUS_OKAY(GPIO_XLNX_PS_DEV_INITITALIZE);
151