at91_pio.c revision 248910
1/*- 2 * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pio.c 248910 2013-03-29 19:04:18Z ian $"); 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/bus.h> 32#include <sys/conf.h> 33#include <sys/kernel.h> 34#include <sys/lock.h> 35#include <sys/mbuf.h> 36#include <sys/malloc.h> 37#include <sys/module.h> 38#include <sys/mutex.h> 39#include <sys/rman.h> 40#include <machine/bus.h> 41 42#include <arm/at91/at91reg.h> 43#include <arm/at91/at91_pioreg.h> 44#include <arm/at91/at91_piovar.h> 45 46struct at91_pio_softc 47{ 48 device_t dev; /* Myself */ 49 void *intrhand; /* Interrupt handle */ 50 struct resource *irq_res; /* IRQ resource */ 51 struct resource *mem_res; /* Memory resource */ 52 struct mtx sc_mtx; /* basically a perimeter lock */ 53 struct cdev *cdev; 54 int flags; 55#define OPENED 1 56}; 57 58static inline uint32_t 59RD4(struct at91_pio_softc *sc, bus_size_t off) 60{ 61 62 return (bus_read_4(sc->mem_res, off)); 63} 64 65static inline void 66WR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val) 67{ 68 69 bus_write_4(sc->mem_res, off, val); 70} 71 72#define AT91_PIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) 73#define AT91_PIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) 74#define AT91_PIO_LOCK_INIT(_sc) \ 75 mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 76 "pio", MTX_SPIN) 77#define AT91_PIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 78#define AT91_PIO_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 79#define AT91_PIO_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 80#define CDEV2SOFTC(dev) ((dev)->si_drv1) 81 82static devclass_t at91_pio_devclass; 83 84/* bus entry points */ 85 86static int at91_pio_probe(device_t dev); 87static int at91_pio_attach(device_t dev); 88static int at91_pio_detach(device_t dev); 89static int at91_pio_intr(void *); 90 91/* helper routines */ 92static int at91_pio_activate(device_t dev); 93static void at91_pio_deactivate(device_t dev); 94 95/* cdev routines */ 96static d_open_t at91_pio_open; 97static d_close_t at91_pio_close; 98static d_ioctl_t at91_pio_ioctl; 99 100static struct cdevsw at91_pio_cdevsw = 101{ 102 .d_version = D_VERSION, 103 .d_open = at91_pio_open, 104 .d_close = at91_pio_close, 105 .d_ioctl = at91_pio_ioctl 106}; 107 108static int 109at91_pio_probe(device_t dev) 110{ 111 const char *name; 112 113 switch (device_get_unit(dev)) { 114 case 0: 115 name = "PIOA"; 116 break; 117 case 1: 118 name = "PIOB"; 119 break; 120 case 2: 121 name = "PIOC"; 122 break; 123 case 3: 124 name = "PIOD"; 125 break; 126 default: 127 name = "PIO"; 128 break; 129 } 130 device_set_desc(dev, name); 131 return (0); 132} 133 134static int 135at91_pio_attach(device_t dev) 136{ 137 struct at91_pio_softc *sc; 138 int err; 139 140 sc = device_get_softc(dev); 141 sc->dev = dev; 142 err = at91_pio_activate(dev); 143 if (err) 144 goto out; 145 146 if (bootverbose) 147 device_printf(dev, "ABSR: %#x OSR: %#x PSR:%#x ODSR: %#x\n", 148 RD4(sc, PIO_ABSR), RD4(sc, PIO_OSR), RD4(sc, PIO_PSR), 149 RD4(sc, PIO_ODSR)); 150 AT91_PIO_LOCK_INIT(sc); 151 152 /* 153 * Activate the interrupt, but disable all interrupts in the hardware. 154 */ 155 WR4(sc, PIO_IDR, 0xffffffff); 156 err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 157 at91_pio_intr, NULL, sc, &sc->intrhand); 158 if (err) { 159 AT91_PIO_LOCK_DESTROY(sc); 160 goto out; 161 } 162 sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT, 163 GID_WHEEL, 0600, "pio%d", device_get_unit(dev)); 164 if (sc->cdev == NULL) { 165 err = ENOMEM; 166 goto out; 167 } 168 sc->cdev->si_drv1 = sc; 169out: 170 if (err) 171 at91_pio_deactivate(dev); 172 return (err); 173} 174 175static int 176at91_pio_detach(device_t dev) 177{ 178 179 return (EBUSY); /* XXX */ 180} 181 182static int 183at91_pio_activate(device_t dev) 184{ 185 struct at91_pio_softc *sc; 186 int rid; 187 188 sc = device_get_softc(dev); 189 rid = 0; 190 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 191 RF_ACTIVE); 192 if (sc->mem_res == NULL) 193 goto errout; 194 rid = 0; 195 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 196 RF_ACTIVE | RF_SHAREABLE); 197 if (sc->irq_res == NULL) 198 goto errout; 199 return (0); 200errout: 201 at91_pio_deactivate(dev); 202 return (ENOMEM); 203} 204 205static void 206at91_pio_deactivate(device_t dev) 207{ 208 struct at91_pio_softc *sc; 209 210 sc = device_get_softc(dev); 211 if (sc->intrhand) 212 bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 213 sc->intrhand = 0; 214 bus_generic_detach(sc->dev); 215 if (sc->mem_res) 216 bus_release_resource(dev, SYS_RES_IOPORT, 217 rman_get_rid(sc->mem_res), sc->mem_res); 218 sc->mem_res = 0; 219 if (sc->irq_res) 220 bus_release_resource(dev, SYS_RES_IRQ, 221 rman_get_rid(sc->irq_res), sc->irq_res); 222 sc->irq_res = 0; 223} 224 225static int 226at91_pio_intr(void *xsc) 227{ 228 struct at91_pio_softc *sc = xsc; 229#if 0 230 uint32_t status; 231 232 /* Reading the status also clears the interrupt. */ 233 status = RD4(sc, PIO_SR); 234 if (status == 0) 235 return; 236 AT91_PIO_LOCK(sc); 237 AT91_PIO_UNLOCK(sc); 238#endif 239 wakeup(sc); 240 return (FILTER_HANDLED); 241} 242 243static int 244at91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 245{ 246 struct at91_pio_softc *sc; 247 248 sc = CDEV2SOFTC(dev); 249 AT91_PIO_LOCK(sc); 250 if (!(sc->flags & OPENED)) { 251 sc->flags |= OPENED; 252#if 0 253 /* Enable interrupts. */ 254#endif 255 } 256 AT91_PIO_UNLOCK(sc); 257 return (0); 258} 259 260static int 261at91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 262{ 263 struct at91_pio_softc *sc; 264 265 sc = CDEV2SOFTC(dev); 266 AT91_PIO_LOCK(sc); 267 sc->flags &= ~OPENED; 268#if 0 269 /* Disable interrupts. */ 270#endif 271 AT91_PIO_UNLOCK(sc); 272 return (0); 273} 274 275static int 276at91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 277 struct thread *td) 278{ 279 280 return (ENXIO); 281} 282 283/* 284 * The following functions are called early in the boot process, so 285 * don't use bus_space, as that isn't yet available when we need to use 286 * them. 287 */ 288 289void 290at91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup) 291{ 292 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 293 294 PIO[PIO_ASR / 4] = periph_a_mask; 295 PIO[PIO_PDR / 4] = periph_a_mask; 296 if (use_pullup) 297 PIO[PIO_PUER / 4] = periph_a_mask; 298 else 299 PIO[PIO_PUDR / 4] = periph_a_mask; 300} 301 302void 303at91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup) 304{ 305 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 306 307 PIO[PIO_BSR / 4] = periph_b_mask; 308 PIO[PIO_PDR / 4] = periph_b_mask; 309 if (use_pullup) 310 PIO[PIO_PUER / 4] = periph_b_mask; 311 else 312 PIO[PIO_PUDR / 4] = periph_b_mask; 313} 314 315void 316at91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) 317{ 318 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 319 320 PIO[PIO_PER / 4] = gpio_mask; 321} 322 323void 324at91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) 325{ 326 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 327 328 PIO[PIO_ODR / 4] = input_enable_mask; 329} 330 331void 332at91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup) 333{ 334 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 335 336 PIO[PIO_OER / 4] = output_enable_mask; 337 if (use_pullup) 338 PIO[PIO_PUER / 4] = output_enable_mask; 339 else 340 PIO[PIO_PUDR / 4] = output_enable_mask; 341} 342 343void 344at91_pio_gpio_set(uint32_t pio, uint32_t data_mask) 345{ 346 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 347 348 PIO[PIO_SODR / 4] = data_mask; 349} 350 351void 352at91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) 353{ 354 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 355 356 PIO[PIO_CODR / 4] = data_mask; 357} 358 359uint8_t 360at91_pio_gpio_get(uint32_t pio, uint32_t data_mask) 361{ 362 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 363 364 return ((PIO[PIO_PDSR / 4] & data_mask)); 365} 366 367void 368at91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch) 369{ 370 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 371 372 if (use_deglitch) 373 PIO[PIO_IFER / 4] = data_mask; 374 else 375 PIO[PIO_IFDR / 4] = data_mask; 376} 377 378void 379at91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, 380 int enable_interrupt) 381{ 382 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 383 384 if (enable_interrupt) 385 PIO[PIO_IER / 4] = data_mask; 386 else 387 PIO[PIO_IDR / 4] = data_mask; 388} 389 390uint32_t 391at91_pio_gpio_clear_interrupt(uint32_t pio) 392{ 393 uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); 394 395 /* Reading this register will clear the interrupts. */ 396 return (PIO[PIO_ISR / 4]); 397} 398 399static device_method_t at91_pio_methods[] = { 400 /* Device interface */ 401 DEVMETHOD(device_probe, at91_pio_probe), 402 DEVMETHOD(device_attach, at91_pio_attach), 403 DEVMETHOD(device_detach, at91_pio_detach), 404 405 DEVMETHOD_END 406}; 407 408static driver_t at91_pio_driver = { 409 "at91_pio", 410 at91_pio_methods, 411 sizeof(struct at91_pio_softc), 412}; 413 414DRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, NULL, 415 NULL); 416