at91_ssc.c revision 160365
1157091Simp/*- 2157091Simp * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3157091Simp * 4157091Simp * Redistribution and use in source and binary forms, with or without 5157091Simp * modification, are permitted provided that the following conditions 6157091Simp * are met: 7157091Simp * 1. Redistributions of source code must retain the above copyright 8157091Simp * notice, this list of conditions and the following disclaimer. 9157091Simp * 2. Redistributions in binary form must reproduce the above copyright 10157091Simp * notice, this list of conditions and the following disclaimer in the 11157091Simp * documentation and/or other materials provided with the distribution. 12157091Simp * 13157091Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14157091Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15157091Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16157091Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17157091Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18157091Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19157091Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20157091Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21157091Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22157091Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23157091Simp */ 24157091Simp 25157091Simp#include <sys/cdefs.h> 26157091Simp__FBSDID("$FreeBSD: head/sys/arm/at91/at91_ssc.c 160365 2006-07-14 22:30:44Z imp $"); 27157091Simp 28157091Simp#include <sys/param.h> 29157091Simp#include <sys/systm.h> 30157091Simp#include <sys/bus.h> 31157091Simp#include <sys/conf.h> 32157091Simp#include <sys/kernel.h> 33157091Simp#include <sys/lock.h> 34157091Simp#include <sys/module.h> 35157091Simp#include <sys/mutex.h> 36157091Simp#include <sys/rman.h> 37157091Simp#include <machine/bus.h> 38157091Simp 39157091Simp#include <arm/at91/at91_sscreg.h> 40157091Simp 41157091Simpstruct at91_ssc_softc 42157091Simp{ 43157091Simp device_t dev; /* Myself */ 44157091Simp void *intrhand; /* Interrupt handle */ 45157091Simp struct resource *irq_res; /* IRQ resource */ 46157091Simp struct resource *mem_res; /* Memory resource */ 47157091Simp struct mtx sc_mtx; /* basically a perimeter lock */ 48157091Simp struct cdev *cdev; 49157091Simp int flags; 50157091Simp#define OPENED 1 51157091Simp}; 52157091Simp 53157091Simpstatic inline uint32_t 54157091SimpRD4(struct at91_ssc_softc *sc, bus_size_t off) 55157091Simp{ 56157091Simp return bus_read_4(sc->mem_res, off); 57157091Simp} 58157091Simp 59157091Simpstatic inline void 60157091SimpWR4(struct at91_ssc_softc *sc, bus_size_t off, uint32_t val) 61157091Simp{ 62157091Simp bus_write_4(sc->mem_res, off, val); 63157091Simp} 64157091Simp 65157091Simp#define AT91_SSC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 66157091Simp#define AT91_SSC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 67157091Simp#define AT91_SSC_LOCK_INIT(_sc) \ 68160365Simp mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->dev), \ 69157091Simp "ssc", MTX_DEF) 70160365Simp#define AT91_SSC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); 71160365Simp#define AT91_SSC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED); 72160365Simp#define AT91_SSC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED); 73157091Simp#define CDEV2SOFTC(dev) ((dev)->si_drv1) 74157091Simp 75157091Simpstatic devclass_t at91_ssc_devclass; 76157091Simp 77157091Simp/* bus entry points */ 78157091Simp 79157091Simpstatic int at91_ssc_probe(device_t dev); 80157091Simpstatic int at91_ssc_attach(device_t dev); 81157091Simpstatic int at91_ssc_detach(device_t dev); 82157091Simpstatic void at91_ssc_intr(void *); 83157091Simp 84157091Simp/* helper routines */ 85157091Simpstatic int at91_ssc_activate(device_t dev); 86157091Simpstatic void at91_ssc_deactivate(device_t dev); 87157091Simp 88157091Simp/* cdev routines */ 89157091Simpstatic d_open_t at91_ssc_open; 90157091Simpstatic d_close_t at91_ssc_close; 91157091Simpstatic d_ioctl_t at91_ssc_ioctl; 92157091Simp 93157091Simpstatic struct cdevsw at91_ssc_cdevsw = 94157091Simp{ 95157091Simp .d_version = D_VERSION, 96157091Simp .d_open = at91_ssc_open, 97157091Simp .d_close = at91_ssc_close, 98157091Simp .d_ioctl = at91_ssc_ioctl 99157091Simp}; 100157091Simp 101157091Simpstatic int 102157091Simpat91_ssc_probe(device_t dev) 103157091Simp{ 104157091Simp device_set_desc(dev, "SSC"); 105157091Simp return (0); 106157091Simp} 107157091Simp 108157091Simpstatic int 109157091Simpat91_ssc_attach(device_t dev) 110157091Simp{ 111157091Simp struct at91_ssc_softc *sc = device_get_softc(dev); 112157091Simp int err; 113157091Simp 114157091Simp sc->dev = dev; 115157091Simp err = at91_ssc_activate(dev); 116157091Simp if (err) 117157091Simp goto out; 118157091Simp 119157091Simp AT91_SSC_LOCK_INIT(sc); 120157091Simp 121157091Simp /* 122157091Simp * Activate the interrupt 123157091Simp */ 124157091Simp err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 125157091Simp at91_ssc_intr, sc, &sc->intrhand); 126157091Simp if (err) { 127157091Simp AT91_SSC_LOCK_DESTROY(sc); 128157091Simp goto out; 129157091Simp } 130157091Simp sc->cdev = make_dev(&at91_ssc_cdevsw, device_get_unit(dev), UID_ROOT, 131157091Simp GID_WHEEL, 0600, "ssc%d", device_get_unit(dev)); 132157091Simp if (sc->cdev == NULL) { 133157091Simp err = ENOMEM; 134157091Simp goto out; 135157091Simp } 136157091Simp sc->cdev->si_drv1 = sc; 137157091Simpout:; 138157091Simp if (err) 139157091Simp at91_ssc_deactivate(dev); 140157091Simp return (err); 141157091Simp} 142157091Simp 143157091Simpstatic int 144157091Simpat91_ssc_detach(device_t dev) 145157091Simp{ 146157091Simp return (EBUSY); /* XXX */ 147157091Simp} 148157091Simp 149157091Simpstatic int 150157091Simpat91_ssc_activate(device_t dev) 151157091Simp{ 152157091Simp struct at91_ssc_softc *sc; 153157091Simp int rid; 154157091Simp 155157091Simp sc = device_get_softc(dev); 156157091Simp rid = 0; 157157091Simp sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 158157091Simp RF_ACTIVE); 159157091Simp if (sc->mem_res == NULL) 160157091Simp goto errout; 161157091Simp rid = 0; 162157091Simp sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 163157091Simp RF_ACTIVE); 164157091Simp if (sc->mem_res == NULL) 165157091Simp goto errout; 166157091Simp return (0); 167157091Simperrout: 168157091Simp at91_ssc_deactivate(dev); 169157091Simp return (ENOMEM); 170157091Simp} 171157091Simp 172157091Simpstatic void 173157091Simpat91_ssc_deactivate(device_t dev) 174157091Simp{ 175157091Simp struct at91_ssc_softc *sc; 176157091Simp 177157091Simp sc = device_get_softc(dev); 178157091Simp if (sc->intrhand) 179157091Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 180157091Simp sc->intrhand = 0; 181157091Simp bus_generic_detach(sc->dev); 182157091Simp if (sc->mem_res) 183157091Simp bus_release_resource(dev, SYS_RES_IOPORT, 184157091Simp rman_get_rid(sc->mem_res), sc->mem_res); 185157091Simp sc->mem_res = 0; 186157091Simp if (sc->irq_res) 187157091Simp bus_release_resource(dev, SYS_RES_IRQ, 188157091Simp rman_get_rid(sc->irq_res), sc->irq_res); 189157091Simp sc->irq_res = 0; 190157091Simp return; 191157091Simp} 192157091Simp 193157091Simpstatic void 194157091Simpat91_ssc_intr(void *xsc) 195157091Simp{ 196157091Simp struct at91_ssc_softc *sc = xsc; 197157091Simp#if 0 198157091Simp uint32_t status; 199157091Simp 200157091Simp /* Reading the status also clears the interrupt */ 201157091Simp status = RD4(sc, SSC_SR); 202157091Simp if (status == 0) 203157091Simp return; 204157091Simp AT91_SSC_LOCK(sc); 205157091Simp AT91_SSC_UNLOCK(sc); 206157091Simp#endif 207157091Simp wakeup(sc); 208157091Simp return; 209157091Simp} 210157091Simp 211157091Simpstatic int 212157091Simpat91_ssc_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 213157091Simp{ 214157091Simp struct at91_ssc_softc *sc; 215157091Simp 216157091Simp sc = CDEV2SOFTC(dev); 217157091Simp AT91_SSC_LOCK(sc); 218157091Simp if (!(sc->flags & OPENED)) { 219157091Simp sc->flags |= OPENED; 220157091Simp#if 0 221157091Simp // Enable interrupts 222157091Simp#endif 223157091Simp } 224157091Simp AT91_SSC_UNLOCK(sc); 225157091Simp return (0); 226157091Simp} 227157091Simp 228157091Simpstatic int 229157091Simpat91_ssc_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 230157091Simp{ 231157091Simp struct at91_ssc_softc *sc; 232157091Simp 233157091Simp sc = CDEV2SOFTC(dev); 234157091Simp AT91_SSC_LOCK(sc); 235157091Simp sc->flags &= ~OPENED; 236157091Simp#if 0 237157091Simp // Disable interrupts 238157091Simp#endif 239157091Simp AT91_SSC_UNLOCK(sc); 240157091Simp return (0); 241157091Simp} 242157091Simp 243157091Simpstatic int 244157091Simpat91_ssc_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 245157091Simp struct thread *td) 246157091Simp{ 247157091Simp return (ENXIO); 248157091Simp} 249157091Simp 250157091Simpstatic device_method_t at91_ssc_methods[] = { 251157091Simp /* Device interface */ 252157091Simp DEVMETHOD(device_probe, at91_ssc_probe), 253157091Simp DEVMETHOD(device_attach, at91_ssc_attach), 254157091Simp DEVMETHOD(device_detach, at91_ssc_detach), 255157091Simp 256157091Simp { 0, 0 } 257157091Simp}; 258157091Simp 259157091Simpstatic driver_t at91_ssc_driver = { 260157091Simp "at91_ssc", 261157091Simp at91_ssc_methods, 262157091Simp sizeof(struct at91_ssc_softc), 263157091Simp}; 264157091Simp 265157091SimpDRIVER_MODULE(at91_ssc, atmelarm, at91_ssc_driver, at91_ssc_devclass, 0, 0); 266