at91_pio.c revision 266196
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 27266196Sian#include "opt_platform.h" 28266196Sian 29157089Simp#include <sys/cdefs.h> 30157089Simp__FBSDID("$FreeBSD: stable/10/sys/arm/at91/at91_pio.c 266196 2014-05-15 21:21:47Z ian $"); 31157089Simp 32157089Simp#include <sys/param.h> 33157089Simp#include <sys/systm.h> 34157089Simp#include <sys/bus.h> 35157089Simp#include <sys/conf.h> 36157089Simp#include <sys/kernel.h> 37157089Simp#include <sys/lock.h> 38157089Simp#include <sys/mbuf.h> 39157089Simp#include <sys/malloc.h> 40157089Simp#include <sys/module.h> 41248911Sian#include <sys/poll.h> 42157089Simp#include <sys/rman.h> 43248911Sian#include <sys/selinfo.h> 44248911Sian#include <sys/sx.h> 45248911Sian#include <sys/uio.h> 46248911Sian#include <machine/at91_gpio.h> 47157089Simp#include <machine/bus.h> 48157089Simp 49213496Scognet#include <arm/at91/at91reg.h> 50157089Simp#include <arm/at91/at91_pioreg.h> 51160072Simp#include <arm/at91/at91_piovar.h> 52157089Simp 53266196Sian#ifdef FDT 54266196Sian#include <dev/fdt/fdt_common.h> 55266196Sian#include <dev/ofw/ofw_bus.h> 56266196Sian#include <dev/ofw/ofw_bus_subr.h> 57266196Sian#endif 58266196Sian 59248911Sian#define MAX_CHANGE 64 60248911Sian 61157089Simpstruct at91_pio_softc 62157089Simp{ 63157089Simp device_t dev; /* Myself */ 64157089Simp void *intrhand; /* Interrupt handle */ 65157089Simp struct resource *irq_res; /* IRQ resource */ 66157089Simp struct resource *mem_res; /* Memory resource */ 67248911Sian struct sx sc_mtx; /* basically a perimeter lock */ 68157089Simp struct cdev *cdev; 69248911Sian struct selinfo selp; 70248911Sian int buflen; 71248911Sian uint8_t buf[MAX_CHANGE]; 72157089Simp int flags; 73234281Smarius#define OPENED 1 74157089Simp}; 75157089Simp 76157089Simpstatic inline uint32_t 77157089SimpRD4(struct at91_pio_softc *sc, bus_size_t off) 78157089Simp{ 79234281Smarius 80213496Scognet return (bus_read_4(sc->mem_res, off)); 81157089Simp} 82157089Simp 83157089Simpstatic inline void 84157089SimpWR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val) 85157089Simp{ 86234281Smarius 87157089Simp bus_write_4(sc->mem_res, off, val); 88157089Simp} 89157089Simp 90248911Sian#define AT91_PIO_LOCK(_sc) sx_xlock(&(_sc)->sc_mtx) 91248911Sian#define AT91_PIO_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_mtx) 92234281Smarius#define AT91_PIO_LOCK_INIT(_sc) \ 93248911Sian sx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev)) 94248911Sian#define AT91_PIO_LOCK_DESTROY(_sc) sx_destroy(&_sc->sc_mtx); 95248911Sian#define AT91_PIO_ASSERT_LOCKED(_sc) sx_assert(&_sc->sc_mtx, SA_XLOCKED); 96248911Sian#define AT91_PIO_ASSERT_UNLOCKED(_sc) sx_assert(&_sc->sc_mtx, SA_UNLOCKED); 97234281Smarius#define CDEV2SOFTC(dev) ((dev)->si_drv1) 98157089Simp 99157089Simpstatic devclass_t at91_pio_devclass; 100157089Simp 101157089Simp/* bus entry points */ 102157089Simp 103157089Simpstatic int at91_pio_probe(device_t dev); 104157089Simpstatic int at91_pio_attach(device_t dev); 105157089Simpstatic int at91_pio_detach(device_t dev); 106248911Sianstatic void at91_pio_intr(void *); 107157089Simp 108157089Simp/* helper routines */ 109157089Simpstatic int at91_pio_activate(device_t dev); 110157089Simpstatic void at91_pio_deactivate(device_t dev); 111157089Simp 112157089Simp/* cdev routines */ 113157089Simpstatic d_open_t at91_pio_open; 114157089Simpstatic d_close_t at91_pio_close; 115248911Sianstatic d_read_t at91_pio_read; 116248911Sianstatic d_poll_t at91_pio_poll; 117157089Simpstatic d_ioctl_t at91_pio_ioctl; 118157089Simp 119157089Simpstatic struct cdevsw at91_pio_cdevsw = 120157089Simp{ 121157089Simp .d_version = D_VERSION, 122157089Simp .d_open = at91_pio_open, 123157089Simp .d_close = at91_pio_close, 124248911Sian .d_read = at91_pio_read, 125248911Sian .d_poll = at91_pio_poll, 126157089Simp .d_ioctl = at91_pio_ioctl 127157089Simp}; 128157089Simp 129157089Simpstatic int 130157089Simpat91_pio_probe(device_t dev) 131157089Simp{ 132160072Simp const char *name; 133266196Sian#ifdef FDT 134266196Sian if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-gpio")) 135266196Sian return (ENXIO); 136266196Sian#endif 137160072Simp switch (device_get_unit(dev)) { 138160072Simp case 0: 139160072Simp name = "PIOA"; 140160072Simp break; 141160072Simp case 1: 142160072Simp name = "PIOB"; 143160072Simp break; 144160072Simp case 2: 145160072Simp name = "PIOC"; 146160072Simp break; 147160072Simp case 3: 148160072Simp name = "PIOD"; 149160072Simp break; 150266196Sian case 4: 151266196Sian name = "PIOE"; 152266196Sian break; 153266196Sian case 5: 154266196Sian name = "PIOF"; 155266196Sian break; 156160072Simp default: 157160072Simp name = "PIO"; 158160072Simp break; 159160072Simp } 160160072Simp device_set_desc(dev, name); 161157089Simp return (0); 162157089Simp} 163157089Simp 164157089Simpstatic int 165157089Simpat91_pio_attach(device_t dev) 166157089Simp{ 167234281Smarius struct at91_pio_softc *sc; 168157089Simp int err; 169157089Simp 170234281Smarius sc = device_get_softc(dev); 171157089Simp sc->dev = dev; 172157089Simp err = at91_pio_activate(dev); 173157089Simp if (err) 174157089Simp goto out; 175157089Simp 176237151Simp if (bootverbose) 177237151Simp device_printf(dev, "ABSR: %#x OSR: %#x PSR:%#x ODSR: %#x\n", 178237151Simp RD4(sc, PIO_ABSR), RD4(sc, PIO_OSR), RD4(sc, PIO_PSR), 179237151Simp RD4(sc, PIO_ODSR)); 180157089Simp AT91_PIO_LOCK_INIT(sc); 181157089Simp 182157089Simp /* 183234281Smarius * Activate the interrupt, but disable all interrupts in the hardware. 184157089Simp */ 185157089Simp WR4(sc, PIO_IDR, 0xffffffff); 186166901Spiso err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 187248911Sian NULL, at91_pio_intr, sc, &sc->intrhand); 188157089Simp if (err) { 189157089Simp AT91_PIO_LOCK_DESTROY(sc); 190157089Simp goto out; 191157089Simp } 192164745Simp sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT, 193164745Simp GID_WHEEL, 0600, "pio%d", device_get_unit(dev)); 194157089Simp if (sc->cdev == NULL) { 195157089Simp err = ENOMEM; 196157089Simp goto out; 197157089Simp } 198157089Simp sc->cdev->si_drv1 = sc; 199225882Skevloout: 200157089Simp if (err) 201157089Simp at91_pio_deactivate(dev); 202157089Simp return (err); 203157089Simp} 204157089Simp 205157089Simpstatic int 206157089Simpat91_pio_detach(device_t dev) 207157089Simp{ 208234281Smarius 209157089Simp return (EBUSY); /* XXX */ 210157089Simp} 211157089Simp 212157089Simpstatic int 213157089Simpat91_pio_activate(device_t dev) 214157089Simp{ 215157089Simp struct at91_pio_softc *sc; 216157089Simp int rid; 217157089Simp 218157089Simp sc = device_get_softc(dev); 219157089Simp rid = 0; 220157089Simp sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 221157089Simp RF_ACTIVE); 222157089Simp if (sc->mem_res == NULL) 223157089Simp goto errout; 224157089Simp rid = 0; 225157089Simp sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 226157089Simp RF_ACTIVE | RF_SHAREABLE); 227157089Simp if (sc->irq_res == NULL) 228157089Simp goto errout; 229157089Simp return (0); 230157089Simperrout: 231157089Simp at91_pio_deactivate(dev); 232157089Simp return (ENOMEM); 233157089Simp} 234157089Simp 235157089Simpstatic void 236157089Simpat91_pio_deactivate(device_t dev) 237157089Simp{ 238157089Simp struct at91_pio_softc *sc; 239157089Simp 240157089Simp sc = device_get_softc(dev); 241157089Simp if (sc->intrhand) 242157089Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 243157089Simp sc->intrhand = 0; 244157089Simp bus_generic_detach(sc->dev); 245157089Simp if (sc->mem_res) 246248911Sian bus_release_resource(dev, SYS_RES_MEMORY, 247157089Simp rman_get_rid(sc->mem_res), sc->mem_res); 248157089Simp sc->mem_res = 0; 249157089Simp if (sc->irq_res) 250157089Simp bus_release_resource(dev, SYS_RES_IRQ, 251157089Simp rman_get_rid(sc->irq_res), sc->irq_res); 252157089Simp sc->irq_res = 0; 253157089Simp} 254157089Simp 255248911Sianstatic void 256157089Simpat91_pio_intr(void *xsc) 257157089Simp{ 258157089Simp struct at91_pio_softc *sc = xsc; 259157089Simp uint32_t status; 260248911Sian int i; 261157089Simp 262234281Smarius /* Reading the status also clears the interrupt. */ 263248911Sian status = RD4(sc, PIO_ISR) & RD4(sc, PIO_IMR); 264248911Sian if (status != 0) { 265248911Sian AT91_PIO_LOCK(sc); 266248911Sian for (i = 0; status != 0 && sc->buflen < MAX_CHANGE; ++i) { 267248911Sian if (status & 1) 268248911Sian sc->buf[sc->buflen++] = (uint8_t)i; 269248911Sian status >>= 1; 270248911Sian } 271248911Sian AT91_PIO_UNLOCK(sc); 272248911Sian wakeup(sc); 273248911Sian selwakeup(&sc->selp); 274248911Sian } 275157089Simp} 276157089Simp 277234281Smariusstatic int 278157089Simpat91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 279157089Simp{ 280157089Simp struct at91_pio_softc *sc; 281157089Simp 282157089Simp sc = CDEV2SOFTC(dev); 283157089Simp AT91_PIO_LOCK(sc); 284157089Simp if (!(sc->flags & OPENED)) { 285157089Simp sc->flags |= OPENED; 286157089Simp } 287157089Simp AT91_PIO_UNLOCK(sc); 288234281Smarius return (0); 289157089Simp} 290157089Simp 291157089Simpstatic int 292157089Simpat91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 293157089Simp{ 294157089Simp struct at91_pio_softc *sc; 295157089Simp 296157089Simp sc = CDEV2SOFTC(dev); 297157089Simp AT91_PIO_LOCK(sc); 298157089Simp sc->flags &= ~OPENED; 299157089Simp AT91_PIO_UNLOCK(sc); 300157089Simp return (0); 301157089Simp} 302157089Simp 303157089Simpstatic int 304248911Sianat91_pio_poll(struct cdev *dev, int events, struct thread *td) 305248911Sian{ 306248911Sian struct at91_pio_softc *sc; 307248911Sian int revents = 0; 308248911Sian 309248911Sian sc = CDEV2SOFTC(dev); 310248911Sian AT91_PIO_LOCK(sc); 311248911Sian if (events & (POLLIN | POLLRDNORM)) { 312248911Sian if (sc->buflen != 0) 313248911Sian revents |= events & (POLLIN | POLLRDNORM); 314248911Sian else 315248911Sian selrecord(td, &sc->selp); 316248911Sian } 317248911Sian AT91_PIO_UNLOCK(sc); 318248911Sian 319248911Sian return (revents); 320248911Sian} 321248911Sian 322248911Sianstatic int 323248911Sianat91_pio_read(struct cdev *dev, struct uio *uio, int flag) 324248911Sian{ 325248911Sian struct at91_pio_softc *sc; 326248911Sian int err, ret, len; 327248911Sian 328248911Sian sc = CDEV2SOFTC(dev); 329248911Sian AT91_PIO_LOCK(sc); 330248911Sian err = 0; 331248911Sian ret = 0; 332248911Sian while (uio->uio_resid) { 333248911Sian while (sc->buflen == 0 && err == 0) 334248911Sian err = msleep(sc, &sc->sc_mtx, PCATCH | PZERO, "prd", 0); 335248911Sian if (err != 0) 336248911Sian break; 337248911Sian len = MIN(sc->buflen, uio->uio_resid); 338248911Sian err = uiomove(sc->buf, len, uio); 339248911Sian if (err != 0) 340248911Sian break; 341248911Sian /* 342248911Sian * If we read the whole thing no datacopy is needed, 343248911Sian * otherwise we move the data down. 344248911Sian */ 345248911Sian ret += len; 346248911Sian if (sc->buflen == len) 347248911Sian sc->buflen = 0; 348248911Sian else { 349248911Sian bcopy(sc->buf + len, sc->buf, sc->buflen - len); 350248911Sian sc->buflen -= len; 351248911Sian } 352248911Sian /* If there's no data left, end the read. */ 353248911Sian if (sc->buflen == 0) 354248911Sian break; 355248911Sian } 356248911Sian AT91_PIO_UNLOCK(sc); 357248911Sian return (err); 358248911Sian} 359248911Sian 360248911Sianstatic void 361248911Sianat91_pio_bang32(struct at91_pio_softc *sc, uint32_t bits, uint32_t datapin, 362248911Sian uint32_t clockpin) 363248911Sian{ 364248911Sian int i; 365248911Sian 366248911Sian for (i = 0; i < 32; i++) { 367248911Sian if (bits & 0x80000000) 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 void 378248911Sianat91_pio_bang(struct at91_pio_softc *sc, uint8_t bits, uint32_t bitcount, 379248911Sian uint32_t datapin, uint32_t clockpin) 380248911Sian{ 381248911Sian int i; 382248911Sian 383248911Sian for (i = 0; i < bitcount; i++) { 384248911Sian if (bits & 0x80) 385248911Sian WR4(sc, PIO_SODR, datapin); 386248911Sian else 387248911Sian WR4(sc, PIO_CODR, datapin); 388248911Sian bits <<= 1; 389248911Sian WR4(sc, PIO_CODR, clockpin); 390248911Sian WR4(sc, PIO_SODR, clockpin); 391248911Sian } 392248911Sian} 393248911Sian 394248911Sianstatic int 395157089Simpat91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 396157089Simp struct thread *td) 397157089Simp{ 398248911Sian struct at91_pio_softc *sc; 399248911Sian struct at91_gpio_cfg *cfg; 400248911Sian struct at91_gpio_info *info; 401248911Sian struct at91_gpio_bang *bang; 402248911Sian struct at91_gpio_bang_many *bangmany; 403248911Sian uint32_t i, num; 404248911Sian uint8_t many[1024], *walker; 405248911Sian int err; 406248911Sian int bitcount; 407234281Smarius 408248911Sian sc = CDEV2SOFTC(dev); 409248911Sian switch(cmd) { 410248911Sian case AT91_GPIO_SET: /* turn bits on */ 411248911Sian WR4(sc, PIO_SODR, *(uint32_t *)data); 412248911Sian return (0); 413248911Sian case AT91_GPIO_CLR: /* turn bits off */ 414248911Sian WR4(sc, PIO_CODR, *(uint32_t *)data); 415248911Sian return (0); 416248911Sian case AT91_GPIO_READ: /* Get the status of input bits */ 417248911Sian *(uint32_t *)data = RD4(sc, PIO_PDSR); 418248911Sian return (0); 419248911Sian case AT91_GPIO_CFG: /* Configure AT91_GPIO pins */ 420248911Sian cfg = (struct at91_gpio_cfg *)data; 421248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_INPUT) { 422248911Sian WR4(sc, PIO_OER, cfg->iomask & ~cfg->input); 423248911Sian WR4(sc, PIO_ODR, cfg->iomask & cfg->input); 424248911Sian } 425248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_HI_Z) { 426248911Sian WR4(sc, PIO_MDDR, cfg->iomask & ~cfg->hi_z); 427248911Sian WR4(sc, PIO_MDER, cfg->iomask & cfg->hi_z); 428248911Sian } 429248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_PULLUP) { 430248911Sian WR4(sc, PIO_PUDR, cfg->iomask & ~cfg->pullup); 431248911Sian WR4(sc, PIO_PUER, cfg->iomask & cfg->pullup); 432248911Sian } 433248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_GLITCH) { 434248911Sian WR4(sc, PIO_IFDR, cfg->iomask & ~cfg->glitch); 435248911Sian WR4(sc, PIO_IFER, cfg->iomask & cfg->glitch); 436248911Sian } 437248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_GPIO) { 438248911Sian WR4(sc, PIO_PDR, cfg->iomask & ~cfg->gpio); 439248911Sian WR4(sc, PIO_PER, cfg->iomask & cfg->gpio); 440248911Sian } 441248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_PERIPH) { 442248911Sian WR4(sc, PIO_ASR, cfg->iomask & ~cfg->periph); 443248911Sian WR4(sc, PIO_BSR, cfg->iomask & cfg->periph); 444248911Sian } 445248911Sian if (cfg->cfgmask & AT91_GPIO_CFG_INTR) { 446248911Sian WR4(sc, PIO_IDR, cfg->iomask & ~cfg->intr); 447248911Sian WR4(sc, PIO_IER, cfg->iomask & cfg->intr); 448248911Sian } 449248911Sian return (0); 450248911Sian case AT91_GPIO_BANG: 451248911Sian bang = (struct at91_gpio_bang *)data; 452248911Sian at91_pio_bang32(sc, bang->bits, bang->datapin, bang->clockpin); 453248911Sian return (0); 454248911Sian case AT91_GPIO_BANG_MANY: 455248911Sian bangmany = (struct at91_gpio_bang_many *)data; 456248911Sian walker = (uint8_t *)bangmany->bits; 457248911Sian bitcount = bangmany->numbits; 458248911Sian while (bitcount > 0) { 459248911Sian num = MIN((bitcount + 7) / 8, sizeof(many)); 460248911Sian err = copyin(walker, many, num); 461248911Sian if (err) 462248911Sian return err; 463248911Sian for (i = 0; i < num && bitcount > 0; i++, bitcount -= 8) 464248911Sian if (bitcount >= 8) 465248911Sian at91_pio_bang(sc, many[i], 8, bangmany->datapin, bangmany->clockpin); 466248911Sian else 467248911Sian at91_pio_bang(sc, many[i], bitcount, bangmany->datapin, bangmany->clockpin); 468248911Sian walker += num; 469248911Sian } 470248911Sian return (0); 471248911Sian case AT91_GPIO_INFO: /* Learn about this device's AT91_GPIO bits */ 472248911Sian info = (struct at91_gpio_info *)data; 473248911Sian info->output_status = RD4(sc, PIO_ODSR); 474248911Sian info->input_status = RD4(sc, PIO_OSR); 475248911Sian info->highz_status = RD4(sc, PIO_MDSR); 476248911Sian info->pullup_status = RD4(sc, PIO_PUSR); 477248911Sian info->glitch_status = RD4(sc, PIO_IFSR); 478248911Sian info->enabled_status = RD4(sc, PIO_PSR); 479248911Sian info->periph_status = RD4(sc, PIO_ABSR); 480248911Sian info->intr_status = RD4(sc, PIO_IMR); 481248911Sian memset(info->extra_status, 0, sizeof(info->extra_status)); 482248911Sian return (0); 483248911Sian } 484248911Sian return (ENOTTY); 485157089Simp} 486157089Simp 487160072Simp/* 488160072Simp * The following functions are called early in the boot process, so 489160072Simp * don't use bus_space, as that isn't yet available when we need to use 490160072Simp * them. 491160072Simp */ 492234281Smarius 493160072Simpvoid 494160363Simpat91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup) 495160072Simp{ 496213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 497160072Simp 498160072Simp PIO[PIO_ASR / 4] = periph_a_mask; 499160072Simp PIO[PIO_PDR / 4] = periph_a_mask; 500160363Simp if (use_pullup) 501160363Simp PIO[PIO_PUER / 4] = periph_a_mask; 502160363Simp else 503160363Simp PIO[PIO_PUDR / 4] = periph_a_mask; 504160072Simp} 505160072Simp 506160072Simpvoid 507160363Simpat91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup) 508160072Simp{ 509213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 510160072Simp 511160072Simp PIO[PIO_BSR / 4] = periph_b_mask; 512160072Simp PIO[PIO_PDR / 4] = periph_b_mask; 513160363Simp if (use_pullup) 514160363Simp PIO[PIO_PUER / 4] = periph_b_mask; 515160363Simp else 516160363Simp PIO[PIO_PUDR / 4] = periph_b_mask; 517160072Simp} 518160072Simp 519160072Simpvoid 520160072Simpat91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) 521160072Simp{ 522213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 523160072Simp 524160072Simp PIO[PIO_PER / 4] = gpio_mask; 525160072Simp} 526160072Simp 527160072Simpvoid 528160072Simpat91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) 529160072Simp{ 530213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 531160072Simp 532160072Simp PIO[PIO_ODR / 4] = input_enable_mask; 533160072Simp} 534160072Simp 535160072Simpvoid 536160363Simpat91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup) 537160072Simp{ 538213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 539160072Simp 540160072Simp PIO[PIO_OER / 4] = output_enable_mask; 541160363Simp if (use_pullup) 542160363Simp PIO[PIO_PUER / 4] = output_enable_mask; 543160363Simp else 544160363Simp PIO[PIO_PUDR / 4] = output_enable_mask; 545160072Simp} 546160072Simp 547160072Simpvoid 548248911Sianat91_pio_gpio_high_z(uint32_t pio, uint32_t high_z_mask, int enable) 549248911Sian{ 550248911Sian uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 551248911Sian 552248911Sian if (enable) 553248911Sian PIO[PIO_MDER / 4] = high_z_mask; 554248911Sian else 555248911Sian PIO[PIO_MDDR / 4] = high_z_mask; 556248911Sian} 557248911Sian 558248911Sianvoid 559160072Simpat91_pio_gpio_set(uint32_t pio, uint32_t data_mask) 560160072Simp{ 561213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 562160072Simp 563160072Simp PIO[PIO_SODR / 4] = data_mask; 564160072Simp} 565160072Simp 566160072Simpvoid 567160072Simpat91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) 568160072Simp{ 569213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 570160072Simp 571160072Simp PIO[PIO_CODR / 4] = data_mask; 572160072Simp} 573160072Simp 574249232Shselaskyuint32_t 575181884Simpat91_pio_gpio_get(uint32_t pio, uint32_t data_mask) 576181884Simp{ 577213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 578181884Simp 579249232Shselasky return (PIO[PIO_PDSR / 4] & data_mask); 580181884Simp} 581181884Simp 582181884Simpvoid 583181884Simpat91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch) 584181884Simp{ 585213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 586181884Simp 587181884Simp if (use_deglitch) 588181884Simp PIO[PIO_IFER / 4] = data_mask; 589181884Simp else 590181884Simp PIO[PIO_IFDR / 4] = data_mask; 591181884Simp} 592181884Simp 593181884Simpvoid 594234281Smariusat91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, 595181884Simp int enable_interrupt) 596181884Simp{ 597213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 598181884Simp 599181884Simp if (enable_interrupt) 600181884Simp PIO[PIO_IER / 4] = data_mask; 601181884Simp else 602181884Simp PIO[PIO_IDR / 4] = data_mask; 603181884Simp} 604181884Simp 605181884Simpuint32_t 606181884Simpat91_pio_gpio_clear_interrupt(uint32_t pio) 607181884Simp{ 608213496Scognet uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 609234281Smarius 610234281Smarius /* Reading this register will clear the interrupts. */ 611181884Simp return (PIO[PIO_ISR / 4]); 612181884Simp} 613181884Simp 614157089Simpstatic device_method_t at91_pio_methods[] = { 615157089Simp /* Device interface */ 616157089Simp DEVMETHOD(device_probe, at91_pio_probe), 617157089Simp DEVMETHOD(device_attach, at91_pio_attach), 618157089Simp DEVMETHOD(device_detach, at91_pio_detach), 619157089Simp 620234281Smarius DEVMETHOD_END 621157089Simp}; 622157089Simp 623157089Simpstatic driver_t at91_pio_driver = { 624157089Simp "at91_pio", 625157089Simp at91_pio_methods, 626157089Simp sizeof(struct at91_pio_softc), 627157089Simp}; 628157089Simp 629266196Sian#ifdef FDT 630266196SianDRIVER_MODULE(at91_pio, simplebus, at91_pio_driver, at91_pio_devclass, NULL, 631266196Sian NULL); 632266196Sian#else 633234281SmariusDRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, NULL, 634234281Smarius NULL); 635266196Sian#endif 636