at91_pio.c revision 157089
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 157089 2006-03-24 07:39:29Z 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 41157089Simp#include <arm/at91/at91_pioreg.h> 42157089Simp 43157089Simpstruct at91_pio_softc 44157089Simp{ 45157089Simp device_t dev; /* Myself */ 46157089Simp void *intrhand; /* Interrupt handle */ 47157089Simp struct resource *irq_res; /* IRQ resource */ 48157089Simp struct resource *mem_res; /* Memory resource */ 49157089Simp struct mtx sc_mtx; /* basically a perimeter lock */ 50157089Simp struct cdev *cdev; 51157089Simp int flags; 52157089Simp#define OPENED 1 53157089Simp}; 54157089Simp 55157089Simpstatic inline uint32_t 56157089SimpRD4(struct at91_pio_softc *sc, bus_size_t off) 57157089Simp{ 58157089Simp return bus_read_4(sc->mem_res, off); 59157089Simp} 60157089Simp 61157089Simpstatic inline void 62157089SimpWR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val) 63157089Simp{ 64157089Simp bus_write_4(sc->mem_res, off, val); 65157089Simp} 66157089Simp 67157089Simp#define AT91_PIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) 68157089Simp#define AT91_PIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) 69157089Simp#define AT91_PIO_LOCK_INIT(_sc) \ 70157089Simp mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 71157089Simp "pio", MTX_SPIN) 72157089Simp#define AT91_PIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 73157089Simp#define AT91_PIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 74157089Simp#define AT91_PIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 75157089Simp#define CDEV2SOFTC(dev) ((dev)->si_drv1) 76157089Simp 77157089Simpstatic devclass_t at91_pio_devclass; 78157089Simp 79157089Simp/* bus entry points */ 80157089Simp 81157089Simpstatic int at91_pio_probe(device_t dev); 82157089Simpstatic int at91_pio_attach(device_t dev); 83157089Simpstatic int at91_pio_detach(device_t dev); 84157089Simpstatic void at91_pio_intr(void *); 85157089Simp 86157089Simp/* helper routines */ 87157089Simpstatic int at91_pio_activate(device_t dev); 88157089Simpstatic void at91_pio_deactivate(device_t dev); 89157089Simp 90157089Simp/* cdev routines */ 91157089Simpstatic d_open_t at91_pio_open; 92157089Simpstatic d_close_t at91_pio_close; 93157089Simpstatic d_ioctl_t at91_pio_ioctl; 94157089Simp 95157089Simpstatic struct cdevsw at91_pio_cdevsw = 96157089Simp{ 97157089Simp .d_version = D_VERSION, 98157089Simp .d_open = at91_pio_open, 99157089Simp .d_close = at91_pio_close, 100157089Simp .d_ioctl = at91_pio_ioctl 101157089Simp}; 102157089Simp 103157089Simpstatic int 104157089Simpat91_pio_probe(device_t dev) 105157089Simp{ 106157089Simp device_set_desc(dev, "PIO"); 107157089Simp return (0); 108157089Simp} 109157089Simp 110157089Simpstatic int 111157089Simpat91_pio_attach(device_t dev) 112157089Simp{ 113157089Simp struct at91_pio_softc *sc = device_get_softc(dev); 114157089Simp int err; 115157089Simp 116157089Simp sc->dev = dev; 117157089Simp err = at91_pio_activate(dev); 118157089Simp if (err) 119157089Simp goto out; 120157089Simp 121157089Simp AT91_PIO_LOCK_INIT(sc); 122157089Simp 123157089Simp /* 124157089Simp * Activate the interrupt, but disable all interrupts in the hardware 125157089Simp */ 126157089Simp WR4(sc, PIO_IDR, 0xffffffff); 127157089Simp err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_FAST, 128157089Simp at91_pio_intr, sc, &sc->intrhand); 129157089Simp if (err) { 130157089Simp AT91_PIO_LOCK_DESTROY(sc); 131157089Simp goto out; 132157089Simp } 133157089Simp sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT 134157089Simp , GID_WHEEL, 0600, "pio%d", device_get_unit(dev)); 135157089Simp if (sc->cdev == NULL) { 136157089Simp err = ENOMEM; 137157089Simp goto out; 138157089Simp } 139157089Simp sc->cdev->si_drv1 = sc; 140157089Simpout:; 141157089Simp if (err) 142157089Simp at91_pio_deactivate(dev); 143157089Simp return (err); 144157089Simp} 145157089Simp 146157089Simpstatic int 147157089Simpat91_pio_detach(device_t dev) 148157089Simp{ 149157089Simp return (EBUSY); /* XXX */ 150157089Simp} 151157089Simp 152157089Simpstatic int 153157089Simpat91_pio_activate(device_t dev) 154157089Simp{ 155157089Simp struct at91_pio_softc *sc; 156157089Simp int rid; 157157089Simp 158157089Simp sc = device_get_softc(dev); 159157089Simp rid = 0; 160157089Simp sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 161157089Simp RF_ACTIVE); 162157089Simp if (sc->mem_res == NULL) 163157089Simp goto errout; 164157089Simp rid = 0; 165157089Simp sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 166157089Simp RF_ACTIVE | RF_SHAREABLE); 167157089Simp if (sc->irq_res == NULL) 168157089Simp goto errout; 169157089Simp return (0); 170157089Simperrout: 171157089Simp at91_pio_deactivate(dev); 172157089Simp return (ENOMEM); 173157089Simp} 174157089Simp 175157089Simpstatic void 176157089Simpat91_pio_deactivate(device_t dev) 177157089Simp{ 178157089Simp struct at91_pio_softc *sc; 179157089Simp 180157089Simp sc = device_get_softc(dev); 181157089Simp if (sc->intrhand) 182157089Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 183157089Simp sc->intrhand = 0; 184157089Simp bus_generic_detach(sc->dev); 185157089Simp if (sc->mem_res) 186157089Simp bus_release_resource(dev, SYS_RES_IOPORT, 187157089Simp rman_get_rid(sc->mem_res), sc->mem_res); 188157089Simp sc->mem_res = 0; 189157089Simp if (sc->irq_res) 190157089Simp bus_release_resource(dev, SYS_RES_IRQ, 191157089Simp rman_get_rid(sc->irq_res), sc->irq_res); 192157089Simp sc->irq_res = 0; 193157089Simp return; 194157089Simp} 195157089Simp 196157089Simpstatic void 197157089Simpat91_pio_intr(void *xsc) 198157089Simp{ 199157089Simp struct at91_pio_softc *sc = xsc; 200157089Simp#if 0 201157089Simp uint32_t status; 202157089Simp 203157089Simp /* Reading the status also clears the interrupt */ 204157089Simp status = RD4(sc, PIO_SR); 205157089Simp if (status == 0) 206157089Simp return; 207157089Simp AT91_PIO_LOCK(sc); 208157089Simp AT91_PIO_UNLOCK(sc); 209157089Simp#endif 210157089Simp wakeup(sc); 211157089Simp return; 212157089Simp} 213157089Simp 214157089Simpstatic int 215157089Simpat91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 216157089Simp{ 217157089Simp struct at91_pio_softc *sc; 218157089Simp 219157089Simp sc = CDEV2SOFTC(dev); 220157089Simp AT91_PIO_LOCK(sc); 221157089Simp if (!(sc->flags & OPENED)) { 222157089Simp sc->flags |= OPENED; 223157089Simp#if 0 224157089Simp // Enable interrupts 225157089Simp#endif 226157089Simp } 227157089Simp AT91_PIO_UNLOCK(sc); 228157089Simp return (0); 229157089Simp} 230157089Simp 231157089Simpstatic int 232157089Simpat91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 233157089Simp{ 234157089Simp struct at91_pio_softc *sc; 235157089Simp 236157089Simp sc = CDEV2SOFTC(dev); 237157089Simp AT91_PIO_LOCK(sc); 238157089Simp sc->flags &= ~OPENED; 239157089Simp#if 0 240157089Simp // Disable interrupts 241157089Simp#endif 242157089Simp AT91_PIO_UNLOCK(sc); 243157089Simp return (0); 244157089Simp} 245157089Simp 246157089Simpstatic int 247157089Simpat91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 248157089Simp struct thread *td) 249157089Simp{ 250157089Simp return (ENXIO); 251157089Simp} 252157089Simp 253157089Simpstatic device_method_t at91_pio_methods[] = { 254157089Simp /* Device interface */ 255157089Simp DEVMETHOD(device_probe, at91_pio_probe), 256157089Simp DEVMETHOD(device_attach, at91_pio_attach), 257157089Simp DEVMETHOD(device_detach, at91_pio_detach), 258157089Simp 259157089Simp { 0, 0 } 260157089Simp}; 261157089Simp 262157089Simpstatic driver_t at91_pio_driver = { 263157089Simp "at91_pio", 264157089Simp at91_pio_methods, 265157089Simp sizeof(struct at91_pio_softc), 266157089Simp}; 267157089Simp 268157089SimpDRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, 0, 0); 269