1 /*
2  * Copyright (c) 2017 Google LLC.
3  * Copyright (c) 2019 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT atmel_sam0_gpio
9 
10 #include <errno.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/dt-bindings/gpio/atmel-sam0-gpio.h>
14 #include <soc.h>
15 #include <zephyr/drivers/interrupt_controller/sam0_eic.h>
16 
17 #include <zephyr/drivers/gpio/gpio_utils.h>
18 
19 #ifndef PORT_PMUX_PMUXE_A_Val
20 #define PORT_PMUX_PMUXE_A_Val (0)
21 #endif
22 
23 struct gpio_sam0_config {
24 	/* gpio_driver_config needs to be first */
25 	struct gpio_driver_config common;
26 	PortGroup *regs;
27 #ifdef CONFIG_SAM0_EIC
28 	uint8_t id;
29 #endif
30 };
31 
32 struct gpio_sam0_data {
33 	/* gpio_driver_data needs to be first */
34 	struct gpio_driver_data common;
35 	const struct device *dev;
36 	gpio_port_pins_t debounce;
37 #ifdef CONFIG_SAM0_EIC
38 	sys_slist_t callbacks;
39 #endif
40 };
41 
42 #ifdef CONFIG_SAM0_EIC
gpio_sam0_isr(uint32_t pins,void * arg)43 static void gpio_sam0_isr(uint32_t pins, void *arg)
44 {
45 	struct gpio_sam0_data *const data = (struct gpio_sam0_data *)arg;
46 
47 	gpio_fire_callbacks(&data->callbacks, data->dev, pins);
48 }
49 #endif
50 
gpio_sam0_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)51 static int gpio_sam0_config(const struct device *dev, gpio_pin_t pin,
52 			    gpio_flags_t flags)
53 {
54 	const struct gpio_sam0_config *config = dev->config;
55 	struct gpio_sam0_data *data = dev->data;
56 	PortGroup *regs = config->regs;
57 	PORT_PINCFG_Type pincfg = {
58 		.reg = 0,
59 	};
60 
61 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
62 		return -ENOTSUP;
63 	}
64 
65 	/* Supports disconnected, input, output, or bidirectional */
66 	if ((flags & GPIO_INPUT) != 0) {
67 		pincfg.bit.INEN = 1;
68 	}
69 	if ((flags & GPIO_OUTPUT) != 0) {
70 		/* Output is incompatible with pull */
71 		if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
72 			return -ENOTSUP;
73 		}
74 		/* Bidirectional is supported */
75 		if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
76 			regs->OUTCLR.reg = BIT(pin);
77 		} else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
78 			regs->OUTSET.reg = BIT(pin);
79 		}
80 		regs->DIRSET.reg = BIT(pin);
81 	} else {
82 		/* Not output, may be input */
83 		regs->DIRCLR.reg = BIT(pin);
84 
85 		/* Pull configuration is supported if not output */
86 		if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
87 			pincfg.bit.PULLEN = 1;
88 			if ((flags & GPIO_PULL_UP) != 0) {
89 				regs->OUTSET.reg = BIT(pin);
90 			} else {
91 				regs->OUTCLR.reg = BIT(pin);
92 			}
93 		}
94 	}
95 
96 	/* Preserve debounce flag for interrupt configuration. */
97 	WRITE_BIT(data->debounce, pin,
98 		  ((flags & SAM0_GPIO_DEBOUNCE) != 0)
99 		  && (pincfg.bit.INEN != 0));
100 
101 	/* Write the now-built pin configuration */
102 	regs->PINCFG[pin] = pincfg;
103 
104 	return 0;
105 }
106 
gpio_sam0_port_get_raw(const struct device * dev,gpio_port_value_t * value)107 static int gpio_sam0_port_get_raw(const struct device *dev,
108 				  gpio_port_value_t *value)
109 {
110 	const struct gpio_sam0_config *config = dev->config;
111 
112 	*value = config->regs->IN.reg;
113 
114 	return 0;
115 }
116 
gpio_sam0_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)117 static int gpio_sam0_port_set_masked_raw(const struct device *dev,
118 					 gpio_port_pins_t mask,
119 					 gpio_port_value_t value)
120 {
121 	const struct gpio_sam0_config *config = dev->config;
122 	uint32_t out = config->regs->OUT.reg;
123 
124 	config->regs->OUT.reg = (out & ~mask) | (value & mask);
125 
126 	return 0;
127 }
128 
gpio_sam0_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)129 static int gpio_sam0_port_set_bits_raw(const struct device *dev,
130 				       gpio_port_pins_t pins)
131 {
132 	const struct gpio_sam0_config *config = dev->config;
133 
134 	config->regs->OUTSET.reg = pins;
135 
136 	return 0;
137 }
138 
gpio_sam0_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)139 static int gpio_sam0_port_clear_bits_raw(const struct device *dev,
140 					 gpio_port_pins_t pins)
141 {
142 	const struct gpio_sam0_config *config = dev->config;
143 
144 	config->regs->OUTCLR.reg = pins;
145 
146 	return 0;
147 }
148 
gpio_sam0_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)149 static int gpio_sam0_port_toggle_bits(const struct device *dev,
150 				      gpio_port_pins_t pins)
151 {
152 	const struct gpio_sam0_config *config = dev->config;
153 
154 	config->regs->OUTTGL.reg = pins;
155 
156 	return 0;
157 }
158 
159 #ifdef CONFIG_SAM0_EIC
160 
gpio_sam0_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)161 static int gpio_sam0_pin_interrupt_configure(const struct device *dev,
162 					     gpio_pin_t pin,
163 					     enum gpio_int_mode mode,
164 					     enum gpio_int_trig trig)
165 {
166 	const struct gpio_sam0_config *config = dev->config;
167 	struct gpio_sam0_data *const data = dev->data;
168 	PortGroup *regs = config->regs;
169 	PORT_PINCFG_Type pincfg = {
170 		.reg = regs->PINCFG[pin].reg,
171 	};
172 	enum sam0_eic_trigger trigger;
173 	int rc = 0;
174 
175 	data->dev = dev;
176 
177 	switch (mode) {
178 	case GPIO_INT_MODE_DISABLED:
179 		pincfg.bit.PMUXEN = 0;
180 		rc = sam0_eic_disable_interrupt(config->id, pin);
181 		if (rc == -EBUSY) {
182 			/* Ignore diagnostic disabling disabled */
183 			rc = 0;
184 		}
185 		if (rc == 0) {
186 			rc = sam0_eic_release(config->id, pin);
187 		}
188 		break;
189 	case GPIO_INT_MODE_LEVEL:
190 	case GPIO_INT_MODE_EDGE:
191 		/* Enabling interrupts on a pin requires disconnecting
192 		 * the pin from the I/O pin controller (PORT) module
193 		 * and connecting it to the External Interrupt
194 		 * Controller (EIC).  This would prevent using the pin
195 		 * as an output, so interrupts are only supported if
196 		 * the pin is configured as input-only.
197 		 */
198 		if ((pincfg.bit.INEN == 0)
199 		    || ((regs->DIR.reg & BIT(pin)) != 0)) {
200 			rc = -ENOTSUP;
201 			break;
202 		}
203 
204 		/* Transfer control to EIC */
205 		pincfg.bit.PMUXEN = 1;
206 		if ((pin & 1U) != 0) {
207 			regs->PMUX[pin / 2U].bit.PMUXO = PORT_PMUX_PMUXE_A_Val;
208 		} else {
209 			regs->PMUX[pin / 2U].bit.PMUXE = PORT_PMUX_PMUXE_A_Val;
210 		}
211 
212 		switch (trig) {
213 		case GPIO_INT_TRIG_LOW:
214 			trigger = (mode == GPIO_INT_MODE_LEVEL)
215 				? SAM0_EIC_LOW
216 				: SAM0_EIC_FALLING;
217 			break;
218 		case GPIO_INT_TRIG_HIGH:
219 			trigger = (mode == GPIO_INT_MODE_LEVEL)
220 				? SAM0_EIC_HIGH
221 				: SAM0_EIC_RISING;
222 			break;
223 		case GPIO_INT_TRIG_BOTH:
224 			trigger = SAM0_EIC_BOTH;
225 			break;
226 		default:
227 			rc = -EINVAL;
228 			break;
229 		}
230 
231 		if (rc == 0) {
232 			rc = sam0_eic_acquire(config->id, pin, trigger,
233 					      (data->debounce & BIT(pin)) != 0,
234 					      gpio_sam0_isr, data);
235 		}
236 		if (rc == 0) {
237 			rc = sam0_eic_enable_interrupt(config->id, pin);
238 		}
239 
240 		break;
241 	default:
242 		rc = -EINVAL;
243 		break;
244 	}
245 
246 	if (rc == 0) {
247 		/* Update the pin configuration */
248 		regs->PINCFG[pin] = pincfg;
249 	}
250 
251 	return rc;
252 }
253 
254 
gpio_sam0_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)255 static int gpio_sam0_manage_callback(const struct device *dev,
256 				     struct gpio_callback *callback, bool set)
257 {
258 	struct gpio_sam0_data *const data = dev->data;
259 
260 	return gpio_manage_callback(&data->callbacks, callback, set);
261 }
262 
gpio_sam0_get_pending_int(const struct device * dev)263 static uint32_t gpio_sam0_get_pending_int(const struct device *dev)
264 {
265 	const struct gpio_sam0_config *config = dev->config;
266 
267 	return sam0_eic_interrupt_pending(config->id);
268 }
269 
270 #endif
271 
272 static const struct gpio_driver_api gpio_sam0_api = {
273 	.pin_configure = gpio_sam0_config,
274 	.port_get_raw = gpio_sam0_port_get_raw,
275 	.port_set_masked_raw = gpio_sam0_port_set_masked_raw,
276 	.port_set_bits_raw = gpio_sam0_port_set_bits_raw,
277 	.port_clear_bits_raw = gpio_sam0_port_clear_bits_raw,
278 	.port_toggle_bits = gpio_sam0_port_toggle_bits,
279 #ifdef CONFIG_SAM0_EIC
280 	.pin_interrupt_configure = gpio_sam0_pin_interrupt_configure,
281 	.manage_callback = gpio_sam0_manage_callback,
282 	.get_pending_int = gpio_sam0_get_pending_int,
283 #endif
284 };
285 
gpio_sam0_init(const struct device * dev)286 static int gpio_sam0_init(const struct device *dev) { return 0; }
287 
288 /* Port A */
289 #if DT_NODE_HAS_STATUS(DT_NODELABEL(porta), okay)
290 
291 static const struct gpio_sam0_config gpio_sam0_config_0 = {
292 	.common = {
293 		.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0),
294 	},
295 	.regs = (PortGroup *)DT_REG_ADDR(DT_NODELABEL(porta)),
296 #ifdef CONFIG_SAM0_EIC
297 	.id = 0,
298 #endif
299 };
300 
301 static struct gpio_sam0_data gpio_sam0_data_0;
302 
303 DEVICE_DT_DEFINE(DT_NODELABEL(porta),
304 		    gpio_sam0_init, NULL,
305 		    &gpio_sam0_data_0, &gpio_sam0_config_0,
306 		    PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,
307 		    &gpio_sam0_api);
308 #endif
309 
310 /* Port B */
311 #if DT_NODE_HAS_STATUS(DT_NODELABEL(portb), okay)
312 
313 static const struct gpio_sam0_config gpio_sam0_config_1 = {
314 	.common = {
315 		.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(1),
316 	},
317 	.regs = (PortGroup *)DT_REG_ADDR(DT_NODELABEL(portb)),
318 #ifdef CONFIG_SAM0_EIC
319 	.id = 1,
320 #endif
321 };
322 
323 static struct gpio_sam0_data gpio_sam0_data_1;
324 
325 DEVICE_DT_DEFINE(DT_NODELABEL(portb),
326 		    gpio_sam0_init, NULL,
327 		    &gpio_sam0_data_1, &gpio_sam0_config_1,
328 		    PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,
329 		    &gpio_sam0_api);
330 #endif
331 
332 /* Port C */
333 #if DT_NODE_HAS_STATUS(DT_NODELABEL(portc), okay)
334 
335 static const struct gpio_sam0_config gpio_sam0_config_2 = {
336 	.common = {
337 		.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(2),
338 	},
339 	.regs = (PortGroup *)DT_REG_ADDR(DT_NODELABEL(portc)),
340 #ifdef CONFIG_SAM0_EIC
341 	.id = 2,
342 #endif
343 };
344 
345 static struct gpio_sam0_data gpio_sam0_data_2;
346 
347 DEVICE_DT_DEFINE(DT_NODELABEL(portc),
348 		    gpio_sam0_init, NULL,
349 		    &gpio_sam0_data_2, &gpio_sam0_config_2,
350 		    PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,
351 		    &gpio_sam0_api);
352 #endif
353 
354 /* Port D */
355 #if DT_NODE_HAS_STATUS(DT_NODELABEL(portd), okay)
356 
357 static const struct gpio_sam0_config gpio_sam0_config_3 = {
358 	.common = {
359 		.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(3),
360 	},
361 	.regs = (PortGroup *)DT_REG_ADDR(DT_NODELABEL(portd)),
362 #ifdef CONFIG_SAM0_EIC
363 	.id = 3,
364 #endif
365 };
366 
367 static struct gpio_sam0_data gpio_sam0_data_3;
368 
369 DEVICE_DT_DEFINE(DT_NODELABEL(portd),
370 		    gpio_sam0_init, NULL,
371 		    &gpio_sam0_data_3, &gpio_sam0_config_3,
372 		    PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,
373 		    &gpio_sam0_api);
374 #endif
375