Lines 1-7
Link Here
|
1 |
/*- |
1 |
/*- |
|
|
2 |
* Copyright (c) 2015, Emmanuel Vadot <manu@bidouilliste.com> |
2 |
* Copyright (c) 2010-2011, Aleksandr Rybalko <ray@ddteam.net> |
3 |
* Copyright (c) 2010-2011, Aleksandr Rybalko <ray@ddteam.net> |
3 |
* Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> |
4 |
* Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> |
4 |
* Copyright (c) 2009, Luiz Otavio O Souza. |
5 |
* Copyright (c) 2009, Luiz Otavio O Souza. |
5 |
* All rights reserved. |
6 |
* All rights reserved. |
6 |
* |
7 |
* |
7 |
* Redistribution and use in source and binary forms, with or without |
8 |
* Redistribution and use in source and binary forms, with or without |
Lines 28-34
Link Here
|
28 |
*/ |
29 |
*/ |
29 |
|
30 |
|
30 |
/* |
31 |
/* |
31 |
* GPIO driver for RT305X SoC. |
32 |
* GPIO driver for RT305X/RT5350 SoC. |
32 |
*/ |
33 |
*/ |
33 |
|
34 |
|
34 |
#include <sys/cdefs.h> |
35 |
#include <sys/cdefs.h> |
Lines 66-72
__FBSDID("$FreeBSD$");
Link Here
|
66 |
/* |
67 |
/* |
67 |
* Helpers |
68 |
* Helpers |
68 |
*/ |
69 |
*/ |
69 |
static void rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, |
70 |
static void rt305x_gpio_pin_configure(device_t dev, struct rt305x_gpio_softc *sc, |
70 |
struct gpio_pin *pin, uint32_t flags); |
71 |
struct gpio_pin *pin, uint32_t flags); |
71 |
|
72 |
|
72 |
/* |
73 |
/* |
Lines 97-120
static int rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
Link Here
|
97 |
static int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin); |
98 |
static int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin); |
98 |
|
99 |
|
99 |
static void |
100 |
static void |
100 |
rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin, |
101 |
rt305x_gpio_pin_configure(device_t dev, struct rt305x_gpio_softc *sc, struct gpio_pin *pin, |
101 |
unsigned int flags) |
102 |
unsigned int flags) |
102 |
{ |
103 |
{ |
103 |
GPIO_LOCK(sc); |
104 |
GPIO_LOCK(sc); |
|
|
105 |
uint32_t reg; |
104 |
|
106 |
|
105 |
/* |
107 |
/* |
106 |
* Manage input/output |
108 |
* Manage input/output |
107 |
*/ |
109 |
*/ |
108 |
if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { |
110 |
if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { |
109 |
pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); |
111 |
pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); |
|
|
112 |
reg = bus_read_4(sc->gpio_mem_res, GPIO_REG(pin->gp_pin, DIR)); |
110 |
if (flags & GPIO_PIN_OUTPUT) { |
113 |
if (flags & GPIO_PIN_OUTPUT) { |
111 |
pin->gp_flags |= GPIO_PIN_OUTPUT; |
114 |
pin->gp_flags |= GPIO_PIN_OUTPUT; |
112 |
GPIO_BIT_SET(sc, pin->gp_pin, DIR); |
115 |
reg |= GPIO_MASK(pin->gp_pin); |
113 |
} |
116 |
} |
114 |
else { |
117 |
else { |
115 |
pin->gp_flags |= GPIO_PIN_INPUT; |
118 |
pin->gp_flags |= GPIO_PIN_INPUT; |
116 |
GPIO_BIT_CLR(sc, pin->gp_pin, DIR); |
119 |
reg &= ~GPIO_MASK(pin->gp_pin); |
117 |
} |
120 |
} |
|
|
121 |
bus_write_4(sc->gpio_mem_res, GPIO_REG(pin->gp_pin, DIR), reg); |
122 |
reg = bus_read_4(sc->gpio_mem_res, GPIO_REG(pin->gp_pin, DIR)); |
118 |
} |
123 |
} |
119 |
|
124 |
|
120 |
if (flags & GPIO_PIN_INVOUT) { |
125 |
if (flags & GPIO_PIN_INVOUT) { |
Lines 141-147
rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin,
Link Here
|
141 |
pin->gp_flags |= GPIO_PIN_REPORT; |
146 |
pin->gp_flags |= GPIO_PIN_REPORT; |
142 |
GPIO_BIT_SET(sc, pin->gp_pin, RENA); |
147 |
GPIO_BIT_SET(sc, pin->gp_pin, RENA); |
143 |
GPIO_BIT_SET(sc, pin->gp_pin, FENA); |
148 |
GPIO_BIT_SET(sc, pin->gp_pin, FENA); |
144 |
device_printf(sc->dev, "Will report interrupt on pin %d\n", |
149 |
device_printf(sc->dev, "Will report interrupt on pin %d\n", |
145 |
pin->gp_pin); |
150 |
pin->gp_pin); |
146 |
|
151 |
|
147 |
} |
152 |
} |
Lines 254-260
rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
Link Here
|
254 |
if (i >= sc->gpio_npins) |
259 |
if (i >= sc->gpio_npins) |
255 |
return (EINVAL); |
260 |
return (EINVAL); |
256 |
|
261 |
|
257 |
rt305x_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); |
262 |
rt305x_gpio_pin_configure(dev, sc, &sc->gpio_pins[i], flags); |
258 |
|
263 |
|
259 |
return (0); |
264 |
return (0); |
260 |
} |
265 |
} |
Lines 275-282
rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
Link Here
|
275 |
|
280 |
|
276 |
|
281 |
|
277 |
GPIO_LOCK(sc); |
282 |
GPIO_LOCK(sc); |
278 |
if (value) GPIO_BIT_SET(sc, i, DATA); |
283 |
if (value) |
279 |
else GPIO_BIT_CLR(sc, i, DATA); |
284 |
bus_write_4(sc->gpio_mem_res, GPIO_REG(pin, SET), GPIO_MASK(pin)); |
|
|
285 |
else |
286 |
bus_write_4(sc->gpio_mem_res, GPIO_REG(pin, RESET), GPIO_MASK(pin)); |
280 |
GPIO_UNLOCK(sc); |
287 |
GPIO_UNLOCK(sc); |
281 |
|
288 |
|
282 |
return (0); |
289 |
return (0); |
Lines 287-292
rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
Link Here
|
287 |
{ |
294 |
{ |
288 |
struct rt305x_gpio_softc *sc = device_get_softc(dev); |
295 |
struct rt305x_gpio_softc *sc = device_get_softc(dev); |
289 |
int i; |
296 |
int i; |
|
|
297 |
uint32_t data; |
290 |
|
298 |
|
291 |
for (i = 0; i < sc->gpio_npins; i++) { |
299 |
for (i = 0; i < sc->gpio_npins; i++) { |
292 |
if (sc->gpio_pins[i].gp_pin == pin) |
300 |
if (sc->gpio_pins[i].gp_pin == pin) |
Lines 297-303
rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
Link Here
|
297 |
return (EINVAL); |
305 |
return (EINVAL); |
298 |
|
306 |
|
299 |
GPIO_LOCK(sc); |
307 |
GPIO_LOCK(sc); |
300 |
*val = GPIO_BIT_GET(sc, i, DATA); |
308 |
data = bus_read_4(sc->gpio_mem_res, GPIO_REG(pin, DATA)); |
|
|
309 |
data >>= GPIO_BIT_SHIFT(pin); |
310 |
*val = data & 1; |
301 |
GPIO_UNLOCK(sc); |
311 |
GPIO_UNLOCK(sc); |
302 |
|
312 |
|
303 |
return (0); |
313 |
return (0); |
Lines 318-324
rt305x_gpio_pin_toggle(device_t dev, uint32_t pin)
Link Here
|
318 |
return (EINVAL); |
328 |
return (EINVAL); |
319 |
|
329 |
|
320 |
GPIO_LOCK(sc); |
330 |
GPIO_LOCK(sc); |
321 |
GPIO_BIT_SET(sc, i, TOG); |
331 |
bus_write_4(sc->gpio_mem_res, GPIO_REG(pin, TOG), GPIO_MASK(pin)); |
322 |
GPIO_UNLOCK(sc); |
332 |
GPIO_UNLOCK(sc); |
323 |
|
333 |
|
324 |
return (0); |
334 |
return (0); |
Lines 358-364
rt305x_gpio_intr(void *arg)
Link Here
|
358 |
* if now reset is high, check how long |
368 |
* if now reset is high, check how long |
359 |
* and do reset if less than 2 seconds |
369 |
* and do reset if less than 2 seconds |
360 |
*/ |
370 |
*/ |
361 |
if ( reset_pin && |
371 |
if ( reset_pin && |
362 |
(time_uptime - sc->reset_gpio_ontime) < 2 ) |
372 |
(time_uptime - sc->reset_gpio_ontime) < 2 ) |
363 |
shutdown_nice(0); |
373 |
shutdown_nice(0); |
364 |
|
374 |
|
Lines 375-388
rt305x_gpio_intr(void *arg)
Link Here
|
375 |
if ( (((value & input) >> i) & 1) != sc->gpio_pins[i].gp_last ) |
385 |
if ( (((value & input) >> i) & 1) != sc->gpio_pins[i].gp_last ) |
376 |
{ |
386 |
{ |
377 |
/* !system=GPIO subsystem=pin7 type=PIN_HIGH period=3 */ |
387 |
/* !system=GPIO subsystem=pin7 type=PIN_HIGH period=3 */ |
378 |
snprintf(notify , sizeof(notify ), "period=%d", |
388 |
snprintf(notify , sizeof(notify ), "period=%d", |
379 |
(uint32_t)time_uptime - sc->gpio_pins[i].gp_time); |
389 |
(uint32_t)time_uptime - sc->gpio_pins[i].gp_time); |
380 |
snprintf(pinname, sizeof(pinname), "pin%02d", i); |
390 |
snprintf(pinname, sizeof(pinname), "pin%02d", i); |
381 |
devctl_notify("GPIO", pinname, |
391 |
devctl_notify("GPIO", pinname, |
382 |
(((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", |
392 |
(((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", |
383 |
notify); |
393 |
notify); |
384 |
printf("GPIO[%s] %s %s\n", pinname, |
394 |
printf("GPIO[%s] %s %s\n", pinname, |
385 |
(((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", |
395 |
(((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", |
386 |
notify); |
396 |
notify); |
387 |
sc->gpio_pins[i].gp_last = ((value & input) >> i) & 1; |
397 |
sc->gpio_pins[i].gp_last = ((value & input) >> i) & 1; |
388 |
sc->gpio_pins[i].gp_time = time_uptime; |
398 |
sc->gpio_pins[i].gp_time = time_uptime; |
Lines 402-450
rt305x_gpio_probe(device_t dev)
Link Here
|
402 |
return (0); |
412 |
return (0); |
403 |
} |
413 |
} |
404 |
|
414 |
|
405 |
static uint64_t |
|
|
406 |
rt305x_gpio_init(device_t dev) |
407 |
{ |
408 |
uint64_t avl = ~0ULL; |
409 |
uint32_t gmode = rt305x_sysctl_get(SYSCTL_GPIOMODE); |
410 |
if (!(gmode & SYSCTL_GPIOMODE_RGMII_GPIO_MODE)) |
411 |
avl &= ~RGMII_GPIO_MODE_MASK; |
412 |
if (!(gmode & SYSCTL_GPIOMODE_SDRAM_GPIO_MODE)) |
413 |
avl &= ~SDRAM_GPIO_MODE_MASK; |
414 |
if (!(gmode & SYSCTL_GPIOMODE_MDIO_GPIO_MODE)) |
415 |
avl &= ~MDIO_GPIO_MODE_MASK; |
416 |
if (!(gmode & SYSCTL_GPIOMODE_JTAG_GPIO_MODE)) |
417 |
avl &= ~JTAG_GPIO_MODE_MASK; |
418 |
if (!(gmode & SYSCTL_GPIOMODE_UARTL_GPIO_MODE)) |
419 |
avl &= ~UARTL_GPIO_MODE_MASK; |
420 |
if (!(gmode & SYSCTL_GPIOMODE_SPI_GPIO_MODE)) |
421 |
avl &= ~SPI_GPIO_MODE_MASK; |
422 |
if (!(gmode & SYSCTL_GPIOMODE_I2C_GPIO_MODE)) |
423 |
avl &= ~I2C_GPIO_MODE_MASK; |
424 |
if ((gmode & SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) != |
425 |
SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) |
426 |
avl &= ~I2C_GPIO_MODE_MASK; |
427 |
/* D-Link DAP-1350 Board have |
428 |
* MDIO_GPIO_MODE |
429 |
* UARTF_GPIO_MODE |
430 |
* SPI_GPIO_MODE |
431 |
* I2C_GPIO_MODE |
432 |
* So we have |
433 |
* 00000001 10000000 01111111 11111110 |
434 |
*/ |
435 |
return (avl); |
436 |
|
437 |
} |
438 |
|
439 |
#define DAP1350_RESET_GPIO 10 |
440 |
|
441 |
static int |
415 |
static int |
442 |
rt305x_gpio_attach(device_t dev) |
416 |
rt305x_gpio_attach(device_t dev) |
443 |
{ |
417 |
{ |
444 |
struct rt305x_gpio_softc *sc = device_get_softc(dev); |
418 |
struct rt305x_gpio_softc *sc = device_get_softc(dev); |
445 |
int i; |
419 |
int i; |
446 |
uint64_t avlpins = 0; |
420 |
uint32_t reg, mask, pinon, pinin; |
447 |
sc->reset_gpio = DAP1350_RESET_GPIO; |
|
|
448 |
|
421 |
|
449 |
KASSERT((device_get_unit(dev) == 0), |
422 |
KASSERT((device_get_unit(dev) == 0), |
450 |
("rt305x_gpio_gpio: Only one gpio module supported")); |
423 |
("rt305x_gpio_gpio: Only one gpio module supported")); |
Lines 462-475
rt305x_gpio_attach(device_t dev)
Link Here
|
462 |
return (ENXIO); |
435 |
return (ENXIO); |
463 |
} |
436 |
} |
464 |
|
437 |
|
465 |
if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, |
438 |
if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, |
466 |
&sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { |
439 |
&sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { |
467 |
device_printf(dev, "unable to allocate IRQ resource\n"); |
440 |
device_printf(dev, "unable to allocate IRQ resource\n"); |
468 |
rt305x_gpio_detach(dev); |
441 |
rt305x_gpio_detach(dev); |
469 |
return (ENXIO); |
442 |
return (ENXIO); |
470 |
} |
443 |
} |
471 |
|
444 |
|
472 |
if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, |
445 |
if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, |
473 |
/* rt305x_gpio_filter, */ |
446 |
/* rt305x_gpio_filter, */ |
474 |
rt305x_gpio_intr, NULL, sc, &sc->gpio_ih))) { |
447 |
rt305x_gpio_intr, NULL, sc, &sc->gpio_ih))) { |
475 |
device_printf(dev, |
448 |
device_printf(dev, |
Lines 479-514
rt305x_gpio_attach(device_t dev)
Link Here
|
479 |
} |
452 |
} |
480 |
|
453 |
|
481 |
sc->dev = dev; |
454 |
sc->dev = dev; |
482 |
avlpins = rt305x_gpio_init(dev); |
455 |
rt305x_gpio_pin_max(dev, &sc->gpio_npins); |
483 |
|
456 |
|
484 |
/* Configure all pins as input */ |
457 |
/* Get the current function set */ |
485 |
/* disable interrupts for all pins */ |
458 |
reg = rt305x_sysctl_get(SYSCTL_GPIOMODE); |
486 |
/* TODO */ |
459 |
/* Enable function bits that are required */ |
487 |
|
460 |
if (resource_int_value(device_get_name(dev), device_get_unit(dev), |
488 |
sc->gpio_npins = NGPIO; |
461 |
"function_set", &mask) == 0) { |
489 |
resource_int_value(device_get_name(dev), device_get_unit(dev), |
462 |
device_printf(dev, "function_set: 0x%x\n", mask); |
490 |
"pins", &sc->gpio_npins); |
463 |
reg |= mask; |
491 |
|
464 |
} |
|
|
465 |
/* Disable function bits that are required */ |
466 |
if (resource_int_value(device_get_name(dev), device_get_unit(dev), |
467 |
"function_clear", &mask) == 0) { |
468 |
device_printf(dev, "function_clear: 0x%x\n", mask); |
469 |
reg &= ~mask; |
470 |
} |
471 |
rt305x_sysctl_set(SYSCTL_GPIOMODE, reg); |
472 |
|
473 |
if (resource_int_value(device_get_name(dev), device_get_unit(dev), |
474 |
"pinmask", &mask) != 0) |
475 |
mask = 0; |
476 |
if (resource_int_value(device_get_name(dev), device_get_unit(dev), |
477 |
"pinon", &pinon) != 0) |
478 |
pinon = 0; |
479 |
if (resource_int_value(device_get_name(dev), device_get_unit(dev), |
480 |
"pinin", &pinin) != 0) |
481 |
pinin = 0; |
482 |
device_printf(dev, "gpio pinmask=0x%x\n", mask); |
483 |
|
484 |
/* Configure all pins, keep the loader settings */ |
485 |
reg = bus_read_4(sc->gpio_mem_res, GPIO_REG(22, DIR)) << GPIO_BIT_SHIFT(22); |
486 |
reg |= bus_read_4(sc->gpio_mem_res, GPIO_REG(0, DIR)); |
492 |
for (i = 0; i < sc->gpio_npins; i++) { |
487 |
for (i = 0; i < sc->gpio_npins; i++) { |
|
|
488 |
if ((mask & (1 << i)) == 0) |
489 |
continue; |
490 |
snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, |
491 |
"pin %d", i); |
493 |
sc->gpio_pins[i].gp_pin = i; |
492 |
sc->gpio_pins[i].gp_pin = i; |
494 |
sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; |
493 |
sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; |
495 |
sc->gpio_pins[i].gp_flags = 0; |
494 |
sc->gpio_pins[i].gp_flags = (reg & (1 << i)) ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT; |
|
|
495 |
} |
496 |
|
497 |
/* Turn on the hinted pins or configure them as inputs. */ |
498 |
for (i = 0; i < sc->gpio_npins; i++) { |
499 |
if ((pinon & (1 << sc->gpio_pins[i].gp_pin)) != 0) { |
500 |
rt305x_gpio_pin_setflags(dev, sc->gpio_pins[i].gp_pin, GPIO_PIN_OUTPUT); |
501 |
rt305x_gpio_pin_set(dev, sc->gpio_pins[i].gp_pin, 1); |
502 |
} |
503 |
if ((pinin & (1 << sc->gpio_pins[i].gp_pin)) != 0) |
504 |
rt305x_gpio_pin_setflags(dev, sc->gpio_pins[i].gp_pin, GPIO_PIN_INPUT); |
496 |
} |
505 |
} |
497 |
|
506 |
|
498 |
/* Setup reset pin interrupt */ |
507 |
/* Setup reset pin interrupt */ |
|
|
508 |
sc->reset_gpio = -1; |
499 |
if (TUNABLE_INT_FETCH("reset_gpio", &sc->reset_gpio)) { |
509 |
if (TUNABLE_INT_FETCH("reset_gpio", &sc->reset_gpio)) { |
500 |
device_printf(dev, "\tHinted reset_gpio %d\n", sc->reset_gpio); |
510 |
device_printf(dev, "\tHinted reset_gpio %d\n", sc->reset_gpio); |
501 |
} |
511 |
} |
502 |
#ifdef notyet |
512 |
#ifdef notyet |
503 |
if (sc->reset_gpio != -1) { |
513 |
if (sc->reset_gpio != -1) { |
504 |
rt305x_gpio_pin_setflags(dev, sc->reset_gpio, |
514 |
rt305x_gpio_pin_setflags(dev, sc->reset_gpio, |
505 |
GPIO_PIN_INPUT|GPIO_PIN_INVOUT| |
515 |
GPIO_PIN_INPUT|GPIO_PIN_INVOUT| |
506 |
GPIO_PIN_INVOUT|GPIO_PIN_REPORT); |
516 |
GPIO_PIN_INVOUT|GPIO_PIN_REPORT); |
507 |
device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); |
517 |
device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); |
508 |
} |
518 |
} |
509 |
#else |
519 |
#else |
510 |
if (sc->reset_gpio != -1) { |
520 |
if (sc->reset_gpio != -1) { |
511 |
rt305x_gpio_pin_setflags(dev, sc->reset_gpio, |
521 |
rt305x_gpio_pin_setflags(dev, sc->reset_gpio, |
512 |
GPIO_PIN_INPUT|GPIO_PIN_INVOUT); |
522 |
GPIO_PIN_INPUT|GPIO_PIN_INVOUT); |
513 |
device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); |
523 |
device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); |
514 |
} |
524 |
} |
Lines 622-626
static driver_t rt305x_gpio_driver = {
Link Here
|
622 |
}; |
632 |
}; |
623 |
static devclass_t rt305x_gpio_devclass; |
633 |
static devclass_t rt305x_gpio_devclass; |
624 |
|
634 |
|
625 |
DRIVER_MODULE(rt305x_gpio, obio, rt305x_gpio_driver, |
635 |
DRIVER_MODULE(rt305x_gpio, obio, rt305x_gpio_driver, |
626 |
rt305x_gpio_devclass, 0, 0); |
636 |
rt305x_gpio_devclass, 0, 0); |