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