avila_gpio.c revision 303975
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: releng/11.0/sys/arm/xscale/ixp425/avila_gpio.c 277996 2015-01-31 19:32:14Z 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#include <dev/gpio/gpiobusvar.h> 53 54#include "gpio_if.h" 55 56#define GPIO_SET_BITS(sc, reg, bits) \ 57 GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, (reg)) | (bits)) 58 59#define GPIO_CLEAR_BITS(sc, reg, bits) \ 60 GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, (reg)) & ~(bits)) 61 62struct avila_gpio_softc { 63 device_t sc_dev; 64 device_t sc_busdev; 65 bus_space_tag_t sc_iot; 66 bus_space_handle_t sc_gpio_ioh; 67 uint32_t sc_valid; 68 struct gpio_pin sc_pins[IXP4XX_GPIO_PINS]; 69}; 70 71struct avila_gpio_pin { 72 const char *name; 73 int pin; 74 int caps; 75}; 76 77#define GPIO_PIN_IO (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT) 78static struct avila_gpio_pin avila_gpio_pins[] = { 79 { "GPIO0", 0, GPIO_PIN_IO }, 80 { "GPIO1", 1, GPIO_PIN_IO }, 81 { "GPIO2", 2, GPIO_PIN_IO }, 82 { "GPIO3", 3, GPIO_PIN_IO }, 83 { "GPIO4", 4, GPIO_PIN_IO }, 84 /* 85 * The following pins are connected to system devices and should not 86 * really be frobbed. 87 */ 88#if 0 89 { "SER_ENA", 5, GPIO_PIN_IO }, 90 { "I2C_SCL", 6, GPIO_PIN_IO }, 91 { "I2C_SDA", 7, GPIO_PIN_IO }, 92 { "PCI_INTD", 8, GPIO_PIN_IO }, 93 { "PCI_INTC", 9, GPIO_PIN_IO }, 94 { "PCI_INTB", 10, GPIO_PIN_IO }, 95 { "PCI_INTA", 11, GPIO_PIN_IO }, 96 { "ATA_INT", 12, GPIO_PIN_IO }, 97 { "PCI_RST", 13, GPIO_PIN_IO }, 98 { "PCI_CLK", 14, GPIO_PIN_OUTPUT }, 99 { "EX_CLK", 15, GPIO_PIN_OUTPUT }, 100#endif 101}; 102#undef GPIO_PIN_IO 103 104/* 105 * Helpers 106 */ 107static void avila_gpio_pin_configure(struct avila_gpio_softc *sc, 108 struct gpio_pin *pin, uint32_t flags); 109static int avila_gpio_pin_flags(struct avila_gpio_softc *sc, uint32_t pin); 110 111/* 112 * Driver stuff 113 */ 114static int avila_gpio_probe(device_t dev); 115static int avila_gpio_attach(device_t dev); 116static int avila_gpio_detach(device_t dev); 117 118/* 119 * GPIO interface 120 */ 121static device_t avila_gpio_get_bus(device_t); 122static int avila_gpio_pin_max(device_t dev, int *maxpin); 123static int avila_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 124static int avila_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 125 *flags); 126static int avila_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 127static int avila_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 128static int avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 129static int avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 130static int avila_gpio_pin_toggle(device_t dev, uint32_t pin); 131 132static int 133avila_gpio_pin_flags(struct avila_gpio_softc *sc, uint32_t pin) 134{ 135 uint32_t v; 136 137 v = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin); 138 139 return (v ? GPIO_PIN_INPUT : GPIO_PIN_OUTPUT); 140} 141 142static void 143avila_gpio_pin_configure(struct avila_gpio_softc *sc, struct gpio_pin *pin, 144 unsigned int flags) 145{ 146 uint32_t mask; 147 148 mask = 1 << pin->gp_pin; 149 150 /* 151 * Manage input/output 152 */ 153 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 154 IXP4XX_GPIO_LOCK(); 155 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 156 if (flags & GPIO_PIN_OUTPUT) { 157 pin->gp_flags |= GPIO_PIN_OUTPUT; 158 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOER, mask); 159 } 160 else { 161 pin->gp_flags |= GPIO_PIN_INPUT; 162 GPIO_SET_BITS(sc, IXP425_GPIO_GPOER, mask); 163 } 164 IXP4XX_GPIO_UNLOCK(); 165 } 166} 167 168static device_t 169avila_gpio_get_bus(device_t dev) 170{ 171 struct avila_gpio_softc *sc; 172 173 sc = device_get_softc(dev); 174 175 return (sc->sc_busdev); 176} 177 178static int 179avila_gpio_pin_max(device_t dev, int *maxpin) 180{ 181 182 *maxpin = IXP4XX_GPIO_PINS - 1; 183 return (0); 184} 185 186static int 187avila_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 188{ 189 struct avila_gpio_softc *sc = device_get_softc(dev); 190 191 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 192 return (EINVAL); 193 194 *caps = sc->sc_pins[pin].gp_caps; 195 return (0); 196} 197 198static int 199avila_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 200{ 201 struct avila_gpio_softc *sc = device_get_softc(dev); 202 203 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 204 return (EINVAL); 205 206 IXP4XX_GPIO_LOCK(); 207 /* refresh since we do not own all the pins */ 208 sc->sc_pins[pin].gp_flags = avila_gpio_pin_flags(sc, pin); 209 *flags = sc->sc_pins[pin].gp_flags; 210 IXP4XX_GPIO_UNLOCK(); 211 212 return (0); 213} 214 215static int 216avila_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 217{ 218 struct avila_gpio_softc *sc = device_get_softc(dev); 219 220 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 221 return (EINVAL); 222 223 memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME); 224 return (0); 225} 226 227static int 228avila_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 229{ 230 struct avila_gpio_softc *sc = device_get_softc(dev); 231 uint32_t mask = 1 << pin; 232 233 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 234 return (EINVAL); 235 236 avila_gpio_pin_configure(sc, &sc->sc_pins[pin], flags); 237 238 return (0); 239} 240 241static int 242avila_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 243{ 244 struct avila_gpio_softc *sc = device_get_softc(dev); 245 uint32_t mask = 1 << pin; 246 247 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 248 return (EINVAL); 249 250 IXP4XX_GPIO_LOCK(); 251 if (value) 252 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask); 253 else 254 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask); 255 IXP4XX_GPIO_UNLOCK(); 256 257 return (0); 258} 259 260static int 261avila_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 262{ 263 struct avila_gpio_softc *sc = device_get_softc(dev); 264 265 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & (1 << pin))) 266 return (EINVAL); 267 268 IXP4XX_GPIO_LOCK(); 269 *val = (GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & (1 << pin)) ? 1 : 0; 270 IXP4XX_GPIO_UNLOCK(); 271 272 return (0); 273} 274 275static int 276avila_gpio_pin_toggle(device_t dev, uint32_t pin) 277{ 278 struct avila_gpio_softc *sc = device_get_softc(dev); 279 uint32_t mask = 1 << pin; 280 int res; 281 282 if (pin >= IXP4XX_GPIO_PINS || !(sc->sc_valid & mask)) 283 return (EINVAL); 284 285 IXP4XX_GPIO_LOCK(); 286 res = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR) & mask; 287 if (res) 288 GPIO_CLEAR_BITS(sc, IXP425_GPIO_GPOUTR, mask); 289 else 290 GPIO_SET_BITS(sc, IXP425_GPIO_GPOUTR, mask); 291 IXP4XX_GPIO_UNLOCK(); 292 293 return (0); 294} 295 296static int 297avila_gpio_probe(device_t dev) 298{ 299 300 device_set_desc(dev, "Gateworks Avila GPIO driver"); 301 return (0); 302} 303 304static int 305avila_gpio_attach(device_t dev) 306{ 307#define N(a) (sizeof(a) / sizeof(a[0])) 308 struct avila_gpio_softc *sc = device_get_softc(dev); 309 struct ixp425_softc *sa = device_get_softc(device_get_parent(dev)); 310 int i; 311 312 sc->sc_dev = dev; 313 sc->sc_iot = sa->sc_iot; 314 sc->sc_gpio_ioh = sa->sc_gpio_ioh; 315 316 for (i = 0; i < N(avila_gpio_pins); i++) { 317 struct avila_gpio_pin *p = &avila_gpio_pins[i]; 318 319 strncpy(sc->sc_pins[p->pin].gp_name, p->name, GPIOMAXNAME); 320 sc->sc_pins[p->pin].gp_pin = p->pin; 321 sc->sc_pins[p->pin].gp_caps = p->caps; 322 sc->sc_pins[p->pin].gp_flags = avila_gpio_pin_flags(sc, p->pin); 323 sc->sc_valid |= 1 << p->pin; 324 } 325 326 sc->sc_busdev = gpiobus_attach_bus(dev); 327 if (sc->sc_busdev == NULL) 328 return (ENXIO); 329 330 return (0); 331#undef N 332} 333 334static int 335avila_gpio_detach(device_t dev) 336{ 337 338 gpiobus_detach_bus(dev); 339 340 return(0); 341} 342 343static device_method_t gpio_avila_methods[] = { 344 DEVMETHOD(device_probe, avila_gpio_probe), 345 DEVMETHOD(device_attach, avila_gpio_attach), 346 DEVMETHOD(device_detach, avila_gpio_detach), 347 348 /* GPIO protocol */ 349 DEVMETHOD(gpio_get_bus, avila_gpio_get_bus), 350 DEVMETHOD(gpio_pin_max, avila_gpio_pin_max), 351 DEVMETHOD(gpio_pin_getname, avila_gpio_pin_getname), 352 DEVMETHOD(gpio_pin_getflags, avila_gpio_pin_getflags), 353 DEVMETHOD(gpio_pin_getcaps, avila_gpio_pin_getcaps), 354 DEVMETHOD(gpio_pin_setflags, avila_gpio_pin_setflags), 355 DEVMETHOD(gpio_pin_get, avila_gpio_pin_get), 356 DEVMETHOD(gpio_pin_set, avila_gpio_pin_set), 357 DEVMETHOD(gpio_pin_toggle, avila_gpio_pin_toggle), 358 {0, 0}, 359}; 360 361static driver_t gpio_avila_driver = { 362 "gpio", 363 gpio_avila_methods, 364 sizeof(struct avila_gpio_softc), 365}; 366static devclass_t gpio_avila_devclass; 367 368DRIVER_MODULE(gpio_avila, ixp, gpio_avila_driver, gpio_avila_devclass, 0, 0); 369MODULE_VERSION(gpio_avila, 1); 370