pxa_gpio.c revision 179595
1/*- 2 * Copyright (c) 2006 Benno Rice. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include <sys/cdefs.h> 26__FBSDID("$FreeBSD: head/sys/arm/xscale/pxa/pxa_gpio.c 179595 2008-06-06 05:08:09Z benno $"); 27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/bus.h> 31#include <sys/kernel.h> 32#include <sys/lock.h> 33#include <sys/interrupt.h> 34#include <sys/module.h> 35#include <sys/malloc.h> 36#include <sys/mutex.h> 37#include <sys/rman.h> 38#include <sys/queue.h> 39#include <sys/taskqueue.h> 40#include <sys/timetc.h> 41#include <machine/bus.h> 42#include <machine/intr.h> 43 44#include <arm/xscale/pxa/pxavar.h> 45#include <arm/xscale/pxa/pxareg.h> 46 47struct pxa_gpio_softc { 48 struct resource * pg_res[4]; 49 bus_space_tag_t pg_bst; 50 bus_space_handle_t pg_bsh; 51 struct mtx pg_mtx; 52 53 uint32_t pg_intr[3]; 54}; 55 56static struct resource_spec pxa_gpio_spec[] = { 57 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 58 { SYS_RES_IRQ, 0, RF_ACTIVE }, 59 { SYS_RES_IRQ, 1, RF_ACTIVE }, 60 { SYS_RES_IRQ, 2, RF_ACTIVE }, 61 { -1, 0 } 62}; 63 64static struct pxa_gpio_softc *pxa_gpio_softc = NULL; 65 66static int pxa_gpio_probe(device_t); 67static int pxa_gpio_attach(device_t); 68 69static driver_filter_t pxa_gpio_intr0; 70static driver_filter_t pxa_gpio_intr1; 71static driver_filter_t pxa_gpio_intrN; 72 73static int 74pxa_gpio_probe(device_t dev) 75{ 76 77 device_set_desc(dev, "GPIO Controller"); 78 return (0); 79} 80 81static int 82pxa_gpio_attach(device_t dev) 83{ 84 int error; 85 void *ihl; 86 struct pxa_gpio_softc *sc; 87 88 sc = (struct pxa_gpio_softc *)device_get_softc(dev); 89 90 if (pxa_gpio_softc != NULL) 91 return (ENXIO); 92 pxa_gpio_softc = sc; 93 94 error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res); 95 if (error) { 96 device_printf(dev, "could not allocate resources\n"); 97 return (ENXIO); 98 } 99 100 sc->pg_bst = rman_get_bustag(sc->pg_res[0]); 101 sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]); 102 103 /* Disable and clear all interrupts. */ 104 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0); 105 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0); 106 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0); 107 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0); 108 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0); 109 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0); 110 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0); 111 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0); 112 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0); 113 114 mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN); 115 116 if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE, 117 pxa_gpio_intr0, NULL, sc, &ihl) != 0) { 118 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); 119 device_printf(dev, "could not set up intr0\n"); 120 return (ENXIO); 121 } 122 123 if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE, 124 pxa_gpio_intr1, NULL, sc, &ihl) != 0) { 125 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); 126 device_printf(dev, "could not set up intr1\n"); 127 return (ENXIO); 128 } 129 130 if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE, 131 pxa_gpio_intrN, NULL, sc, &ihl) != 0) { 132 bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); 133 device_printf(dev, "could not set up intrN\n"); 134 return (ENXIO); 135 } 136 137 return (0); 138} 139 140static int 141pxa_gpio_intr0(void *arg) 142{ 143 struct pxa_gpio_softc *sc; 144 145 sc = (struct pxa_gpio_softc *)arg; 146 147 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1); 148 sc->pg_intr[0] |= 1; 149 150 return (FILTER_HANDLED); 151} 152 153static int 154pxa_gpio_intr1(void *arg) 155{ 156 struct pxa_gpio_softc *sc; 157 158 sc = (struct pxa_gpio_softc *)arg; 159 160 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2); 161 sc->pg_intr[1] |= 2; 162 163 return (FILTER_HANDLED); 164} 165 166static int 167pxa_gpio_intrN(void *arg) 168{ 169 uint32_t gedr0, gedr1, gedr2; 170 struct pxa_gpio_softc *sc; 171 172 sc = (struct pxa_gpio_softc *)arg; 173 174 gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0); 175 gedr0 &= 0xfffffffc; 176 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0); 177 178 gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1); 179 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1); 180 181 gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2); 182 gedr2 &= 0x001fffff; 183 bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2); 184 185 sc->pg_intr[0] |= gedr0; 186 sc->pg_intr[1] |= gedr1; 187 sc->pg_intr[2] |= gedr2; 188 189 return (FILTER_HANDLED); 190} 191 192static device_method_t pxa_gpio_methods[] = { 193 DEVMETHOD(device_probe, pxa_gpio_probe), 194 DEVMETHOD(device_attach, pxa_gpio_attach), 195 196 {0, 0} 197}; 198 199static driver_t pxa_gpio_driver = { 200 "gpio", 201 pxa_gpio_methods, 202 sizeof(struct pxa_gpio_softc), 203}; 204 205static devclass_t pxa_gpio_devclass; 206 207DRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0); 208 209#define pxagpio_reg_read(softc, reg) \ 210 bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg) 211#define pxagpio_reg_write(softc, reg, val) \ 212 bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val) 213 214uint32_t 215pxa_gpio_get_function(int gpio) 216{ 217 struct pxa_gpio_softc *sc; 218 uint32_t rv, io; 219 220 sc = pxa_gpio_softc; 221 222 rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio); 223 rv = GPIO_FN(rv); 224 225 io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)); 226 if (io & GPIO_BIT(gpio)) 227 rv |= GPIO_OUT; 228 229 io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio)); 230 if (io & GPIO_BIT(gpio)) 231 rv |= GPIO_SET; 232 233 return (rv); 234} 235 236uint32_t 237pxa_gpio_set_function(int gpio, uint32_t fn) 238{ 239 struct pxa_gpio_softc *sc; 240 uint32_t rv, bit, oldfn; 241 242 sc = pxa_gpio_softc; 243 244 oldfn = pxa_gpio_get_function(gpio); 245 246 if (GPIO_FN(fn) == GPIO_FN(oldfn) && 247 GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) { 248 /* 249 * The pin's function is not changing. 250 * For Alternate Functions and GPIO input, we can just 251 * return now. 252 * For GPIO output pins, check the initial state is 253 * the same. 254 * 255 * Return 'fn' instead of 'oldfn' so the caller can 256 * reliably detect that we didn't change anything. 257 * (The initial state might be different for non- 258 * GPIO output pins). 259 */ 260 if (!GPIO_IS_GPIO_OUT(fn) || 261 GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn)) 262 return (fn); 263 } 264 265 /* 266 * See section 4.1.3.7 of the PXA2x0 Developer's Manual for 267 * the correct procedure for changing GPIO pin functions. 268 */ 269 270 bit = GPIO_BIT(gpio); 271 272 /* 273 * 1. Configure the correct set/clear state of the pin 274 */ 275 if (GPIO_FN_IS_SET(fn)) 276 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit); 277 else 278 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit); 279 280 /* 281 * 2. Configure the pin as an input or output as appropriate 282 */ 283 rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit; 284 if (GPIO_FN_IS_OUT(fn)) 285 rv |= bit; 286 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv); 287 288 /* 289 * 3. Configure the pin's function 290 */ 291 bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio); 292 fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio); 293 rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit; 294 pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn); 295 296 return (oldfn); 297} 298 299/* 300 * GPIO "interrupt" handling. 301 */ 302 303void 304pxa_gpio_mask_irq(int irq) 305{ 306 uint32_t val; 307 struct pxa_gpio_softc *sc; 308 int gpio; 309 310 sc = pxa_gpio_softc; 311 gpio = IRQ_TO_GPIO(irq); 312 313 val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); 314 val &= ~GPIO_BIT(gpio); 315 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); 316} 317 318void 319pxa_gpio_unmask_irq(int irq) 320{ 321 uint32_t val; 322 struct pxa_gpio_softc *sc; 323 int gpio; 324 325 sc = pxa_gpio_softc; 326 gpio = IRQ_TO_GPIO(irq); 327 328 val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); 329 val |= GPIO_BIT(gpio); 330 pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); 331} 332 333int 334pxa_gpio_get_next_irq() 335{ 336 struct pxa_gpio_softc *sc; 337 int gpio; 338 339 sc = pxa_gpio_softc; 340 341 if (sc->pg_intr[0] != 0) { 342 gpio = ffs(sc->pg_intr[0]) - 1; 343 sc->pg_intr[0] &= ~(1 << gpio); 344 return (GPIO_TO_IRQ(gpio)); 345 } 346 if (sc->pg_intr[1] != 0) { 347 gpio = ffs(sc->pg_intr[1]) - 1; 348 sc->pg_intr[1] &= ~(1 << gpio); 349 return (GPIO_TO_IRQ(gpio + 32)); 350 } 351 if (sc->pg_intr[2] != 0) { 352 gpio = ffs(sc->pg_intr[2]) - 1; 353 sc->pg_intr[2] &= ~(1 << gpio); 354 return (GPIO_TO_IRQ(gpio + 64)); 355 } 356 357 return (-1); 358} 359