1 /*
2  * Copyright (c) 2018 Justin Watson
3  * Copyright (c) 2020-2023 Gerson Fernando Budke <nandojve@gmail.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #define DT_DRV_COMPAT atmel_sam4l_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/irq.h>
18 
19 #include <zephyr/drivers/gpio/gpio_utils.h>
20 
21 typedef void (*config_func_t)(const struct device *dev);
22 
23 struct gpio_sam_config {
24 	/* gpio_driver_config needs to be first */
25 	struct gpio_driver_config common;
26 	Gpio *regs;
27 	config_func_t config_func;
28 
29 	const struct atmel_sam_pmc_config clock_cfg;
30 };
31 
32 struct gpio_sam_runtime {
33 	/* gpio_driver_data needs to be first */
34 	struct gpio_driver_data common;
35 	sys_slist_t cb;
36 };
37 
38 #define GPIO_SAM_ALL_PINS    0xFFFFFFFF
39 
gpio_sam_port_configure(const struct device * dev,uint32_t mask,gpio_flags_t flags)40 static int gpio_sam_port_configure(const struct device *dev,
41 				   uint32_t mask,
42 				   gpio_flags_t flags)
43 {
44 	const struct gpio_sam_config * const cfg = dev->config;
45 	Gpio * const gpio = cfg->regs;
46 
47 	/* No hardware support */
48 	if (flags & GPIO_SINGLE_ENDED) {
49 		return -ENOTSUP;
50 	}
51 
52 	if (!(flags & (GPIO_OUTPUT | GPIO_INPUT))) {
53 		gpio->IERC = mask;
54 		gpio->PUERC = mask;
55 		gpio->PDERC = mask;
56 		gpio->GPERS = mask;
57 		gpio->ODERC = mask;
58 		gpio->STERC = mask;
59 
60 		return 0;
61 	}
62 
63 	/*
64 	 * Always enable schmitt-trigger because SAM4L GPIO Ctrl
65 	 * is Input only or Input/Output.
66 	 */
67 	gpio->STERS = mask;
68 
69 	if (flags & GPIO_OUTPUT) {
70 		if (flags & GPIO_OUTPUT_INIT_HIGH) {
71 			gpio->OVRS = mask;
72 		}
73 		if (flags & GPIO_OUTPUT_INIT_LOW) {
74 			gpio->OVRC = mask;
75 		}
76 		gpio->ODERS = mask;
77 	} else {
78 		gpio->ODERC = mask;
79 	}
80 
81 	gpio->PUERC = mask;
82 	gpio->PDERC = mask;
83 	if (flags & GPIO_PULL_UP) {
84 		gpio->PUERS = mask;
85 	} else if (flags & GPIO_PULL_DOWN) {
86 		gpio->PDERS = mask;
87 	}
88 
89 	/* Enable the GPIO to control the pin (instead of a peripheral). */
90 	gpio->GPERS = mask;
91 
92 	return 0;
93 }
94 
gpio_sam_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)95 static int gpio_sam_config(const struct device *dev,
96 			   gpio_pin_t pin,
97 			   gpio_flags_t flags)
98 {
99 	return gpio_sam_port_configure(dev, BIT(pin), flags);
100 }
101 
gpio_sam_port_get_raw(const struct device * dev,uint32_t * value)102 static int gpio_sam_port_get_raw(const struct device *dev,
103 				 uint32_t *value)
104 {
105 	const struct gpio_sam_config * const cfg = dev->config;
106 	Gpio * const gpio = cfg->regs;
107 
108 	*value = gpio->PVR;
109 
110 	return 0;
111 }
112 
gpio_sam_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)113 static int gpio_sam_port_set_masked_raw(const struct device *dev,
114 					uint32_t mask,
115 					uint32_t value)
116 {
117 	const struct gpio_sam_config * const cfg = dev->config;
118 	Gpio * const gpio = cfg->regs;
119 
120 	gpio->OVR = (gpio->PVR & ~mask) | (mask & value);
121 
122 	return 0;
123 }
124 
gpio_sam_port_set_bits_raw(const struct device * dev,uint32_t mask)125 static int gpio_sam_port_set_bits_raw(const struct device *dev,
126 				      uint32_t mask)
127 {
128 	const struct gpio_sam_config * const cfg = dev->config;
129 	Gpio * const gpio = cfg->regs;
130 
131 	gpio->OVRS = mask;
132 
133 	return 0;
134 }
135 
gpio_sam_port_clear_bits_raw(const struct device * dev,uint32_t mask)136 static int gpio_sam_port_clear_bits_raw(const struct device *dev,
137 					uint32_t mask)
138 {
139 	const struct gpio_sam_config * const cfg = dev->config;
140 	Gpio * const gpio = cfg->regs;
141 
142 	gpio->OVRC = mask;
143 
144 	return 0;
145 }
146 
gpio_sam_port_toggle_bits(const struct device * dev,uint32_t mask)147 static int gpio_sam_port_toggle_bits(const struct device *dev,
148 				     uint32_t mask)
149 {
150 	const struct gpio_sam_config * const cfg = dev->config;
151 	Gpio * const gpio = cfg->regs;
152 
153 	gpio->OVRT = mask;
154 
155 	return 0;
156 }
157 
gpio_sam_port_interrupt_configure(const struct device * dev,uint32_t mask,enum gpio_int_mode mode,enum gpio_int_trig trig)158 static int gpio_sam_port_interrupt_configure(const struct device *dev,
159 					     uint32_t mask,
160 					     enum gpio_int_mode mode,
161 					     enum gpio_int_trig trig)
162 {
163 	const struct gpio_sam_config * const cfg = dev->config;
164 	Gpio * const gpio = cfg->regs;
165 
166 	if (mode == GPIO_INT_MODE_LEVEL) {
167 		return -ENOTSUP;
168 	}
169 
170 	gpio->IERC = mask;
171 	gpio->IMR0C = mask;
172 	gpio->IMR1C = mask;
173 
174 	if (trig != GPIO_INT_TRIG_BOTH) {
175 		if (trig == GPIO_INT_TRIG_HIGH) {
176 			gpio->IMR0S = mask;
177 		} else {
178 			gpio->IMR1S = mask;
179 		}
180 	}
181 
182 	if (mode != GPIO_INT_MODE_DISABLED) {
183 		gpio->IFRC = mask;
184 		gpio->IERS = mask;
185 	}
186 
187 	return 0;
188 }
189 
gpio_sam_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)190 static int gpio_sam_pin_interrupt_configure(const struct device *dev,
191 					    gpio_pin_t pin,
192 					    enum gpio_int_mode mode,
193 					    enum gpio_int_trig trig)
194 {
195 	return gpio_sam_port_interrupt_configure(dev, BIT(pin), mode, trig);
196 }
197 
gpio_sam_isr(const struct device * dev)198 static void gpio_sam_isr(const struct device *dev)
199 {
200 	const struct gpio_sam_config * const cfg = dev->config;
201 	Gpio * const gpio = cfg->regs;
202 	struct gpio_sam_runtime *context = dev->data;
203 	uint32_t int_stat;
204 
205 	int_stat = gpio->IFR;
206 	gpio->IFRC = int_stat;
207 
208 	gpio_fire_callbacks(&context->cb, dev, int_stat);
209 }
210 
gpio_sam_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)211 static int gpio_sam_manage_callback(const struct device *port,
212 				    struct gpio_callback *callback,
213 				    bool set)
214 {
215 	struct gpio_sam_runtime *context = port->data;
216 
217 	return gpio_manage_callback(&context->cb, callback, set);
218 }
219 
220 static const struct gpio_driver_api gpio_sam_api = {
221 	.pin_configure = gpio_sam_config,
222 	.port_get_raw = gpio_sam_port_get_raw,
223 	.port_set_masked_raw = gpio_sam_port_set_masked_raw,
224 	.port_set_bits_raw = gpio_sam_port_set_bits_raw,
225 	.port_clear_bits_raw = gpio_sam_port_clear_bits_raw,
226 	.port_toggle_bits = gpio_sam_port_toggle_bits,
227 	.pin_interrupt_configure = gpio_sam_pin_interrupt_configure,
228 	.manage_callback = gpio_sam_manage_callback,
229 };
230 
gpio_sam_init(const struct device * dev)231 int gpio_sam_init(const struct device *dev)
232 {
233 	const struct gpio_sam_config * const cfg = dev->config;
234 
235 	/* Enable GPIO clock in PM */
236 	(void)clock_control_on(SAM_DT_PMC_CONTROLLER,
237 			       (clock_control_subsys_t)&cfg->clock_cfg);
238 
239 	cfg->config_func(dev);
240 
241 	return 0;
242 }
243 
244 #define GPIO_SAM_IRQ_CONNECT(n, m)					\
245 	do {								\
246 		IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, m, irq),		\
247 			    DT_INST_IRQ_BY_IDX(n, m, priority),		\
248 			    gpio_sam_isr,				\
249 			    DEVICE_DT_INST_GET(n), 0);			\
250 		irq_enable(DT_INST_IRQ_BY_IDX(n, m, irq));		\
251 	} while (false)
252 
253 #define GPIO_SAM_INIT(n)						\
254 	static void port_##n##_sam_config_func(const struct device *dev);\
255 									\
256 	static const struct gpio_sam_config port_##n##_sam_config = {	\
257 		.common = {						\
258 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
259 		},							\
260 		.regs = (Gpio *)DT_INST_REG_ADDR(n),			\
261 		.clock_cfg = SAM_DT_INST_CLOCK_PMC_CFG(n),		\
262 		.config_func = port_##n##_sam_config_func,		\
263 	};								\
264 									\
265 	static struct gpio_sam_runtime port_##n##_sam_runtime;		\
266 									\
267 	DEVICE_DT_INST_DEFINE(n, gpio_sam_init, NULL,			\
268 			    &port_##n##_sam_runtime,			\
269 			    &port_##n##_sam_config, PRE_KERNEL_1,	\
270 			    CONFIG_GPIO_INIT_PRIORITY,			\
271 			    &gpio_sam_api);				\
272 									\
273 	static void port_##n##_sam_config_func(const struct device *dev)\
274 	{								\
275 		GPIO_SAM_IRQ_CONNECT(n, 0);				\
276 		GPIO_SAM_IRQ_CONNECT(n, 1);				\
277 		GPIO_SAM_IRQ_CONNECT(n, 2);				\
278 		GPIO_SAM_IRQ_CONNECT(n, 3);				\
279 	}
280 
281 DT_INST_FOREACH_STATUS_OKAY(GPIO_SAM_INIT)
282