1 /*
2  * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or
3  * an affiliate of Cypress Semiconductor Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @brief GPIO driver for Infineon CAT1 MCU family.
10  *
11  * Note:
12  * - Trigger detection on pin rising or falling edge (GPIO_INT_TRIG_BOTH)
13  *   is not supported in current version of GPIO CAT1 driver.
14  */
15 
16 #define DT_DRV_COMPAT  infineon_cat1_gpio
17 
18 #include <zephyr/drivers/gpio.h>
19 #include <zephyr/drivers/gpio/gpio_utils.h>
20 #include <zephyr/irq.h>
21 
22 #include <cy_gpio.h>
23 
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(gpio_cat1, CONFIG_GPIO_LOG_LEVEL);
26 
27 /* Device config structure */
28 struct gpio_cat1_config {
29 	/* gpio_driver_config needs to be first */
30 	struct gpio_driver_config common;
31 	GPIO_PRT_Type              *regs;
32 	uint8_t ngpios;
33 	uint8_t intr_priority;
34 };
35 
36 /* Data structure */
37 struct gpio_cat1_data {
38 	/* gpio_driver_data needs to be first */
39 	struct gpio_driver_data common;
40 
41 	/* device's owner of this data */
42 	const struct device *dev;
43 
44 	/* callbacks list */
45 	sys_slist_t callbacks;
46 };
47 
gpio_cat1_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)48 static int gpio_cat1_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
49 {
50 	uint32_t drive_mode = CY_GPIO_DM_HIGHZ;
51 	bool pin_val = false;
52 	const struct gpio_cat1_config *const cfg = dev->config;
53 	GPIO_PRT_Type *const base = cfg->regs;
54 
55 	switch (flags & (GPIO_INPUT | GPIO_OUTPUT | GPIO_DISCONNECTED)) {
56 	case GPIO_INPUT:
57 		if ((flags & GPIO_PULL_UP) && (flags & GPIO_PULL_DOWN)) {
58 			drive_mode = CY_GPIO_DM_PULLUP_DOWN;
59 		} else if (flags & GPIO_PULL_UP) {
60 			drive_mode = CY_GPIO_DM_PULLUP;
61 			pin_val = true;
62 		} else if (flags & GPIO_PULL_DOWN) {
63 			drive_mode = CY_GPIO_DM_PULLDOWN;
64 		} else {
65 			drive_mode = CY_GPIO_DM_HIGHZ;
66 		}
67 		break;
68 
69 	case GPIO_OUTPUT:
70 		if (flags & GPIO_SINGLE_ENDED) {
71 			if (flags & GPIO_LINE_OPEN_DRAIN) {
72 				drive_mode = CY_GPIO_DM_OD_DRIVESLOW;
73 				pin_val = true;
74 			} else {
75 				drive_mode = CY_GPIO_DM_OD_DRIVESHIGH;
76 				pin_val = false;
77 			}
78 		} else {
79 			drive_mode = CY_GPIO_DM_STRONG;
80 			pin_val = (flags & GPIO_OUTPUT_INIT_HIGH) ? true : false;
81 		}
82 		break;
83 
84 	case GPIO_DISCONNECTED:
85 		Cy_GPIO_SetInterruptMask(base, pin, 0);
86 		drive_mode = CY_GPIO_DM_ANALOG;
87 		pin_val = false;
88 		break;
89 
90 	default:
91 		return -ENOTSUP;
92 	}
93 
94 	Cy_GPIO_Pin_FastInit(base, pin, drive_mode, pin_val, HSIOM_SEL_GPIO);
95 
96 	return 0;
97 }
98 
gpio_cat1_port_get_raw(const struct device * dev,uint32_t * value)99 static int gpio_cat1_port_get_raw(const struct device *dev,
100 				  uint32_t *value)
101 {
102 	const struct gpio_cat1_config *const cfg = dev->config;
103 	GPIO_PRT_Type *const base = cfg->regs;
104 
105 	*value = GPIO_PRT_IN(base);
106 
107 	return 0;
108 }
109 
gpio_cat1_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)110 static int gpio_cat1_port_set_masked_raw(const struct device *dev,
111 					 uint32_t mask, uint32_t value)
112 {
113 	const struct gpio_cat1_config *const cfg = dev->config;
114 	GPIO_PRT_Type *const base = cfg->regs;
115 
116 	GPIO_PRT_OUT(base) = (GPIO_PRT_OUT(base) & ~mask) | (mask & value);
117 
118 	return 0;
119 }
120 
gpio_cat1_port_set_bits_raw(const struct device * dev,uint32_t mask)121 static int gpio_cat1_port_set_bits_raw(const struct device *dev,
122 				       uint32_t mask)
123 {
124 	const struct gpio_cat1_config *const cfg = dev->config;
125 	GPIO_PRT_Type *const base = cfg->regs;
126 
127 	GPIO_PRT_OUT_SET(base) = mask;
128 
129 	return 0;
130 }
131 
gpio_cat1_port_clear_bits_raw(const struct device * dev,uint32_t mask)132 static int gpio_cat1_port_clear_bits_raw(const struct device *dev,
133 					 uint32_t mask)
134 {
135 	const struct gpio_cat1_config *const cfg = dev->config;
136 	GPIO_PRT_Type *const base = cfg->regs;
137 
138 	GPIO_PRT_OUT_CLR(base) = mask;
139 
140 	return 0;
141 }
142 
gpio_cat1_port_toggle_bits(const struct device * dev,uint32_t mask)143 static int gpio_cat1_port_toggle_bits(const struct device *dev,
144 				      uint32_t mask)
145 {
146 	const struct gpio_cat1_config *const cfg = dev->config;
147 	GPIO_PRT_Type *const base = cfg->regs;
148 
149 	GPIO_PRT_OUT_INV(base) = mask;
150 
151 	return 0;
152 }
153 
gpio_cat1_get_pending_int(const struct device * dev)154 static uint32_t gpio_cat1_get_pending_int(const struct device *dev)
155 {
156 	const struct gpio_cat1_config *const cfg = dev->config;
157 	GPIO_PRT_Type *const base = cfg->regs;
158 
159 	return GPIO_PRT_INTR_MASKED(base);
160 }
161 
gpio_isr_handler(const struct device * dev)162 static void gpio_isr_handler(const struct device *dev)
163 {
164 	const struct gpio_cat1_config *const cfg = dev->config;
165 	GPIO_PRT_Type *const base = cfg->regs;
166 	uint32_t pins = GPIO_PRT_INTR_MASKED(base);
167 
168 	for (uint8_t i = 0; i < CY_GPIO_PINS_MAX; i++) {
169 		Cy_GPIO_ClearInterrupt(base, i);
170 	}
171 
172 	if (dev) {
173 		gpio_fire_callbacks(&((struct gpio_cat1_data *const)(dev)->data)->callbacks, dev,
174 				    pins);
175 	}
176 
177 
178 }
179 
gpio_cat1_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)180 static int gpio_cat1_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
181 					     enum gpio_int_mode mode, enum gpio_int_trig trig)
182 {
183 	uint32_t trig_pdl = CY_GPIO_INTR_DISABLE;
184 	const struct gpio_cat1_config *const cfg = dev->config;
185 	GPIO_PRT_Type *const base = cfg->regs;
186 
187 	/* Level interrupts (GPIO_INT_MODE_LEVEL) is not supported */
188 	if (mode == GPIO_INT_MODE_LEVEL) {
189 		return -ENOTSUP;
190 	}
191 
192 	switch (trig) {
193 	case GPIO_INT_TRIG_LOW:
194 		trig_pdl = CY_GPIO_INTR_FALLING;
195 		break;
196 
197 	case GPIO_INT_TRIG_HIGH:
198 		trig_pdl = CY_GPIO_INTR_RISING;
199 		break;
200 
201 	case GPIO_INT_TRIG_BOTH:
202 		trig_pdl = CY_GPIO_INTR_BOTH;
203 		break;
204 
205 	default:
206 		return -ENOTSUP;
207 	}
208 
209 	Cy_GPIO_SetInterruptEdge(base, pin, trig_pdl);
210 	Cy_GPIO_SetInterruptMask(base, pin,
211 				 (uint32_t)(mode == GPIO_INT_MODE_DISABLED) ? false : true);
212 
213 	return 0;
214 }
215 
gpio_cat1_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)216 static int gpio_cat1_manage_callback(const struct device *port,
217 				     struct gpio_callback *callback,
218 				     bool set)
219 {
220 	return gpio_manage_callback(&((struct gpio_cat1_data *const)(port)->data)->callbacks,
221 				    callback, set);
222 }
223 
224 static DEVICE_API(gpio, gpio_cat1_api) = {
225 	.pin_configure = gpio_cat1_configure,
226 	.port_get_raw = gpio_cat1_port_get_raw,
227 	.port_set_masked_raw = gpio_cat1_port_set_masked_raw,
228 	.port_set_bits_raw = gpio_cat1_port_set_bits_raw,
229 	.port_clear_bits_raw = gpio_cat1_port_clear_bits_raw,
230 	.port_toggle_bits = gpio_cat1_port_toggle_bits,
231 	.pin_interrupt_configure = gpio_cat1_pin_interrupt_configure,
232 	.manage_callback = gpio_cat1_manage_callback,
233 	.get_pending_int = gpio_cat1_get_pending_int,
234 };
235 
236 #define GPIO_CAT1_INIT_FUNC(n)                                                                     \
237 	static int gpio_cat1##n##_init(const struct device *dev)                                   \
238 	{                                                                                          \
239 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_isr_handler,           \
240 			    DEVICE_DT_INST_GET(n), 0);                                             \
241 		irq_enable(DT_INST_IRQN(n));                                                       \
242                                                                                                    \
243 		return 0;                                                                          \
244 	}
245 
246 #define GPIO_CAT1_INIT(n)                                                                          \
247                                                                                                    \
248 	static const struct gpio_cat1_config _cat1_gpio##n##_config = {                            \
249 		.common =                                                                          \
250 			{                                                                          \
251 				.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),               \
252 			},                                                                         \
253 		.intr_priority = DT_INST_IRQ_BY_IDX(n, 0, priority),                               \
254 		.ngpios = DT_INST_PROP(n, ngpios),                                                 \
255 		.regs = (GPIO_PRT_Type *)DT_INST_REG_ADDR(n),                                      \
256 	};                                                                                         \
257                                                                                                    \
258 	static struct gpio_cat1_data _cat1_gpio##n##_data;                                         \
259                                                                                                    \
260 	GPIO_CAT1_INIT_FUNC(n)                                                                     \
261                                                                                                    \
262 	DEVICE_DT_INST_DEFINE(n, gpio_cat1##n##_init, NULL, &_cat1_gpio##n##_data,                 \
263 			      &_cat1_gpio##n##_config, POST_KERNEL,                                \
264 			      CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_cat1_api);
265 
266 DT_INST_FOREACH_STATUS_OKAY(GPIO_CAT1_INIT)
267