at91_pio.c revision 249232
1157089Simp/*- 2157089Simp * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3248911Sian * Copyright (C) 2012 Ian Lepore. All rights reserved. 4157089Simp * 5157089Simp * Redistribution and use in source and binary forms, with or without 6157089Simp * modification, are permitted provided that the following conditions 7157089Simp * are met: 8157089Simp * 1. Redistributions of source code must retain the above copyright 9157089Simp * notice, this list of conditions and the following disclaimer. 10157089Simp * 2. Redistributions in binary form must reproduce the above copyright 11157089Simp * notice, this list of conditions and the following disclaimer in the 12157089Simp * documentation and/or other materials provided with the distribution. 13157089Simp * 14185265Simp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15185265Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16185265Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17185265Simp * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18185265Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19185265Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20185265Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21185265Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22185265Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23185265Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24185265Simp * SUCH DAMAGE. 25157089Simp */ 26157089Simp 27157089Simp#include <sys/cdefs.h> 28157089Simp__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pio.c 249232 2013-04-07 13:03:57Z hselasky $"); 29157089Simp 30157089Simp#include <sys/param.h> 31157089Simp#include <sys/systm.h> 32157089Simp#include <sys/bus.h> 33157089Simp#include <sys/conf.h> 34157089Simp#include <sys/kernel.h> 35157089Simp#include <sys/lock.h> 36157089Simp#include <sys/mbuf.h> 37157089Simp#include <sys/malloc.h> 38157089Simp#include <sys/module.h> 39248911Sian#include <sys/poll.h> 40157089Simp#include <sys/rman.h> 41248911Sian#include <sys/selinfo.h> 42248911Sian#include <sys/sx.h> 43248911Sian#include <sys/uio.h> 44248911Sian#include <machine/at91_gpio.h> 45157089Simp#include <machine/bus.h> 46157089Simp 47213496Scognet#include <arm/at91/at91reg.h> 48157089Simp#include <arm/at91/at91_pioreg.h> 49160072Simp#include <arm/at91/at91_piovar.h> 50157089Simp 51248911Sian#define MAX_CHANGE 64 52248911Sian 53157089Simpstruct at91_pio_softc 54157089Simp{ 55157089Simp device_t dev; /* Myself */ 56157089Simp void *intrhand; /* Interrupt handle */ 57157089Simp struct resource *irq_res; /* IRQ resource */ 58157089Simp struct resource *mem_res; /* Memory resource */ 59248911Sian struct sx sc_mtx; /* basically a perimeter lock */ 60157089Simp struct cdev *cdev; 61248911Sian struct selinfo selp; 62248911Sian int buflen; 63248911Sian uint8_t buf[MAX_CHANGE]; 64157089Simp int flags; 65234281Smarius#define OPENED 1 66157089Simp}; 67157089Simp 68157089Simpstatic inline uint32_t 69157089SimpRD4(struct at91_pio_softc *sc, bus_size_t off) 70157089Simp{ 71234281Smarius 72213496Scognet return (bus_read_4(sc->mem_res, off)); 73157089Simp} 74157089Simp 75157089Simpstatic inline void 76157089SimpWR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val) 77157089Simp{ 78234281Smarius 79157089Simp bus_write_4(sc->mem_res, off, val); 80157089Simp} 81157089Simp 82248911Sian#define AT91_PIO_LOCK(_sc) sx_xlock(&(_sc)->sc_mtx) 83248911Sian#define AT91_PIO_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_mtx) 84234281Smarius#define AT91_PIO_LOCK_INIT(_sc) \ 85248911Sian sx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev)) 86248911Sian#define AT91_PIO_LOCK_DESTROY(_sc) sx_destroy(&_sc->sc_mtx); 87248911Sian#define AT91_PIO_ASSERT_LOCKED(_sc) sx_assert(&_sc->sc_mtx, SA_XLOCKED); 88248911Sian#define AT91_PIO_ASSERT_UNLOCKED(_sc) sx_assert(&_sc->sc_mtx, SA_UNLOCKED); 89234281Smarius#define CDEV2SOFTC(dev) ((dev)->si_drv1) 90157089Simp 91157089Simpstatic devclass_t at91_pio_devclass; 92157089Simp 93157089Simp/* bus entry points */ 94157089Simp 95157089Simpstatic int at91_pio_probe(device_t dev); 96157089Simpstatic int at91_pio_attach(device_t dev); 97157089Simpstatic int at91_pio_detach(device_t dev); 98248911Sianstatic void at91_pio_intr(void *); 99157089Simp 100157089Simp/* helper routines */ 101157089Simpstatic int at91_pio_activate(device_t dev); 102157089Simpstatic void at91_pio_deactivate(device_t dev); 103157089Simp 104157089Simp/* cdev routines */ 105157089Simpstatic d_open_t at91_pio_open; 106157089Simpstatic d_close_t at91_pio_close; 107248911Sianstatic d_read_t at91_pio_read; 108248911Sianstatic d_poll_t at91_pio_poll; 109157089Simpstatic d_ioctl_t at91_pio_ioctl; 110157089Simp 111157089Simpstatic struct cdevsw at91_pio_cdevsw = 112157089Simp{ 113157089Simp .d_version = D_VERSION, 114157089Simp .d_open = at91_pio_open, 115157089Simp .d_close = at91_pio_close, 116248911Sian .d_read = at91_pio_read, 117248911Sian .d_poll = at91_pio_poll, 118157089Simp .d_ioctl = at91_pio_ioctl 119157089Simp}; 120157089Simp 121157089Simpstatic int 122157089Simpat91_pio_probe(device_t dev) 123157089Simp{ 124160072Simp const char *name; 125160072Simp 126160072Simp switch (device_get_unit(dev)) { 127160072Simp case 0: 128160072Simp name = "PIOA"; 129160072Simp break; 130160072Simp case 1: 131160072Simp name = "PIOB"; 132160072Simp break; 133160072Simp case 2: 134160072Simp name = "PIOC"; 135160072Simp break; 136160072Simp case 3: 137160072Simp name = "PIOD"; 138160072Simp break; 139160072Simp default: 140160072Simp name = "PIO"; 141160072Simp break; 142160072Simp } 143160072Simp device_set_desc(dev, name); 144157089Simp return (0); 145157089Simp} 146157089Simp 147157089Simpstatic int 148157089Simpat91_pio_attach(device_t dev) 149157089Simp{ 150234281Smarius struct at91_pio_softc *sc; 151157089Simp int err; 152157089Simp 153234281Smarius sc = device_get_softc(dev); 154157089Simp sc->dev = dev; 155157089Simp err = at91_pio_activate(dev); 156157089Simp if (err) 157157089Simp goto out; 158157089Simp 159237151Simp if (bootverbose) 160237151Simp device_printf(dev, "ABSR: %#x OSR: %#x PSR:%#x ODSR: %#x\n", 161237151Simp RD4(sc, PIO_ABSR), RD4(sc, PIO_OSR), RD4(sc, PIO_PSR), 162237151Simp RD4(sc, PIO_ODSR)); 163157089Simp AT91_PIO_LOCK_INIT(sc); 164157089Simp 165157089Simp /* 166234281Smarius * Activate the interrupt, but disable all interrupts in the hardware. 167157089Simp */ 168157089Simp WR4(sc, PIO_IDR, 0xffffffff); 169166901Spiso err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 170248911Sian NULL, at91_pio_intr, sc, &sc->intrhand); 171157089Simp if (err) { 172157089Simp AT91_PIO_LOCK_DESTROY(sc); 173157089Simp goto out; 174157089Simp } 175164745Simp sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT, 176164745Simp GID_WHEEL, 0600, "pio%d", device_get_unit(dev)); 177157089Simp if (sc->cdev == NULL) { 178157089Simp err = ENOMEM; 179157089Simp goto out; 180157089Simp } 181157089Simp sc->cdev->si_drv1 = sc; 182225882Skevloout: 183157089Simp if (err) 184157089Simp at91_pio_deactivate(dev); 185157089Simp return (err); 186157089Simp} 187157089Simp 188157089Simpstatic int 189157089Simpat91_pio_detach(device_t dev) 190157089Simp{ 191234281Smarius 192157089Simp return (EBUSY); /* XXX */ 193157089Simp} 194157089Simp 195157089Simpstatic int 196157089Simpat91_pio_activate(device_t dev) 197157089Simp{ 198157089Simp struct at91_pio_softc *sc; 199157089Simp int rid; 200157089Simp 201157089Simp sc = device_get_softc(dev); 202157089Simp rid = 0; 203157089Simp sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 204157089Simp RF_ACTIVE); 205157089Simp if (sc->mem_res == NULL) 206157089Simp goto errout; 207157089Simp rid = 0; 208157089Simp sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 209157089Simp RF_ACTIVE | RF_SHAREABLE); 210157089Simp if (sc->irq_res == NULL) 211157089Simp goto errout; 212157089Simp return (0); 213157089Simperrout: 214157089Simp at91_pio_deactivate(dev); 215157089Simp return (ENOMEM); 216157089Simp} 217157089Simp 218157089Simpstatic void 219157089Simpat91_pio_deactivate(device_t dev) 220157089Simp{ 221157089Simp struct at91_pio_softc *sc; 222157089Simp 223157089Simp sc = device_get_softc(dev); 224157089Simp if (sc->intrhand) 225157089Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 226157089Simp sc->intrhand = 0; 227157089Simp bus_generic_detach(sc->dev); 228157089Simp if (sc->mem_res) 229248911Sian bus_release_resource(dev, SYS_RES_MEMORY, 230157089Simp rman_get_rid(sc->mem_res), sc->mem_res); 231157089Simp sc->mem_res = 0; 232157089Simp if (sc->irq_res) 233157089Simp bus_release_resource(dev, SYS_RES_IRQ, 234157089Simp rman_get_rid(sc->irq_res), sc->irq_res); 235157089Simp sc->irq_res = 0; 236157089Simp} 237157089Simp 238248911Sianstatic void 239157089Simpat91_pio_intr(void *xsc) 240157089Simp{ 241157089Simp struct at91_pio_softc *sc = xsc; 242157089Simp uint32_t status; 243248911Sian int i; 244157089Simp 245234281Smarius /* Reading the status also clears the interrupt. */ 246248911Sian status = RD4(sc, PIO_ISR) & RD4(sc, PIO_IMR); 247248911Sian if (status != 0) { 248248911Sian AT91_PIO_LOCK(sc); 249248911Sian for (i = 0; status != 0 && sc->buflen < MAX_CHANGE; ++i) { 250248911Sian if (status & 1) 251248911Sian sc->buf[sc->buflen++] = (uint8_t)i; 252248911Sian status >>= 1; 253248911Sian } 254248911Sian AT91_PIO_UNLOCK(sc); 255248911Sian wakeup(sc); 256248911Sian selwakeup(&sc->selp); 257248911Sian } 258157089Simp} 259157089Simp 260234281Smariusstatic int 261157089Simpat91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 262157089Simp{ 263157089Simp struct at91_pio_softc *sc; 264157089Simp 265157089Simp sc = CDEV2SOFTC(dev); 266157089Simp AT91_PIO_LOCK(sc); 267157089Simp if (!(sc->flags & OPENED)) { 268157089Simp sc->flags |= OPENED; 269157089Simp } 270157089Simp AT91_PIO_UNLOCK(sc); 271234281Smarius return (0); 272157089Simp} 273157089Simp 274157089Simpstatic int 275157089Simpat91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 276157089Simp{ 277157089Simp struct at91_pio_softc *sc; 278157089Simp 279157089Simp sc = CDEV2SOFTC(dev); 280157089Simp AT91_PIO_LOCK(sc); 281157089Simp sc->flags &= ~OPENED; 282157089Simp AT91_PIO_UNLOCK(sc); 283157089Simp return (0); 284157089Simp} 285157089Simp 286157089Simpstatic int 287248911Sianat91_pio_poll(struct cdev *dev, int events, struct thread *td) 288248911Sian{ 289248911Sian struct at91_pio_softc *sc; 290248911Sian int revents = 0; 291248911Sian 292248911Sian sc = CDEV2SOFTC(dev); 293248911Sian AT91_PIO_LOCK(sc); 294248911Sian if (events & (POLLIN | POLLRDNORM)) { 295248911Sian if (sc->buflen != 0) 296248911Sian revents |= events & (POLLIN | POLLRDNORM); 297248911Sian else 298248911Sian selrecord(td, &sc->selp); 299248911Sian } 300248911Sian AT91_PIO_UNLOCK(sc); 301248911Sian 302248911Sian return (revents); 303248911Sian} 304248911Sian 305248911Sianstatic int 306248911Sianat91_pio_read(struct cdev *dev, struct uio *uio, int flag) 307248911Sian{ 308248911Sian struct at91_pio_softc *sc; 309248911Sian int err, ret, len; 310248911Sian 311248911Sian sc = CDEV2SOFTC(dev); 312248911Sian AT91_PIO_LOCK(sc); 313248911Sian err = 0; 314248911Sian ret = 0; 315248911Sian while (uio->uio_resid) { 316248911Sian while (sc->buflen == 0 && err == 0) 317248911Sian err = msleep(sc, &sc->sc_mtx, PCATCH | PZERO, "prd", 0); 318248911Sian if (err != 0) 319248911Sian break; 320248911Sian len = MIN(sc->buflen, uio->uio_resid); 321248911Sian err = uiomove(sc->buf, len, uio); 322248911Sian if (err != 0) 323248911Sian break; 324248911Sian /* 325248911Sian * If we read the whole thing no datacopy is needed, 326248911Sian * otherwise we move the data down. 327248911Sian */ 328248911Sian ret += len; 329248911Sian if (sc->buflen == len) 330248911Sian sc->buflen = 0; 331248911Sian else { 332248911Sian bcopy(sc->buf + len, sc->buf, sc->buflen - len); 333248911Sian sc->buflen -= len; 334248911Sian } 335248911Sian /* If there's no data left, end the read. */ 336248911Sian if (sc->buflen == 0) 337248911Sian break; 338248911Sian } 339248911Sian AT91_PIO_UNLOCK(sc); 340248911Sian return (err); 341248911Sian} 342248911Sian 343248911Sianstatic void 344248911Sianat91_pio_bang32(struct at91_pio_softc *sc, uint32_t bits, uint32_t datapin, 345248911Sian uint32_t clockpin) 346248911Sian{ 347248911Sian int i; 348248911Sian 349248911Sian for (i = 0; i < 32; i++) { 350248911Sian if (bits & 0x80000000) 351248911Sian WR4(sc, PIO_SODR, datapin); 352248911Sian else 353248911Sian WR4(sc, PIO_CODR, datapin); 354248911Sian bits <<= 1; 355248911Sian WR4(sc, PIO_CODR, clockpin); 356248911Sian WR4(sc, PIO_SODR, clockpin); 357248911Sian } 358248911Sian} 359248911Sian 360248911Sianstatic void 361248911Sianat91_pio_bang(struct at91_pio_softc *sc, uint8_t bits, uint32_t bitcount, 362248911Sian uint32_t datapin, uint32_t clockpin) 363248911Sian{ 364248911Sian int i; 365248911Sian 366248911Sian for (i = 0; i < bitcount; i++) { 367248911Sian if (bits & 0x80) 368248911Sian WR4(sc, PIO_SODR, datapin); 369248911Sian else 370248911Sian WR4(sc, PIO_CODR, datapin); 371248911Sian bits <<= 1; 372248911Sian WR4(sc, PIO_CODR, clockpin); 373248911Sian WR4(sc, PIO_SODR, clockpin); 374248911Sian } 375248911Sian} 376248911Sian 377248911Sianstatic int 378157089Simpat91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 379157089Simp struct thread *td) 380157089Simp{ 381248911Sian struct at91_pio_softc *sc; 382248911Sian struct at91_gpio_cfg *cfg; 383248911Sian struct at91_gpio_info *info; 384248911Sian struct at91_gpio_bang *bang; 385248911Sian struct at91_gpio_bang_many *bangmany; 386248911Sian uint32_t i, num; 387248911Sian uint8_t many[1024], *walker; 388248911Sian int err; 389248911Sian int bitcount; 390234281Smarius 391248911Sian sc = CDEV2SOFTC(dev); 392248911Sian switch(cmd) { 393248911Sian case AT91_GPIO_SET: /* turn bits on */ 394248911Sian WR4(sc, PIO_SODR, *(uint32_t *)data); 395248911Sian return (0); 396248911Sian case AT91_GPIO_CLR: /* turn bits off */ 397248911Sian WR4(sc, PIO_CODR, *(uint32_t *)data); 398248911Sian return (0); 399248911Sian case AT91_GPIO_READ: /* Get the status of input bits */ 400248911Sian *(uint32_t *)data = RD4(sc, PIO_PDSR); 401248911Sian return (0); 402248911Sian case AT91_GPIO_CFG: /* Configure AT91_GPIO pins */ 403248911Sian cfg = (struct at91_gpio_cfg *)data; 404248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_INPUT) { 405248911Sian WR4(sc, PIO_OER, cfg->iomask & ~cfg->input); 406248911Sian WR4(sc, PIO_ODR, cfg->iomask & cfg->input); 407248911Sian } 408248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_HI_Z) { 409248911Sian WR4(sc, PIO_MDDR, cfg->iomask & ~cfg->hi_z); 410248911Sian WR4(sc, PIO_MDER, cfg->iomask & cfg->hi_z); 411248911Sian } 412248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_PULLUP) { 413248911Sian WR4(sc, PIO_PUDR, cfg->iomask & ~cfg->pullup); 414248911Sian WR4(sc, PIO_PUER, cfg->iomask & cfg->pullup); 415248911Sian } 416248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_GLITCH) { 417248911Sian WR4(sc, PIO_IFDR, cfg->iomask & ~cfg->glitch); 418248911Sian WR4(sc, PIO_IFER, cfg->iomask & cfg->glitch); 419248911Sian } 420248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_GPIO) { 421248911Sian WR4(sc, PIO_PDR, cfg->iomask & ~cfg->gpio); 422248911Sian WR4(sc, PIO_PER, cfg->iomask & cfg->gpio); 423248911Sian } 424248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_PERIPH) { 425248911Sian WR4(sc, PIO_ASR, cfg->iomask & ~cfg->periph); 426248911Sian WR4(sc, PIO_BSR, cfg->iomask & cfg->periph); 427248911Sian } 428248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_INTR) { 429248911Sian WR4(sc, PIO_IDR, cfg->iomask & ~cfg->intr); 430248911Sian WR4(sc, PIO_IER, cfg->iomask & cfg->intr); 431248911Sian } 432248911Sian return (0); 433248911Sian case AT91_GPIO_BANG: 434248911Sian bang = (struct at91_gpio_bang *)data; 435248911Sian at91_pio_bang32(sc, bang->bits, bang->datapin, bang->clockpin); 436248911Sian return (0); 437248911Sian case AT91_GPIO_BANG_MANY: 438248911Sian bangmany = (struct at91_gpio_bang_many *)data; 439248911Sian walker = (uint8_t *)bangmany->bits; 440248911Sian bitcount = bangmany->numbits; 441248911Sian while (bitcount > 0) { 442248911Sian num = MIN((bitcount + 7) / 8, sizeof(many)); 443248911Sian err = copyin(walker, many, num); 444248911Sian if (err) 445248911Sian return err; 446248911Sian for (i = 0; i < num && bitcount > 0; i++, bitcount -= 8) 447248911Sian if (bitcount >= 8) 448248911Sian at91_pio_bang(sc, many[i], 8, bangmany->datapin, bangmany->clockpin); 449248911Sian else 450248911Sian at91_pio_bang(sc, many[i], bitcount, bangmany->datapin, bangmany->clockpin); 451248911Sian walker += num; 452248911Sian } 453248911Sian return (0); 454248911Sian case AT91_GPIO_INFO: /* Learn about this device's AT91_GPIO bits */ 455248911Sian info = (struct at91_gpio_info *)data; 456248911Sian info->output_status = RD4(sc, PIO_ODSR); 457248911Sian info->input_status = RD4(sc, PIO_OSR); 458248911Sian info->highz_status = RD4(sc, PIO_MDSR); 459248911Sian info->pullup_status = RD4(sc, PIO_PUSR); 460248911Sian info->glitch_status = RD4(sc, PIO_IFSR); 461248911Sian info->enabled_status = RD4(sc, PIO_PSR); 462248911Sian info->periph_status = RD4(sc, PIO_ABSR); 463248911Sian info->intr_status = RD4(sc, PIO_IMR); 464248911Sian memset(info->extra_status, 0, sizeof(info->extra_status)); 465248911Sian return (0); 466248911Sian } 467248911Sian return (ENOTTY); 468157089Simp} 469157089Simp 470160072Simp/* 471160072Simp * The following functions are called early in the boot process, so 472160072Simp * don't use bus_space, as that isn't yet available when we need to use 473160072Simp * them. 474160072Simp */ 475234281Smarius 476160072Simpvoid 477160363Simpat91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup) 478160072Simp{ 479213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 480160072Simp 481160072Simp PIO[PIO_ASR / 4] = periph_a_mask; 482160072Simp PIO[PIO_PDR / 4] = periph_a_mask; 483160363Simp if (use_pullup) 484160363Simp PIO[PIO_PUER / 4] = periph_a_mask; 485160363Simp else 486160363Simp PIO[PIO_PUDR / 4] = periph_a_mask; 487160072Simp} 488160072Simp 489160072Simpvoid 490160363Simpat91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup) 491160072Simp{ 492213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 493160072Simp 494160072Simp PIO[PIO_BSR / 4] = periph_b_mask; 495160072Simp PIO[PIO_PDR / 4] = periph_b_mask; 496160363Simp if (use_pullup) 497160363Simp PIO[PIO_PUER / 4] = periph_b_mask; 498160363Simp else 499160363Simp PIO[PIO_PUDR / 4] = periph_b_mask; 500160072Simp} 501160072Simp 502160072Simpvoid 503160072Simpat91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) 504160072Simp{ 505213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 506160072Simp 507160072Simp PIO[PIO_PER / 4] = gpio_mask; 508160072Simp} 509160072Simp 510160072Simpvoid 511160072Simpat91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) 512160072Simp{ 513213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 514160072Simp 515160072Simp PIO[PIO_ODR / 4] = input_enable_mask; 516160072Simp} 517160072Simp 518160072Simpvoid 519160363Simpat91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup) 520160072Simp{ 521213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 522160072Simp 523160072Simp PIO[PIO_OER / 4] = output_enable_mask; 524160363Simp if (use_pullup) 525160363Simp PIO[PIO_PUER / 4] = output_enable_mask; 526160363Simp else 527160363Simp PIO[PIO_PUDR / 4] = output_enable_mask; 528160072Simp} 529160072Simp 530160072Simpvoid 531248911Sianat91_pio_gpio_high_z(uint32_t pio, uint32_t high_z_mask, int enable) 532248911Sian{ 533248911Sian uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 534248911Sian 535248911Sian if (enable) 536248911Sian PIO[PIO_MDER / 4] = high_z_mask; 537248911Sian else 538248911Sian PIO[PIO_MDDR / 4] = high_z_mask; 539248911Sian} 540248911Sian 541248911Sianvoid 542160072Simpat91_pio_gpio_set(uint32_t pio, uint32_t data_mask) 543160072Simp{ 544213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 545160072Simp 546160072Simp PIO[PIO_SODR / 4] = data_mask; 547160072Simp} 548160072Simp 549160072Simpvoid 550160072Simpat91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) 551160072Simp{ 552213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 553160072Simp 554160072Simp PIO[PIO_CODR / 4] = data_mask; 555160072Simp} 556160072Simp 557249232Shselaskyuint32_t 558181884Simpat91_pio_gpio_get(uint32_t pio, uint32_t data_mask) 559181884Simp{ 560213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 561181884Simp 562249232Shselasky return (PIO[PIO_PDSR / 4] & data_mask); 563181884Simp} 564181884Simp 565181884Simpvoid 566181884Simpat91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch) 567181884Simp{ 568213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 569181884Simp 570181884Simp if (use_deglitch) 571181884Simp PIO[PIO_IFER / 4] = data_mask; 572181884Simp else 573181884Simp PIO[PIO_IFDR / 4] = data_mask; 574181884Simp} 575181884Simp 576181884Simpvoid 577234281Smariusat91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, 578181884Simp int enable_interrupt) 579181884Simp{ 580213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 581181884Simp 582181884Simp if (enable_interrupt) 583181884Simp PIO[PIO_IER / 4] = data_mask; 584181884Simp else 585181884Simp PIO[PIO_IDR / 4] = data_mask; 586181884Simp} 587181884Simp 588181884Simpuint32_t 589181884Simpat91_pio_gpio_clear_interrupt(uint32_t pio) 590181884Simp{ 591213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 592234281Smarius 593234281Smarius /* Reading this register will clear the interrupts. */ 594181884Simp return (PIO[PIO_ISR / 4]); 595181884Simp} 596181884Simp 597157089Simpstatic device_method_t at91_pio_methods[] = { 598157089Simp /* Device interface */ 599157089Simp DEVMETHOD(device_probe, at91_pio_probe), 600157089Simp DEVMETHOD(device_attach, at91_pio_attach), 601157089Simp DEVMETHOD(device_detach, at91_pio_detach), 602157089Simp 603234281Smarius DEVMETHOD_END 604157089Simp}; 605157089Simp 606157089Simpstatic driver_t at91_pio_driver = { 607157089Simp "at91_pio", 608157089Simp at91_pio_methods, 609157089Simp sizeof(struct at91_pio_softc), 610157089Simp}; 611157089Simp 612234281SmariusDRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, NULL, 613234281Smarius NULL); 614