1 /*
2  * Copyright (c) 2018 Justin Watson
3  * Copyright (c) 2023 Gerson Fernando Budke
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT atmel_sam_gpio
9 
10 #include <errno.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 #include <soc.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/drivers/clock_control/atmel_sam_pmc.h>
17 #include <zephyr/dt-bindings/gpio/atmel-sam-gpio.h>
18 #include <zephyr/irq.h>
19 
20 #include <zephyr/drivers/gpio/gpio_utils.h>
21 
22 typedef void (*config_func_t)(const struct device *dev);
23 
24 struct gpio_sam_config {
25 	/* gpio_driver_config needs to be first */
26 	struct gpio_driver_config common;
27 	Pio *regs;
28 	config_func_t config_func;
29 
30 	const struct atmel_sam_pmc_config clock_cfg;
31 };
32 
33 struct gpio_sam_runtime {
34 	/* gpio_driver_data needs to be first */
35 	struct gpio_driver_data common;
36 	sys_slist_t cb;
37 };
38 
39 #define GPIO_SAM_ALL_PINS    0xFFFFFFFF
40 
gpio_sam_port_configure(const struct device * dev,uint32_t mask,gpio_flags_t flags)41 static int gpio_sam_port_configure(const struct device *dev, uint32_t mask,
42 				   gpio_flags_t flags)
43 {
44 	const struct gpio_sam_config * const cfg = dev->config;
45 	Pio * const pio = cfg->regs;
46 
47 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
48 		if ((flags & GPIO_LINE_OPEN_DRAIN) != 0) {
49 			/* Enable open-drain drive mode */
50 			pio->PIO_MDER = mask;
51 		} else {
52 			/* Open-drain is the only supported single-ended mode */
53 			return -ENOTSUP;
54 		}
55 	} else {
56 		/* Disable open-drain drive mode */
57 		pio->PIO_MDDR = mask;
58 	}
59 
60 	if (!(flags & (GPIO_OUTPUT | GPIO_INPUT))) {
61 		/* Neither input nor output mode is selected */
62 
63 		/* Disable the interrupt. */
64 		pio->PIO_IDR = mask;
65 		/* Disable pull-up. */
66 		pio->PIO_PUDR = mask;
67 #if defined(CONFIG_SOC_SERIES_SAM4S) || \
68 	defined(CONFIG_SOC_SERIES_SAM4E) || \
69 	defined(CONFIG_SOC_SERIES_SAME70) || \
70 	defined(CONFIG_SOC_SERIES_SAMV71)
71 		/* Disable pull-down. */
72 		pio->PIO_PPDDR = mask;
73 #endif
74 		/* Let the PIO control the pin (instead of a peripheral). */
75 		pio->PIO_PER = mask;
76 		/* Disable output. */
77 		pio->PIO_ODR = mask;
78 
79 		return 0;
80 	}
81 
82 	/* Setup the pin direction. */
83 	if (flags & GPIO_OUTPUT) {
84 		if (flags & GPIO_OUTPUT_INIT_HIGH) {
85 			/* Set the pin. */
86 			pio->PIO_SODR = mask;
87 		}
88 		if (flags & GPIO_OUTPUT_INIT_LOW) {
89 			/* Clear the pin. */
90 			pio->PIO_CODR = mask;
91 		}
92 		/* Enable the output */
93 		pio->PIO_OER = mask;
94 		/* Enable direct control of output level via PIO_ODSR */
95 		pio->PIO_OWER = mask;
96 	} else {
97 		/* Disable the output */
98 		pio->PIO_ODR = mask;
99 	}
100 
101 	/* Note: Input is always enabled. */
102 
103 	/* Setup selected Pull resistor.
104 	 *
105 	 * A pull cannot be enabled if the opposite pull is enabled.
106 	 * Clear both pulls, then enable the one we need.
107 	 */
108 	pio->PIO_PUDR = mask;
109 #if defined(CONFIG_SOC_SERIES_SAM4S) || \
110 	defined(CONFIG_SOC_SERIES_SAM4E) || \
111 	defined(CONFIG_SOC_SERIES_SAME70) || \
112 	defined(CONFIG_SOC_SERIES_SAMV71)
113 	pio->PIO_PPDDR = mask;
114 #endif
115 	if (flags & GPIO_PULL_UP) {
116 		/* Enable pull-up. */
117 		pio->PIO_PUER = mask;
118 #if defined(CONFIG_SOC_SERIES_SAM4S) || \
119 	defined(CONFIG_SOC_SERIES_SAM4E) || \
120 	defined(CONFIG_SOC_SERIES_SAME70) || \
121 	defined(CONFIG_SOC_SERIES_SAMV71)
122 
123 	/* Setup Pull-down resistor. */
124 	} else if (flags & GPIO_PULL_DOWN) {
125 		/* Enable pull-down. */
126 		pio->PIO_PPDER = mask;
127 #endif
128 	}
129 
130 #if defined(CONFIG_SOC_SERIES_SAM3X)
131 	/* Setup debounce. */
132 	if (flags & SAM_GPIO_DEBOUNCE) {
133 		pio->PIO_DIFSR = mask;
134 	} else {
135 		pio->PIO_SCIFSR = mask;
136 	}
137 #elif defined(CONFIG_SOC_SERIES_SAM4S) || \
138 	defined(CONFIG_SOC_SERIES_SAM4E) || \
139 	defined(CONFIG_SOC_SERIES_SAME70) || \
140 	defined(CONFIG_SOC_SERIES_SAMV71)
141 
142 	/* Setup debounce. */
143 	if (flags & SAM_GPIO_DEBOUNCE) {
144 		pio->PIO_IFSCER = mask;
145 	} else {
146 		pio->PIO_IFSCDR = mask;
147 	}
148 #endif
149 
150 	/* Enable the PIO to control the pin (instead of a peripheral). */
151 	pio->PIO_PER = mask;
152 
153 	return 0;
154 }
155 
gpio_sam_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)156 static int gpio_sam_config(const struct device *dev, gpio_pin_t pin,
157 			   gpio_flags_t flags)
158 {
159 	return gpio_sam_port_configure(dev, BIT(pin), flags);
160 }
161 
gpio_sam_port_get_raw(const struct device * dev,uint32_t * value)162 static int gpio_sam_port_get_raw(const struct device *dev, uint32_t *value)
163 {
164 	const struct gpio_sam_config * const cfg = dev->config;
165 	Pio * const pio = cfg->regs;
166 
167 	*value = pio->PIO_PDSR;
168 
169 	return 0;
170 }
171 
gpio_sam_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)172 static int gpio_sam_port_set_masked_raw(const struct device *dev,
173 					uint32_t mask,
174 					uint32_t value)
175 {
176 	const struct gpio_sam_config * const cfg = dev->config;
177 	Pio * const pio = cfg->regs;
178 
179 	pio->PIO_ODSR = (pio->PIO_ODSR & ~mask) | (mask & value);
180 
181 	return 0;
182 }
183 
gpio_sam_port_set_bits_raw(const struct device * dev,uint32_t mask)184 static int gpio_sam_port_set_bits_raw(const struct device *dev, uint32_t mask)
185 {
186 	const struct gpio_sam_config * const cfg = dev->config;
187 	Pio * const pio = cfg->regs;
188 
189 	/* Set pins. */
190 	pio->PIO_SODR = mask;
191 
192 	return 0;
193 }
194 
gpio_sam_port_clear_bits_raw(const struct device * dev,uint32_t mask)195 static int gpio_sam_port_clear_bits_raw(const struct device *dev,
196 					uint32_t mask)
197 {
198 	const struct gpio_sam_config * const cfg = dev->config;
199 	Pio * const pio = cfg->regs;
200 
201 	/* Clear pins. */
202 	pio->PIO_CODR = mask;
203 
204 	return 0;
205 }
206 
gpio_sam_port_toggle_bits(const struct device * dev,uint32_t mask)207 static int gpio_sam_port_toggle_bits(const struct device *dev, uint32_t mask)
208 {
209 	const struct gpio_sam_config * const cfg = dev->config;
210 	Pio * const pio = cfg->regs;
211 
212 	/* Toggle pins. */
213 	pio->PIO_ODSR ^= mask;
214 
215 	return 0;
216 }
217 
gpio_sam_port_interrupt_configure(const struct device * dev,uint32_t mask,enum gpio_int_mode mode,enum gpio_int_trig trig)218 static int gpio_sam_port_interrupt_configure(const struct device *dev,
219 					     uint32_t mask,
220 					     enum gpio_int_mode mode,
221 					     enum gpio_int_trig trig)
222 {
223 	const struct gpio_sam_config * const cfg = dev->config;
224 	Pio * const pio = cfg->regs;
225 
226 	/* Disable the interrupt. */
227 	pio->PIO_IDR = mask;
228 	/* Disable additional interrupt modes. */
229 	pio->PIO_AIMDR = mask;
230 
231 	if (trig != GPIO_INT_TRIG_BOTH) {
232 		/* Enable additional interrupt modes to support single
233 		 * edge/level detection.
234 		 */
235 		pio->PIO_AIMER = mask;
236 
237 		if (mode == GPIO_INT_MODE_EDGE) {
238 			pio->PIO_ESR = mask;
239 		} else {
240 			pio->PIO_LSR = mask;
241 		}
242 
243 		uint32_t rising_edge;
244 
245 		if (trig == GPIO_INT_TRIG_HIGH) {
246 			rising_edge = mask;
247 		} else {
248 			rising_edge = ~mask;
249 		}
250 
251 		/* Set to high-level or rising edge. */
252 		pio->PIO_REHLSR = rising_edge & mask;
253 		/* Set to low-level or falling edge. */
254 		pio->PIO_FELLSR = ~rising_edge & mask;
255 	}
256 
257 	if (mode != GPIO_INT_MODE_DISABLED) {
258 		/* Clear any pending interrupts */
259 		(void)pio->PIO_ISR;
260 		/* Enable the interrupt. */
261 		pio->PIO_IER = mask;
262 	}
263 
264 	return 0;
265 }
266 
gpio_sam_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)267 static int gpio_sam_pin_interrupt_configure(const struct device *dev,
268 					    gpio_pin_t pin,
269 					    enum gpio_int_mode mode,
270 					    enum gpio_int_trig trig)
271 {
272 	return gpio_sam_port_interrupt_configure(dev, BIT(pin), mode, trig);
273 }
274 
gpio_sam_isr(const struct device * dev)275 static void gpio_sam_isr(const struct device *dev)
276 {
277 	const struct gpio_sam_config * const cfg = dev->config;
278 	Pio * const pio = cfg->regs;
279 	struct gpio_sam_runtime *context = dev->data;
280 	uint32_t int_stat;
281 
282 	int_stat = pio->PIO_ISR;
283 
284 	gpio_fire_callbacks(&context->cb, dev, int_stat);
285 }
286 
gpio_sam_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)287 static int gpio_sam_manage_callback(const struct device *port,
288 				    struct gpio_callback *callback,
289 				    bool set)
290 {
291 	struct gpio_sam_runtime *context = port->data;
292 
293 	return gpio_manage_callback(&context->cb, callback, set);
294 }
295 
296 static const struct gpio_driver_api gpio_sam_api = {
297 	.pin_configure = gpio_sam_config,
298 	.port_get_raw = gpio_sam_port_get_raw,
299 	.port_set_masked_raw = gpio_sam_port_set_masked_raw,
300 	.port_set_bits_raw = gpio_sam_port_set_bits_raw,
301 	.port_clear_bits_raw = gpio_sam_port_clear_bits_raw,
302 	.port_toggle_bits = gpio_sam_port_toggle_bits,
303 	.pin_interrupt_configure = gpio_sam_pin_interrupt_configure,
304 	.manage_callback = gpio_sam_manage_callback,
305 };
306 
gpio_sam_init(const struct device * dev)307 int gpio_sam_init(const struct device *dev)
308 {
309 	const struct gpio_sam_config * const cfg = dev->config;
310 
311 	/* Enable GPIO clock in PMC. This is necessary to enable interrupts */
312 	(void)clock_control_on(SAM_DT_PMC_CONTROLLER,
313 			       (clock_control_subsys_t)&cfg->clock_cfg);
314 
315 	cfg->config_func(dev);
316 
317 	return 0;
318 }
319 
320 #define GPIO_SAM_INIT(n)						\
321 	static void port_##n##_sam_config_func(const struct device *dev);	\
322 									\
323 	static const struct gpio_sam_config port_##n##_sam_config = {	\
324 		.common = {						\
325 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
326 		},							\
327 		.regs = (Pio *)DT_INST_REG_ADDR(n),			\
328 		.clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n),		\
329 		.config_func = port_##n##_sam_config_func,		\
330 	};								\
331 									\
332 	static struct gpio_sam_runtime port_##n##_sam_runtime;		\
333 									\
334 	DEVICE_DT_INST_DEFINE(n, gpio_sam_init, NULL,			\
335 			    &port_##n##_sam_runtime,			\
336 			    &port_##n##_sam_config, PRE_KERNEL_1,	\
337 			    CONFIG_GPIO_INIT_PRIORITY,			\
338 			    &gpio_sam_api);				\
339 									\
340 	static void port_##n##_sam_config_func(const struct device *dev)	\
341 	{								\
342 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),	\
343 			    gpio_sam_isr,				\
344 			    DEVICE_DT_INST_GET(n), 0);			\
345 		irq_enable(DT_INST_IRQN(n));				\
346 	}
347 
348 DT_INST_FOREACH_STATUS_OKAY(GPIO_SAM_INIT)
349