1/*- 2 * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3 * Copyright (c) 2009, Luiz Otavio O Souza. 4 * Copyright (c) 2010, Andrew Thompson <thompsa@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30/* 31 * GPIO driver for Gateworks Avilia 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/bus.h> 40 41#include <sys/kernel.h> 42#include <sys/module.h> 43#include <sys/rman.h> 44#include <sys/lock.h> 45#include <sys/mutex.h> 46#include <sys/gpio.h> 47 48#include <machine/bus.h> 49#include <machine/resource.h> 50#include <arm/xscale/ixp425/ixp425reg.h> 51#include <arm/xscale/ixp425/ixp425var.h> 52 53#include "gpio_if.h" 54 55#define GPIO_SET_BITS(sc, reg, bits) \ 56 GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, (reg)) | (bits)) 57 58#define GPIO_CLEAR_BITS(sc, reg, bits) \ 59 GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, (reg)) & ~(bits)) 60 61struct avila_gpio_softc { 62 device_t sc_dev; 63 bus_space_tag_t sc_iot; 64 bus_space_handle_t sc_gpio_ioh; 65 uint32_t sc_valid; 66 struct gpio_pin sc_pins[IXP4XX_GPIO_PINS]; 67}; 68 69struct avila_gpio_pin { 70 const char *name; 71 int pin; 72 int caps; 73}; 74 75#define GPIO_PIN_IO (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT) 76static struct avila_gpio_pin avila_gpio_pins[] = { 77 { "GPIO0", 0, GPIO_PIN_IO }, 78 { "GPIO1", 1, GPIO_PIN_IO }, 79 { "GPIO2", 2, GPIO_PIN_IO }, 80 { "GPIO3", 3, GPIO_PIN_IO }, 81 { "GPIO4", 4, GPIO_PIN_IO }, 82 /* 83 * The following pins are connected to system devices and should not 84 * really be frobbed. 85 */ 86#if 0 87 { "SER_ENA", 5, GPIO_PIN_IO }, 88 { "I2C_SCL", 6, GPIO_PIN_IO }, 89 { "I2C_SDA", 7, GPIO_PIN_IO }, 90 { "PCI_INTD", 8, GPIO_PIN_IO }, 91 { "PCI_INTC", 9, GPIO_PIN_IO }, 92 { "PCI_INTB", 10, GPIO_PIN_IO }, 93 { "PCI_INTA", 11, GPIO_PIN_IO }, 94 { "ATA_INT", 12, GPIO_PIN_IO }, 95 { "PCI_RST", 13, GPIO_PIN_IO }, 96 { "PCI_CLK", 14, GPIO_PIN_OUTPUT }, 97 { "EX_CLK", 15, GPIO_PIN_OUTPUT }, 98#endif 99}; 100#undef GPIO_PIN_IO 101 102/* 103 * Helpers 104 */ 105static void avila_gpio_pin_configure(struct avila_gpio_softc *sc, 106 struct gpio_pin *pin, uint32_t flags); 107static int avila_gpio_pin_flags(struct avila_gpio_softc *sc, uint32_t pin); 108 109/* 110 * Driver stuff 111 */ 112static int avila_gpio_probe(device_t dev); 113static int avila_gpio_attach(device_t dev); 114static int avila_gpio_detach(device_t dev); 115 116/* 117 * GPIO interface 118 */ 119static int avila_gpio_pin_max(device_t dev, int *maxpin); 120static int avila_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 121static int avila_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 122 *flags); 123static int avila_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 124static int avila_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 125static int avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 126static int avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 127static int avila_gpio_pin_toggle(device_t dev, uint32_t pin); 128 129static int 130avila_gpio_pin_flags(struct avila_gpio_softc *sc, uint32_t pin) 131{ 132 uint32_t v; 133 134 v = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin); 135 136 return (v ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT); 137} 138 139static void 140avila_gpio_pin_configure(struct avila_gpio_softc *sc, struct gpio_pin *pin, 141 unsigned int flags) 142{ 143 uint32_t mask; 144 145 mask = 1 << pin->gp_pin; 146 147 /* 148 * Manage input/output 149 */ 150 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 151 IXP4XX_GPIO_LOCK(); 152 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 153 if (flags & GPIO_PIN_OUTPUT) { 154 pin->gp_flags |= GPIO_PIN_OUTPUT; 155 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOER, mask); 156 } 157 else { 158 pin->gp_flags |= GPIO_PIN_INPUT; 159 GPIO_SET_BITS(sc, IXP425_GPIO_GPOER, mask); 160 } 161 IXP4XX_GPIO_UNLOCK(); 162 } 163} 164 165static int 166avila_gpio_pin_max(device_t dev, int *maxpin) 167{ 168 169 *maxpin = IXP4XX_GPIO_PINS - 1; 170 return (0); 171} 172 173static int 174avila_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 175{ 176 struct avila_gpio_softc *sc = device_get_softc(dev); 177 178 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 179 return (EINVAL); 180 181 *caps = sc->sc_pins[pin].gp_caps; 182 return (0); 183} 184 185static int 186avila_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 187{ 188 struct avila_gpio_softc *sc = device_get_softc(dev); 189 190 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 191 return (EINVAL); 192 193 IXP4XX_GPIO_LOCK(); 194 /* refresh since we do not own all the pins */ 195 sc->sc_pins[pin].gp_flags = avila_gpio_pin_flags(sc, pin); 196 *flags = sc->sc_pins[pin].gp_flags; 197 IXP4XX_GPIO_UNLOCK(); 198 199 return (0); 200} 201 202static int 203avila_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 204{ 205 struct avila_gpio_softc *sc = device_get_softc(dev); 206 207 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 208 return (EINVAL); 209 210 memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME); 211 return (0); 212} 213 214static int 215avila_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 216{ 217 struct avila_gpio_softc *sc = device_get_softc(dev); 218 uint32_t mask = 1 << pin; 219 220 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 221 return (EINVAL); 222 223 /* Check for unwanted flags. */ 224 if ((flags & sc->sc_pins[pin].gp_caps) != flags) 225 return (EINVAL); 226 227 /* Can't mix input/output together */ 228 if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 229 (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 230 return (EINVAL); 231 232 avila_gpio_pin_configure(sc, &sc->sc_pins[pin], flags); 233 return (0); 234} 235 236static int 237avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 238{ 239 struct avila_gpio_softc *sc = device_get_softc(dev); 240 uint32_t mask = 1 << pin; 241 242 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 243 return (EINVAL); 244 245 IXP4XX_GPIO_LOCK(); 246 if (value) 247 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask); 248 else 249 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask); 250 IXP4XX_GPIO_UNLOCK(); 251 252 return (0); 253} 254 255static int 256avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 257{ 258 struct avila_gpio_softc *sc = device_get_softc(dev); 259 260 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 261 return (EINVAL); 262 263 IXP4XX_GPIO_LOCK(); 264 *val = (GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin)) ? 1 : 0; 265 IXP4XX_GPIO_UNLOCK(); 266 267 return (0); 268} 269 270static int 271avila_gpio_pin_toggle(device_t dev, uint32_t pin) 272{ 273 struct avila_gpio_softc *sc = device_get_softc(dev); 274 uint32_t mask = 1 << pin; 275 int res; 276 277 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 278 return (EINVAL); 279 280 IXP4XX_GPIO_LOCK(); 281 res = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & mask; 282 if (res) 283 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask); 284 else 285 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask); 286 IXP4XX_GPIO_UNLOCK(); 287 288 return (0); 289} 290 291static int 292avila_gpio_probe(device_t dev) 293{ 294 295 device_set_desc(dev, "Gateworks Avila GPIO driver"); 296 return (0); 297} 298 299static int 300avila_gpio_attach(device_t dev) 301{ 302#define N(a) (sizeof(a) / sizeof(a[0])) 303 struct avila_gpio_softc *sc = device_get_softc(dev); 304 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 305 int i; 306 307 sc->sc_dev = dev; 308 sc->sc_iot = sa->sc_iot; 309 sc->sc_gpio_ioh = sa->sc_gpio_ioh; 310 311 for (i = 0; i < N(avila_gpio_pins); i++) { 312 struct avila_gpio_pin *p = &avila_gpio_pins[i]; 313 314 strncpy(sc->sc_pins[p->pin].gp_name, p->name, GPIOMAXNAME); 315 sc->sc_pins[p->pin].gp_pin = p->pin; 316 sc->sc_pins[p->pin].gp_caps = p->caps; 317 sc->sc_pins[p->pin].gp_flags = avila_gpio_pin_flags(sc, p->pin); 318 sc->sc_valid |= 1 << p->pin; 319 } 320 321 device_add_child(dev, "gpioc", device_get_unit(dev)); 322 device_add_child(dev, "gpiobus", device_get_unit(dev)); 323 return (bus_generic_attach(dev)); 324#undef N 325} 326 327static int 328avila_gpio_detach(device_t dev) 329{ 330 331 bus_generic_detach(dev); 332 333 return(0); 334} 335 336static device_method_t gpio_avila_methods[] = { 337 DEVMETHOD(device_probe, avila_gpio_probe), 338 DEVMETHOD(device_attach, avila_gpio_attach), 339 DEVMETHOD(device_detach, avila_gpio_detach), 340 341 /* GPIO protocol */ 342 DEVMETHOD(gpio_pin_max, avila_gpio_pin_max), 343 DEVMETHOD(gpio_pin_getname, avila_gpio_pin_getname), 344 DEVMETHOD(gpio_pin_getflags, avila_gpio_pin_getflags), 345 DEVMETHOD(gpio_pin_getcaps, avila_gpio_pin_getcaps), 346 DEVMETHOD(gpio_pin_setflags, avila_gpio_pin_setflags), 347 DEVMETHOD(gpio_pin_get, avila_gpio_pin_get), 348 DEVMETHOD(gpio_pin_set, avila_gpio_pin_set), 349 DEVMETHOD(gpio_pin_toggle, avila_gpio_pin_toggle), 350 {0, 0}, 351}; 352 353static driver_t gpio_avila_driver = { 354 "gpio_avila", 355 gpio_avila_methods, 356 sizeof(struct avila_gpio_softc), 357}; 358static devclass_t gpio_avila_devclass; 359extern devclass_t gpiobus_devclass, gpioc_devclass; 360extern driver_t gpiobus_driver, gpioc_driver; 361 362DRIVER_MODULE(gpio_avila, ixp, gpio_avila_driver, gpio_avila_devclass, 0, 0); 363DRIVER_MODULE(gpiobus, gpio_avila, gpiobus_driver, gpiobus_devclass, 0, 0); 364DRIVER_MODULE(gpioc, gpio_avila, gpioc_driver, gpioc_devclass, 0, 0); 365MODULE_VERSION(gpio_avila, 1); 366