1 /*
2  * Copyright (c) 2016 Freescale Semiconductor, Inc.
3  * Copyright 2017, 2023-2024 NXP
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT nxp_kinetis_gpio
9 
10 #include <errno.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/dt-bindings/gpio/nxp-kinetis-gpio.h>
14 #include <zephyr/irq.h>
15 #include <soc.h>
16 #include <fsl_common.h>
17 
18 #include <zephyr/drivers/gpio/gpio_utils.h>
19 
20 struct gpio_mcux_config {
21 	/* gpio_driver_config needs to be first */
22 	struct gpio_driver_config common;
23 	GPIO_Type *gpio_base;
24 	PORT_Type *port_base;
25 	unsigned int flags;
26 };
27 
28 struct gpio_mcux_data {
29 	/* gpio_driver_data needs to be first */
30 	struct gpio_driver_data common;
31 	/* port ISR callback routine address */
32 	sys_slist_t callbacks;
33 };
34 
gpio_mcux_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)35 static int gpio_mcux_configure(const struct device *dev,
36 			       gpio_pin_t pin, gpio_flags_t flags)
37 {
38 	const struct gpio_mcux_config *config = dev->config;
39 	GPIO_Type *gpio_base = config->gpio_base;
40 	PORT_Type *port_base = config->port_base;
41 	uint32_t mask = 0U;
42 	uint32_t pcr = 0U;
43 
44 	/* Check for an invalid pin number */
45 	if (pin >= ARRAY_SIZE(port_base->PCR)) {
46 		return -EINVAL;
47 	}
48 
49 	if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
50 		return -ENOTSUP;
51 	}
52 
53 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
54 		return -ENOTSUP;
55 	}
56 
57 	/* The flags contain options that require touching registers in the
58 	 * GPIO module and the corresponding PORT module.
59 	 *
60 	 * Start with the GPIO module and set up the pin direction register.
61 	 * 0 - pin is input, 1 - pin is output
62 	 */
63 
64 	switch (flags & GPIO_DIR_MASK) {
65 	case GPIO_INPUT:
66 		gpio_base->PDDR &= ~BIT(pin);
67 		break;
68 	case GPIO_OUTPUT:
69 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
70 			gpio_base->PSOR = BIT(pin);
71 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
72 			gpio_base->PCOR = BIT(pin);
73 		}
74 		gpio_base->PDDR |= BIT(pin);
75 		break;
76 	default:
77 		return -ENOTSUP;
78 	}
79 
80 	/* Set PCR mux to GPIO for the pin we are configuring */
81 	mask |= PORT_PCR_MUX_MASK;
82 	pcr |= PORT_PCR_MUX(PORT_MUX_GPIO);
83 
84 #if defined(FSL_FEATURE_PORT_HAS_INPUT_BUFFER) && FSL_FEATURE_PORT_HAS_INPUT_BUFFER
85 	/* Enable digital input buffer */
86 	pcr |= PORT_PCR_IBE_MASK;
87 #endif
88 
89 	/* Now do the PORT module. Figure out the pullup/pulldown
90 	 * configuration, but don't write it to the PCR register yet.
91 	 */
92 	mask |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
93 
94 	if ((flags & GPIO_PULL_UP) != 0) {
95 		/* Enable the pull and select the pullup resistor. */
96 		pcr |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
97 
98 	} else if ((flags & GPIO_PULL_DOWN) != 0) {
99 		/* Enable the pull and select the pulldown resistor, deselect
100 		 * the pullup resistor.
101 		 */
102 		pcr |= PORT_PCR_PE_MASK;
103 	}
104 
105 #if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH
106 	/* Determine the drive strength */
107 	switch (flags & KINETIS_GPIO_DS_MASK) {
108 	case KINETIS_GPIO_DS_DFLT:
109 		/* Default is low drive strength */
110 		mask |= PORT_PCR_DSE_MASK;
111 		break;
112 	case KINETIS_GPIO_DS_ALT:
113 		/* Alternate is high drive strength */
114 		pcr |= PORT_PCR_DSE_MASK;
115 		break;
116 	default:
117 		return -ENOTSUP;
118 	}
119 #endif /* defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH */
120 
121 	/* Accessing by pin, we only need to write one PCR register. */
122 	port_base->PCR[pin] = (port_base->PCR[pin] & ~mask) | pcr;
123 
124 	return 0;
125 }
126 
gpio_mcux_port_get_raw(const struct device * dev,uint32_t * value)127 static int gpio_mcux_port_get_raw(const struct device *dev, uint32_t *value)
128 {
129 	const struct gpio_mcux_config *config = dev->config;
130 	GPIO_Type *gpio_base = config->gpio_base;
131 
132 	*value = gpio_base->PDIR;
133 
134 	return 0;
135 }
136 
gpio_mcux_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)137 static int gpio_mcux_port_set_masked_raw(const struct device *dev,
138 					 uint32_t mask,
139 					 uint32_t value)
140 {
141 	const struct gpio_mcux_config *config = dev->config;
142 	GPIO_Type *gpio_base = config->gpio_base;
143 
144 	gpio_base->PDOR = (gpio_base->PDOR & ~mask) | (mask & value);
145 
146 	return 0;
147 }
148 
gpio_mcux_port_set_bits_raw(const struct device * dev,uint32_t mask)149 static int gpio_mcux_port_set_bits_raw(const struct device *dev,
150 				       uint32_t mask)
151 {
152 	const struct gpio_mcux_config *config = dev->config;
153 	GPIO_Type *gpio_base = config->gpio_base;
154 
155 	gpio_base->PSOR = mask;
156 
157 	return 0;
158 }
159 
gpio_mcux_port_clear_bits_raw(const struct device * dev,uint32_t mask)160 static int gpio_mcux_port_clear_bits_raw(const struct device *dev,
161 					 uint32_t mask)
162 {
163 	const struct gpio_mcux_config *config = dev->config;
164 	GPIO_Type *gpio_base = config->gpio_base;
165 
166 	gpio_base->PCOR = mask;
167 
168 	return 0;
169 }
170 
gpio_mcux_port_toggle_bits(const struct device * dev,uint32_t mask)171 static int gpio_mcux_port_toggle_bits(const struct device *dev, uint32_t mask)
172 {
173 	const struct gpio_mcux_config *config = dev->config;
174 	GPIO_Type *gpio_base = config->gpio_base;
175 
176 	gpio_base->PTOR = mask;
177 
178 	return 0;
179 }
180 
181 #if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
get_port_pcr_irqc_value_from_flags(const struct device * dev,uint32_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)182 static uint32_t get_port_pcr_irqc_value_from_flags(const struct device *dev,
183 						   uint32_t pin,
184 						   enum gpio_int_mode mode,
185 						   enum gpio_int_trig trig)
186 {
187 	port_interrupt_t port_interrupt = 0;
188 
189 	if (mode == GPIO_INT_MODE_DISABLED) {
190 		port_interrupt = kPORT_InterruptOrDMADisabled;
191 	} else {
192 		if (mode == GPIO_INT_MODE_LEVEL) {
193 			if (trig == GPIO_INT_TRIG_LOW) {
194 				port_interrupt = kPORT_InterruptLogicZero;
195 			} else {
196 				port_interrupt = kPORT_InterruptLogicOne;
197 			}
198 		} else {
199 			switch (trig) {
200 			case GPIO_INT_TRIG_LOW:
201 				port_interrupt = kPORT_InterruptFallingEdge;
202 				break;
203 			case GPIO_INT_TRIG_HIGH:
204 				port_interrupt = kPORT_InterruptRisingEdge;
205 				break;
206 			case GPIO_INT_TRIG_BOTH:
207 				port_interrupt = kPORT_InterruptEitherEdge;
208 				break;
209 			default:
210 				return -EINVAL;
211 			}
212 		}
213 	}
214 
215 	return PORT_PCR_IRQC(port_interrupt);
216 }
217 #endif  /* !defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT */
218 
219 #if (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
220 		FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
221 
222 #define GPIO_MCUX_INTERRUPT_DISABLED		0
223 #define GPIO_MCUX_INTERRUPT_LOGIC_0		0x8
224 #define GPIO_MCUX_INTERRUPT_RISING_EDGE		0x9
225 #define GPIO_MCUX_INTERRUPT_FALLING_EDGE	0xA
226 #define GPIO_MCUX_INTERRUPT_BOTH_EDGE		0xB
227 #define GPIO_MCUX_INTERRUPT_LOGIC_1		0xC
228 
get_gpio_icr_irqc_value_from_flags(const struct device * dev,uint32_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)229 static uint32_t get_gpio_icr_irqc_value_from_flags(const struct device *dev,
230 						   uint32_t pin,
231 						   enum gpio_int_mode mode,
232 						   enum gpio_int_trig trig)
233 {
234 	uint8_t gpio_interrupt = 0;
235 
236 	if (mode == GPIO_INT_MODE_DISABLED) {
237 		gpio_interrupt = GPIO_MCUX_INTERRUPT_DISABLED;
238 	} else {
239 		if (mode == GPIO_INT_MODE_LEVEL) {
240 			if (trig == GPIO_INT_TRIG_LOW) {
241 				gpio_interrupt = GPIO_MCUX_INTERRUPT_LOGIC_0;
242 			} else {
243 				gpio_interrupt = GPIO_MCUX_INTERRUPT_LOGIC_1;
244 			}
245 		} else {
246 			switch (trig) {
247 			case GPIO_INT_TRIG_LOW:
248 				gpio_interrupt = GPIO_MCUX_INTERRUPT_FALLING_EDGE;
249 				break;
250 			case GPIO_INT_TRIG_HIGH:
251 				gpio_interrupt = GPIO_MCUX_INTERRUPT_RISING_EDGE;
252 				break;
253 			case GPIO_INT_TRIG_BOTH:
254 				gpio_interrupt = GPIO_MCUX_INTERRUPT_BOTH_EDGE;
255 				break;
256 			default:
257 				return -EINVAL;
258 			}
259 		}
260 	}
261 
262 	return GPIO_ICR_IRQC(gpio_interrupt);
263 }
264 #endif  /* (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) */
265 
gpio_mcux_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)266 static int gpio_mcux_pin_interrupt_configure(const struct device *dev,
267 					     gpio_pin_t pin, enum gpio_int_mode mode,
268 					     enum gpio_int_trig trig)
269 {
270 	const struct gpio_mcux_config *config = dev->config;
271 	GPIO_Type *gpio_base = config->gpio_base;
272 	PORT_Type *port_base = config->port_base;
273 
274 	/* Check for an invalid pin number */
275 	if (pin >= ARRAY_SIZE(port_base->PCR)) {
276 		return -EINVAL;
277 	}
278 
279 	/* Check for an invalid pin configuration */
280 	if ((mode != GPIO_INT_MODE_DISABLED) &&
281 	    ((gpio_base->PDDR & BIT(pin)) != 0)) {
282 		return -EINVAL;
283 	}
284 
285 	/* Check if GPIO port supports interrupts */
286 	if ((mode != GPIO_INT_MODE_DISABLED) &&
287 	    ((config->flags & GPIO_INT_ENABLE) == 0U)) {
288 		return -ENOTSUP;
289 	}
290 
291 #if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
292 	uint32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, mode, trig);
293 
294 	port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr;
295 #elif (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
296 		FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
297 	uint32_t icr = get_gpio_icr_irqc_value_from_flags(dev, pin, mode, trig);
298 
299 	gpio_base->ICR[pin] = (gpio_base->ICR[pin] & ~GPIO_ICR_IRQC_MASK) | icr;
300 #endif  /* !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) */
301 
302 	return 0;
303 }
304 
gpio_mcux_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)305 static int gpio_mcux_manage_callback(const struct device *dev,
306 				     struct gpio_callback *callback, bool set)
307 {
308 	struct gpio_mcux_data *data = dev->data;
309 
310 	return gpio_manage_callback(&data->callbacks, callback, set);
311 }
312 
gpio_mcux_port_isr(const struct device * dev)313 static void gpio_mcux_port_isr(const struct device *dev)
314 {
315 	const struct gpio_mcux_config *config = dev->config;
316 	struct gpio_mcux_data *data = dev->data;
317 	uint32_t int_status;
318 
319 #if !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) && FSL_FEATURE_PORT_HAS_NO_INTERRUPT)
320 	int_status = config->port_base->ISFR;
321 
322 	/* Clear the port interrupts */
323 	config->port_base->ISFR = int_status;
324 #elif (defined(FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT) && \
325 		FSL_FEATURE_GPIO_HAS_INTERRUPT_CHANNEL_SELECT)
326 	int_status = config->gpio_base->ISFR[0];
327 
328 	/* Clear the gpio interrupts */
329 	config->gpio_base->ISFR[0] = int_status;
330 #else
331 	int_status = 0U;
332 	ARG_UNUSED(config);
333 #endif  /* !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) */
334 
335 	gpio_fire_callbacks(&data->callbacks, dev, int_status);
336 }
337 
338 #define GPIO_HAS_SHARED_IRQ DT_HAS_COMPAT_STATUS_OKAY(nxp_gpio_cluster)
339 
340 #if GPIO_HAS_SHARED_IRQ
gpio_mcux_shared_cluster_isr(const struct device * ports[])341 static void gpio_mcux_shared_cluster_isr(const struct device *ports[])
342 {
343 	const struct device **current_port = &ports[0];
344 
345 	while (*current_port != NULL) {
346 		gpio_mcux_port_isr(*current_port);
347 		current_port++;
348 	}
349 }
350 
351 #define CLUSTER_ARRAY_ELEMENT(node_id) DEVICE_DT_GET(node_id),
352 
353 #define GPIO_MCUX_CLUSTER_INIT(node_id)								\
354 	const struct device *shared_array##node_id[DT_CHILD_NUM_STATUS_OKAY(node_id) + 1] =	\
355 		{DT_FOREACH_CHILD_STATUS_OKAY(node_id, CLUSTER_ARRAY_ELEMENT) NULL};	\
356 												\
357 	static int gpio_mcux_shared_interrupt_init##node_id(void)	\
358 	{								\
359 		IRQ_CONNECT(DT_IRQN(node_id),				\
360 			    DT_IRQ(node_id, priority),			\
361 			    gpio_mcux_shared_cluster_isr,		\
362 			    shared_array##node_id, 0);			\
363 		irq_enable(DT_IRQN(node_id));				\
364 									\
365 		return 0;						\
366 	}								\
367 	SYS_INIT(gpio_mcux_shared_interrupt_init##node_id, POST_KERNEL, 0);
368 
DT_FOREACH_STATUS_OKAY(nxp_gpio_cluster,GPIO_MCUX_CLUSTER_INIT)369 DT_FOREACH_STATUS_OKAY(nxp_gpio_cluster, GPIO_MCUX_CLUSTER_INIT)
370 #endif
371 
372 #ifdef CONFIG_GPIO_GET_DIRECTION
373 static int gpio_mcux_port_get_direction(const struct device *dev, gpio_port_pins_t map,
374 					gpio_port_pins_t *inputs, gpio_port_pins_t *outputs)
375 {
376 	const struct gpio_mcux_config *config = dev->config;
377 	GPIO_Type *gpio_base = config->gpio_base;
378 
379 	map &= config->common.port_pin_mask;
380 
381 	if (inputs != NULL) {
382 		*inputs = map & (~gpio_base->PDDR);
383 	}
384 
385 	if (outputs != NULL) {
386 		*outputs = map & gpio_base->PDDR;
387 	}
388 
389 	return 0;
390 }
391 #endif /* CONFIG_GPIO_GET_DIRECTION */
392 
393 static DEVICE_API(gpio, gpio_mcux_driver_api) = {
394 	.pin_configure = gpio_mcux_configure,
395 	.port_get_raw = gpio_mcux_port_get_raw,
396 	.port_set_masked_raw = gpio_mcux_port_set_masked_raw,
397 	.port_set_bits_raw = gpio_mcux_port_set_bits_raw,
398 	.port_clear_bits_raw = gpio_mcux_port_clear_bits_raw,
399 	.port_toggle_bits = gpio_mcux_port_toggle_bits,
400 	.pin_interrupt_configure = gpio_mcux_pin_interrupt_configure,
401 	.manage_callback = gpio_mcux_manage_callback,
402 #ifdef CONFIG_GPIO_GET_DIRECTION
403 	.port_get_direction = gpio_mcux_port_get_direction,
404 #endif /* CONFIG_GPIO_GET_DIRECTION */
405 };
406 
407 #define GPIO_MCUX_IRQ_INIT(n)						\
408 	do {								\
409 		IRQ_CONNECT(DT_INST_IRQN(n),				\
410 			    DT_INST_IRQ(n, priority),			\
411 			    gpio_mcux_port_isr,				\
412 			    DEVICE_DT_INST_GET(n), 0);			\
413 									\
414 		irq_enable(DT_INST_IRQN(n));				\
415 	} while (false)
416 
417 #define GPIO_PORT_BASE_ADDR(n) DT_REG_ADDR(DT_INST_PHANDLE(n, nxp_kinetis_port))
418 
419 #define GPIO_DEVICE_INIT_MCUX(n)					\
420 	static int gpio_mcux_port## n ## _init(const struct device *dev); \
421 									\
422 	static const struct gpio_mcux_config gpio_mcux_port## n ## _config = {\
423 		.common = {						\
424 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
425 		},							\
426 		.gpio_base = (GPIO_Type *) DT_INST_REG_ADDR(n),		\
427 		.port_base = (PORT_Type *) GPIO_PORT_BASE_ADDR(n),	\
428 		.flags = UTIL_AND(UTIL_OR(DT_INST_IRQ_HAS_IDX(n, 0),	\
429 				GPIO_HAS_SHARED_IRQ), GPIO_INT_ENABLE), \
430 	};								\
431 									\
432 	static struct gpio_mcux_data gpio_mcux_port## n ##_data;	\
433 									\
434 	DEVICE_DT_INST_DEFINE(n,					\
435 			    gpio_mcux_port## n ##_init,			\
436 			    NULL,					\
437 			    &gpio_mcux_port## n ##_data,		\
438 			    &gpio_mcux_port## n##_config,		\
439 			    POST_KERNEL,				\
440 			    CONFIG_GPIO_INIT_PRIORITY,			\
441 			    &gpio_mcux_driver_api);			\
442 									\
443 	static int gpio_mcux_port## n ##_init(const struct device *dev)	\
444 	{								\
445 		IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0),			\
446 			(GPIO_MCUX_IRQ_INIT(n);))			\
447 		return 0;						\
448 	}
449 
450 DT_INST_FOREACH_STATUS_OKAY(GPIO_DEVICE_INIT_MCUX)
451