1 /* $OpenBSD: gscpcib.c,v 1.6 2009/03/29 21:53:52 sthen Exp $ */ 2 /* 3 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /* 19 * Special driver for the National Semiconductor Geode SC1100 PCI-ISA bridge 20 * that attaches instead of pcib(4). In addition to the core pcib(4) 21 * functionality this driver provides support for the GPIO interface. 22 */ 23 24 #include <sys/param.h> 25 #include <sys/systm.h> 26 #include <sys/device.h> 27 #include <sys/gpio.h> 28 #include <sys/kernel.h> 29 30 #include <machine/bus.h> 31 32 #include <dev/pci/pcireg.h> 33 #include <dev/pci/pcivar.h> 34 #include <dev/pci/pcidevs.h> 35 36 #include <dev/gpio/gpiovar.h> 37 38 #include <i386/pci/gscpcibreg.h> 39 40 struct gscpcib_softc { 41 struct device sc_dev; 42 43 /* GPIO interface */ 44 bus_space_tag_t sc_gpio_iot; 45 bus_space_handle_t sc_gpio_ioh; 46 struct gpio_chipset_tag sc_gpio_gc; 47 gpio_pin_t sc_gpio_pins[GSCGPIO_NPINS]; 48 }; 49 50 int gscpcib_match(struct device *, void *, void *); 51 void gscpcib_attach(struct device *, struct device *, void *); 52 53 int gscpcib_gpio_pin_read(void *, int); 54 void gscpcib_gpio_pin_write(void *, int, int); 55 void gscpcib_gpio_pin_ctl(void *, int, int); 56 57 /* arch/i386/pci/pcib.c */ 58 void pcibattach(struct device *, struct device *, void *); 59 60 struct cfattach gscpcib_ca = { 61 sizeof (struct gscpcib_softc), 62 gscpcib_match, 63 gscpcib_attach 64 }; 65 66 struct cfdriver gscpcib_cd = { 67 NULL, "gscpcib", DV_DULL 68 }; 69 70 int 71 gscpcib_match(struct device *parent, void *match, void *aux) 72 { 73 struct pci_attach_args *pa = aux; 74 75 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_BRIDGE || 76 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_BRIDGE_ISA) 77 return (0); 78 79 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_NS && 80 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_NS_SC1100_ISA) 81 return (2); /* supersede pcib(4) */ 82 83 return (0); 84 } 85 86 void 87 gscpcib_attach(struct device *parent, struct device *self, void *aux) 88 { 89 #ifndef SMALL_KERNEL 90 struct gscpcib_softc *sc = (struct gscpcib_softc *)self; 91 struct pci_attach_args *pa = aux; 92 struct gpiobus_attach_args gba; 93 pcireg_t gpiobase; 94 int i; 95 int gpio_present = 0; 96 97 /* Map GPIO I/O space */ 98 gpiobase = pci_conf_read(pa->pa_pc, pa->pa_tag, GSCGPIO_BASE); 99 sc->sc_gpio_iot = pa->pa_iot; 100 if (PCI_MAPREG_IO_ADDR(gpiobase) == 0 || 101 bus_space_map(sc->sc_gpio_iot, PCI_MAPREG_IO_ADDR(gpiobase), 102 GSCGPIO_SIZE, 0, &sc->sc_gpio_ioh)) { 103 printf(": can't map GPIO i/o space"); 104 goto corepcib; 105 } 106 107 /* Initialize pins array */ 108 for (i = 0; i < GSCGPIO_NPINS; i++) { 109 sc->sc_gpio_pins[i].pin_num = i; 110 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | 111 GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | 112 GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 113 GPIO_PIN_PULLUP; 114 115 /* Read initial state */ 116 sc->sc_gpio_pins[i].pin_state = gscpcib_gpio_pin_read(sc, i) ? 117 GPIO_PIN_HIGH : GPIO_PIN_LOW; 118 } 119 120 /* Create controller tag */ 121 sc->sc_gpio_gc.gp_cookie = sc; 122 sc->sc_gpio_gc.gp_pin_read = gscpcib_gpio_pin_read; 123 sc->sc_gpio_gc.gp_pin_write = gscpcib_gpio_pin_write; 124 sc->sc_gpio_gc.gp_pin_ctl = gscpcib_gpio_pin_ctl; 125 126 gba.gba_name = "gpio"; 127 gba.gba_gc = &sc->sc_gpio_gc; 128 gba.gba_pins = sc->sc_gpio_pins; 129 gba.gba_npins = GSCGPIO_NPINS; 130 131 gpio_present = 1; 132 133 corepcib: 134 #endif /* !SMALL_KERNEL */ 135 /* Provide core pcib(4) functionality */ 136 pcibattach(parent, self, aux); 137 138 #ifndef SMALL_KERNEL 139 /* Attach GPIO framework */ 140 if (gpio_present) 141 config_found(&sc->sc_dev, &gba, gpiobus_print); 142 #endif /* !SMALL_KERNEL */ 143 } 144 145 #ifndef SMALL_KERNEL 146 static __inline void 147 gscpcib_gpio_pin_select(struct gscpcib_softc *sc, int pin) 148 { 149 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, GSCGPIO_SEL, pin); 150 } 151 152 int 153 gscpcib_gpio_pin_read(void *arg, int pin) 154 { 155 struct gscpcib_softc *sc = arg; 156 int reg, shift; 157 u_int32_t data; 158 159 reg = (pin < 32 ? GSCGPIO_GPDI0 : GSCGPIO_GPDI1); 160 shift = pin % 32; 161 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 162 163 return ((data >> shift) & 0x1); 164 } 165 166 void 167 gscpcib_gpio_pin_write(void *arg, int pin, int value) 168 { 169 struct gscpcib_softc *sc = arg; 170 int reg, shift; 171 u_int32_t data; 172 173 reg = (pin < 32 ? GSCGPIO_GPDO0 : GSCGPIO_GPDO1); 174 shift = pin % 32; 175 data = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg); 176 if (value == 0) 177 data &= ~(1 << shift); 178 else if (value == 1) 179 data |= (1 << shift); 180 181 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, reg, data); 182 } 183 184 void 185 gscpcib_gpio_pin_ctl(void *arg, int pin, int flags) 186 { 187 struct gscpcib_softc *sc = arg; 188 u_int32_t conf; 189 190 gscpcib_gpio_pin_select(sc, pin); 191 conf = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, 192 GSCGPIO_CONF); 193 194 conf &= ~(GSCGPIO_CONF_OUTPUTEN | GSCGPIO_CONF_PUSHPULL | 195 GSCGPIO_CONF_PULLUP); 196 if ((flags & GPIO_PIN_TRISTATE) == 0) 197 conf |= GSCGPIO_CONF_OUTPUTEN; 198 if (flags & GPIO_PIN_PUSHPULL) 199 conf |= GSCGPIO_CONF_PUSHPULL; 200 if (flags & GPIO_PIN_PULLUP) 201 conf |= GSCGPIO_CONF_PULLUP; 202 bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh, 203 GSCGPIO_CONF, conf); 204 } 205 #endif /* !SMALL_KERNEL */ 206