at91_pio.c revision 160072
1157089Simp/*- 2157089Simp * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3157089Simp * 4157089Simp * Redistribution and use in source and binary forms, with or without 5157089Simp * modification, are permitted provided that the following conditions 6157089Simp * are met: 7157089Simp * 1. Redistributions of source code must retain the above copyright 8157089Simp * notice, this list of conditions and the following disclaimer. 9157089Simp * 2. Redistributions in binary form must reproduce the above copyright 10157089Simp * notice, this list of conditions and the following disclaimer in the 11157089Simp * documentation and/or other materials provided with the distribution. 12157089Simp * 13157089Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14157089Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15157089Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16157089Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17157089Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18157089Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19157089Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20157089Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21157089Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22157089Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23157089Simp */ 24157089Simp 25157089Simp#include <sys/cdefs.h> 26157089Simp__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pio.c 160072 2006-07-02 03:50:44Z imp $"); 27157089Simp 28157089Simp#include <sys/param.h> 29157089Simp#include <sys/systm.h> 30157089Simp#include <sys/bus.h> 31157089Simp#include <sys/conf.h> 32157089Simp#include <sys/kernel.h> 33157089Simp#include <sys/lock.h> 34157089Simp#include <sys/mbuf.h> 35157089Simp#include <sys/malloc.h> 36157089Simp#include <sys/module.h> 37157089Simp#include <sys/mutex.h> 38157089Simp#include <sys/rman.h> 39157089Simp#include <machine/bus.h> 40157089Simp 41160072Simp#include <arm/at91/at91rm92reg.h> 42157089Simp#include <arm/at91/at91_pioreg.h> 43160072Simp#include <arm/at91/at91_piovar.h> 44157089Simp 45157089Simpstruct at91_pio_softc 46157089Simp{ 47157089Simp device_t dev; /* Myself */ 48157089Simp void *intrhand; /* Interrupt handle */ 49157089Simp struct resource *irq_res; /* IRQ resource */ 50157089Simp struct resource *mem_res; /* Memory resource */ 51157089Simp struct mtx sc_mtx; /* basically a perimeter lock */ 52157089Simp struct cdev *cdev; 53157089Simp int flags; 54157089Simp#define OPENED 1 55157089Simp}; 56157089Simp 57157089Simpstatic inline uint32_t 58157089SimpRD4(struct at91_pio_softc *sc, bus_size_t off) 59157089Simp{ 60157089Simp return bus_read_4(sc->mem_res, off); 61157089Simp} 62157089Simp 63157089Simpstatic inline void 64157089SimpWR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val) 65157089Simp{ 66157089Simp bus_write_4(sc->mem_res, off, val); 67157089Simp} 68157089Simp 69157089Simp#define AT91_PIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) 70157089Simp#define AT91_PIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) 71157089Simp#define AT91_PIO_LOCK_INIT(_sc) \ 72157089Simp mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 73157089Simp "pio", MTX_SPIN) 74157089Simp#define AT91_PIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 75157089Simp#define AT91_PIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 76157089Simp#define AT91_PIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 77157089Simp#define CDEV2SOFTC(dev) ((dev)->si_drv1) 78157089Simp 79157089Simpstatic devclass_t at91_pio_devclass; 80157089Simp 81157089Simp/* bus entry points */ 82157089Simp 83157089Simpstatic int at91_pio_probe(device_t dev); 84157089Simpstatic int at91_pio_attach(device_t dev); 85157089Simpstatic int at91_pio_detach(device_t dev); 86157089Simpstatic void at91_pio_intr(void *); 87157089Simp 88157089Simp/* helper routines */ 89157089Simpstatic int at91_pio_activate(device_t dev); 90157089Simpstatic void at91_pio_deactivate(device_t dev); 91157089Simp 92157089Simp/* cdev routines */ 93157089Simpstatic d_open_t at91_pio_open; 94157089Simpstatic d_close_t at91_pio_close; 95157089Simpstatic d_ioctl_t at91_pio_ioctl; 96157089Simp 97157089Simpstatic struct cdevsw at91_pio_cdevsw = 98157089Simp{ 99157089Simp .d_version = D_VERSION, 100157089Simp .d_open = at91_pio_open, 101157089Simp .d_close = at91_pio_close, 102157089Simp .d_ioctl = at91_pio_ioctl 103157089Simp}; 104157089Simp 105157089Simpstatic int 106157089Simpat91_pio_probe(device_t dev) 107157089Simp{ 108160072Simp const char *name; 109160072Simp 110160072Simp switch (device_get_unit(dev)) { 111160072Simp case 0: 112160072Simp name = "PIOA"; 113160072Simp break; 114160072Simp case 1: 115160072Simp name = "PIOB"; 116160072Simp break; 117160072Simp case 2: 118160072Simp name = "PIOC"; 119160072Simp break; 120160072Simp case 3: 121160072Simp name = "PIOD"; 122160072Simp break; 123160072Simp default: 124160072Simp name = "PIO"; 125160072Simp break; 126160072Simp } 127160072Simp device_set_desc(dev, name); 128157089Simp return (0); 129157089Simp} 130157089Simp 131157089Simpstatic int 132157089Simpat91_pio_attach(device_t dev) 133157089Simp{ 134157089Simp struct at91_pio_softc *sc = device_get_softc(dev); 135157089Simp int err; 136157089Simp 137157089Simp sc->dev = dev; 138157089Simp err = at91_pio_activate(dev); 139157089Simp if (err) 140157089Simp goto out; 141157089Simp 142160072Simp device_printf(dev, "ABSR: %#x OSR: %#x PSR:%#x ODSR: %#x\n", 143160072Simp RD4(sc, PIO_ABSR), RD4(sc, PIO_OSR), RD4(sc, PIO_PSR), 144160072Simp RD4(sc, PIO_ODSR)); 145157089Simp AT91_PIO_LOCK_INIT(sc); 146157089Simp 147157089Simp /* 148157089Simp * Activate the interrupt, but disable all interrupts in the hardware 149157089Simp */ 150157089Simp WR4(sc, PIO_IDR, 0xffffffff); 151157089Simp err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_FAST, 152157089Simp at91_pio_intr, sc, &sc->intrhand); 153157089Simp if (err) { 154157089Simp AT91_PIO_LOCK_DESTROY(sc); 155157089Simp goto out; 156157089Simp } 157157089Simp sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT 158157089Simp , GID_WHEEL, 0600, "pio%d", device_get_unit(dev)); 159157089Simp if (sc->cdev == NULL) { 160157089Simp err = ENOMEM; 161157089Simp goto out; 162157089Simp } 163157089Simp sc->cdev->si_drv1 = sc; 164157089Simpout:; 165157089Simp if (err) 166157089Simp at91_pio_deactivate(dev); 167157089Simp return (err); 168157089Simp} 169157089Simp 170157089Simpstatic int 171157089Simpat91_pio_detach(device_t dev) 172157089Simp{ 173157089Simp return (EBUSY); /* XXX */ 174157089Simp} 175157089Simp 176157089Simpstatic int 177157089Simpat91_pio_activate(device_t dev) 178157089Simp{ 179157089Simp struct at91_pio_softc *sc; 180157089Simp int rid; 181157089Simp 182157089Simp sc = device_get_softc(dev); 183157089Simp rid = 0; 184157089Simp sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 185157089Simp RF_ACTIVE); 186157089Simp if (sc->mem_res == NULL) 187157089Simp goto errout; 188157089Simp rid = 0; 189157089Simp sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 190157089Simp RF_ACTIVE | RF_SHAREABLE); 191157089Simp if (sc->irq_res == NULL) 192157089Simp goto errout; 193157089Simp return (0); 194157089Simperrout: 195157089Simp at91_pio_deactivate(dev); 196157089Simp return (ENOMEM); 197157089Simp} 198157089Simp 199157089Simpstatic void 200157089Simpat91_pio_deactivate(device_t dev) 201157089Simp{ 202157089Simp struct at91_pio_softc *sc; 203157089Simp 204157089Simp sc = device_get_softc(dev); 205157089Simp if (sc->intrhand) 206157089Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 207157089Simp sc->intrhand = 0; 208157089Simp bus_generic_detach(sc->dev); 209157089Simp if (sc->mem_res) 210157089Simp bus_release_resource(dev, SYS_RES_IOPORT, 211157089Simp rman_get_rid(sc->mem_res), sc->mem_res); 212157089Simp sc->mem_res = 0; 213157089Simp if (sc->irq_res) 214157089Simp bus_release_resource(dev, SYS_RES_IRQ, 215157089Simp rman_get_rid(sc->irq_res), sc->irq_res); 216157089Simp sc->irq_res = 0; 217157089Simp return; 218157089Simp} 219157089Simp 220157089Simpstatic void 221157089Simpat91_pio_intr(void *xsc) 222157089Simp{ 223157089Simp struct at91_pio_softc *sc = xsc; 224157089Simp#if 0 225157089Simp uint32_t status; 226157089Simp 227157089Simp /* Reading the status also clears the interrupt */ 228157089Simp status = RD4(sc, PIO_SR); 229157089Simp if (status == 0) 230157089Simp return; 231157089Simp AT91_PIO_LOCK(sc); 232157089Simp AT91_PIO_UNLOCK(sc); 233157089Simp#endif 234157089Simp wakeup(sc); 235157089Simp return; 236157089Simp} 237157089Simp 238157089Simpstatic int 239157089Simpat91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 240157089Simp{ 241157089Simp struct at91_pio_softc *sc; 242157089Simp 243157089Simp sc = CDEV2SOFTC(dev); 244157089Simp AT91_PIO_LOCK(sc); 245157089Simp if (!(sc->flags & OPENED)) { 246157089Simp sc->flags |= OPENED; 247157089Simp#if 0 248157089Simp // Enable interrupts 249157089Simp#endif 250157089Simp } 251157089Simp AT91_PIO_UNLOCK(sc); 252157089Simp return (0); 253157089Simp} 254157089Simp 255157089Simpstatic int 256157089Simpat91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 257157089Simp{ 258157089Simp struct at91_pio_softc *sc; 259157089Simp 260157089Simp sc = CDEV2SOFTC(dev); 261157089Simp AT91_PIO_LOCK(sc); 262157089Simp sc->flags &= ~OPENED; 263157089Simp#if 0 264157089Simp // Disable interrupts 265157089Simp#endif 266157089Simp AT91_PIO_UNLOCK(sc); 267157089Simp return (0); 268157089Simp} 269157089Simp 270157089Simpstatic int 271157089Simpat91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 272157089Simp struct thread *td) 273157089Simp{ 274157089Simp return (ENXIO); 275157089Simp} 276157089Simp 277160072Simp/* 278160072Simp * The following functions are called early in the boot process, so 279160072Simp * don't use bus_space, as that isn't yet available when we need to use 280160072Simp * them. 281160072Simp */ 282160072Simpvoid 283160072Simpat91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask) 284160072Simp{ 285160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 286160072Simp 287160072Simp PIO[PIO_ASR / 4] = periph_a_mask; 288160072Simp PIO[PIO_PDR / 4] = periph_a_mask; 289160072Simp} 290160072Simp 291160072Simpvoid 292160072Simpat91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask) 293160072Simp{ 294160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 295160072Simp 296160072Simp PIO[PIO_BSR / 4] = periph_b_mask; 297160072Simp PIO[PIO_PDR / 4] = periph_b_mask; 298160072Simp} 299160072Simp 300160072Simpvoid 301160072Simpat91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) 302160072Simp{ 303160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 304160072Simp 305160072Simp PIO[PIO_PER / 4] = gpio_mask; 306160072Simp} 307160072Simp 308160072Simpvoid 309160072Simpat91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) 310160072Simp{ 311160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 312160072Simp 313160072Simp PIO[PIO_ODR / 4] = input_enable_mask; 314160072Simp} 315160072Simp 316160072Simpvoid 317160072Simpat91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask) 318160072Simp{ 319160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 320160072Simp 321160072Simp PIO[PIO_OER / 4] = output_enable_mask; 322160072Simp} 323160072Simp 324160072Simpvoid 325160072Simpat91_pio_gpio_set(uint32_t pio, uint32_t data_mask) 326160072Simp{ 327160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 328160072Simp 329160072Simp PIO[PIO_SODR / 4] = data_mask; 330160072Simp} 331160072Simp 332160072Simpvoid 333160072Simpat91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) 334160072Simp{ 335160072Simp uint32_t *PIO = (uint32_t *)(AT91RM92_BASE + pio); 336160072Simp 337160072Simp PIO[PIO_CODR / 4] = data_mask; 338160072Simp} 339160072Simp 340157089Simpstatic device_method_t at91_pio_methods[] = { 341157089Simp /* Device interface */ 342157089Simp DEVMETHOD(device_probe, at91_pio_probe), 343157089Simp DEVMETHOD(device_attach, at91_pio_attach), 344157089Simp DEVMETHOD(device_detach, at91_pio_detach), 345157089Simp 346157089Simp { 0, 0 } 347157089Simp}; 348157089Simp 349157089Simpstatic driver_t at91_pio_driver = { 350157089Simp "at91_pio", 351157089Simp at91_pio_methods, 352157089Simp sizeof(struct at91_pio_softc), 353157089Simp}; 354157089Simp 355157089SimpDRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, 0, 0); 356