1 /*
2 * Copyright (c) 2015 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT snps_designware_gpio
8
9 #include <errno.h>
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/dt-bindings/gpio/snps-designware-gpio.h>
14 #include "gpio_dw.h"
15 #include <zephyr/drivers/gpio/gpio_utils.h>
16
17 #include <zephyr/pm/device.h>
18 #include <zephyr/sys/sys_io.h>
19 #include <zephyr/init.h>
20 #include <zephyr/sys/util.h>
21 #include <zephyr/sys/__assert.h>
22 #include <zephyr/drivers/clock_control.h>
23 #include <zephyr/irq.h>
24
25 #ifdef CONFIG_IOAPIC
26 #include <zephyr/drivers/interrupt_controller/ioapic.h>
27 #endif
28
29 static int gpio_dw_port_set_bits_raw(const struct device *port, uint32_t mask);
30 static int gpio_dw_port_clear_bits_raw(const struct device *port,
31 uint32_t mask);
32
33 /*
34 * ARC architecture configure IP through IO auxiliary registers.
35 * Other architectures as ARM and x86 configure IP through MMIO registers
36 */
37 #ifdef GPIO_DW_IO_ACCESS
dw_read(uint32_t base_addr,uint32_t offset)38 static inline uint32_t dw_read(uint32_t base_addr, uint32_t offset)
39 {
40 return sys_in32(base_addr + offset);
41 }
42
dw_write(uint32_t base_addr,uint32_t offset,uint32_t val)43 static inline void dw_write(uint32_t base_addr, uint32_t offset,
44 uint32_t val)
45 {
46 sys_out32(val, base_addr + offset);
47 }
48
dw_set_bit(uint32_t base_addr,uint32_t offset,uint32_t bit,bool value)49 static void dw_set_bit(uint32_t base_addr, uint32_t offset,
50 uint32_t bit, bool value)
51 {
52 if (!value) {
53 sys_io_clear_bit(base_addr + offset, bit);
54 } else {
55 sys_io_set_bit(base_addr + offset, bit);
56 }
57 }
58 #else
dw_read(uint32_t base_addr,uint32_t offset)59 static inline uint32_t dw_read(uint32_t base_addr, uint32_t offset)
60 {
61 return sys_read32(base_addr + offset);
62 }
63
dw_write(uint32_t base_addr,uint32_t offset,uint32_t val)64 static inline void dw_write(uint32_t base_addr, uint32_t offset,
65 uint32_t val)
66 {
67 sys_write32(val, base_addr + offset);
68 }
69
dw_set_bit(uint32_t base_addr,uint32_t offset,uint32_t bit,bool value)70 static void dw_set_bit(uint32_t base_addr, uint32_t offset,
71 uint32_t bit, bool value)
72 {
73 if (!value) {
74 sys_clear_bit(base_addr + offset, bit);
75 } else {
76 sys_set_bit(base_addr + offset, bit);
77 }
78 }
79 #endif
80
dw_base_to_block_base(uint32_t base_addr)81 static inline int dw_base_to_block_base(uint32_t base_addr)
82 {
83 return (base_addr & 0xFFFFFFC0);
84 }
85
dw_derive_port_from_base(uint32_t base_addr)86 static inline int dw_derive_port_from_base(uint32_t base_addr)
87 {
88 uint32_t port = (base_addr & 0x3f) / 12U;
89 return port;
90 }
91
dw_interrupt_support(const struct gpio_dw_config * config)92 static inline int dw_interrupt_support(const struct gpio_dw_config *config)
93 {
94 return ((int)(config->irq_num) > 0U);
95 }
96
dw_get_ext_port(uint32_t base_addr)97 static inline uint32_t dw_get_ext_port(uint32_t base_addr)
98 {
99 uint32_t ext_port;
100
101 /* 4-port GPIO implementation translates from base address to port */
102 switch (dw_derive_port_from_base(base_addr)) {
103 case 1:
104 ext_port = EXT_PORTB;
105 break;
106 case 2:
107 ext_port = EXT_PORTC;
108 break;
109 case 3:
110 ext_port = EXT_PORTD;
111 break;
112 case 0:
113 default:
114 ext_port = EXT_PORTA;
115 break;
116 }
117
118 return ext_port;
119 }
120
dw_get_data_port(uint32_t base_addr)121 static inline uint32_t dw_get_data_port(uint32_t base_addr)
122 {
123 uint32_t dr_port;
124
125 /* 4-port GPIO implementation translates from base address to port */
126 switch (dw_derive_port_from_base(base_addr)) {
127 case 1:
128 dr_port = SWPORTB_DR;
129 break;
130 case 2:
131 dr_port = SWPORTC_DR;
132 break;
133 case 3:
134 dr_port = SWPORTD_DR;
135 break;
136 case 0:
137 default:
138 dr_port = SWPORTA_DR;
139 break;
140 }
141
142 return dr_port;
143 }
144
dw_get_dir_port(uint32_t base_addr)145 static inline uint32_t dw_get_dir_port(uint32_t base_addr)
146 {
147 uint32_t ddr_port;
148
149 /* 4-port GPIO implementation translates from base address to port */
150 switch (dw_derive_port_from_base(base_addr)) {
151 case 1:
152 ddr_port = SWPORTB_DDR;
153 break;
154 case 2:
155 ddr_port = SWPORTC_DDR;
156 break;
157 case 3:
158 ddr_port = SWPORTD_DDR;
159 break;
160 case 0:
161 default:
162 ddr_port = SWPORTA_DDR;
163 break;
164 }
165
166 return ddr_port;
167 }
168
gpio_dw_pin_interrupt_configure(const struct device * port,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)169 static int gpio_dw_pin_interrupt_configure(const struct device *port,
170 gpio_pin_t pin,
171 enum gpio_int_mode mode,
172 enum gpio_int_trig trig)
173 {
174 struct gpio_dw_runtime *context = port->data;
175 const struct gpio_dw_config *config = port->config;
176 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
177 uint32_t port_base_addr = context->base_addr;
178 uint32_t dir_port = dw_get_dir_port(port_base_addr);
179 uint32_t data_port = dw_get_data_port(port_base_addr);
180 uint32_t dir_reg;
181
182 /* Check for invalid pin number */
183 if (pin >= config->ngpios) {
184 return -EINVAL;
185 }
186
187 /* Only PORT-A supports interrupts */
188 if (data_port != SWPORTA_DR) {
189 return -ENOTSUP;
190 }
191
192 if (mode != GPIO_INT_MODE_DISABLED) {
193 /* Check if GPIO port supports interrupts */
194 if (!dw_interrupt_support(config)) {
195 return -ENOTSUP;
196 }
197
198 /* Interrupt to be enabled but pin is not set to input */
199 dir_reg = dw_read(base_addr, dir_port) & BIT(pin);
200 if (dir_reg != 0U) {
201 return -EINVAL;
202 }
203 }
204
205 /* Does not support both edges */
206 if ((mode == GPIO_INT_MODE_EDGE) &&
207 (trig == GPIO_INT_TRIG_BOTH)) {
208 return -ENOTSUP;
209 }
210
211 /* Clear interrupt enable */
212 dw_set_bit(base_addr, INTEN, pin, false);
213
214 /* Mask and clear interrupt */
215 dw_set_bit(base_addr, INTMASK, pin, true);
216 dw_write(base_addr, PORTA_EOI, BIT(pin));
217
218 if (mode != GPIO_INT_MODE_DISABLED) {
219 /* level (0) or edge (1) */
220 dw_set_bit(base_addr, INTTYPE_LEVEL, pin,
221 (mode == GPIO_INT_MODE_EDGE));
222
223 /* Active low/high */
224 dw_set_bit(base_addr, INT_POLARITY, pin,
225 (trig == GPIO_INT_TRIG_HIGH));
226
227 /* Finally enabling interrupt */
228 dw_set_bit(base_addr, INTEN, pin, true);
229 dw_set_bit(base_addr, INTMASK, pin, false);
230 }
231
232 return 0;
233 }
234
dw_pin_config(const struct device * port,uint32_t pin,int flags)235 static inline void dw_pin_config(const struct device *port,
236 uint32_t pin, int flags)
237 {
238 struct gpio_dw_runtime *context = port->data;
239 const struct gpio_dw_config *config = port->config;
240 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
241 uint32_t port_base_addr = context->base_addr;
242 uint32_t dir_port = dw_get_dir_port(port_base_addr);
243 bool pin_is_output, need_debounce;
244
245 /* Set init value then direction */
246 pin_is_output = (flags & GPIO_OUTPUT) != 0U;
247
248 dw_set_bit(base_addr, dir_port, pin, pin_is_output);
249
250 if (pin_is_output) {
251 if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
252 gpio_dw_port_set_bits_raw(port, BIT(pin));
253 } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
254 gpio_dw_port_clear_bits_raw(port, BIT(pin));
255 }
256 }
257
258 /* Use built-in debounce.
259 * Note debounce circuit is only available if also supporting
260 * interrupts according to datasheet.
261 */
262 if (dw_interrupt_support(config) && (dir_port == SWPORTA_DDR)) {
263 need_debounce = (flags & DW_GPIO_DEBOUNCE);
264 dw_set_bit(base_addr, PORTA_DEBOUNCE, pin, need_debounce);
265 }
266 }
267
gpio_dw_config(const struct device * port,gpio_pin_t pin,gpio_flags_t flags)268 static inline int gpio_dw_config(const struct device *port,
269 gpio_pin_t pin,
270 gpio_flags_t flags)
271 {
272 const struct gpio_dw_config *config = port->config;
273 uint32_t io_flags;
274
275 /* Check for invalid pin number */
276 if (pin >= config->ngpios) {
277 return -EINVAL;
278 }
279
280 /* Does not support disconnected pin, and
281 * not supporting both input/output at same time.
282 */
283 io_flags = flags & (GPIO_INPUT | GPIO_OUTPUT);
284 if ((io_flags == GPIO_DISCONNECTED)
285 || (io_flags == (GPIO_INPUT | GPIO_OUTPUT))) {
286 return -ENOTSUP;
287 }
288
289 /* No open-drain support */
290 if ((flags & GPIO_SINGLE_ENDED) != 0U) {
291 return -ENOTSUP;
292 }
293
294 /* Does not support pull-up/pull-down */
295 if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0U) {
296 return -ENOTSUP;
297 }
298
299 dw_pin_config(port, pin, flags);
300
301 return 0;
302 }
303
gpio_dw_port_get_raw(const struct device * port,uint32_t * value)304 static int gpio_dw_port_get_raw(const struct device *port, uint32_t *value)
305 {
306 struct gpio_dw_runtime *context = port->data;
307 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
308 uint32_t port_base_addr = context->base_addr;
309 uint32_t ext_port = dw_get_ext_port(port_base_addr);
310
311 *value = dw_read(base_addr, ext_port);
312
313 return 0;
314 }
315
gpio_dw_port_set_masked_raw(const struct device * port,uint32_t mask,uint32_t value)316 static int gpio_dw_port_set_masked_raw(const struct device *port,
317 uint32_t mask, uint32_t value)
318 {
319 struct gpio_dw_runtime *context = port->data;
320 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
321 uint32_t port_base_addr = context->base_addr;
322 uint32_t data_port = dw_get_data_port(port_base_addr);
323 uint32_t pins;
324
325 pins = dw_read(base_addr, data_port);
326 pins = (pins & ~mask) | (mask & value);
327 dw_write(base_addr, data_port, pins);
328
329 return 0;
330 }
331
gpio_dw_port_set_bits_raw(const struct device * port,uint32_t mask)332 static int gpio_dw_port_set_bits_raw(const struct device *port, uint32_t mask)
333 {
334 struct gpio_dw_runtime *context = port->data;
335 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
336 uint32_t port_base_addr = context->base_addr;
337 uint32_t data_port = dw_get_data_port(port_base_addr);
338 uint32_t pins;
339
340 pins = dw_read(base_addr, data_port);
341 pins |= mask;
342 dw_write(base_addr, data_port, pins);
343
344 return 0;
345 }
346
gpio_dw_port_clear_bits_raw(const struct device * port,uint32_t mask)347 static int gpio_dw_port_clear_bits_raw(const struct device *port,
348 uint32_t mask)
349 {
350 struct gpio_dw_runtime *context = port->data;
351 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
352 uint32_t port_base_addr = context->base_addr;
353 uint32_t data_port = dw_get_data_port(port_base_addr);
354 uint32_t pins;
355
356 pins = dw_read(base_addr, data_port);
357 pins &= ~mask;
358 dw_write(base_addr, data_port, pins);
359
360 return 0;
361 }
362
gpio_dw_port_toggle_bits(const struct device * port,uint32_t mask)363 static int gpio_dw_port_toggle_bits(const struct device *port, uint32_t mask)
364 {
365 struct gpio_dw_runtime *context = port->data;
366 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
367 uint32_t port_base_addr = context->base_addr;
368 uint32_t data_port = dw_get_data_port(port_base_addr);
369 uint32_t pins;
370
371 pins = dw_read(base_addr, data_port);
372 pins ^= mask;
373 dw_write(base_addr, data_port, pins);
374
375 return 0;
376 }
377
gpio_dw_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)378 static inline int gpio_dw_manage_callback(const struct device *port,
379 struct gpio_callback *callback,
380 bool set)
381 {
382 struct gpio_dw_runtime *context = port->data;
383
384 return gpio_manage_callback(&context->callbacks, callback, set);
385 }
386
387 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts)
gpio_dw_isr(const struct device * port)388 static void gpio_dw_isr(const struct device *port)
389 {
390 struct gpio_dw_runtime *context = port->data;
391 uint32_t base_addr = dw_base_to_block_base(context->base_addr);
392 uint32_t int_status;
393
394 int_status = dw_read(base_addr, INTSTATUS);
395
396 dw_write(base_addr, PORTA_EOI, int_status);
397
398 gpio_fire_callbacks(&context->callbacks, port, int_status);
399 }
400 #endif /* DT_ANY_INST_HAS_PROP_STATUS_OKAY(interrupts) */
401
402 static const struct gpio_driver_api api_funcs = {
403 .pin_configure = gpio_dw_config,
404 .port_get_raw = gpio_dw_port_get_raw,
405 .port_set_masked_raw = gpio_dw_port_set_masked_raw,
406 .port_set_bits_raw = gpio_dw_port_set_bits_raw,
407 .port_clear_bits_raw = gpio_dw_port_clear_bits_raw,
408 .port_toggle_bits = gpio_dw_port_toggle_bits,
409 .pin_interrupt_configure = gpio_dw_pin_interrupt_configure,
410 .manage_callback = gpio_dw_manage_callback,
411 };
412
gpio_dw_initialize(const struct device * port)413 static int gpio_dw_initialize(const struct device *port)
414 {
415 struct gpio_dw_runtime *context = port->data;
416 const struct gpio_dw_config *config = port->config;
417 uint32_t base_addr;
418
419 if (dw_interrupt_support(config)) {
420
421 base_addr = dw_base_to_block_base(context->base_addr);
422
423 /* interrupts in sync with system clock */
424 dw_set_bit(base_addr, INT_CLOCK_SYNC, LS_SYNC_POS, 1);
425
426 /* mask and disable interrupts */
427 dw_write(base_addr, INTMASK, ~(0));
428 dw_write(base_addr, INTEN, 0);
429 dw_write(base_addr, PORTA_EOI, ~(0));
430
431 config->config_func(port);
432 }
433
434 return 0;
435 }
436
437 /* Bindings to the platform */
438 #define INST_IRQ_FLAGS(n) \
439 COND_CODE_1(DT_INST_IRQ_HAS_CELL(n, flags), (DT_INST_IRQ(n, flags)), (0))
440
441 #define GPIO_CFG_IRQ(idx, n) \
442 IRQ_CONNECT(DT_INST_IRQN_BY_IDX(n, idx), \
443 DT_INST_IRQ(n, priority), gpio_dw_isr, \
444 DEVICE_DT_INST_GET(n), INST_IRQ_FLAGS(n)); \
445 irq_enable(DT_INST_IRQN_BY_IDX(n, idx)); \
446
447 #define GPIO_DW_INIT(n) \
448 static void gpio_config_##n##_irq(const struct device *port) \
449 { \
450 ARG_UNUSED(port); \
451 LISTIFY(DT_NUM_IRQS(DT_DRV_INST(n)), GPIO_CFG_IRQ, (), n) \
452 } \
453 \
454 static const struct gpio_dw_config gpio_dw_config_##n = { \
455 .common = { \
456 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
457 }, \
458 .irq_num = COND_CODE_1(DT_INST_IRQ_HAS_IDX(n, 0), (DT_INST_IRQN(n)), (0)), \
459 .ngpios = DT_INST_PROP(n, ngpios), \
460 .config_func = gpio_config_##n##_irq, \
461 }; \
462 \
463 static struct gpio_dw_runtime gpio_##n##_runtime = { \
464 .base_addr = DT_INST_REG_ADDR(n), \
465 }; \
466 \
467 DEVICE_DT_INST_DEFINE(n, gpio_dw_initialize, NULL, &gpio_##n##_runtime, \
468 &gpio_dw_config_##n, PRE_KERNEL_1, \
469 CONFIG_GPIO_INIT_PRIORITY, &api_funcs); \
470
471 DT_INST_FOREACH_STATUS_OKAY(GPIO_DW_INIT)
472