avila_gpio.c revision 278786
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: stable/10/sys/arm/xscale/ixp425/avila_gpio.c 278786 2015-02-14 21:16:19Z loos $"); 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 avila_gpio_pin_configure(sc, &sc->sc_pins[pin], flags); 224 225 return (0); 226} 227 228static int 229avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 230{ 231 struct avila_gpio_softc *sc = device_get_softc(dev); 232 uint32_t mask = 1 << pin; 233 234 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 235 return (EINVAL); 236 237 IXP4XX_GPIO_LOCK(); 238 if (value) 239 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask); 240 else 241 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask); 242 IXP4XX_GPIO_UNLOCK(); 243 244 return (0); 245} 246 247static int 248avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 249{ 250 struct avila_gpio_softc *sc = device_get_softc(dev); 251 252 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 253 return (EINVAL); 254 255 IXP4XX_GPIO_LOCK(); 256 *val = (GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin)) ? 1 : 0; 257 IXP4XX_GPIO_UNLOCK(); 258 259 return (0); 260} 261 262static int 263avila_gpio_pin_toggle(device_t dev, uint32_t pin) 264{ 265 struct avila_gpio_softc *sc = device_get_softc(dev); 266 uint32_t mask = 1 << pin; 267 int res; 268 269 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 270 return (EINVAL); 271 272 IXP4XX_GPIO_LOCK(); 273 res = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & mask; 274 if (res) 275 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask); 276 else 277 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask); 278 IXP4XX_GPIO_UNLOCK(); 279 280 return (0); 281} 282 283static int 284avila_gpio_probe(device_t dev) 285{ 286 287 device_set_desc(dev, "Gateworks Avila GPIO driver"); 288 return (0); 289} 290 291static int 292avila_gpio_attach(device_t dev) 293{ 294#define N(a) (sizeof(a) / sizeof(a[0])) 295 struct avila_gpio_softc *sc = device_get_softc(dev); 296 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 297 int i; 298 299 sc->sc_dev = dev; 300 sc->sc_iot = sa->sc_iot; 301 sc->sc_gpio_ioh = sa->sc_gpio_ioh; 302 303 for (i = 0; i < N(avila_gpio_pins); i++) { 304 struct avila_gpio_pin *p = &avila_gpio_pins[i]; 305 306 strncpy(sc->sc_pins[p->pin].gp_name, p->name, GPIOMAXNAME); 307 sc->sc_pins[p->pin].gp_pin = p->pin; 308 sc->sc_pins[p->pin].gp_caps = p->caps; 309 sc->sc_pins[p->pin].gp_flags = avila_gpio_pin_flags(sc, p->pin); 310 sc->sc_valid |= 1 << p->pin; 311 } 312 313 device_add_child(dev, "gpioc", -1); 314 device_add_child(dev, "gpiobus", -1); 315 316 return (bus_generic_attach(dev)); 317#undef N 318} 319 320static int 321avila_gpio_detach(device_t dev) 322{ 323 324 bus_generic_detach(dev); 325 326 return(0); 327} 328 329static device_method_t gpio_avila_methods[] = { 330 DEVMETHOD(device_probe, avila_gpio_probe), 331 DEVMETHOD(device_attach, avila_gpio_attach), 332 DEVMETHOD(device_detach, avila_gpio_detach), 333 334 /* GPIO protocol */ 335 DEVMETHOD(gpio_pin_max, avila_gpio_pin_max), 336 DEVMETHOD(gpio_pin_getname, avila_gpio_pin_getname), 337 DEVMETHOD(gpio_pin_getflags, avila_gpio_pin_getflags), 338 DEVMETHOD(gpio_pin_getcaps, avila_gpio_pin_getcaps), 339 DEVMETHOD(gpio_pin_setflags, avila_gpio_pin_setflags), 340 DEVMETHOD(gpio_pin_get, avila_gpio_pin_get), 341 DEVMETHOD(gpio_pin_set, avila_gpio_pin_set), 342 DEVMETHOD(gpio_pin_toggle, avila_gpio_pin_toggle), 343 {0, 0}, 344}; 345 346static driver_t gpio_avila_driver = { 347 "gpio_avila", 348 gpio_avila_methods, 349 sizeof(struct avila_gpio_softc), 350}; 351static devclass_t gpio_avila_devclass; 352extern devclass_t gpiobus_devclass, gpioc_devclass; 353extern driver_t gpiobus_driver, gpioc_driver; 354 355DRIVER_MODULE(gpio_avila, ixp, gpio_avila_driver, gpio_avila_devclass, 0, 0); 356DRIVER_MODULE(gpiobus, gpio_avila, gpiobus_driver, gpiobus_devclass, 0, 0); 357DRIVER_MODULE(gpioc, gpio_avila, gpioc_driver, gpioc_devclass, 0, 0); 358MODULE_VERSION(gpio_avila, 1); 359