xref: /freebsd/sys/dev/p2sb/lewisburg_gpio.c (revision ba58fd668a0e544b4af225f6dfee402e3213a8bf)
13706af42SArnaud Ysmal /*-
23706af42SArnaud Ysmal  * Copyright (c) 2018 Stormshield
33706af42SArnaud Ysmal  * All rights reserved.
43706af42SArnaud Ysmal  *
53706af42SArnaud Ysmal  * Redistribution and use in source and binary forms, with or without
63706af42SArnaud Ysmal  * modification, are permitted provided that the following conditions
73706af42SArnaud Ysmal  * are met:
83706af42SArnaud Ysmal  * 1. Redistributions of source code must retain the above copyright
93706af42SArnaud Ysmal  *    notice, this list of conditions and the following disclaimer.
103706af42SArnaud Ysmal  * 2. Redistributions in binary form must reproduce the above copyright
113706af42SArnaud Ysmal  *    notice, this list of conditions and the following disclaimer in the
123706af42SArnaud Ysmal  *    documentation and/or other materials provided with the distribution.
133706af42SArnaud Ysmal  *
143706af42SArnaud Ysmal  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153706af42SArnaud Ysmal  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163706af42SArnaud Ysmal  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173706af42SArnaud Ysmal  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183706af42SArnaud Ysmal  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193706af42SArnaud Ysmal  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203706af42SArnaud Ysmal  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213706af42SArnaud Ysmal  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223706af42SArnaud Ysmal  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233706af42SArnaud Ysmal  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243706af42SArnaud Ysmal  * SUCH DAMAGE.
253706af42SArnaud Ysmal  */
263706af42SArnaud Ysmal 
273706af42SArnaud Ysmal #include <sys/param.h>		/* defines used in kernel.h */
283706af42SArnaud Ysmal #include <sys/module.h>
293706af42SArnaud Ysmal #include <sys/systm.h>
303706af42SArnaud Ysmal #include <sys/errno.h>
313706af42SArnaud Ysmal #include <sys/kernel.h>		/* types used in module initialization */
323706af42SArnaud Ysmal #include <sys/conf.h>		/* cdevsw struct */
333706af42SArnaud Ysmal #include <sys/uio.h>		/* uio struct */
343706af42SArnaud Ysmal #include <sys/malloc.h>
353706af42SArnaud Ysmal #include <sys/bus.h>		/* structs, prototypes for pci bus stuff and DEVMETHOD macros! */
363706af42SArnaud Ysmal #include <sys/gpio.h>
373706af42SArnaud Ysmal 
383706af42SArnaud Ysmal #include <machine/bus.h>
393706af42SArnaud Ysmal #include <sys/rman.h>
403706af42SArnaud Ysmal #include <machine/resource.h>
413706af42SArnaud Ysmal 
423706af42SArnaud Ysmal #include <dev/gpio/gpiobusvar.h>
433706af42SArnaud Ysmal 
443706af42SArnaud Ysmal #include "gpio_if.h"
453706af42SArnaud Ysmal 
463706af42SArnaud Ysmal #include "lewisburg_gpiocm.h"
473706af42SArnaud Ysmal 
483706af42SArnaud Ysmal #define P2SB_GROUP_GPIO_MAX_PINS 24
493706af42SArnaud Ysmal struct lbggpio_softc
503706af42SArnaud Ysmal {
513706af42SArnaud Ysmal 	device_t		sc_busdev;
523706af42SArnaud Ysmal 	int groupid;
533706af42SArnaud Ysmal 	int pins_off;
543706af42SArnaud Ysmal 	int npins;
553706af42SArnaud Ysmal 	char grpname;
563706af42SArnaud Ysmal 	struct gpio_pin gpio_setup[P2SB_GROUP_GPIO_MAX_PINS];
573706af42SArnaud Ysmal };
583706af42SArnaud Ysmal 
593706af42SArnaud Ysmal static device_t
lbggpio_get_bus(device_t dev)603706af42SArnaud Ysmal lbggpio_get_bus(device_t dev)
613706af42SArnaud Ysmal {
623706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
633706af42SArnaud Ysmal 
643706af42SArnaud Ysmal 	sc = device_get_softc(dev);
653706af42SArnaud Ysmal 
663706af42SArnaud Ysmal 	return (sc->sc_busdev);
673706af42SArnaud Ysmal }
683706af42SArnaud Ysmal 
693706af42SArnaud Ysmal static int
lbggpio_pin_max(device_t dev,int * maxpin)703706af42SArnaud Ysmal lbggpio_pin_max(device_t dev, int *maxpin)
713706af42SArnaud Ysmal {
723706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
733706af42SArnaud Ysmal 
743706af42SArnaud Ysmal 	if (maxpin == NULL)
753706af42SArnaud Ysmal 		return (EINVAL);
763706af42SArnaud Ysmal 
773706af42SArnaud Ysmal 	sc = device_get_softc(dev);
783706af42SArnaud Ysmal 
793706af42SArnaud Ysmal 	*maxpin = sc->npins - 1;
803706af42SArnaud Ysmal 
813706af42SArnaud Ysmal 	return (0);
823706af42SArnaud Ysmal }
833706af42SArnaud Ysmal 
843706af42SArnaud Ysmal static int
lbggpio_pin_getname(device_t dev,uint32_t pin,char * name)853706af42SArnaud Ysmal lbggpio_pin_getname(device_t dev, uint32_t pin, char *name)
863706af42SArnaud Ysmal {
873706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
883706af42SArnaud Ysmal 
893706af42SArnaud Ysmal 	if (name == NULL)
903706af42SArnaud Ysmal 		return (EINVAL);
913706af42SArnaud Ysmal 
923706af42SArnaud Ysmal 	if (pin >= sc->npins)
933706af42SArnaud Ysmal 		return (EINVAL);
943706af42SArnaud Ysmal 
953706af42SArnaud Ysmal 	strlcpy(name, sc->gpio_setup[pin].gp_name, GPIOMAXNAME);
963706af42SArnaud Ysmal 
973706af42SArnaud Ysmal 	return (0);
983706af42SArnaud Ysmal }
993706af42SArnaud Ysmal 
1003706af42SArnaud Ysmal static int
lbggpio_pin_getflags(device_t dev,uint32_t pin,uint32_t * flags)1013706af42SArnaud Ysmal lbggpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
1023706af42SArnaud Ysmal {
1033706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1043706af42SArnaud Ysmal 
1053706af42SArnaud Ysmal 	if (flags == NULL)
1063706af42SArnaud Ysmal 		return (EINVAL);
1073706af42SArnaud Ysmal 
1083706af42SArnaud Ysmal 	if (pin >= sc->npins)
1093706af42SArnaud Ysmal 		return (EINVAL);
1103706af42SArnaud Ysmal 
1113706af42SArnaud Ysmal 	*flags = sc->gpio_setup[pin].gp_flags;
1123706af42SArnaud Ysmal 
1133706af42SArnaud Ysmal 	return (0);
1143706af42SArnaud Ysmal }
1153706af42SArnaud Ysmal 
1163706af42SArnaud Ysmal static int
lbggpio_pin_getcaps(device_t dev,uint32_t pin,uint32_t * caps)1173706af42SArnaud Ysmal lbggpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
1183706af42SArnaud Ysmal {
1193706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1203706af42SArnaud Ysmal 
1213706af42SArnaud Ysmal 	if (caps == NULL)
1223706af42SArnaud Ysmal 		return (EINVAL);
1233706af42SArnaud Ysmal 
1243706af42SArnaud Ysmal 	if (pin >= sc->npins)
1253706af42SArnaud Ysmal 		return (EINVAL);
1263706af42SArnaud Ysmal 
1273706af42SArnaud Ysmal 	*caps = sc->gpio_setup[pin].gp_caps;
1283706af42SArnaud Ysmal 
1293706af42SArnaud Ysmal 	return (0);
1303706af42SArnaud Ysmal }
1313706af42SArnaud Ysmal 
1323706af42SArnaud Ysmal static int
lbggpio_pin_setflags(device_t dev,uint32_t pin,uint32_t flags)1333706af42SArnaud Ysmal lbggpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
1343706af42SArnaud Ysmal {
1353706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1363706af42SArnaud Ysmal 
1373706af42SArnaud Ysmal 	if (pin >= sc->npins)
1383706af42SArnaud Ysmal 		return (EINVAL);
1393706af42SArnaud Ysmal 
1403706af42SArnaud Ysmal 	/* Check for unwanted flags. */
1413706af42SArnaud Ysmal 	if ((flags & sc->gpio_setup[pin].gp_caps) != flags)
1423706af42SArnaud Ysmal 		return (EINVAL);
1433706af42SArnaud Ysmal 
1443706af42SArnaud Ysmal 	lbggpiocm_pin_setflags(device_get_parent(dev), dev, pin, flags);
1453706af42SArnaud Ysmal 	sc->gpio_setup[pin].gp_flags = flags;
1463706af42SArnaud Ysmal 
1473706af42SArnaud Ysmal 	return (0);
1483706af42SArnaud Ysmal }
1493706af42SArnaud Ysmal 
1503706af42SArnaud Ysmal static int
lbggpio_pin_get(device_t dev,uint32_t pin,uint32_t * value)1513706af42SArnaud Ysmal lbggpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
1523706af42SArnaud Ysmal {
1533706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1543706af42SArnaud Ysmal 
1553706af42SArnaud Ysmal 	if (value == NULL)
1563706af42SArnaud Ysmal 		return (EINVAL);
1573706af42SArnaud Ysmal 
1583706af42SArnaud Ysmal 	if (pin >= sc->npins)
1593706af42SArnaud Ysmal 		return (EINVAL);
1603706af42SArnaud Ysmal 
1613706af42SArnaud Ysmal 	return (lbggpiocm_pin_get(device_get_parent(dev), dev, pin, value));
1623706af42SArnaud Ysmal }
1633706af42SArnaud Ysmal 
1643706af42SArnaud Ysmal static int
lbggpio_pin_set(device_t dev,uint32_t pin,uint32_t value)1653706af42SArnaud Ysmal lbggpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
1663706af42SArnaud Ysmal {
1673706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1683706af42SArnaud Ysmal 
1693706af42SArnaud Ysmal 	if (pin >= sc->npins)
1703706af42SArnaud Ysmal 		return (EINVAL);
1713706af42SArnaud Ysmal 
1723706af42SArnaud Ysmal 	return (lbggpiocm_pin_set(device_get_parent(dev), dev, pin, value));
1733706af42SArnaud Ysmal }
1743706af42SArnaud Ysmal 
1753706af42SArnaud Ysmal static int
lbggpio_pin_toggle(device_t dev,uint32_t pin)1763706af42SArnaud Ysmal lbggpio_pin_toggle(device_t dev, uint32_t pin)
1773706af42SArnaud Ysmal {
1783706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1793706af42SArnaud Ysmal 
1803706af42SArnaud Ysmal 	if (pin >= sc->npins)
1813706af42SArnaud Ysmal 		return (EINVAL);
1823706af42SArnaud Ysmal 
1833706af42SArnaud Ysmal 	return (lbggpiocm_pin_toggle(device_get_parent(dev), dev, pin));
1843706af42SArnaud Ysmal }
1853706af42SArnaud Ysmal 
1863706af42SArnaud Ysmal static int
lbggpio_probe(device_t dev)1873706af42SArnaud Ysmal lbggpio_probe(device_t dev)
1883706af42SArnaud Ysmal {
1893706af42SArnaud Ysmal 	struct lbggpio_softc *sc = device_get_softc(dev);
1903706af42SArnaud Ysmal 	/* X is a placeholder for the actual one letter group name. */
1913706af42SArnaud Ysmal 	static char desc[] = "LewisBurg GPIO Group X";
1923706af42SArnaud Ysmal 
1933706af42SArnaud Ysmal 	sc->npins = lbggpiocm_get_group_npins(device_get_parent(dev), dev);
1943706af42SArnaud Ysmal 	sc->grpname = lbggpiocm_get_group_name(device_get_parent(dev), dev);
1953706af42SArnaud Ysmal 	if (sc->npins <= 0)
1963706af42SArnaud Ysmal 		return (ENXIO);
1973706af42SArnaud Ysmal 
1983706af42SArnaud Ysmal 	desc[sizeof(desc)-2] = sc->grpname;
1993706af42SArnaud Ysmal 	device_set_desc_copy(dev, desc);
2003706af42SArnaud Ysmal 	return (BUS_PROBE_DEFAULT);
2013706af42SArnaud Ysmal }
2023706af42SArnaud Ysmal 
2033706af42SArnaud Ysmal static int
lbggpio_attach(device_t dev)2043706af42SArnaud Ysmal lbggpio_attach(device_t dev)
2053706af42SArnaud Ysmal {
2063706af42SArnaud Ysmal 	uint32_t i;
2073706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
2083706af42SArnaud Ysmal 
2093706af42SArnaud Ysmal 	sc = device_get_softc(dev);
2103706af42SArnaud Ysmal 	/* GPIO config */
2113706af42SArnaud Ysmal 	for (i = 0; i < sc->npins; ++i) {
2123706af42SArnaud Ysmal 		sc->gpio_setup[i].gp_pin = i;
2133706af42SArnaud Ysmal 		snprintf(sc->gpio_setup[i].gp_name,
2143706af42SArnaud Ysmal 		    sizeof(sc->gpio_setup[i].gp_name),
2153706af42SArnaud Ysmal 		    "GPIO %c%u", sc->grpname, i);
2163706af42SArnaud Ysmal 		sc->gpio_setup[i].gp_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
2173706af42SArnaud Ysmal 	}
2183706af42SArnaud Ysmal 
2193706af42SArnaud Ysmal 	/* support gpio */
2203706af42SArnaud Ysmal 	sc->sc_busdev = gpiobus_attach_bus(dev);
2213706af42SArnaud Ysmal 	if (sc->sc_busdev == NULL)
2223706af42SArnaud Ysmal 		return (ENXIO);
2233706af42SArnaud Ysmal 
2243706af42SArnaud Ysmal 	return (0);
2253706af42SArnaud Ysmal }
2263706af42SArnaud Ysmal 
2273706af42SArnaud Ysmal static int
lbggpio_detach(device_t dev)2283706af42SArnaud Ysmal lbggpio_detach(device_t dev)
2293706af42SArnaud Ysmal {
2303706af42SArnaud Ysmal 	struct lbggpio_softc *sc;
2313706af42SArnaud Ysmal 
2323706af42SArnaud Ysmal 	sc = device_get_softc(dev);
2333706af42SArnaud Ysmal 
2343706af42SArnaud Ysmal 	if (sc->sc_busdev)
2353706af42SArnaud Ysmal 		gpiobus_detach_bus(dev);
2363706af42SArnaud Ysmal 
2373706af42SArnaud Ysmal 	return (0);
2383706af42SArnaud Ysmal }
2393706af42SArnaud Ysmal 
2403706af42SArnaud Ysmal static device_method_t lbggpio_methods[] = {
2413706af42SArnaud Ysmal 	/* Device interface */
2423706af42SArnaud Ysmal 	DEVMETHOD(device_probe,		lbggpio_probe),
2433706af42SArnaud Ysmal 	DEVMETHOD(device_attach,	lbggpio_attach),
2443706af42SArnaud Ysmal 	DEVMETHOD(device_detach,	lbggpio_detach),
2453706af42SArnaud Ysmal 
2463706af42SArnaud Ysmal 	/* GPIO protocol */
2473706af42SArnaud Ysmal 	DEVMETHOD(gpio_get_bus,		lbggpio_get_bus),
2483706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_max,		lbggpio_pin_max),
2493706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_getcaps,	lbggpio_pin_getcaps),
2503706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_getflags,	lbggpio_pin_getflags),
2513706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_setflags,	lbggpio_pin_setflags),
2523706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_getname,	lbggpio_pin_getname),
2533706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_set,		lbggpio_pin_set),
2543706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_get,		lbggpio_pin_get),
2553706af42SArnaud Ysmal 	DEVMETHOD(gpio_pin_toggle,	lbggpio_pin_toggle),
2563706af42SArnaud Ysmal 
2573706af42SArnaud Ysmal 	DEVMETHOD_END
2583706af42SArnaud Ysmal };
2593706af42SArnaud Ysmal 
2603706af42SArnaud Ysmal static driver_t lbggpio_driver = {
2613706af42SArnaud Ysmal 	"gpio",
2623706af42SArnaud Ysmal 	lbggpio_methods,
2633706af42SArnaud Ysmal 	sizeof(struct lbggpio_softc)
2643706af42SArnaud Ysmal };
2653706af42SArnaud Ysmal 
266*ba58fd66SJohn Baldwin DRIVER_MODULE(lbggpio, lbggpiocm, lbggpio_driver, NULL, NULL);
2673706af42SArnaud Ysmal MODULE_DEPEND(lbggpio, gpiobus, 1, 1, 1);
268