1183840Sraj/*- 2183840Sraj * Copyright (c) 2006 Benno Rice. 3183840Sraj * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. 4183840Sraj * All rights reserved. 5183840Sraj * 6183840Sraj * Adapted and extended for Marvell SoCs by Semihalf. 7183840Sraj * 8183840Sraj * Redistribution and use in source and binary forms, with or without 9183840Sraj * modification, are permitted provided that the following conditions 10183840Sraj * are met: 11183840Sraj * 1. Redistributions of source code must retain the above copyright 12183840Sraj * notice, this list of conditions and the following disclaimer. 13183840Sraj * 2. Redistributions in binary form must reproduce the above copyright 14183840Sraj * notice, this list of conditions and the following disclaimer in the 15183840Sraj * documentation and/or other materials provided with the distribution. 16183840Sraj * 17183840Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18183840Sraj * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19183840Sraj * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20183840Sraj * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21183840Sraj * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22183840Sraj * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23183840Sraj * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24183840Sraj * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25183840Sraj * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26183840Sraj * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27183840Sraj * 28183840Sraj * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1 29183840Sraj */ 30183840Sraj 31183840Sraj#include <sys/cdefs.h> 32183840Sraj__FBSDID("$FreeBSD$"); 33183840Sraj 34183840Sraj#include <sys/param.h> 35183840Sraj#include <sys/systm.h> 36183840Sraj#include <sys/bus.h> 37183840Sraj#include <sys/kernel.h> 38183840Sraj#include <sys/lock.h> 39183840Sraj#include <sys/interrupt.h> 40183840Sraj#include <sys/module.h> 41183840Sraj#include <sys/malloc.h> 42183840Sraj#include <sys/mutex.h> 43183840Sraj#include <sys/rman.h> 44183840Sraj#include <sys/queue.h> 45183840Sraj#include <sys/timetc.h> 46183840Sraj#include <machine/bus.h> 47209131Sraj#include <machine/fdt.h> 48183840Sraj#include <machine/intr.h> 49183840Sraj 50209131Sraj#include <dev/fdt/fdt_common.h> 51209131Sraj#include <dev/ofw/ofw_bus.h> 52209131Sraj#include <dev/ofw/ofw_bus_subr.h> 53209131Sraj 54183840Sraj#include <arm/mv/mvvar.h> 55183840Sraj#include <arm/mv/mvreg.h> 56183840Sraj 57183840Sraj#define GPIO_MAX_INTR_COUNT 8 58183840Sraj#define GPIO_PINS_PER_REG 32 59183840Sraj 60183840Srajstruct mv_gpio_softc { 61183840Sraj struct resource * res[GPIO_MAX_INTR_COUNT + 1]; 62183840Sraj void *ih_cookie[GPIO_MAX_INTR_COUNT]; 63183840Sraj bus_space_tag_t bst; 64183840Sraj bus_space_handle_t bsh; 65183840Sraj uint8_t pin_num; /* number of GPIO pins */ 66183840Sraj uint8_t irq_num; /* number of real IRQs occupied by GPIO controller */ 67183840Sraj}; 68183840Sraj 69186909Srajextern struct resource_spec mv_gpio_res[]; 70183840Sraj 71183840Srajstatic struct mv_gpio_softc *mv_gpio_softc = NULL; 72183840Srajstatic uint32_t gpio_setup[MV_GPIO_MAX_NPINS]; 73183840Sraj 74183840Srajstatic int mv_gpio_probe(device_t); 75183840Srajstatic int mv_gpio_attach(device_t); 76217069Sjhbstatic int mv_gpio_intr(void *); 77183840Sraj 78183840Srajstatic void mv_gpio_intr_handler(int pin); 79183840Srajstatic uint32_t mv_gpio_reg_read(uint32_t reg); 80183840Srajstatic void mv_gpio_reg_write(uint32_t reg, uint32_t val); 81183840Srajstatic void mv_gpio_reg_set(uint32_t reg, uint32_t val); 82183840Srajstatic void mv_gpio_reg_clear(uint32_t reg, uint32_t val); 83183840Sraj 84183840Srajstatic void mv_gpio_blink(uint32_t pin, uint8_t enable); 85183840Srajstatic void mv_gpio_polarity(uint32_t pin, uint8_t enable); 86183840Srajstatic void mv_gpio_level(uint32_t pin, uint8_t enable); 87183840Srajstatic void mv_gpio_edge(uint32_t pin, uint8_t enable); 88183840Srajstatic void mv_gpio_out_en(uint32_t pin, uint8_t enable); 89183840Srajstatic void mv_gpio_int_ack(uint32_t pin); 90183840Srajstatic void mv_gpio_value_set(uint32_t pin, uint8_t val); 91183840Srajstatic uint32_t mv_gpio_value_get(uint32_t pin); 92183840Sraj 93183840Srajstatic device_method_t mv_gpio_methods[] = { 94183840Sraj DEVMETHOD(device_probe, mv_gpio_probe), 95183840Sraj DEVMETHOD(device_attach, mv_gpio_attach), 96183840Sraj { 0, 0 } 97183840Sraj}; 98183840Sraj 99183840Srajstatic driver_t mv_gpio_driver = { 100183840Sraj "gpio", 101183840Sraj mv_gpio_methods, 102183840Sraj sizeof(struct mv_gpio_softc), 103183840Sraj}; 104183840Sraj 105183840Srajstatic devclass_t mv_gpio_devclass; 106183840Sraj 107209131SrajDRIVER_MODULE(gpio, simplebus, mv_gpio_driver, mv_gpio_devclass, 0, 0); 108183840Sraj 109209131Srajtypedef int (*gpios_phandler_t)(phandle_t, pcell_t *, int); 110209131Sraj 111209131Srajstruct gpio_ctrl_entry { 112209131Sraj const char *compat; 113209131Sraj gpios_phandler_t handler; 114209131Sraj}; 115209131Sraj 116209131Srajint mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len); 117209131Srajint gpio_get_config_from_dt(void); 118209131Sraj 119209131Srajstruct gpio_ctrl_entry gpio_controllers[] = { 120209131Sraj { "mrvl,gpio", &mv_handle_gpios_prop }, 121209131Sraj { NULL, NULL } 122209131Sraj}; 123209131Sraj 124183840Srajstatic int 125183840Srajmv_gpio_probe(device_t dev) 126183840Sraj{ 127183840Sraj 128266152Sian if (!ofw_bus_status_okay(dev)) 129266152Sian return (ENXIO); 130266152Sian 131209131Sraj if (!ofw_bus_is_compatible(dev, "mrvl,gpio")) 132209131Sraj return (ENXIO); 133209131Sraj 134183840Sraj device_set_desc(dev, "Marvell Integrated GPIO Controller"); 135183840Sraj return (0); 136183840Sraj} 137183840Sraj 138183840Srajstatic int 139183840Srajmv_gpio_attach(device_t dev) 140183840Sraj{ 141186901Sraj int error, i; 142186901Sraj struct mv_gpio_softc *sc; 143183840Sraj uint32_t dev_id, rev_id; 144183840Sraj 145183840Sraj sc = (struct mv_gpio_softc *)device_get_softc(dev); 146209131Sraj if (sc == NULL) 147183840Sraj return (ENXIO); 148209131Sraj 149183840Sraj mv_gpio_softc = sc; 150183840Sraj 151191140Sraj /* Get chip id and revision */ 152183840Sraj soc_id(&dev_id, &rev_id); 153183840Sraj 154183840Sraj if (dev_id == MV_DEV_88F5182 || 155183840Sraj dev_id == MV_DEV_88F5281 || 156191140Sraj dev_id == MV_DEV_MV78100 || 157191140Sraj dev_id == MV_DEV_MV78100_Z0 ) { 158183840Sraj sc->pin_num = 32; 159183840Sraj sc->irq_num = 4; 160183840Sraj 161238873Shrs } else if (dev_id == MV_DEV_88F6281 || 162238873Shrs dev_id == MV_DEV_88F6282) { 163183840Sraj sc->pin_num = 50; 164183840Sraj sc->irq_num = 7; 165183840Sraj 166183840Sraj } else { 167191140Sraj device_printf(dev, "unknown chip id=0x%x\n", dev_id); 168183840Sraj return (ENXIO); 169183840Sraj } 170183840Sraj 171186909Sraj error = bus_alloc_resources(dev, mv_gpio_res, sc->res); 172183840Sraj if (error) { 173183840Sraj device_printf(dev, "could not allocate resources\n"); 174183840Sraj return (ENXIO); 175183840Sraj } 176183840Sraj 177183840Sraj sc->bst = rman_get_bustag(sc->res[0]); 178183840Sraj sc->bsh = rman_get_bushandle(sc->res[0]); 179183840Sraj 180183840Sraj /* Disable and clear all interrupts */ 181183840Sraj bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0); 182183840Sraj bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0); 183183840Sraj bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0); 184183840Sraj 185218388Smarcel if (sc->pin_num > GPIO_PINS_PER_REG) { 186183840Sraj bus_space_write_4(sc->bst, sc->bsh, 187183840Sraj GPIO_HI_INT_EDGE_MASK, 0); 188183840Sraj bus_space_write_4(sc->bst, sc->bsh, 189183840Sraj GPIO_HI_INT_LEV_MASK, 0); 190183840Sraj bus_space_write_4(sc->bst, sc->bsh, 191183840Sraj GPIO_HI_INT_CAUSE, 0); 192183840Sraj } 193183840Sraj 194183840Sraj for (i = 0; i < sc->irq_num; i++) { 195183840Sraj if (bus_setup_intr(dev, sc->res[1 + i], 196217069Sjhb INTR_TYPE_MISC, mv_gpio_intr, NULL, 197183840Sraj sc, &sc->ih_cookie[i]) != 0) { 198186909Sraj bus_release_resources(dev, mv_gpio_res, sc->res); 199183840Sraj device_printf(dev, "could not set up intr %d\n", i); 200183840Sraj return (ENXIO); 201183840Sraj } 202183840Sraj } 203183840Sraj 204224051Smarcel return (platform_gpio_init()); 205183840Sraj} 206183840Sraj 207217069Sjhbstatic int 208183840Srajmv_gpio_intr(void *arg) 209183840Sraj{ 210186909Sraj uint32_t int_cause, gpio_val; 211186909Sraj uint32_t int_cause_hi, gpio_val_hi = 0; 212186909Sraj int i; 213183840Sraj 214183840Sraj int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE); 215183840Sraj gpio_val = mv_gpio_reg_read(GPIO_DATA_IN); 216183840Sraj gpio_val &= int_cause; 217218388Smarcel if (mv_gpio_softc->pin_num > GPIO_PINS_PER_REG) { 218183840Sraj int_cause_hi = mv_gpio_reg_read(GPIO_HI_INT_CAUSE); 219183840Sraj gpio_val_hi = mv_gpio_reg_read(GPIO_HI_DATA_IN); 220183840Sraj gpio_val_hi &= int_cause_hi; 221183840Sraj } 222183840Sraj 223183840Sraj i = 0; 224183840Sraj while (gpio_val != 0) { 225183840Sraj if (gpio_val & 1) 226183840Sraj mv_gpio_intr_handler(i); 227183840Sraj gpio_val >>= 1; 228183840Sraj i++; 229183840Sraj } 230183840Sraj 231218388Smarcel if (mv_gpio_softc->pin_num > GPIO_PINS_PER_REG) { 232183840Sraj i = 0; 233183840Sraj while (gpio_val_hi != 0) { 234183840Sraj if (gpio_val_hi & 1) 235183840Sraj mv_gpio_intr_handler(i + GPIO_PINS_PER_REG); 236183840Sraj gpio_val_hi >>= 1; 237183840Sraj i++; 238183840Sraj } 239183840Sraj } 240217069Sjhb 241217069Sjhb return (FILTER_HANDLED); 242183840Sraj} 243183840Sraj 244183840Sraj/* 245183840Sraj * GPIO interrupt handling 246183840Sraj */ 247183840Sraj 248186901Srajstatic struct intr_event *gpio_events[MV_GPIO_MAX_NPINS]; 249183840Sraj 250183840Srajint 251183840Srajmv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, 252183840Sraj void (*hand)(void *), void *arg, int pin, int flags, void **cookiep) 253183840Sraj{ 254183840Sraj struct intr_event *event; 255183840Sraj int error; 256183840Sraj 257183840Sraj if (pin < 0 || pin >= mv_gpio_softc->pin_num) 258183840Sraj return (ENXIO); 259183840Sraj event = gpio_events[pin]; 260183840Sraj if (event == NULL) { 261183840Sraj error = intr_event_create(&event, (void *)pin, 0, pin, 262183840Sraj (void (*)(void *))mv_gpio_intr_mask, 263183840Sraj (void (*)(void *))mv_gpio_intr_unmask, 264183840Sraj (void (*)(void *))mv_gpio_int_ack, 265183840Sraj NULL, 266183840Sraj "gpio%d:", pin); 267183840Sraj if (error != 0) 268183840Sraj return (error); 269183840Sraj gpio_events[pin] = event; 270183840Sraj } 271183840Sraj 272186901Sraj intr_event_add_handler(event, name, filt, hand, arg, 273186901Sraj intr_priority(flags), flags, cookiep); 274183840Sraj return (0); 275183840Sraj} 276183840Sraj 277183840Srajvoid 278183840Srajmv_gpio_intr_mask(int pin) 279183840Sraj{ 280183840Sraj 281183840Sraj if (pin >= mv_gpio_softc->pin_num) 282183840Sraj return; 283183840Sraj 284209131Sraj if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE) 285183840Sraj mv_gpio_edge(pin, 0); 286183840Sraj else 287183840Sraj mv_gpio_level(pin, 0); 288183840Sraj} 289183840Sraj 290183840Srajvoid 291183840Srajmv_gpio_intr_unmask(int pin) 292183840Sraj{ 293183840Sraj 294183840Sraj if (pin >= mv_gpio_softc->pin_num) 295183840Sraj return; 296183840Sraj 297209131Sraj if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE) 298183840Sraj mv_gpio_edge(pin, 1); 299183840Sraj else 300183840Sraj mv_gpio_level(pin, 1); 301183840Sraj} 302183840Sraj 303183840Srajstatic void 304183840Srajmv_gpio_intr_handler(int pin) 305183840Sraj{ 306186901Sraj struct intr_event *event; 307183840Sraj 308183840Sraj event = gpio_events[pin]; 309183840Sraj if (event == NULL || TAILQ_EMPTY(&event->ie_handlers)) 310183840Sraj return; 311183840Sraj 312183840Sraj intr_event_handle(event, NULL); 313183840Sraj} 314183840Sraj 315209131Srajstatic int 316209131Srajmv_gpio_configure(uint32_t pin, uint32_t flags) 317183840Sraj{ 318183840Sraj 319183840Sraj if (pin >= mv_gpio_softc->pin_num) 320183840Sraj return (EINVAL); 321183840Sraj 322209131Sraj if (flags & MV_GPIO_OUT_BLINK) 323209131Sraj mv_gpio_blink(pin, 1); 324209131Sraj if (flags & MV_GPIO_IN_POL_LOW) 325209131Sraj mv_gpio_polarity(pin, 1); 326209131Sraj if (flags & MV_GPIO_IN_IRQ_EDGE) 327209131Sraj mv_gpio_edge(pin, 1); 328209131Sraj if (flags & MV_GPIO_IN_IRQ_LEVEL) 329209131Sraj mv_gpio_level(pin, 1); 330183840Sraj 331209131Sraj gpio_setup[pin] = flags; 332183840Sraj 333183840Sraj return (0); 334183840Sraj} 335183840Sraj 336183840Srajvoid 337183840Srajmv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable) 338183840Sraj{ 339183840Sraj 340183840Sraj mv_gpio_value_set(pin, val); 341183840Sraj mv_gpio_out_en(pin, enable); 342183840Sraj} 343183840Sraj 344183840Srajuint8_t 345183840Srajmv_gpio_in(uint32_t pin) 346183840Sraj{ 347183840Sraj 348219684Smarcel return (mv_gpio_value_get(pin) ? 1 : 0); 349183840Sraj} 350183840Sraj 351183840Srajstatic uint32_t 352183840Srajmv_gpio_reg_read(uint32_t reg) 353183840Sraj{ 354183840Sraj 355183840Sraj return (bus_space_read_4(mv_gpio_softc->bst, 356183840Sraj mv_gpio_softc->bsh, reg)); 357183840Sraj} 358183840Sraj 359183840Srajstatic void 360183840Srajmv_gpio_reg_write(uint32_t reg, uint32_t val) 361183840Sraj{ 362183840Sraj 363183840Sraj bus_space_write_4(mv_gpio_softc->bst, 364183840Sraj mv_gpio_softc->bsh, reg, val); 365183840Sraj} 366183840Sraj 367183840Srajstatic void 368183840Srajmv_gpio_reg_set(uint32_t reg, uint32_t pin) 369183840Sraj{ 370183840Sraj uint32_t reg_val; 371183840Sraj 372183840Sraj reg_val = mv_gpio_reg_read(reg); 373183840Sraj reg_val |= GPIO(pin); 374183840Sraj mv_gpio_reg_write(reg, reg_val); 375183840Sraj} 376183840Sraj 377183840Srajstatic void 378183840Srajmv_gpio_reg_clear(uint32_t reg, uint32_t pin) 379183840Sraj{ 380183840Sraj uint32_t reg_val; 381183840Sraj 382183840Sraj reg_val = mv_gpio_reg_read(reg); 383183840Sraj reg_val &= ~(GPIO(pin)); 384183840Sraj mv_gpio_reg_write(reg, reg_val); 385183840Sraj} 386183840Sraj 387183840Srajstatic void 388183840Srajmv_gpio_out_en(uint32_t pin, uint8_t enable) 389183840Sraj{ 390183840Sraj uint32_t reg; 391183840Sraj 392183840Sraj if (pin >= mv_gpio_softc->pin_num) 393183840Sraj return; 394183840Sraj 395183840Sraj if (pin >= GPIO_PINS_PER_REG) { 396183840Sraj reg = GPIO_HI_DATA_OUT_EN_CTRL; 397183840Sraj pin -= GPIO_PINS_PER_REG; 398183840Sraj } else 399183840Sraj reg = GPIO_DATA_OUT_EN_CTRL; 400183840Sraj 401183840Sraj if (enable) 402183840Sraj mv_gpio_reg_clear(reg, pin); 403183840Sraj else 404183840Sraj mv_gpio_reg_set(reg, pin); 405183840Sraj} 406183840Sraj 407183840Srajstatic void 408183840Srajmv_gpio_blink(uint32_t pin, uint8_t enable) 409183840Sraj{ 410183840Sraj uint32_t reg; 411183840Sraj 412183840Sraj if (pin >= mv_gpio_softc->pin_num) 413183840Sraj return; 414183840Sraj 415183840Sraj if (pin >= GPIO_PINS_PER_REG) { 416183840Sraj reg = GPIO_HI_BLINK_EN; 417183840Sraj pin -= GPIO_PINS_PER_REG; 418183840Sraj } else 419183840Sraj reg = GPIO_BLINK_EN; 420183840Sraj 421183840Sraj if (enable) 422183840Sraj mv_gpio_reg_set(reg, pin); 423183840Sraj else 424183840Sraj mv_gpio_reg_clear(reg, pin); 425183840Sraj} 426183840Sraj 427183840Srajstatic void 428183840Srajmv_gpio_polarity(uint32_t pin, uint8_t enable) 429183840Sraj{ 430183840Sraj uint32_t reg; 431183840Sraj 432183840Sraj if (pin >= mv_gpio_softc->pin_num) 433183840Sraj return; 434183840Sraj 435183840Sraj if (pin >= GPIO_PINS_PER_REG) { 436183840Sraj reg = GPIO_HI_DATA_IN_POLAR; 437183840Sraj pin -= GPIO_PINS_PER_REG; 438183840Sraj } else 439183840Sraj reg = GPIO_DATA_IN_POLAR; 440183840Sraj 441183840Sraj if (enable) 442183840Sraj mv_gpio_reg_set(reg, pin); 443183840Sraj else 444183840Sraj mv_gpio_reg_clear(reg, pin); 445183840Sraj} 446183840Sraj 447183840Srajstatic void 448183840Srajmv_gpio_level(uint32_t pin, uint8_t enable) 449183840Sraj{ 450183840Sraj uint32_t reg; 451183840Sraj 452183840Sraj if (pin >= mv_gpio_softc->pin_num) 453183840Sraj return; 454183840Sraj 455183840Sraj if (pin >= GPIO_PINS_PER_REG) { 456183840Sraj reg = GPIO_HI_INT_LEV_MASK; 457183840Sraj pin -= GPIO_PINS_PER_REG; 458183840Sraj } else 459183840Sraj reg = GPIO_INT_LEV_MASK; 460183840Sraj 461183840Sraj if (enable) 462183840Sraj mv_gpio_reg_set(reg, pin); 463183840Sraj else 464183840Sraj mv_gpio_reg_clear(reg, pin); 465183840Sraj} 466183840Sraj 467183840Srajstatic void 468183840Srajmv_gpio_edge(uint32_t pin, uint8_t enable) 469183840Sraj{ 470183840Sraj uint32_t reg; 471183840Sraj 472183840Sraj if (pin >= mv_gpio_softc->pin_num) 473183840Sraj return; 474183840Sraj 475183840Sraj if (pin >= GPIO_PINS_PER_REG) { 476183840Sraj reg = GPIO_HI_INT_EDGE_MASK; 477183840Sraj pin -= GPIO_PINS_PER_REG; 478183840Sraj } else 479183840Sraj reg = GPIO_INT_EDGE_MASK; 480183840Sraj 481183840Sraj if (enable) 482183840Sraj mv_gpio_reg_set(reg, pin); 483183840Sraj else 484183840Sraj mv_gpio_reg_clear(reg, pin); 485183840Sraj} 486183840Sraj 487183840Srajstatic void 488183840Srajmv_gpio_int_ack(uint32_t pin) 489183840Sraj{ 490183840Sraj uint32_t reg; 491183840Sraj 492183840Sraj if (pin >= mv_gpio_softc->pin_num) 493183840Sraj return; 494183840Sraj 495183840Sraj if (pin >= GPIO_PINS_PER_REG) { 496183840Sraj reg = GPIO_HI_INT_CAUSE; 497183840Sraj pin -= GPIO_PINS_PER_REG; 498183840Sraj } else 499183840Sraj reg = GPIO_INT_CAUSE; 500183840Sraj 501183840Sraj mv_gpio_reg_clear(reg, pin); 502183840Sraj} 503183840Sraj 504183840Srajstatic uint32_t 505183840Srajmv_gpio_value_get(uint32_t pin) 506183840Sraj{ 507183840Sraj uint32_t reg, reg_val; 508183840Sraj 509183840Sraj if (pin >= mv_gpio_softc->pin_num) 510183840Sraj return (0); 511183840Sraj 512183840Sraj if (pin >= GPIO_PINS_PER_REG) { 513183840Sraj reg = GPIO_HI_DATA_IN; 514183840Sraj pin -= GPIO_PINS_PER_REG; 515183840Sraj } else 516183840Sraj reg = GPIO_DATA_IN; 517183840Sraj 518183840Sraj reg_val = mv_gpio_reg_read(reg); 519183840Sraj 520183840Sraj return (reg_val & GPIO(pin)); 521183840Sraj} 522183840Sraj 523183840Srajstatic void 524183840Srajmv_gpio_value_set(uint32_t pin, uint8_t val) 525183840Sraj{ 526183840Sraj uint32_t reg; 527183840Sraj 528183840Sraj if (pin >= mv_gpio_softc->pin_num) 529183840Sraj return; 530183840Sraj 531183840Sraj if (pin >= GPIO_PINS_PER_REG) { 532183840Sraj reg = GPIO_HI_DATA_OUT; 533183840Sraj pin -= GPIO_PINS_PER_REG; 534183840Sraj } else 535183840Sraj reg = GPIO_DATA_OUT; 536183840Sraj 537183840Sraj if (val) 538183840Sraj mv_gpio_reg_set(reg, pin); 539183840Sraj else 540183840Sraj mv_gpio_reg_clear(reg, pin); 541183840Sraj} 542209131Sraj 543209131Srajint 544209131Srajmv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len) 545209131Sraj{ 546209131Sraj pcell_t gpio_cells, pincnt; 547209131Sraj int inc, t, tuples, tuple_size; 548209131Sraj int dir, flags, pin; 549209131Sraj u_long gpio_ctrl, size; 550209131Sraj struct mv_gpio_softc sc; 551209131Sraj 552209131Sraj pincnt = 0; 553239367Shrs if (!OF_hasprop(ctrl, "gpio-controller")) 554209131Sraj /* Node is not a GPIO controller. */ 555209131Sraj return (ENXIO); 556209131Sraj 557209131Sraj if (OF_getprop(ctrl, "#gpio-cells", &gpio_cells, sizeof(pcell_t)) < 0) 558209131Sraj return (ENXIO); 559209131Sraj 560209131Sraj gpio_cells = fdt32_to_cpu(gpio_cells); 561209131Sraj if (gpio_cells != 3) 562209131Sraj return (ENXIO); 563209131Sraj 564209131Sraj tuple_size = gpio_cells * sizeof(pcell_t) + sizeof(phandle_t); 565209131Sraj tuples = len / tuple_size; 566209131Sraj 567209131Sraj if (fdt_regsize(ctrl, &gpio_ctrl, &size)) 568209131Sraj return (ENXIO); 569209131Sraj 570209131Sraj if (OF_getprop(ctrl, "pin-count", &pincnt, sizeof(pcell_t)) < 0) 571209131Sraj return (ENXIO); 572209131Sraj sc.pin_num = fdt32_to_cpu(pincnt); 573209131Sraj 574209131Sraj /* 575209131Sraj * Skip controller reference, since controller's phandle is given 576209131Sraj * explicitly (in a function argument). 577209131Sraj */ 578209131Sraj inc = sizeof(ihandle_t) / sizeof(pcell_t); 579209131Sraj gpios += inc; 580209131Sraj 581209131Sraj for (t = 0; t < tuples; t++) { 582209131Sraj pin = fdt32_to_cpu(gpios[0]); 583209131Sraj dir = fdt32_to_cpu(gpios[1]); 584209131Sraj flags = fdt32_to_cpu(gpios[2]); 585209131Sraj 586209131Sraj mv_gpio_configure(pin, flags); 587209131Sraj 588209131Sraj if (dir == 1) 589209131Sraj /* Input. */ 590209131Sraj mv_gpio_out_en(pin, 0); 591209131Sraj else { 592209131Sraj /* Output. */ 593209131Sraj if (flags & MV_GPIO_OUT_OPEN_DRAIN) 594209131Sraj mv_gpio_out(pin, 0, 1); 595209131Sraj 596209131Sraj if (flags & MV_GPIO_OUT_OPEN_SRC) 597209131Sraj mv_gpio_out(pin, 1, 1); 598209131Sraj } 599209131Sraj gpios += gpio_cells + inc; 600209131Sraj } 601209131Sraj 602209131Sraj return (0); 603209131Sraj} 604209131Sraj 605209131Sraj#define MAX_PINS_PER_NODE 5 606209131Sraj#define GPIOS_PROP_CELLS 4 607209131Srajint 608209131Srajplatform_gpio_init(void) 609209131Sraj{ 610209131Sraj phandle_t child, parent, root, ctrl; 611209131Sraj pcell_t gpios[MAX_PINS_PER_NODE * GPIOS_PROP_CELLS]; 612209131Sraj struct gpio_ctrl_entry *e; 613209131Sraj int len, rv; 614209131Sraj 615209131Sraj root = OF_finddevice("/"); 616209131Sraj len = 0; 617209131Sraj parent = root; 618209131Sraj 619209131Sraj /* Traverse through entire tree to find nodes with 'gpios' prop */ 620209131Sraj for (child = OF_child(parent); child != 0; child = OF_peer(child)) { 621209131Sraj 622209131Sraj /* Find a 'leaf'. Start the search from this node. */ 623209131Sraj while (OF_child(child)) { 624209131Sraj parent = child; 625209131Sraj child = OF_child(child); 626209131Sraj } 627209131Sraj if ((len = OF_getproplen(child, "gpios")) > 0) { 628209131Sraj 629209131Sraj if (len > sizeof(gpios)) 630209131Sraj return (ENXIO); 631209131Sraj 632209131Sraj /* Get 'gpios' property. */ 633209131Sraj OF_getprop(child, "gpios", &gpios, len); 634209131Sraj 635209131Sraj e = (struct gpio_ctrl_entry *)&gpio_controllers; 636209131Sraj 637209131Sraj /* Find and call a handler. */ 638209131Sraj for (; e->compat; e++) { 639209131Sraj /* 640209131Sraj * First cell of 'gpios' property should 641209131Sraj * contain a ref. to a node defining GPIO 642209131Sraj * controller. 643209131Sraj */ 644265967Sian ctrl = OF_xref_phandle(fdt32_to_cpu(gpios[0])); 645209131Sraj 646209131Sraj if (fdt_is_compatible(ctrl, e->compat)) 647209131Sraj /* Call a handler. */ 648209131Sraj if ((rv = e->handler(ctrl, 649209131Sraj (pcell_t *)&gpios, len))) 650209131Sraj return (rv); 651209131Sraj } 652209131Sraj } 653209131Sraj 654209131Sraj if (OF_peer(child) == 0) { 655209131Sraj /* No more siblings. */ 656209131Sraj child = parent; 657209131Sraj parent = OF_parent(child); 658209131Sraj } 659209131Sraj } 660209131Sraj return (0); 661209131Sraj} 662