1179595Sbenno/*- 2179595Sbenno * Copyright (c) 2006 Benno Rice. All rights reserved. 3179595Sbenno * 4179595Sbenno * Redistribution and use in source and binary forms, with or without 5179595Sbenno * modification, are permitted provided that the following conditions 6179595Sbenno * are met: 7179595Sbenno * 1. Redistributions of source code must retain the above copyright 8179595Sbenno * notice, this list of conditions and the following disclaimer. 9179595Sbenno * 2. Redistributions in binary form must reproduce the above copyright 10179595Sbenno * notice, this list of conditions and the following disclaimer in the 11179595Sbenno * documentation and/or other materials provided with the distribution. 12179595Sbenno * 13179595Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14179595Sbenno * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15179595Sbenno * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16179595Sbenno * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17179595Sbenno * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18179595Sbenno * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19179595Sbenno * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20179595Sbenno * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21179595Sbenno * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22179595Sbenno * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23179595Sbenno */ 24179595Sbenno 25179595Sbenno#include <sys/cdefs.h> 26179595Sbenno__FBSDID("$FreeBSD: releng/10.2/sys/arm/xscale/pxa/pxa_gpio.c 179595 2008-06-06 05:08:09Z benno $"); 27179595Sbenno 28179595Sbenno#include <sys/param.h> 29179595Sbenno#include <sys/systm.h> 30179595Sbenno#include <sys/bus.h> 31179595Sbenno#include <sys/kernel.h> 32179595Sbenno#include <sys/lock.h> 33179595Sbenno#include <sys/interrupt.h> 34179595Sbenno#include <sys/module.h> 35179595Sbenno#include <sys/malloc.h> 36179595Sbenno#include <sys/mutex.h> 37179595Sbenno#include <sys/rman.h> 38179595Sbenno#include <sys/queue.h> 39179595Sbenno#include <sys/taskqueue.h> 40179595Sbenno#include <sys/timetc.h> 41179595Sbenno#include <machine/bus.h> 42179595Sbenno#include <machine/intr.h> 43179595Sbenno 44179595Sbenno#include <arm/xscale/pxa/pxavar.h> 45179595Sbenno#include <arm/xscale/pxa/pxareg.h> 46179595Sbenno 47179595Sbennostruct pxa_gpio_softc { 48179595Sbenno struct resource * pg_res[4]; 49179595Sbenno bus_space_tag_t pg_bst; 50179595Sbenno bus_space_handle_t pg_bsh; 51179595Sbenno struct mtx pg_mtx; 52179595Sbenno 53179595Sbenno uint32_t pg_intr[3]; 54179595Sbenno}; 55179595Sbenno 56179595Sbennostatic struct resource_spec pxa_gpio_spec[] = { 57179595Sbenno { SYS_RES_MEMORY, 0, RF_ACTIVE }, 58179595Sbenno { SYS_RES_IRQ, 0, RF_ACTIVE }, 59179595Sbenno { SYS_RES_IRQ, 1, RF_ACTIVE }, 60179595Sbenno { SYS_RES_IRQ, 2, RF_ACTIVE }, 61179595Sbenno { -1, 0 } 62179595Sbenno}; 63179595Sbenno 64179595Sbennostatic struct pxa_gpio_softc *pxa_gpio_softc = NULL; 65179595Sbenno 66179595Sbennostatic int pxa_gpio_probe(device_t); 67179595Sbennostatic int pxa_gpio_attach(device_t); 68179595Sbenno 69179595Sbennostatic driver_filter_t pxa_gpio_intr0; 70179595Sbennostatic driver_filter_t pxa_gpio_intr1; 71179595Sbennostatic driver_filter_t pxa_gpio_intrN; 72179595Sbenno 73179595Sbennostatic int 74179595Sbennopxa_gpio_probe(device_t dev) 75179595Sbenno{ 76179595Sbenno 77179595Sbenno device_set_desc(dev, "GPIO Controller"); 78179595Sbenno return (0); 79179595Sbenno} 80179595Sbenno 81179595Sbennostatic int 82179595Sbennopxa_gpio_attach(device_t dev) 83179595Sbenno{ 84179595Sbenno int error; 85179595Sbenno void *ihl; 86179595Sbenno struct pxa_gpio_softc *sc; 87179595Sbenno 88179595Sbenno sc = (struct pxa_gpio_softc *)device_get_softc(dev); 89179595Sbenno 90179595Sbenno if (pxa_gpio_softc != NULL) 91179595Sbenno return (ENXIO); 92179595Sbenno pxa_gpio_softc = sc; 93179595Sbenno 94179595Sbenno error = bus_alloc_resources(dev, pxa_gpio_spec, sc->pg_res); 95179595Sbenno if (error) { 96179595Sbenno device_printf(dev, "could not allocate resources\n"); 97179595Sbenno return (ENXIO); 98179595Sbenno } 99179595Sbenno 100179595Sbenno sc->pg_bst = rman_get_bustag(sc->pg_res[0]); 101179595Sbenno sc->pg_bsh = rman_get_bushandle(sc->pg_res[0]); 102179595Sbenno 103179595Sbenno /* Disable and clear all interrupts. */ 104179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER0, 0); 105179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER1, 0); 106179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GRER2, 0); 107179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER0, 0); 108179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER1, 0); 109179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GFER2, 0); 110179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, ~0); 111179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, ~0); 112179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, ~0); 113179595Sbenno 114179595Sbenno mtx_init(&sc->pg_mtx, "GPIO mutex", NULL, MTX_SPIN); 115179595Sbenno 116179595Sbenno if (bus_setup_intr(dev, sc->pg_res[1], INTR_TYPE_MISC|INTR_MPSAFE, 117179595Sbenno pxa_gpio_intr0, NULL, sc, &ihl) != 0) { 118179595Sbenno bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); 119179595Sbenno device_printf(dev, "could not set up intr0\n"); 120179595Sbenno return (ENXIO); 121179595Sbenno } 122179595Sbenno 123179595Sbenno if (bus_setup_intr(dev, sc->pg_res[2], INTR_TYPE_MISC|INTR_MPSAFE, 124179595Sbenno pxa_gpio_intr1, NULL, sc, &ihl) != 0) { 125179595Sbenno bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); 126179595Sbenno device_printf(dev, "could not set up intr1\n"); 127179595Sbenno return (ENXIO); 128179595Sbenno } 129179595Sbenno 130179595Sbenno if (bus_setup_intr(dev, sc->pg_res[3], INTR_TYPE_MISC|INTR_MPSAFE, 131179595Sbenno pxa_gpio_intrN, NULL, sc, &ihl) != 0) { 132179595Sbenno bus_release_resources(dev, pxa_gpio_spec, sc->pg_res); 133179595Sbenno device_printf(dev, "could not set up intrN\n"); 134179595Sbenno return (ENXIO); 135179595Sbenno } 136179595Sbenno 137179595Sbenno return (0); 138179595Sbenno} 139179595Sbenno 140179595Sbennostatic int 141179595Sbennopxa_gpio_intr0(void *arg) 142179595Sbenno{ 143179595Sbenno struct pxa_gpio_softc *sc; 144179595Sbenno 145179595Sbenno sc = (struct pxa_gpio_softc *)arg; 146179595Sbenno 147179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x1); 148179595Sbenno sc->pg_intr[0] |= 1; 149179595Sbenno 150179595Sbenno return (FILTER_HANDLED); 151179595Sbenno} 152179595Sbenno 153179595Sbennostatic int 154179595Sbennopxa_gpio_intr1(void *arg) 155179595Sbenno{ 156179595Sbenno struct pxa_gpio_softc *sc; 157179595Sbenno 158179595Sbenno sc = (struct pxa_gpio_softc *)arg; 159179595Sbenno 160179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, 0x2); 161179595Sbenno sc->pg_intr[1] |= 2; 162179595Sbenno 163179595Sbenno return (FILTER_HANDLED); 164179595Sbenno} 165179595Sbenno 166179595Sbennostatic int 167179595Sbennopxa_gpio_intrN(void *arg) 168179595Sbenno{ 169179595Sbenno uint32_t gedr0, gedr1, gedr2; 170179595Sbenno struct pxa_gpio_softc *sc; 171179595Sbenno 172179595Sbenno sc = (struct pxa_gpio_softc *)arg; 173179595Sbenno 174179595Sbenno gedr0 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0); 175179595Sbenno gedr0 &= 0xfffffffc; 176179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR0, gedr0); 177179595Sbenno 178179595Sbenno gedr1 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1); 179179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR1, gedr1); 180179595Sbenno 181179595Sbenno gedr2 = bus_space_read_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2); 182179595Sbenno gedr2 &= 0x001fffff; 183179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, GPIO_GEDR2, gedr2); 184179595Sbenno 185179595Sbenno sc->pg_intr[0] |= gedr0; 186179595Sbenno sc->pg_intr[1] |= gedr1; 187179595Sbenno sc->pg_intr[2] |= gedr2; 188179595Sbenno 189179595Sbenno return (FILTER_HANDLED); 190179595Sbenno} 191179595Sbenno 192179595Sbennostatic device_method_t pxa_gpio_methods[] = { 193179595Sbenno DEVMETHOD(device_probe, pxa_gpio_probe), 194179595Sbenno DEVMETHOD(device_attach, pxa_gpio_attach), 195179595Sbenno 196179595Sbenno {0, 0} 197179595Sbenno}; 198179595Sbenno 199179595Sbennostatic driver_t pxa_gpio_driver = { 200179595Sbenno "gpio", 201179595Sbenno pxa_gpio_methods, 202179595Sbenno sizeof(struct pxa_gpio_softc), 203179595Sbenno}; 204179595Sbenno 205179595Sbennostatic devclass_t pxa_gpio_devclass; 206179595Sbenno 207179595SbennoDRIVER_MODULE(pxagpio, pxa, pxa_gpio_driver, pxa_gpio_devclass, 0, 0); 208179595Sbenno 209179595Sbenno#define pxagpio_reg_read(softc, reg) \ 210179595Sbenno bus_space_read_4(sc->pg_bst, sc->pg_bsh, reg) 211179595Sbenno#define pxagpio_reg_write(softc, reg, val) \ 212179595Sbenno bus_space_write_4(sc->pg_bst, sc->pg_bsh, reg, val) 213179595Sbenno 214179595Sbennouint32_t 215179595Sbennopxa_gpio_get_function(int gpio) 216179595Sbenno{ 217179595Sbenno struct pxa_gpio_softc *sc; 218179595Sbenno uint32_t rv, io; 219179595Sbenno 220179595Sbenno sc = pxa_gpio_softc; 221179595Sbenno 222179595Sbenno rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) >> GPIO_FN_SHIFT(gpio); 223179595Sbenno rv = GPIO_FN(rv); 224179595Sbenno 225179595Sbenno io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)); 226179595Sbenno if (io & GPIO_BIT(gpio)) 227179595Sbenno rv |= GPIO_OUT; 228179595Sbenno 229179595Sbenno io = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPLR0, gpio)); 230179595Sbenno if (io & GPIO_BIT(gpio)) 231179595Sbenno rv |= GPIO_SET; 232179595Sbenno 233179595Sbenno return (rv); 234179595Sbenno} 235179595Sbenno 236179595Sbennouint32_t 237179595Sbennopxa_gpio_set_function(int gpio, uint32_t fn) 238179595Sbenno{ 239179595Sbenno struct pxa_gpio_softc *sc; 240179595Sbenno uint32_t rv, bit, oldfn; 241179595Sbenno 242179595Sbenno sc = pxa_gpio_softc; 243179595Sbenno 244179595Sbenno oldfn = pxa_gpio_get_function(gpio); 245179595Sbenno 246179595Sbenno if (GPIO_FN(fn) == GPIO_FN(oldfn) && 247179595Sbenno GPIO_FN_IS_OUT(fn) == GPIO_FN_IS_OUT(oldfn)) { 248179595Sbenno /* 249179595Sbenno * The pin's function is not changing. 250179595Sbenno * For Alternate Functions and GPIO input, we can just 251179595Sbenno * return now. 252179595Sbenno * For GPIO output pins, check the initial state is 253179595Sbenno * the same. 254179595Sbenno * 255179595Sbenno * Return 'fn' instead of 'oldfn' so the caller can 256179595Sbenno * reliably detect that we didn't change anything. 257179595Sbenno * (The initial state might be different for non- 258179595Sbenno * GPIO output pins). 259179595Sbenno */ 260179595Sbenno if (!GPIO_IS_GPIO_OUT(fn) || 261179595Sbenno GPIO_FN_IS_SET(fn) == GPIO_FN_IS_SET(oldfn)) 262179595Sbenno return (fn); 263179595Sbenno } 264179595Sbenno 265179595Sbenno /* 266179595Sbenno * See section 4.1.3.7 of the PXA2x0 Developer's Manual for 267179595Sbenno * the correct procedure for changing GPIO pin functions. 268179595Sbenno */ 269179595Sbenno 270179595Sbenno bit = GPIO_BIT(gpio); 271179595Sbenno 272179595Sbenno /* 273179595Sbenno * 1. Configure the correct set/clear state of the pin 274179595Sbenno */ 275179595Sbenno if (GPIO_FN_IS_SET(fn)) 276179595Sbenno pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPSR0, gpio), bit); 277179595Sbenno else 278179595Sbenno pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPCR0, gpio), bit); 279179595Sbenno 280179595Sbenno /* 281179595Sbenno * 2. Configure the pin as an input or output as appropriate 282179595Sbenno */ 283179595Sbenno rv = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio)) & ~bit; 284179595Sbenno if (GPIO_FN_IS_OUT(fn)) 285179595Sbenno rv |= bit; 286179595Sbenno pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GPDR0, gpio), rv); 287179595Sbenno 288179595Sbenno /* 289179595Sbenno * 3. Configure the pin's function 290179595Sbenno */ 291179595Sbenno bit = GPIO_FN_MASK << GPIO_FN_SHIFT(gpio); 292179595Sbenno fn = GPIO_FN(fn) << GPIO_FN_SHIFT(gpio); 293179595Sbenno rv = pxagpio_reg_read(sc, GPIO_FN_REG(gpio)) & ~bit; 294179595Sbenno pxagpio_reg_write(sc, GPIO_FN_REG(gpio), rv | fn); 295179595Sbenno 296179595Sbenno return (oldfn); 297179595Sbenno} 298179595Sbenno 299179595Sbenno/* 300179595Sbenno * GPIO "interrupt" handling. 301179595Sbenno */ 302179595Sbenno 303179595Sbennovoid 304179595Sbennopxa_gpio_mask_irq(int irq) 305179595Sbenno{ 306179595Sbenno uint32_t val; 307179595Sbenno struct pxa_gpio_softc *sc; 308179595Sbenno int gpio; 309179595Sbenno 310179595Sbenno sc = pxa_gpio_softc; 311179595Sbenno gpio = IRQ_TO_GPIO(irq); 312179595Sbenno 313179595Sbenno val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); 314179595Sbenno val &= ~GPIO_BIT(gpio); 315179595Sbenno pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); 316179595Sbenno} 317179595Sbenno 318179595Sbennovoid 319179595Sbennopxa_gpio_unmask_irq(int irq) 320179595Sbenno{ 321179595Sbenno uint32_t val; 322179595Sbenno struct pxa_gpio_softc *sc; 323179595Sbenno int gpio; 324179595Sbenno 325179595Sbenno sc = pxa_gpio_softc; 326179595Sbenno gpio = IRQ_TO_GPIO(irq); 327179595Sbenno 328179595Sbenno val = pxagpio_reg_read(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio)); 329179595Sbenno val |= GPIO_BIT(gpio); 330179595Sbenno pxagpio_reg_write(sc, PXA250_GPIO_REG(GPIO_GRER0, gpio), val); 331179595Sbenno} 332179595Sbenno 333179595Sbennoint 334179595Sbennopxa_gpio_get_next_irq() 335179595Sbenno{ 336179595Sbenno struct pxa_gpio_softc *sc; 337179595Sbenno int gpio; 338179595Sbenno 339179595Sbenno sc = pxa_gpio_softc; 340179595Sbenno 341179595Sbenno if (sc->pg_intr[0] != 0) { 342179595Sbenno gpio = ffs(sc->pg_intr[0]) - 1; 343179595Sbenno sc->pg_intr[0] &= ~(1 << gpio); 344179595Sbenno return (GPIO_TO_IRQ(gpio)); 345179595Sbenno } 346179595Sbenno if (sc->pg_intr[1] != 0) { 347179595Sbenno gpio = ffs(sc->pg_intr[1]) - 1; 348179595Sbenno sc->pg_intr[1] &= ~(1 << gpio); 349179595Sbenno return (GPIO_TO_IRQ(gpio + 32)); 350179595Sbenno } 351179595Sbenno if (sc->pg_intr[2] != 0) { 352179595Sbenno gpio = ffs(sc->pg_intr[2]) - 1; 353179595Sbenno sc->pg_intr[2] &= ~(1 << gpio); 354179595Sbenno return (GPIO_TO_IRQ(gpio + 64)); 355179595Sbenno } 356179595Sbenno 357179595Sbenno return (-1); 358179595Sbenno} 359