1 /*
2  * Copyright 2022 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_s32_gpio
8 
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/gpio/gpio_utils.h>
11 
12 #include <Siul2_Port_Ip.h>
13 #include <Siul2_Dio_Ip.h>
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 
28 struct gpio_nxp_s32_config {
29 	/* gpio_driver_config needs to be first */
30 	struct gpio_driver_config common;
31 
32 	Siul2_Dio_Ip_GpioType *gpio_base;
33 	Siul2_Port_Ip_PortType *port_base;
34 
35 #ifdef CONFIG_NXP_S32_EIRQ
36 	struct eirq_nxp_s32_info *eirq_info;
37 #endif
38 };
39 
40 struct gpio_nxp_s32_data {
41 	/* gpio_driver_data needs to be first */
42 	struct gpio_driver_data common;
43 
44 #ifdef CONFIG_NXP_S32_EIRQ
45 	sys_slist_t callbacks;
46 #endif
47 };
48 
nxp_s32_gpio_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)49 static int nxp_s32_gpio_configure(const struct device *dev, gpio_pin_t pin,
50 				  gpio_flags_t flags)
51 {
52 	const struct gpio_nxp_s32_config *port_config = dev->config;
53 	Siul2_Dio_Ip_GpioType *gpio_base = port_config->gpio_base;
54 	Siul2_Port_Ip_PortType *port_base = port_config->port_base;
55 	Siul2_Port_Ip_PortPullConfig pull_config;
56 
57 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
58 		return -ENOTSUP;
59 	}
60 
61 	switch (flags & GPIO_DIR_MASK) {
62 	case GPIO_INPUT:
63 		Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_IN);
64 		break;
65 	case GPIO_OUTPUT:
66 		Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_OUT);
67 		break;
68 	case GPIO_INPUT | GPIO_OUTPUT:
69 		Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_IN_OUT);
70 		break;
71 	default:
72 		Siul2_Port_Ip_SetPinDirection(port_base, pin, SIUL2_PORT_HI_Z);
73 		break;
74 	}
75 
76 	Siul2_Port_Ip_SetOutputBuffer(port_base, pin,
77 					(flags & GPIO_OUTPUT), PORT_MUX_AS_GPIO);
78 
79 	switch (flags & (GPIO_OUTPUT | GPIO_OUTPUT_INIT_HIGH | GPIO_OUTPUT_INIT_LOW)) {
80 	case GPIO_OUTPUT_HIGH:
81 		Siul2_Dio_Ip_WritePin(gpio_base, pin, 1);
82 		break;
83 	case GPIO_OUTPUT_LOW:
84 		Siul2_Dio_Ip_WritePin(gpio_base, pin, 0);
85 		break;
86 	default:
87 		break;
88 	}
89 
90 	if ((flags & GPIO_PULL_UP) != 0) {
91 		pull_config = PORT_INTERNAL_PULL_UP_ENABLED;
92 	} else if ((flags & GPIO_PULL_DOWN) != 0) {
93 		pull_config = PORT_INTERNAL_PULL_DOWN_ENABLED;
94 	} else {
95 		pull_config = PORT_INTERNAL_PULL_NOT_ENABLED;
96 	}
97 	Siul2_Port_Ip_SetPullSel(port_base, pin, pull_config);
98 
99 	return 0;
100 }
101 
nxp_s32_gpio_port_get_raw(const struct device * port,uint32_t * value)102 static int nxp_s32_gpio_port_get_raw(const struct device *port, uint32_t *value)
103 {
104 	const struct gpio_nxp_s32_config *config = port->config;
105 
106 	*value = Siul2_Dio_Ip_ReadPins(config->gpio_base);
107 
108 	return 0;
109 }
110 
nxp_s32_gpio_port_set_masked_raw(const struct device * port,gpio_port_pins_t mask,gpio_port_value_t value)111 static int nxp_s32_gpio_port_set_masked_raw(const struct device *port,
112 					    gpio_port_pins_t mask,
113 					    gpio_port_value_t value)
114 {
115 	const struct gpio_nxp_s32_config *config = port->config;
116 	Siul2_Dio_Ip_GpioType *gpio_base = config->gpio_base;
117 	gpio_port_pins_t pins_value = Siul2_Dio_Ip_GetPinsOutput(gpio_base);
118 
119 	pins_value = (pins_value & ~mask) | (mask & value);
120 	Siul2_Dio_Ip_WritePins(gpio_base, pins_value);
121 
122 	return 0;
123 }
124 
nxp_s32_gpio_port_set_bits_raw(const struct device * port,gpio_port_pins_t pins)125 static int nxp_s32_gpio_port_set_bits_raw(const struct device *port,
126 					  gpio_port_pins_t pins)
127 {
128 	const struct gpio_nxp_s32_config *config = port->config;
129 
130 	Siul2_Dio_Ip_SetPins(config->gpio_base, pins);
131 
132 	return 0;
133 }
134 
nxp_s32_gpio_port_clear_bits_raw(const struct device * port,gpio_port_pins_t pins)135 static int nxp_s32_gpio_port_clear_bits_raw(const struct device *port,
136 					    gpio_port_pins_t pins)
137 {
138 	const struct gpio_nxp_s32_config *config = port->config;
139 
140 	Siul2_Dio_Ip_ClearPins(config->gpio_base, pins);
141 
142 	return 0;
143 }
144 
nxp_s32_gpio_port_toggle_bits(const struct device * port,gpio_port_pins_t pins)145 static int nxp_s32_gpio_port_toggle_bits(const struct device *port,
146 					 gpio_port_pins_t pins)
147 {
148 	const struct gpio_nxp_s32_config *config = port->config;
149 
150 	Siul2_Dio_Ip_TogglePins(config->gpio_base, pins);
151 
152 	return 0;
153 }
154 
155 #ifdef CONFIG_NXP_S32_EIRQ
156 
nxp_s32_gpio_pin_to_line(const struct eirq_nxp_s32_info * eirq_info,uint8_t pin)157 static uint8_t nxp_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 
nxp_s32_gpio_eirq_get_trigger(Siul2_Icu_Ip_EdgeType * edge_type,enum gpio_int_mode mode,enum gpio_int_trig trigger)170 static int nxp_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 
nxp_s32_gpio_isr(uint8_t pin,void * arg)200 static void nxp_s32_gpio_isr(uint8_t pin, void *arg)
201 {
202 	const struct device *dev = (struct device *)arg;
203 	struct gpio_nxp_s32_data *data = dev->data;
204 
205 	gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
206 }
207 #endif /* CONFIG_NXP_S32_EIRQ */
208 
nxp_s32_gpio_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)209 static int nxp_s32_gpio_pin_interrupt_configure(const struct device *dev,
210 						gpio_pin_t pin,
211 						enum gpio_int_mode mode,
212 						enum gpio_int_trig trig)
213 {
214 #ifdef CONFIG_NXP_S32_EIRQ
215 	const struct gpio_nxp_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 = nxp_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 (nxp_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 						nxp_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
258 	ARG_UNUSED(dev);
259 	ARG_UNUSED(pin);
260 	ARG_UNUSED(mode);
261 	ARG_UNUSED(trig);
262 
263 	return -ENOTSUP;
264 #endif
265 }
266 
nxp_s32_gpio_manage_callback(const struct device * dev,struct gpio_callback * cb,bool set)267 static int nxp_s32_gpio_manage_callback(const struct device *dev,
268 					struct gpio_callback *cb, bool set)
269 {
270 #ifdef CONFIG_NXP_S32_EIRQ
271 	struct gpio_nxp_s32_data *data = dev->data;
272 
273 	return gpio_manage_callback(&data->callbacks, cb, set);
274 #else
275 	ARG_UNUSED(dev);
276 	ARG_UNUSED(cb);
277 	ARG_UNUSED(set);
278 
279 	return -ENOTSUP;
280 #endif
281 }
282 
nxp_s32_gpio_get_pending_int(const struct device * dev)283 static uint32_t nxp_s32_gpio_get_pending_int(const struct device *dev)
284 {
285 #ifdef CONFIG_NXP_S32_EIRQ
286 	const struct gpio_nxp_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
304 	ARG_UNUSED(dev);
305 
306 	return -ENOTSUP;
307 #endif
308 }
309 
310 static const struct gpio_driver_api gpio_nxp_s32_driver_api = {
311 	.pin_configure = nxp_s32_gpio_configure,
312 	.port_get_raw = nxp_s32_gpio_port_get_raw,
313 	.port_set_masked_raw = nxp_s32_gpio_port_set_masked_raw,
314 	.port_set_bits_raw = nxp_s32_gpio_port_set_bits_raw,
315 	.port_clear_bits_raw = nxp_s32_gpio_port_clear_bits_raw,
316 	.port_toggle_bits = nxp_s32_gpio_port_toggle_bits,
317 	.pin_interrupt_configure = nxp_s32_gpio_pin_interrupt_configure,
318 	.manage_callback = nxp_s32_gpio_manage_callback,
319 	.get_pending_int = nxp_s32_gpio_get_pending_int
320 };
321 
322 /* Calculate the port pin mask based on ngpios and gpio-reserved-ranges node
323  * properties. Multiple reserved ranges are not supported.
324  *
325  * For example, for the following gpio node definition:
326  *
327  *	gpioo: gpio@40521716 {
328  *              ...
329  *		ngpios = <14>;
330  *		gpio-reserved-ranges = <0 10>;
331  *	};
332  *
333  * the generated mask will be will be 0x3C00.
334  */
335 #define GPIO_NXP_S32_RESERVED_PIN_MASK(n)					\
336 	(GENMASK(DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 0) +		\
337 			DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 1) - 1,	\
338 		 DT_INST_PROP_BY_IDX(n, gpio_reserved_ranges, 0)		\
339 	))
340 
341 #define GPIO_NXP_S32_PORT_PIN_MASK(n)						\
342 	COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpio_reserved_ranges),		\
343 		(GPIO_PORT_PIN_MASK_FROM_DT_INST(n)				\
344 			& ~(GPIO_NXP_S32_RESERVED_PIN_MASK(n))),		\
345 		(GPIO_PORT_PIN_MASK_FROM_DT_INST(n)))
346 
347 #define GPIO_NXP_S32_REG_ADDR(n)						\
348 	((Siul2_Dio_Ip_GpioType *)DT_INST_REG_ADDR_BY_NAME(n, pgpdo))
349 
350 #define GPIO_NXP_S32_PORT_REG_ADDR(n)						\
351 	((Siul2_Port_Ip_PortType *)DT_INST_REG_ADDR_BY_NAME(n, mscr))
352 
353 #ifdef CONFIG_NXP_S32_EIRQ
354 #define GPIO_NXP_S32_EIRQ_NODE(n)						\
355 	DT_INST_PHANDLE(n, interrupt_parent)
356 
357 #define GPIO_NXP_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_NXP_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_NXP_S32_EIRQ_NODE(n), okay),		\
369 		(static struct eirq_nxp_s32_info eirq_nxp_s32_info_##n = {	\
370 			.eirq_dev = DEVICE_DT_GET(GPIO_NXP_S32_EIRQ_NODE(n)),	\
371 			.gpio_pin_lines = {					\
372 				LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)),		\
373 					GPIO_NXP_S32_EIRQ_PIN_LINE, (,), n)	\
374 			},							\
375 			.num_lines = DT_NUM_IRQS(DT_DRV_INST(n))		\
376 		};								\
377 		))
378 
379 #define GPIO_NXP_S32_GET_EIRQ_INFO(n)						\
380 	.eirq_info = UTIL_AND(DT_NODE_HAS_STATUS(GPIO_NXP_S32_EIRQ_NODE(n), okay),\
381 				&eirq_nxp_s32_info_##n)
382 #else
383 #define GPIO_NXP_S32_SET_EIRQ_INFO(n)
384 #define GPIO_NXP_S32_GET_EIRQ_INFO(n)
385 #endif /* CONFIG_NXP_S32_EIRQ */
386 
387 #define GPIO_NXP_S32_DEVICE_INIT(n)						\
388 	GPIO_NXP_S32_SET_EIRQ_INFO(n)						\
389 	static const struct gpio_nxp_s32_config gpio_nxp_s32_config_##n = {	\
390 		.common = {							\
391 			.port_pin_mask = GPIO_NXP_S32_PORT_PIN_MASK(n),		\
392 		},								\
393 		.gpio_base = GPIO_NXP_S32_REG_ADDR(n),				\
394 		.port_base = GPIO_NXP_S32_PORT_REG_ADDR(n),			\
395 		GPIO_NXP_S32_GET_EIRQ_INFO(n)					\
396 	};									\
397 	static struct gpio_nxp_s32_data gpio_nxp_s32_data_##n;			\
398 	static int gpio_nxp_s32_init_##n(const struct device *dev)		\
399 	{									\
400 		return 0;							\
401 	}									\
402 	DEVICE_DT_INST_DEFINE(n,						\
403 			gpio_nxp_s32_init_##n,					\
404 			NULL,							\
405 			&gpio_nxp_s32_data_##n,					\
406 			&gpio_nxp_s32_config_##n,				\
407 			POST_KERNEL,						\
408 			CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,			\
409 			&gpio_nxp_s32_driver_api);
410 
411 DT_INST_FOREACH_STATUS_OKAY(GPIO_NXP_S32_DEVICE_INIT)
412