1 /*
2  * Copyright (c) 2021, Yonatan Schachter
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/irq.h>
10 
11 /* pico-sdk includes */
12 #include <hardware/gpio.h>
13 #include <hardware/regs/intctrl.h>
14 #include <hardware/structs/iobank0.h>
15 
16 #include <zephyr/drivers/gpio/gpio_utils.h>
17 
18 #define DT_DRV_COMPAT raspberrypi_pico_gpio
19 
20 #define ALL_EVENTS (GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE \
21 		| GPIO_IRQ_LEVEL_LOW | GPIO_IRQ_LEVEL_HIGH)
22 
23 struct gpio_rpi_config {
24 	struct gpio_driver_config common;
25 	void (*bank_config_func)(void);
26 };
27 
28 struct gpio_rpi_data {
29 	struct gpio_driver_data common;
30 	sys_slist_t callbacks;
31 	uint32_t int_enabled_mask;
32 	uint32_t single_ended_mask;
33 	uint32_t open_drain_mask;
34 };
35 
gpio_rpi_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)36 static int gpio_rpi_configure(const struct device *dev,
37 				gpio_pin_t pin,
38 				gpio_flags_t flags)
39 {
40 	struct gpio_rpi_data *data = dev->data;
41 
42 	gpio_set_pulls(pin,
43 		(flags & GPIO_PULL_UP) != 0U,
44 		(flags & GPIO_PULL_DOWN) != 0U);
45 
46 	/* Avoid gpio_init, since that also clears previously set direction/high/low */
47 	gpio_set_function(pin, GPIO_FUNC_SIO);
48 
49 	if (flags & GPIO_OUTPUT) {
50 		if (flags & GPIO_SINGLE_ENDED) {
51 			data->single_ended_mask |= BIT(pin);
52 
53 			/* Setting the initial state of output data, and output enable.
54 			 * The output data will not change from here on, only output
55 			 * enable will. If none of the GPIO_OUTPUT_INIT_* flags have
56 			 * been set then fall back to the non-agressive input mode.
57 			 */
58 			if (flags & GPIO_LINE_OPEN_DRAIN) {
59 				data->open_drain_mask |= BIT(pin);
60 				gpio_put(pin, 0);
61 				gpio_set_dir(pin, flags & GPIO_OUTPUT_INIT_LOW);
62 			} else {
63 				data->open_drain_mask &= ~(BIT(pin));
64 				gpio_put(pin, 1);
65 				gpio_set_dir(pin, flags & GPIO_OUTPUT_INIT_HIGH);
66 			}
67 		} else {
68 			data->single_ended_mask &= ~(BIT(pin));
69 			if (flags & GPIO_OUTPUT_INIT_HIGH) {
70 				gpio_put(pin, 1);
71 			} else if (flags & GPIO_OUTPUT_INIT_LOW) {
72 				gpio_put(pin, 0);
73 			}
74 			gpio_set_dir(pin, GPIO_OUT);
75 		}
76 	} else if (flags & GPIO_INPUT) {
77 		gpio_set_dir(pin, GPIO_IN);
78 	}
79 
80 	return 0;
81 }
82 
gpio_rpi_port_get_raw(const struct device * dev,uint32_t * value)83 static int gpio_rpi_port_get_raw(const struct device *dev, uint32_t *value)
84 {
85 	*value = gpio_get_all();
86 	return 0;
87 }
88 
gpio_rpi_port_set_masked_raw(const struct device * port,uint32_t mask,uint32_t value)89 static int gpio_rpi_port_set_masked_raw(const struct device *port,
90 					uint32_t mask, uint32_t value)
91 {
92 	struct gpio_rpi_data *data = port->data;
93 	/* First handle push-pull pins: */
94 	gpio_put_masked(mask & ~data->single_ended_mask, value);
95 	/* Then handle open-drain pins: */
96 	gpio_set_dir_masked(mask & data->single_ended_mask & data->open_drain_mask, ~value);
97 	/* Then handle open-source pins: */
98 	gpio_set_dir_masked(mask & data->single_ended_mask & ~data->open_drain_mask, value);
99 	return 0;
100 }
101 
gpio_rpi_port_set_bits_raw(const struct device * port,uint32_t pins)102 static int gpio_rpi_port_set_bits_raw(const struct device *port,
103 					uint32_t pins)
104 {
105 	struct gpio_rpi_data *data = port->data;
106 	/* First handle push-pull pins: */
107 	gpio_set_mask(pins & ~data->single_ended_mask);
108 	/* Then handle open-drain pins: */
109 	gpio_set_dir_in_masked(pins & data->single_ended_mask & data->open_drain_mask);
110 	/* Then handle open-source pins: */
111 	gpio_set_dir_out_masked(pins & data->single_ended_mask & ~data->open_drain_mask);
112 	return 0;
113 }
114 
gpio_rpi_port_clear_bits_raw(const struct device * port,uint32_t pins)115 static int gpio_rpi_port_clear_bits_raw(const struct device *port,
116 					uint32_t pins)
117 {
118 	struct gpio_rpi_data *data = port->data;
119 	/* First handle push-pull pins: */
120 	gpio_clr_mask(pins & ~data->single_ended_mask);
121 	/* Then handle open-drain pins: */
122 	gpio_set_dir_out_masked(pins & data->single_ended_mask & data->open_drain_mask);
123 	/* Then handle open-source pins: */
124 	gpio_set_dir_in_masked(pins & data->single_ended_mask & ~data->open_drain_mask);
125 	return 0;
126 }
127 
gpio_rpi_port_toggle_bits(const struct device * port,uint32_t pins)128 static int gpio_rpi_port_toggle_bits(const struct device *port,
129 					uint32_t pins)
130 {
131 	struct gpio_rpi_data *data = port->data;
132 	/* First handle push-pull pins: */
133 	gpio_xor_mask(pins & ~data->single_ended_mask);
134 	/* Then handle single-ended pins: */
135 	/* (unfortunately there's no pico-sdk api call that can be used for this,
136 	 * but it's possible by accessing the registers directly)
137 	 */
138 	sio_hw->gpio_oe_togl = (pins & data->single_ended_mask);
139 	return 0;
140 }
141 
gpio_rpi_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)142 static int gpio_rpi_pin_interrupt_configure(const struct device *dev,
143 						gpio_pin_t pin,
144 						enum gpio_int_mode mode,
145 						enum gpio_int_trig trig)
146 {
147 	struct gpio_rpi_data *data = dev->data;
148 	uint32_t events = 0;
149 
150 	gpio_set_irq_enabled(pin, ALL_EVENTS, false);
151 	if (mode != GPIO_INT_DISABLE) {
152 		if (mode & GPIO_INT_EDGE) {
153 			if (trig & GPIO_INT_LOW_0) {
154 				events |= GPIO_IRQ_EDGE_FALL;
155 			}
156 			if (trig & GPIO_INT_HIGH_1) {
157 				events |= GPIO_IRQ_EDGE_RISE;
158 			}
159 		} else {
160 			if (trig & GPIO_INT_LOW_0) {
161 				events |= GPIO_IRQ_LEVEL_LOW;
162 			}
163 			if (trig & GPIO_INT_HIGH_1) {
164 				events |= GPIO_IRQ_LEVEL_HIGH;
165 			}
166 		}
167 		gpio_set_irq_enabled(pin, events, true);
168 	}
169 	WRITE_BIT(data->int_enabled_mask, pin, mode != GPIO_INT_DISABLE);
170 	return 0;
171 }
172 
gpio_rpi_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)173 static int gpio_rpi_manage_callback(const struct device *dev,
174 				struct gpio_callback *callback, bool set)
175 {
176 	struct gpio_rpi_data *data = dev->data;
177 
178 	return gpio_manage_callback(&data->callbacks, callback, set);
179 }
180 
181 static const struct gpio_driver_api gpio_rpi_driver_api = {
182 	.pin_configure = gpio_rpi_configure,
183 	.port_get_raw = gpio_rpi_port_get_raw,
184 	.port_set_masked_raw = gpio_rpi_port_set_masked_raw,
185 	.port_set_bits_raw = gpio_rpi_port_set_bits_raw,
186 	.port_clear_bits_raw = gpio_rpi_port_clear_bits_raw,
187 	.port_toggle_bits = gpio_rpi_port_toggle_bits,
188 	.pin_interrupt_configure = gpio_rpi_pin_interrupt_configure,
189 	.manage_callback = gpio_rpi_manage_callback,
190 };
191 
gpio_rpi_isr(const struct device * dev)192 static void gpio_rpi_isr(const struct device *dev)
193 {
194 	struct gpio_rpi_data *data = dev->data;
195 	io_irq_ctrl_hw_t *irq_ctrl_base;
196 	const io_rw_32 *status_reg;
197 	uint32_t events;
198 	uint32_t pin;
199 
200 	irq_ctrl_base = &iobank0_hw->proc0_irq_ctrl;
201 	for (pin = 0; pin < NUM_BANK0_GPIOS; pin++) {
202 		status_reg = &irq_ctrl_base->ints[pin / 8];
203 		events = (*status_reg >> 4 * (pin % 8)) & ALL_EVENTS;
204 		if (events) {
205 			gpio_acknowledge_irq(pin, ALL_EVENTS);
206 			gpio_fire_callbacks(&data->callbacks, dev, BIT(pin));
207 		}
208 	}
209 }
210 
gpio_rpi_bank_init(const struct device * dev)211 static int gpio_rpi_bank_init(const struct device *dev)
212 {
213 	const struct gpio_rpi_config *config = dev->config;
214 
215 	config->bank_config_func();
216 	return 0;
217 }
218 
219 #define GPIO_RPI_INIT(idx)							\
220 	static void bank_##idx##_config_func(void)				\
221 	{									\
222 		IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority),	\
223 			    gpio_rpi_isr, DEVICE_DT_INST_GET(idx), 0);		\
224 		irq_enable(DT_INST_IRQN(idx));					\
225 	}									\
226 	static const struct gpio_rpi_config gpio_rpi_##idx##_config = {		\
227 		.bank_config_func = bank_##idx##_config_func,			\
228 		.common =							\
229 		{								\
230 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx),	\
231 		}								\
232 	};									\
233 										\
234 	static struct gpio_rpi_data gpio_rpi_##idx##_data;			\
235 										\
236 	DEVICE_DT_INST_DEFINE(idx, gpio_rpi_bank_init, NULL,			\
237 				&gpio_rpi_##idx##_data,				\
238 				&gpio_rpi_##idx##_config,			\
239 				POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY,		\
240 				&gpio_rpi_driver_api);
241 
242 DT_INST_FOREACH_STATUS_OKAY(GPIO_RPI_INIT)
243