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 #define DEV_CFG(_dev) ((const struct gpio_xlnx_ps_dev_cfg *)(_dev)->config)
24 #define DEV_DATA(_dev) ((struct gpio_xlnx_ps_dev_data *const)(_dev)->data)
25 
26 /*
27  * An API is required for this driver, but as no pin access is provided at
28  * this level, use the default API contents provided by the driver subsystem.
29  */
30 static DEVICE_API(gpio, gpio_xlnx_ps_default_apis);
31 
32 /**
33  * @brief Initialize a Xilinx PS GPIO controller parent device
34  *
35  * Initialize a Xilinx PS GPIO controller parent device, whose task it is
36  * to handle the IRQ line of each controller instance, while the configuration,
37  * status and data acquisition of each MIO / EMIO GPIO pin associated with
38  * the parent controller instance is handled via the respective GPIO pin
39  * bank's child device.
40  *
41  * @param dev Pointer to the PS GPIO controller's device.
42  *
43  * @retval Always 0.
44  */
gpio_xlnx_ps_init(const struct device * dev)45 static int gpio_xlnx_ps_init(const struct device *dev)
46 {
47 	const struct gpio_xlnx_ps_dev_cfg *dev_conf = DEV_CFG(dev);
48 	struct gpio_xlnx_ps_dev_data *dev_data = DEV_DATA(dev);
49 	uint32_t bank;
50 
51 	/* Perform the actual memory map operation in the parent device */
52 	DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE);
53 	dev_data->base = DEVICE_MMIO_NAMED_GET(dev, reg_base);
54 	__ASSERT(dev_data->base != 0, "%s map register space failed", dev->name);
55 
56 	/* Propagate the virtual base address to the bank devices */
57 	for (bank = 0; bank < dev_conf->num_banks; bank++) {
58 		struct gpio_xlnx_ps_bank_dev_data *bank_data =
59 			dev_conf->bank_devices[bank]->data;
60 		__ASSERT(bank_data != NULL, "%s bank %u data unresolved", dev->name, bank);
61 		bank_data->base = dev_data->base;
62 	}
63 
64 	/* Initialize the device's interrupt */
65 	dev_conf->config_func(dev);
66 
67 	return 0;
68 }
69 
70 /**
71  * @brief Xilinx PS GPIO controller parent device ISR
72  *
73  * Interrupt service routine for the Xilinx PS GPIO controller's
74  * IRQ. The ISR iterates all associated MIO / EMIO GPIO pink bank
75  * child device instances and checks each bank's interrupt status.
76  * If any pending interrupt is detected within a GPIO pin bank,
77  * the callbacks registered for the respective bank are triggered
78  * using the functionality provided by the GPIO sub-system.
79  *
80  * @param dev Pointer to the PS GPIO controller's device.
81  */
gpio_xlnx_ps_isr(const struct device * dev)82 static void gpio_xlnx_ps_isr(const struct device *dev)
83 {
84 	const struct gpio_xlnx_ps_dev_cfg *dev_conf = DEV_CFG(dev);
85 
86 	const struct gpio_driver_api *api;
87 	struct gpio_xlnx_ps_bank_dev_data *bank_data;
88 
89 	uint32_t bank;
90 	uint32_t int_mask;
91 
92 	for (bank = 0; bank < dev_conf->num_banks; bank++) {
93 		api = dev_conf->bank_devices[bank]->api;
94 		int_mask = 0;
95 
96 		if (api != NULL) {
97 			int_mask = api->get_pending_int(dev_conf->bank_devices[bank]);
98 		}
99 		if (int_mask) {
100 			bank_data = (struct gpio_xlnx_ps_bank_dev_data *)
101 				dev_conf->bank_devices[bank]->data;
102 			gpio_fire_callbacks(&bank_data->callbacks,
103 				dev_conf->bank_devices[bank], int_mask);
104 		}
105 	}
106 }
107 
108 /* Device definition macros */
109 
110 /*
111  * Macros generating a list of all associated GPIO pin bank child
112  * devices for the parent controller device's config data struct
113  * specified in the device tree.
114  */
115 
116 #define GPIO_XLNX_PS_GEN_BANK_ARRAY(idx)\
117 static const struct device *const gpio_xlnx_ps##idx##_banks[] = {\
118 	DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(idx, DEVICE_DT_GET, (,))\
119 };
120 
121 /* Device config & run-time data struct creation macros */
122 #define GPIO_XLNX_PS_DEV_DATA(idx)\
123 static struct gpio_xlnx_ps_dev_data gpio_xlnx_ps##idx##_data = {\
124 	.base = 0x0,\
125 };
126 
127 #define GPIO_XLNX_PS_DEV_CONFIG(idx)\
128 static const struct gpio_xlnx_ps_dev_cfg gpio_xlnx_ps##idx##_cfg = {\
129 	DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(idx)),\
130 	.bank_devices = gpio_xlnx_ps##idx##_banks,\
131 	.num_banks = ARRAY_SIZE(gpio_xlnx_ps##idx##_banks),\
132 	.config_func = gpio_xlnx_ps##idx##_irq_config\
133 };
134 
135 /*
136  * Macro used to generate each parent controller device's IRQ attach
137  * function.
138  */
139 #define GPIO_XLNX_PS_DEV_CONFIG_IRQ_FUNC(idx)\
140 static void gpio_xlnx_ps##idx##_irq_config(const struct device *dev)\
141 {\
142 	ARG_UNUSED(dev);\
143 	IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority),\
144 		    gpio_xlnx_ps_isr, DEVICE_DT_INST_GET(idx), 0);\
145 	irq_enable(DT_INST_IRQN(idx));\
146 }
147 
148 /* Device definition macro */
149 #define GPIO_XLNX_PS_DEV_DEFINE(idx)\
150 DEVICE_DT_INST_DEFINE(idx, gpio_xlnx_ps_init, NULL,\
151 	&gpio_xlnx_ps##idx##_data, &gpio_xlnx_ps##idx##_cfg,\
152 	PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_xlnx_ps_default_apis);
153 
154 /*
155  * Top-level device initialization macro, executed for each PS GPIO
156  * parent device entry contained in the device tree which has status
157  * "okay".
158  */
159 #define GPIO_XLNX_PS_DEV_INITITALIZE(idx)\
160 GPIO_XLNX_PS_GEN_BANK_ARRAY(idx)\
161 GPIO_XLNX_PS_DEV_CONFIG_IRQ_FUNC(idx)\
162 GPIO_XLNX_PS_DEV_DATA(idx)\
163 GPIO_XLNX_PS_DEV_CONFIG(idx)\
164 GPIO_XLNX_PS_DEV_DEFINE(idx)
165 
166 /*
167  * Register & initialize all instances of the Processor System's MIO / EMIO GPIO
168  * controller specified in the device tree.
169  */
170 DT_INST_FOREACH_STATUS_OKAY(GPIO_XLNX_PS_DEV_INITITALIZE);
171