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