1 /*
2  * Copyright (c) 2016 Freescale Semiconductor, Inc.
3  * Copyright (c) 2017, NXP
4  * Copyright (c) 2018 Foundries.io
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #define DT_DRV_COMPAT openisa_rv32m1_gpio
10 
11 #include <errno.h>
12 #include <zephyr/device.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/irq.h>
15 #include <soc.h>
16 #include <fsl_common.h>
17 #include <fsl_port.h>
18 #include <zephyr/drivers/clock_control.h>
19 
20 #include <zephyr/drivers/gpio/gpio_utils.h>
21 
22 struct gpio_rv32m1_config {
23 	/* gpio_driver_config needs to be first */
24 	struct gpio_driver_config common;
25 	GPIO_Type *gpio_base;
26 	PORT_Type *port_base;
27 	unsigned int flags;
28 	const struct device *clock_dev;
29 	clock_control_subsys_t clock_subsys;
30 	int (*irq_config_func)(const struct device *dev);
31 };
32 
33 struct gpio_rv32m1_data {
34 	/* gpio_driver_data needs to be first */
35 	struct gpio_driver_data common;
36 	/* port ISR callback routine address */
37 	sys_slist_t callbacks;
38 };
39 
get_port_pcr_irqc_value_from_flags(const struct device * dev,uint32_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)40 static uint32_t get_port_pcr_irqc_value_from_flags(const struct device *dev,
41 						   uint32_t pin,
42 						   enum gpio_int_mode mode,
43 						   enum gpio_int_trig trig)
44 {
45 	port_interrupt_t port_interrupt = 0;
46 
47 	if (mode == GPIO_INT_MODE_DISABLED) {
48 		port_interrupt = kPORT_InterruptOrDMADisabled;
49 	} else {
50 		if (mode == GPIO_INT_MODE_LEVEL) {
51 			if (trig == GPIO_INT_TRIG_LOW) {
52 				port_interrupt = kPORT_InterruptLogicZero;
53 			} else {
54 				port_interrupt = kPORT_InterruptLogicOne;
55 			}
56 		} else {
57 			switch (trig) {
58 			case GPIO_INT_TRIG_LOW:
59 				port_interrupt = kPORT_InterruptFallingEdge;
60 				break;
61 			case GPIO_INT_TRIG_HIGH:
62 				port_interrupt = kPORT_InterruptRisingEdge;
63 				break;
64 			case GPIO_INT_TRIG_BOTH:
65 				port_interrupt = kPORT_InterruptEitherEdge;
66 				break;
67 			}
68 		}
69 	}
70 
71 	return PORT_PCR_IRQC(port_interrupt);
72 }
73 
gpio_rv32m1_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)74 static int gpio_rv32m1_configure(const struct device *dev,
75 				 gpio_pin_t pin, gpio_flags_t flags)
76 {
77 	const struct gpio_rv32m1_config *config = dev->config;
78 	GPIO_Type *gpio_base = config->gpio_base;
79 	PORT_Type *port_base = config->port_base;
80 	uint32_t mask = 0U;
81 	uint32_t pcr = 0U;
82 
83 	/* Check for an invalid pin number */
84 	if (pin >= ARRAY_SIZE(port_base->PCR)) {
85 		return -EINVAL;
86 	}
87 
88 	/* Check for an invalid pin configuration */
89 	if ((flags & GPIO_INT_ENABLE) && ((flags & GPIO_INPUT) == 0)) {
90 		return -EINVAL;
91 	}
92 
93 	if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
94 		return -ENOTSUP;
95 	}
96 
97 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
98 		return -ENOTSUP;
99 	}
100 
101 	/* Check if GPIO port supports interrupts */
102 	if ((flags & GPIO_INT_ENABLE) &&
103 	    ((config->flags & GPIO_INT_ENABLE) == 0U)) {
104 		return -ENOTSUP;
105 	}
106 
107 	/* The flags contain options that require touching registers in the
108 	 * GPIO module and the corresponding PORT module.
109 	 *
110 	 * Start with the GPIO module and set up the pin direction register.
111 	 * 0 - pin is input, 1 - pin is output
112 	 */
113 
114 	switch (flags & GPIO_DIR_MASK) {
115 	case GPIO_INPUT:
116 		gpio_base->PDDR &= ~BIT(pin);
117 		break;
118 	case GPIO_OUTPUT:
119 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
120 			gpio_base->PSOR = BIT(pin);
121 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
122 			gpio_base->PCOR = BIT(pin);
123 		}
124 		gpio_base->PDDR |= BIT(pin);
125 		break;
126 	default:
127 		return -ENOTSUP;
128 	}
129 
130 	/* Set PCR mux to GPIO for the pin we are configuring */
131 	mask |= PORT_PCR_MUX_MASK;
132 	pcr |= PORT_PCR_MUX(kPORT_MuxAsGpio);
133 
134 	/* Now do the PORT module. Figure out the pullup/pulldown
135 	 * configuration, but don't write it to the PCR register yet.
136 	 */
137 	mask |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
138 
139 	if ((flags & GPIO_PULL_UP) != 0) {
140 		/* Enable the pull and select the pullup resistor. */
141 		pcr |= PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;
142 
143 	} else if ((flags & GPIO_PULL_DOWN) != 0) {
144 		/* Enable the pull and select the pulldown resistor (deselect
145 		 * the pullup resistor.
146 		 */
147 		pcr |= PORT_PCR_PE_MASK;
148 	}
149 
150 	/* Still in the PORT module. Figure out the interrupt configuration,
151 	 * but don't write it to the PCR register yet.
152 	 */
153 	mask |= PORT_PCR_IRQC_MASK;
154 
155 	/* Accessing by pin, we only need to write one PCR register. */
156 	port_base->PCR[pin] = (port_base->PCR[pin] & ~mask) | pcr;
157 
158 	return 0;
159 }
160 
gpio_rv32m1_port_get_raw(const struct device * dev,uint32_t * value)161 static int gpio_rv32m1_port_get_raw(const struct device *dev, uint32_t *value)
162 {
163 	const struct gpio_rv32m1_config *config = dev->config;
164 	GPIO_Type *gpio_base = config->gpio_base;
165 
166 	*value = gpio_base->PDIR;
167 
168 	return 0;
169 }
170 
gpio_rv32m1_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)171 static int gpio_rv32m1_port_set_masked_raw(const struct device *dev,
172 					   uint32_t mask,
173 					   uint32_t value)
174 {
175 	const struct gpio_rv32m1_config *config = dev->config;
176 	GPIO_Type *gpio_base = config->gpio_base;
177 
178 	gpio_base->PDOR = (gpio_base->PDOR & ~mask) | (mask & value);
179 
180 	return 0;
181 }
182 
gpio_rv32m1_port_set_bits_raw(const struct device * dev,uint32_t mask)183 static int gpio_rv32m1_port_set_bits_raw(const struct device *dev,
184 					 uint32_t mask)
185 {
186 	const struct gpio_rv32m1_config *config = dev->config;
187 	GPIO_Type *gpio_base = config->gpio_base;
188 
189 	gpio_base->PSOR = mask;
190 
191 	return 0;
192 }
193 
gpio_rv32m1_port_clear_bits_raw(const struct device * dev,uint32_t mask)194 static int gpio_rv32m1_port_clear_bits_raw(const struct device *dev,
195 					   uint32_t mask)
196 {
197 	const struct gpio_rv32m1_config *config = dev->config;
198 	GPIO_Type *gpio_base = config->gpio_base;
199 
200 	gpio_base->PCOR = mask;
201 
202 	return 0;
203 }
204 
gpio_rv32m1_port_toggle_bits(const struct device * dev,uint32_t mask)205 static int gpio_rv32m1_port_toggle_bits(const struct device *dev,
206 					uint32_t mask)
207 {
208 	const struct gpio_rv32m1_config *config = dev->config;
209 	GPIO_Type *gpio_base = config->gpio_base;
210 
211 	gpio_base->PTOR = mask;
212 
213 	return 0;
214 }
215 
gpio_rv32m1_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)216 static int gpio_rv32m1_pin_interrupt_configure(const struct device *dev,
217 					       gpio_pin_t pin,
218 					       enum gpio_int_mode mode,
219 					       enum gpio_int_trig trig)
220 {
221 	const struct gpio_rv32m1_config *config = dev->config;
222 	PORT_Type *port_base = config->port_base;
223 
224 	/* Check for an invalid pin number */
225 	if (pin >= ARRAY_SIZE(port_base->PCR)) {
226 		return -EINVAL;
227 	}
228 
229 	/* Check if GPIO port supports interrupts */
230 	if ((mode != GPIO_INT_MODE_DISABLED) &&
231 	    ((config->flags & GPIO_INT_ENABLE) == 0U)) {
232 		return -ENOTSUP;
233 	}
234 
235 	uint32_t pcr = get_port_pcr_irqc_value_from_flags(dev, pin, mode, trig);
236 
237 	port_base->PCR[pin] = (port_base->PCR[pin] & ~PORT_PCR_IRQC_MASK) | pcr;
238 
239 	return 0;
240 }
241 
242 
gpio_rv32m1_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)243 static int gpio_rv32m1_manage_callback(const struct device *dev,
244 				       struct gpio_callback *callback,
245 				       bool set)
246 {
247 	struct gpio_rv32m1_data *data = dev->data;
248 
249 	gpio_manage_callback(&data->callbacks, callback, set);
250 
251 	return 0;
252 }
253 
gpio_rv32m1_port_isr(const struct device * dev)254 static void gpio_rv32m1_port_isr(const struct device *dev)
255 {
256 	const struct gpio_rv32m1_config *config = dev->config;
257 	struct gpio_rv32m1_data *data = dev->data;
258 	uint32_t int_status;
259 
260 	int_status = config->port_base->ISFR;
261 
262 	/* Clear the port interrupts before invoking callbacks */
263 	config->port_base->ISFR = int_status;
264 
265 	gpio_fire_callbacks(&data->callbacks, dev, int_status);
266 }
267 
gpio_rv32m1_init(const struct device * dev)268 static int gpio_rv32m1_init(const struct device *dev)
269 {
270 	const struct gpio_rv32m1_config *config = dev->config;
271 	int ret;
272 
273 	if (config->clock_dev) {
274 		if (!device_is_ready(config->clock_dev)) {
275 			return -ENODEV;
276 		}
277 
278 		ret = clock_control_on(config->clock_dev, config->clock_subsys);
279 		if (ret < 0) {
280 			return ret;
281 		}
282 	}
283 
284 	return config->irq_config_func(dev);
285 }
286 
287 static const struct gpio_driver_api gpio_rv32m1_driver_api = {
288 	.pin_configure = gpio_rv32m1_configure,
289 	.port_get_raw = gpio_rv32m1_port_get_raw,
290 	.port_set_masked_raw = gpio_rv32m1_port_set_masked_raw,
291 	.port_set_bits_raw = gpio_rv32m1_port_set_bits_raw,
292 	.port_clear_bits_raw = gpio_rv32m1_port_clear_bits_raw,
293 	.port_toggle_bits = gpio_rv32m1_port_toggle_bits,
294 	.pin_interrupt_configure = gpio_rv32m1_pin_interrupt_configure,
295 	.manage_callback = gpio_rv32m1_manage_callback,
296 };
297 
298 #define INST_DT_PORT_ADDR(n) \
299 	DT_REG_ADDR(DT_INST_PHANDLE(n, openisa_rv32m1_port))
300 #define INST_DT_CLK_CTRL_DEV(n) \
301 	UTIL_AND(DT_INST_NODE_HAS_PROP(n, clocks), DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)))
302 #define INST_DT_CLK_CELL_NAME(n) \
303 	UTIL_AND(DT_INST_NODE_HAS_PROP(n, clocks), DT_INST_CLOCKS_CELL(n, name))
304 
305 #define GPIO_RV32M1_INIT(n) \
306 	static int gpio_rv32m1_##n##_init(const struct device *dev);	\
307 									\
308 	static const struct gpio_rv32m1_config gpio_rv32m1_##n##_config = {\
309 		.common = {						\
310 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
311 		},							\
312 		.gpio_base = (GPIO_Type *) DT_INST_REG_ADDR(n),		\
313 		.port_base = (PORT_Type *) INST_DT_PORT_ADDR(n),	\
314 		.flags = GPIO_INT_ENABLE,				\
315 		.irq_config_func = gpio_rv32m1_##n##_init,		\
316 		.clock_dev = INST_DT_CLK_CTRL_DEV(n),			\
317 		.clock_subsys = (clock_control_subsys_t)		\
318 				INST_DT_CLK_CELL_NAME(n)		\
319 	};								\
320 									\
321 	static struct gpio_rv32m1_data gpio_rv32m1_##n##_data;		\
322 									\
323 	DEVICE_DT_INST_DEFINE(n,					\
324 			    gpio_rv32m1_init,				\
325 			    NULL,					\
326 			    &gpio_rv32m1_##n##_data,			\
327 			    &gpio_rv32m1_##n##_config,			\
328 			    PRE_KERNEL_1,				\
329 			    CONFIG_GPIO_INIT_PRIORITY,			\
330 			    &gpio_rv32m1_driver_api);			\
331 									\
332 	static int gpio_rv32m1_##n##_init(const struct device *dev)	\
333 	{								\
334 		IRQ_CONNECT(DT_INST_IRQN(n),				\
335 			    0,						\
336 			    gpio_rv32m1_port_isr,			\
337 			    DEVICE_DT_INST_GET(n), 0);			\
338 									\
339 		irq_enable(DT_INST_IRQN(0));				\
340 									\
341 		return 0;						\
342 	}
343 
344 DT_INST_FOREACH_STATUS_OKAY(GPIO_RV32M1_INIT)
345