diff options
Diffstat (limited to 'sys/arch/armv7/sunxi/sxipio.c')
-rw-r--r-- | sys/arch/armv7/sunxi/sxipio.c | 127 |
1 files changed, 124 insertions, 3 deletions
diff --git a/sys/arch/armv7/sunxi/sxipio.c b/sys/arch/armv7/sunxi/sxipio.c index 9a493435a92..41663f5f0f5 100644 --- a/sys/arch/armv7/sunxi/sxipio.c +++ b/sys/arch/armv7/sunxi/sxipio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sxipio.c,v 1.7 2015/05/20 03:49:23 jsg Exp $ */ +/* $OpenBSD: sxipio.c,v 1.8 2016/08/12 16:02:31 kettenis Exp $ */ /* * Copyright (c) 2010 Miodrag Vallat. * Copyright (c) 2013 Artturi Alm @@ -21,11 +21,14 @@ #include <sys/device.h> #include <sys/gpio.h> #include <sys/evcount.h> +#include <sys/malloc.h> #include <machine/bus.h> #include <machine/intr.h> #include <dev/gpio/gpiovar.h> +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_pinctrl.h> #include <armv7/armv7/armv7var.h> #include <armv7/sunxi/sunxireg.h> @@ -48,7 +51,6 @@ SXIPIO_PH_NPIN + SXIPIO_PI_NPIN) #define SXIPIO_PS_NPIN 84 /* for DRAM controller */ - struct intrhand { int (*ih_func)(void *); /* handler */ void *ih_arg; /* arg for handler */ @@ -69,6 +71,9 @@ struct sxipio_softc { int sc_min_il; int sc_irq; + struct sxipio_pin *sc_pins; + int sc_npins; + struct gpio_chipset_tag sc_gpio_tag[SXIPIO_NPORT]; gpio_pin_t sc_gpio_pins[SXIPIO_NPORT][32]; @@ -87,6 +92,7 @@ struct sxipio_softc { void sxipio_attach(struct device *, struct device *, void *); void sxipio_attach_gpio(struct device *); +int sxipio_pinctrl(uint32_t, void *); struct cfattach sxipio_ca = { sizeof (struct sxipio_softc), NULL, sxipio_attach @@ -100,11 +106,39 @@ struct sxipio_softc *sxipio_sc = NULL; bus_space_tag_t sxipio_iot; bus_space_handle_t sxipio_ioh; +#include "sxipio_pins.h" + +struct sxipio_pins { + const char *compat; + struct sxipio_pin *pins; + int npins; +}; + +struct sxipio_pins sxipio_pins[] = { + { + "allwinner,sun4i-a10-pinctrl", + sun4i_a10_pins, nitems(sun4i_a10_pins) + }, + { + "allwinner,sun5i-a13-pinctrl", + sun5i_a13_pins, nitems(sun5i_a13_pins) + }, + { + "allwinner,sun5i-a10s-pinctrl", + sun5i_a10s_pins, nitems(sun5i_a10s_pins) + }, + { + "allwinner,sun7i-a20-pinctrl", + sun7i_a20_pins, nitems(sun7i_a20_pins) + } +}; + void sxipio_attach(struct device *parent, struct device *self, void *args) { struct sxipio_softc *sc = (struct sxipio_softc *)self; struct armv7_attach_args *aa = args; + int node, i; /* XXX check unit, bail if != 0 */ @@ -118,9 +152,23 @@ sxipio_attach(struct device *parent, struct device *self, void *args) sc->sc_irq = aa->aa_dev->irq[0]; + node = OF_finddevice("/soc@01c00000/pinctrl@01c20800"); + if (node != -1) { + for (i = 0; i < nitems(sxipio_pins); i++) { + if (OF_is_compatible(node, sxipio_pins[i].compat)) { + sc->sc_pins = sxipio_pins[i].pins; + sc->sc_npins = sxipio_pins[i].npins; + break; + } + } + + if (sc->sc_pins) + pinctrl_register(node, sxipio_pinctrl, sc); + } + config_defer(self, sxipio_attach_gpio); - printf("\n"); + printf(": %d pins\n", sc->sc_npins); } /* @@ -353,3 +401,76 @@ sxipio_togglepin(int pin) return data & mask ? GPIO_PIN_HIGH : GPIO_PIN_LOW; } + +int +sxipio_pinctrl(uint32_t phandle, void *cookie) +{ + struct sxipio_softc *sc = cookie; + char func[32]; + char *names, *name; + int port, pin, off; + int mux, drive, pull; + int node; + int len; + int i, j; + int s; + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return -1; + + len = OF_getprop(node, "allwinner,function", func, sizeof(func)); + if (len <= 0 || len >= sizeof(func)) + return -1; + + len = OF_getproplen(node, "allwinner,pins"); + if (len <= 0) + return -1; + + names = malloc(len, M_TEMP, M_WAITOK); + OF_getprop(node, "allwinner,pins", names, len); + + drive = OF_getpropint(node, "allwinner,drive", 0); + pull = OF_getpropint(node, "allwinner,pull", 0); + + name = names; + while (len > 0) { + /* Lookup the pin. */ + for (i = 0; i < sc->sc_npins; i++) { + if (strcmp(name, sc->sc_pins[i].name) == 0) + break; + } + if (i >= sc->sc_npins) + goto err; + + /* Lookup the function of the pin. */ + for (j = 0; j < nitems(sc->sc_pins[i].funcs); j++) { + if (strcmp(func, sc->sc_pins[i].funcs[j].name) == 0) + break; + } + if (j > nitems(sc->sc_pins[i].funcs)) + goto err; + + port = sc->sc_pins[i].port; + pin = sc->sc_pins[i].pin; + mux = sc->sc_pins[i].funcs[j].mux; + + s = splhigh(); + off = (pin & 0x7) << 2; + SXICMS4(sc, SXIPIO_CFG(port, pin), 0x7 << off, mux << off); + off = (pin & 0xf) << 1; + SXICMS4(sc, SXIPIO_DRV(port, pin), 0x3 << off, drive << off); + SXICMS4(sc, SXIPIO_PUL(port, pin), 0x3 << off, pull << off); + splx(s); + + len -= strlen(name) + 1; + name += strlen(name) + 1; + } + + free(names, M_TEMP, len); + return 0; + +err: + free(names, M_TEMP, len); + return -1; +} |