On Wed, Jan 29, 2020 at 10:47:28PM +0800, Nathanael Rensen wrote: > The diff below adds gpio(4) support to wbsio(4) for Nuvoton NCT5104D > (pcengines APU2).
I'm resurrecting this thread. I was looking for GPIO support for APU2 board and found this patch in archives. Any chance of taking it in? Patch below: > It is based on Matt Dainty's diff posted to this list > in November 2018: > > https://marc.info/?l=openbsd-tech&m=154134941027009&w=2 > > A key difference from Matt Dainty's original diff is the use of > config_search() rather than config_found() to avoid problems with > the lm78 driver mentioned in his post. > > Nathanael > > Index: sys/dev/isa/wbsioreg.h > =================================================================== > RCS file: /cvs/src/sys/dev/isa/wbsioreg.h,v > retrieving revision 1.5 > diff -u -p -r1.5 wbsioreg.h > --- sys/dev/isa/wbsioreg.h 17 Dec 2019 01:34:59 -0000 1.5 > +++ sys/dev/isa/wbsioreg.h 29 Jan 2020 14:30:28 -0000 > @@ -30,8 +30,15 @@ > > /* Configuration Space Registers */ > #define WBSIO_LDN 0x07 /* Logical Device Number */ > +#define WBSIO_MF 0x1c /* Multi Function Selection */ > +#define WBSIO_MF_UARTD (1 << 2) > +#define WBSIO_MF_UARTC (1 << 3) > +#define WBSIO_MF_GP67 (1 << 4) > #define WBSIO_ID 0x20 /* Device ID */ > #define WBSIO_REV 0x21 /* Device Revision */ > +#define WBSIO_CR27 0x27 /* Global Option */ > +#define WBSIO_SF 0x2f /* Strapping Function */ > +#define WBSIO_LDN_EN 0x30 /* Logical Device Enable */ > > #define WBSIO_ID_W83627HF 0x52 > #define WBSIO_ID_W83627THF 0x82 > @@ -52,8 +59,38 @@ > #define WBSIO_ID_NCT6795D 0xd3 > > /* Logical Device Number (LDN) Assignments */ > +#define WBSIO_LDN_GPIO1 0x07 > +#define WBSIO_LDN_WDT 0x08 > +#define WBSIO_LDN_GPIO2 0x09 /* Not used */ > #define WBSIO_LDN_HM 0x0b > +#define WBSIO_LDN_GPIO3 0x0f > > /* Hardware Monitor Control Registers (LDN B) */ > #define WBSIO_HM_ADDR_MSB 0x60 /* Address [15:8] */ > #define WBSIO_HM_ADDR_LSB 0x61 /* Address [7:0] */ > + > +/* GPIO Control Registers (LDN 7) */ > +/* GPIOn registers are offset by n*4 bytes */ > +#define WBSIO_GPIO_IO 0xe0 /* GPIO Direction */ > +#define WBSIO_GPIO_DATA 0xe1 /* GPIO Data */ > +#define WBSIO_GPIO_INVERT 0xe2 /* GPIO Invert */ > +#define WBSIO_GPIO_STATUS 0xe3 /* GPIO Status */ > +#define WBSIO_GPIO0_EN (1 << 0) > +#define WBSIO_GPIO1_EN (1 << 1) > +#define WBSIO_GPIO6_EN (1 << 6) > +#define WBSIO_GPIO0_NPINS 8 > +#define WBSIO_GPIO1_NPINS 8 > +#define WBSIO_GPIO6_NPINS 1 > +#define WBSIO_GPIO_NPINS (WBSIO_GPIO0_NPINS + WBSIO_GPIO1_NPINS + \ > + WBSIO_GPIO6_NPINS) > + > +/* WDT Control Registers (LDN 8) */ > +#define WBSIO_WDT_ENABLE 0x30 > +#define WBSIO_WDT_CONTROL 0xf0 > +#define WBSIO_WDT_COUNTER 0xf1 > +#define WBSIO_WDT_MINUTE (1 << 3) > +#define WBSIO_WDT_FAST (1 << 4) > + > +/* GPIO Control Registers (LDN F) */ > +/* GPIOn register is offset by n bytes */ > +#define WBSIO_GPIO_PP_OD 0xe0 /* GPIO Push-Pull/Open Drain */ > Index: sys/dev/isa/wbsio.c > =================================================================== > RCS file: /cvs/src/sys/dev/isa/wbsio.c,v > retrieving revision 1.11 > diff -u -p -r1.11 wbsio.c > --- sys/dev/isa/wbsio.c 17 Dec 2019 01:34:59 -0000 1.11 > +++ sys/dev/isa/wbsio.c 29 Jan 2020 14:30:28 -0000 > @@ -23,11 +23,13 @@ > #include <sys/device.h> > #include <sys/kernel.h> > #include <sys/systm.h> > +#include <sys/gpio.h> > > #include <machine/bus.h> > > #include <dev/isa/isavar.h> > #include <dev/isa/wbsioreg.h> > +#include <dev/gpio/gpiovar.h> > > #ifdef WBSIO_DEBUG > #define DPRINTF(x) printf x > @@ -40,12 +42,22 @@ struct wbsio_softc { > > bus_space_tag_t sc_iot; > bus_space_handle_t sc_ioh; > + > + struct gpio_chipset_tag sc_gpio_gc; > + gpio_pin_t sc_gpio_pins[WBSIO_GPIO_NPINS]; > }; > > int wbsio_probe(struct device *, void *, void *); > void wbsio_attach(struct device *, struct device *, void *); > +int wbsio_search_cb(struct device *, void *, void *); > int wbsio_print(void *, const char *); > > +int wbsio_gpio_pin_to_group(struct wbsio_softc *, int); > +int wbsio_gpio_pin_read(struct wbsio_softc *, int); > +int wbsio_gpio_read(void *, int); > +void wbsio_gpio_write(void *, int, int); > +void wbsio_gpio_ctl(void *, int, int); > + > struct cfattach wbsio_ca = { > sizeof(struct wbsio_softc), > wbsio_probe, > @@ -56,6 +68,11 @@ struct cfdriver wbsio_cd = { > NULL, "wbsio", DV_DULL > }; > > +struct wbsio_aux { > + struct isa_attach_args ia; > + struct gpiobus_attach_args gba; > +}; > + > static __inline void > wbsio_conf_enable(bus_space_tag_t iot, bus_space_handle_t ioh) > { > @@ -132,9 +149,10 @@ wbsio_attach(struct device *parent, stru > { > struct wbsio_softc *sc = (void *)self; > struct isa_attach_args *ia = aux; > - struct isa_attach_args nia; > - u_int8_t devid, reg, reg0, reg1; > + struct wbsio_aux wbsio_aux; > + u_int8_t devid, reg, reg0, reg1, mf; > u_int16_t iobase; > + int i, npins = 0, group, gpin; > > /* Map ISA I/O space */ > sc->sc_iot = ia->ia_iot; > @@ -219,17 +237,123 @@ wbsio_attach(struct device *parent, stru > > printf("\n"); > > + sc->sc_gpio_gc.gp_cookie = sc; > + sc->sc_gpio_gc.gp_pin_read = wbsio_gpio_read; > + sc->sc_gpio_gc.gp_pin_write = wbsio_gpio_write; > + sc->sc_gpio_gc.gp_pin_ctl = wbsio_gpio_ctl; > + > + if (devid == WBSIO_ID_NCT5104D) { > + /* Read Multi Function Register */ > + mf = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_MF); > + > + /* Select GPIO logical device */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, > + WBSIO_LDN, WBSIO_LDN_GPIO1); > + reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_LDN_EN); > + > + /* UART C is inactive, use the pins as GPIO instead */ > + if ((mf & WBSIO_MF_UARTC) == 0) { > + reg |= WBSIO_GPIO0_EN; > + npins += WBSIO_GPIO0_NPINS; > + } > + > + /* UART D is inactive, use the pins as GPIO instead */ > + if ((mf & WBSIO_MF_UARTD) == 0) { > + reg |= WBSIO_GPIO1_EN; > + npins += WBSIO_GPIO1_NPINS; > + } > + > + /* GP67 is available, use it as a GPIO pin */ > + if (((wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_CR27) & > + (1 << 2)) == 0) && (mf & WBSIO_MF_GP67)) { > + reg |= WBSIO_GPIO6_EN; > + npins += WBSIO_GPIO6_NPINS; > + } > + } > + > + /* Enable the GPIO pins */ > + if (npins > 0) > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN_EN, reg); > + > + for (i = 0; i < npins; i++) { > + sc->sc_gpio_pins[i].pin_num = i; > + sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | > + GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | > + GPIO_PIN_INVIN | GPIO_PIN_INVOUT; > + > + /* Work out the GPIO owning this pin */ > + group = wbsio_gpio_pin_to_group(sc, i); > + > + /* Read existing I/O direction */ > + reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_IO + (group << 2)); > + gpin = reg & 1 << (i % 8); > + sc->sc_gpio_pins[i].pin_flags = gpin ? > + GPIO_PIN_INPUT : GPIO_PIN_OUTPUT; > + > + /* Read existing inversion status */ > + reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_INVERT + (group << 2)); > + sc->sc_gpio_pins[i].pin_flags |= (reg & (1 << (i % 8))) ? > + (gpin ? GPIO_PIN_INVIN : GPIO_PIN_INVOUT) : 0; > + > + /* Read existing push-pull/open drain. Note the logical > + * device change to read this > + */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, > + WBSIO_LDN_GPIO3); > + reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_PP_OD + group); > + sc->sc_gpio_pins[i].pin_flags |= (reg & (1 << (i % 8))) ? > + GPIO_PIN_OPENDRAIN : GPIO_PIN_PUSHPULL; > + > + /* Read existing pin state switching back to the original > + * logical device again > + */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, > + WBSIO_LDN_GPIO1); > + sc->sc_gpio_pins[i].pin_state = wbsio_gpio_pin_read(sc, i); > + } > + > + bzero(&wbsio_aux, sizeof(wbsio_aux)); > + wbsio_aux.ia = *ia; > + wbsio_aux.ia.ia_iobase = iobase; > + /* pass devid to wb_match() */ > + wbsio_aux.ia.ia_aux = (void *)(u_long)devid; > + wbsio_aux.gba.gba_name = "gpio"; > + wbsio_aux.gba.gba_gc = &sc->sc_gpio_gc; > + wbsio_aux.gba.gba_pins = sc->sc_gpio_pins; > + wbsio_aux.gba.gba_npins = npins; > + > + config_search(wbsio_search_cb, self, &wbsio_aux); > + > /* Escape from configuration mode */ > wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); > +} > > - if (iobase == 0) > - return; > +int > +wbsio_search_cb(struct device *parent, void *match, void *aux) > +{ > + struct wbsio_aux *wbaux = aux; > + struct cfdata *cf = match; > + cfprint_t print = NULL; > + > + aux = NULL; > + > + if (strcmp(wbaux->gba.gba_name, cf->cf_driver->cd_name) == 0) { > + if (wbaux->gba.gba_npins > 0) { > + aux = &wbaux->gba; > + print = gpiobus_print; > + } > + } else if (wbaux->ia.ia_iobase != 0) { > + aux = &wbaux->ia; > + print = wbsio_print; > + } > > - nia = *ia; > - nia.ia_iobase = iobase; > - nia.ia_aux = (void *)(u_long)devid; /* pass devid down to wb_match() */ > + if (aux != NULL && cf->cf_attach->ca_match(parent, match, aux)) > + config_attach(parent, match, aux, print); > > - config_found(self, &nia, wbsio_print); > + return 0; > } > > int > @@ -244,4 +368,150 @@ wbsio_print(void *aux, const char *pnp) > if (ia->ia_iosize > 1) > printf("/%d", ia->ia_iosize); > return (UNCONF); > +} > + > +/* Assumes the chip is unlocked and the correct logical device is selected */ > +int > +wbsio_gpio_pin_to_group(struct wbsio_softc *sc, int pin) > +{ > + u_int8_t reg; > + int n = pin / 8; > + int group; > + > + /* Read the enabled GPIO group, mask out any other potential bits */ > + reg = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, WBSIO_LDN_EN) & > + (WBSIO_GPIO0_EN | WBSIO_GPIO1_EN | WBSIO_GPIO6_EN); > + > + for (group = 0; group < 8; group++) { > + if ((reg & 1 << group) == 0) > + continue; > + if (n == 0) > + break; > + n--; > + } > + return group; > +} > + > +int > +wbsio_gpio_pin_read(struct wbsio_softc *sc, int pin) > +{ > + return (wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_DATA + (wbsio_gpio_pin_to_group(sc, pin) << 2)) & > + (1 << (pin % 8))) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; > +} > + > +int > +wbsio_gpio_read(void *arg, int pin) > +{ > + struct wbsio_softc *sc = arg; > + int value; > + > + /* Enter configuration mode */ > + wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); > + > + /* Select GPIO logical device */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); > + > + /* Read pin state */ > + value = wbsio_gpio_pin_read(sc, pin); > + > + /* Escape from configuration mode */ > + wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); > + > + return (value); > +} > + > +void > +wbsio_gpio_write(void *arg, int pin, int value) > +{ > + struct wbsio_softc *sc = arg; > + u_int8_t data; > + int group; > + > + /* Enter configuration mode */ > + wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); > + > + /* Select GPIO logical device */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); > + > + /* Work out the GPIO owning this pin */ > + group = wbsio_gpio_pin_to_group(sc, pin); > + > + /* Write pin state */ > + data = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_DATA + (group << 2)); > + > + if (value == GPIO_PIN_LOW) > + data &= ~(1 << (pin % 8)); > + else if (value == GPIO_PIN_HIGH) > + data |= (1 << (pin % 8)); > + > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_DATA + (group << 2), > + data); > + > + /* Escape from configuration mode */ > + wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); > +} > + > +void > +wbsio_gpio_ctl(void *arg, int pin, int flags) > +{ > + struct wbsio_softc *sc = arg; > + u_int8_t data; > + int group, gpin; > + > + /* Enter configuration mode */ > + wbsio_conf_enable(sc->sc_iot, sc->sc_ioh); > + > + /* Select GPIO logical device */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); > + > + /* Work out the GPIO group owning this pin */ > + group = wbsio_gpio_pin_to_group(sc, pin); > + > + /* Set I/O direction */ > + data = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_IO + (group << 2)); > + > + gpin = flags & GPIO_PIN_INPUT; > + if (gpin) > + data |= (1 << (pin % 8)); > + else > + data &= ~(1 << (pin % 8)); > + > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_IO + (group << 2), > + data); > + > + /* Set inversion */ > + data = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_INVERT + (group << 2)); > + > + if ((gpin && flags & GPIO_PIN_INVIN) || > + (!gpin && flags & GPIO_PIN_INVOUT)) > + data |= (1 << (pin % 8)); > + else > + data &= ~(1 << (pin % 8)); > + > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_INVERT + (group << 2), data); > + > + /* Set push-pull/open drain */ > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO3); > + > + data = wbsio_conf_read(sc->sc_iot, sc->sc_ioh, > + WBSIO_GPIO_PP_OD + group); > + > + if (flags & GPIO_PIN_OPENDRAIN) > + data |= (1 << (pin % 8)); > + if (flags & GPIO_PIN_PUSHPULL) > + data &= ~(1 << (pin % 8)); > + > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_GPIO_PP_OD + group, > + data); > + > + wbsio_conf_write(sc->sc_iot, sc->sc_ioh, WBSIO_LDN, WBSIO_LDN_GPIO1); > + sc->sc_gpio_pins[pin].pin_state = wbsio_gpio_pin_read(sc, pin); > + > + /* Escape from configuration mode */ > + wbsio_conf_disable(sc->sc_iot, sc->sc_ioh); > } > Index: share/man/man4/wbsio.4 > =================================================================== > RCS file: /cvs/src/share/man/man4/wbsio.4,v > retrieving revision 1.3 > diff -u -p -r1.3 wbsio.4 > --- share/man/man4/wbsio.4 16 Jul 2013 16:05:49 -0000 1.3 > +++ share/man/man4/wbsio.4 29 Jan 2020 14:30:28 -0000 > @@ -27,7 +27,8 @@ > The > .Nm > driver provides support for the Winbond LPC Super I/O ICs. > -Only the hardware monitoring function is currently supported. > +GPIO is supported for NCT5104D. For other revisions only the > +hardware monitoring function is currently supported. > .Pp > Support for the hardware monitor function is provided through the > .Xr lm 4 >
signature.asc
Description: PGP signature