gpio.c revision 265967
1/*- 2 * Copyright (c) 2006 Benno Rice. 3 * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. 4 * All rights reserved. 5 * 6 * Adapted and extended for Marvell SoCs by Semihalf. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/10/sys/arm/mv/gpio.c 265967 2014-05-13 17:59:17Z ian $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/lock.h> 39#include <sys/interrupt.h> 40#include <sys/module.h> 41#include <sys/malloc.h> 42#include <sys/mutex.h> 43#include <sys/rman.h> 44#include <sys/queue.h> 45#include <sys/timetc.h> 46#include <machine/bus.h> 47#include <machine/fdt.h> 48#include <machine/intr.h> 49 50#include <dev/fdt/fdt_common.h> 51#include <dev/ofw/ofw_bus.h> 52#include <dev/ofw/ofw_bus_subr.h> 53 54#include <arm/mv/mvvar.h> 55#include <arm/mv/mvreg.h> 56 57#define GPIO_MAX_INTR_COUNT 8 58#define GPIO_PINS_PER_REG 32 59 60struct mv_gpio_softc { 61 struct resource * res[GPIO_MAX_INTR_COUNT + 1]; 62 void *ih_cookie[GPIO_MAX_INTR_COUNT]; 63 bus_space_tag_t bst; 64 bus_space_handle_t bsh; 65 uint8_t pin_num; /* number of GPIO pins */ 66 uint8_t irq_num; /* number of real IRQs occupied by GPIO controller */ 67}; 68 69extern struct resource_spec mv_gpio_res[]; 70 71static struct mv_gpio_softc *mv_gpio_softc = NULL; 72static uint32_t gpio_setup[MV_GPIO_MAX_NPINS]; 73 74static int mv_gpio_probe(device_t); 75static int mv_gpio_attach(device_t); 76static int mv_gpio_intr(void *); 77 78static void mv_gpio_intr_handler(int pin); 79static uint32_t mv_gpio_reg_read(uint32_t reg); 80static void mv_gpio_reg_write(uint32_t reg, uint32_t val); 81static void mv_gpio_reg_set(uint32_t reg, uint32_t val); 82static void mv_gpio_reg_clear(uint32_t reg, uint32_t val); 83 84static void mv_gpio_blink(uint32_t pin, uint8_t enable); 85static void mv_gpio_polarity(uint32_t pin, uint8_t enable); 86static void mv_gpio_level(uint32_t pin, uint8_t enable); 87static void mv_gpio_edge(uint32_t pin, uint8_t enable); 88static void mv_gpio_out_en(uint32_t pin, uint8_t enable); 89static void mv_gpio_int_ack(uint32_t pin); 90static void mv_gpio_value_set(uint32_t pin, uint8_t val); 91static uint32_t mv_gpio_value_get(uint32_t pin); 92 93static device_method_t mv_gpio_methods[] = { 94 DEVMETHOD(device_probe, mv_gpio_probe), 95 DEVMETHOD(device_attach, mv_gpio_attach), 96 { 0, 0 } 97}; 98 99static driver_t mv_gpio_driver = { 100 "gpio", 101 mv_gpio_methods, 102 sizeof(struct mv_gpio_softc), 103}; 104 105static devclass_t mv_gpio_devclass; 106 107DRIVER_MODULE(gpio, simplebus, mv_gpio_driver, mv_gpio_devclass, 0, 0); 108 109typedef int (*gpios_phandler_t)(phandle_t, pcell_t *, int); 110 111struct gpio_ctrl_entry { 112 const char *compat; 113 gpios_phandler_t handler; 114}; 115 116int mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len); 117int gpio_get_config_from_dt(void); 118 119struct gpio_ctrl_entry gpio_controllers[] = { 120 { "mrvl,gpio", &mv_handle_gpios_prop }, 121 { NULL, NULL } 122}; 123 124static int 125mv_gpio_probe(device_t dev) 126{ 127 128 if (!ofw_bus_is_compatible(dev, "mrvl,gpio")) 129 return (ENXIO); 130 131 device_set_desc(dev, "Marvell Integrated GPIO Controller"); 132 return (0); 133} 134 135static int 136mv_gpio_attach(device_t dev) 137{ 138 int error, i; 139 struct mv_gpio_softc *sc; 140 uint32_t dev_id, rev_id; 141 142 sc = (struct mv_gpio_softc *)device_get_softc(dev); 143 if (sc == NULL) 144 return (ENXIO); 145 146 mv_gpio_softc = sc; 147 148 /* Get chip id and revision */ 149 soc_id(&dev_id, &rev_id); 150 151 if (dev_id == MV_DEV_88F5182 || 152 dev_id == MV_DEV_88F5281 || 153 dev_id == MV_DEV_MV78100 || 154 dev_id == MV_DEV_MV78100_Z0 ) { 155 sc->pin_num = 32; 156 sc->irq_num = 4; 157 158 } else if (dev_id == MV_DEV_88F6281 || 159 dev_id == MV_DEV_88F6282) { 160 sc->pin_num = 50; 161 sc->irq_num = 7; 162 163 } else { 164 device_printf(dev, "unknown chip id=0x%x\n", dev_id); 165 return (ENXIO); 166 } 167 168 error = bus_alloc_resources(dev, mv_gpio_res, sc->res); 169 if (error) { 170 device_printf(dev, "could not allocate resources\n"); 171 return (ENXIO); 172 } 173 174 sc->bst = rman_get_bustag(sc->res[0]); 175 sc->bsh = rman_get_bushandle(sc->res[0]); 176 177 /* Disable and clear all interrupts */ 178 bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0); 179 bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0); 180 bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0); 181 182 if (sc->pin_num > GPIO_PINS_PER_REG) { 183 bus_space_write_4(sc->bst, sc->bsh, 184 GPIO_HI_INT_EDGE_MASK, 0); 185 bus_space_write_4(sc->bst, sc->bsh, 186 GPIO_HI_INT_LEV_MASK, 0); 187 bus_space_write_4(sc->bst, sc->bsh, 188 GPIO_HI_INT_CAUSE, 0); 189 } 190 191 for (i = 0; i < sc->irq_num; i++) { 192 if (bus_setup_intr(dev, sc->res[1 + i], 193 INTR_TYPE_MISC, mv_gpio_intr, NULL, 194 sc, &sc->ih_cookie[i]) != 0) { 195 bus_release_resources(dev, mv_gpio_res, sc->res); 196 device_printf(dev, "could not set up intr %d\n", i); 197 return (ENXIO); 198 } 199 } 200 201 return (platform_gpio_init()); 202} 203 204static int 205mv_gpio_intr(void *arg) 206{ 207 uint32_t int_cause, gpio_val; 208 uint32_t int_cause_hi, gpio_val_hi = 0; 209 int i; 210 211 int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE); 212 gpio_val = mv_gpio_reg_read(GPIO_DATA_IN); 213 gpio_val &= int_cause; 214 if (mv_gpio_softc->pin_num > GPIO_PINS_PER_REG) { 215 int_cause_hi = mv_gpio_reg_read(GPIO_HI_INT_CAUSE); 216 gpio_val_hi = mv_gpio_reg_read(GPIO_HI_DATA_IN); 217 gpio_val_hi &= int_cause_hi; 218 } 219 220 i = 0; 221 while (gpio_val != 0) { 222 if (gpio_val & 1) 223 mv_gpio_intr_handler(i); 224 gpio_val >>= 1; 225 i++; 226 } 227 228 if (mv_gpio_softc->pin_num > GPIO_PINS_PER_REG) { 229 i = 0; 230 while (gpio_val_hi != 0) { 231 if (gpio_val_hi & 1) 232 mv_gpio_intr_handler(i + GPIO_PINS_PER_REG); 233 gpio_val_hi >>= 1; 234 i++; 235 } 236 } 237 238 return (FILTER_HANDLED); 239} 240 241/* 242 * GPIO interrupt handling 243 */ 244 245static struct intr_event *gpio_events[MV_GPIO_MAX_NPINS]; 246 247int 248mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, 249 void (*hand)(void *), void *arg, int pin, int flags, void **cookiep) 250{ 251 struct intr_event *event; 252 int error; 253 254 if (pin < 0 || pin >= mv_gpio_softc->pin_num) 255 return (ENXIO); 256 event = gpio_events[pin]; 257 if (event == NULL) { 258 error = intr_event_create(&event, (void *)pin, 0, pin, 259 (void (*)(void *))mv_gpio_intr_mask, 260 (void (*)(void *))mv_gpio_intr_unmask, 261 (void (*)(void *))mv_gpio_int_ack, 262 NULL, 263 "gpio%d:", pin); 264 if (error != 0) 265 return (error); 266 gpio_events[pin] = event; 267 } 268 269 intr_event_add_handler(event, name, filt, hand, arg, 270 intr_priority(flags), flags, cookiep); 271 return (0); 272} 273 274void 275mv_gpio_intr_mask(int pin) 276{ 277 278 if (pin >= mv_gpio_softc->pin_num) 279 return; 280 281 if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE) 282 mv_gpio_edge(pin, 0); 283 else 284 mv_gpio_level(pin, 0); 285} 286 287void 288mv_gpio_intr_unmask(int pin) 289{ 290 291 if (pin >= mv_gpio_softc->pin_num) 292 return; 293 294 if (gpio_setup[pin] & MV_GPIO_IN_IRQ_EDGE) 295 mv_gpio_edge(pin, 1); 296 else 297 mv_gpio_level(pin, 1); 298} 299 300static void 301mv_gpio_intr_handler(int pin) 302{ 303 struct intr_event *event; 304 305 event = gpio_events[pin]; 306 if (event == NULL || TAILQ_EMPTY(&event->ie_handlers)) 307 return; 308 309 intr_event_handle(event, NULL); 310} 311 312static int 313mv_gpio_configure(uint32_t pin, uint32_t flags) 314{ 315 316 if (pin >= mv_gpio_softc->pin_num) 317 return (EINVAL); 318 319 if (flags & MV_GPIO_OUT_BLINK) 320 mv_gpio_blink(pin, 1); 321 if (flags & MV_GPIO_IN_POL_LOW) 322 mv_gpio_polarity(pin, 1); 323 if (flags & MV_GPIO_IN_IRQ_EDGE) 324 mv_gpio_edge(pin, 1); 325 if (flags & MV_GPIO_IN_IRQ_LEVEL) 326 mv_gpio_level(pin, 1); 327 328 gpio_setup[pin] = flags; 329 330 return (0); 331} 332 333void 334mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable) 335{ 336 337 mv_gpio_value_set(pin, val); 338 mv_gpio_out_en(pin, enable); 339} 340 341uint8_t 342mv_gpio_in(uint32_t pin) 343{ 344 345 return (mv_gpio_value_get(pin) ? 1 : 0); 346} 347 348static uint32_t 349mv_gpio_reg_read(uint32_t reg) 350{ 351 352 return (bus_space_read_4(mv_gpio_softc->bst, 353 mv_gpio_softc->bsh, reg)); 354} 355 356static void 357mv_gpio_reg_write(uint32_t reg, uint32_t val) 358{ 359 360 bus_space_write_4(mv_gpio_softc->bst, 361 mv_gpio_softc->bsh, reg, val); 362} 363 364static void 365mv_gpio_reg_set(uint32_t reg, uint32_t pin) 366{ 367 uint32_t reg_val; 368 369 reg_val = mv_gpio_reg_read(reg); 370 reg_val |= GPIO(pin); 371 mv_gpio_reg_write(reg, reg_val); 372} 373 374static void 375mv_gpio_reg_clear(uint32_t reg, uint32_t pin) 376{ 377 uint32_t reg_val; 378 379 reg_val = mv_gpio_reg_read(reg); 380 reg_val &= ~(GPIO(pin)); 381 mv_gpio_reg_write(reg, reg_val); 382} 383 384static void 385mv_gpio_out_en(uint32_t pin, uint8_t enable) 386{ 387 uint32_t reg; 388 389 if (pin >= mv_gpio_softc->pin_num) 390 return; 391 392 if (pin >= GPIO_PINS_PER_REG) { 393 reg = GPIO_HI_DATA_OUT_EN_CTRL; 394 pin -= GPIO_PINS_PER_REG; 395 } else 396 reg = GPIO_DATA_OUT_EN_CTRL; 397 398 if (enable) 399 mv_gpio_reg_clear(reg, pin); 400 else 401 mv_gpio_reg_set(reg, pin); 402} 403 404static void 405mv_gpio_blink(uint32_t pin, uint8_t enable) 406{ 407 uint32_t reg; 408 409 if (pin >= mv_gpio_softc->pin_num) 410 return; 411 412 if (pin >= GPIO_PINS_PER_REG) { 413 reg = GPIO_HI_BLINK_EN; 414 pin -= GPIO_PINS_PER_REG; 415 } else 416 reg = GPIO_BLINK_EN; 417 418 if (enable) 419 mv_gpio_reg_set(reg, pin); 420 else 421 mv_gpio_reg_clear(reg, pin); 422} 423 424static void 425mv_gpio_polarity(uint32_t pin, uint8_t enable) 426{ 427 uint32_t reg; 428 429 if (pin >= mv_gpio_softc->pin_num) 430 return; 431 432 if (pin >= GPIO_PINS_PER_REG) { 433 reg = GPIO_HI_DATA_IN_POLAR; 434 pin -= GPIO_PINS_PER_REG; 435 } else 436 reg = GPIO_DATA_IN_POLAR; 437 438 if (enable) 439 mv_gpio_reg_set(reg, pin); 440 else 441 mv_gpio_reg_clear(reg, pin); 442} 443 444static void 445mv_gpio_level(uint32_t pin, uint8_t enable) 446{ 447 uint32_t reg; 448 449 if (pin >= mv_gpio_softc->pin_num) 450 return; 451 452 if (pin >= GPIO_PINS_PER_REG) { 453 reg = GPIO_HI_INT_LEV_MASK; 454 pin -= GPIO_PINS_PER_REG; 455 } else 456 reg = GPIO_INT_LEV_MASK; 457 458 if (enable) 459 mv_gpio_reg_set(reg, pin); 460 else 461 mv_gpio_reg_clear(reg, pin); 462} 463 464static void 465mv_gpio_edge(uint32_t pin, uint8_t enable) 466{ 467 uint32_t reg; 468 469 if (pin >= mv_gpio_softc->pin_num) 470 return; 471 472 if (pin >= GPIO_PINS_PER_REG) { 473 reg = GPIO_HI_INT_EDGE_MASK; 474 pin -= GPIO_PINS_PER_REG; 475 } else 476 reg = GPIO_INT_EDGE_MASK; 477 478 if (enable) 479 mv_gpio_reg_set(reg, pin); 480 else 481 mv_gpio_reg_clear(reg, pin); 482} 483 484static void 485mv_gpio_int_ack(uint32_t pin) 486{ 487 uint32_t reg; 488 489 if (pin >= mv_gpio_softc->pin_num) 490 return; 491 492 if (pin >= GPIO_PINS_PER_REG) { 493 reg = GPIO_HI_INT_CAUSE; 494 pin -= GPIO_PINS_PER_REG; 495 } else 496 reg = GPIO_INT_CAUSE; 497 498 mv_gpio_reg_clear(reg, pin); 499} 500 501static uint32_t 502mv_gpio_value_get(uint32_t pin) 503{ 504 uint32_t reg, reg_val; 505 506 if (pin >= mv_gpio_softc->pin_num) 507 return (0); 508 509 if (pin >= GPIO_PINS_PER_REG) { 510 reg = GPIO_HI_DATA_IN; 511 pin -= GPIO_PINS_PER_REG; 512 } else 513 reg = GPIO_DATA_IN; 514 515 reg_val = mv_gpio_reg_read(reg); 516 517 return (reg_val & GPIO(pin)); 518} 519 520static void 521mv_gpio_value_set(uint32_t pin, uint8_t val) 522{ 523 uint32_t reg; 524 525 if (pin >= mv_gpio_softc->pin_num) 526 return; 527 528 if (pin >= GPIO_PINS_PER_REG) { 529 reg = GPIO_HI_DATA_OUT; 530 pin -= GPIO_PINS_PER_REG; 531 } else 532 reg = GPIO_DATA_OUT; 533 534 if (val) 535 mv_gpio_reg_set(reg, pin); 536 else 537 mv_gpio_reg_clear(reg, pin); 538} 539 540int 541mv_handle_gpios_prop(phandle_t ctrl, pcell_t *gpios, int len) 542{ 543 pcell_t gpio_cells, pincnt; 544 int inc, t, tuples, tuple_size; 545 int dir, flags, pin; 546 u_long gpio_ctrl, size; 547 struct mv_gpio_softc sc; 548 549 pincnt = 0; 550 if (!OF_hasprop(ctrl, "gpio-controller")) 551 /* Node is not a GPIO controller. */ 552 return (ENXIO); 553 554 if (OF_getprop(ctrl, "#gpio-cells", &gpio_cells, sizeof(pcell_t)) < 0) 555 return (ENXIO); 556 557 gpio_cells = fdt32_to_cpu(gpio_cells); 558 if (gpio_cells != 3) 559 return (ENXIO); 560 561 tuple_size = gpio_cells * sizeof(pcell_t) + sizeof(phandle_t); 562 tuples = len / tuple_size; 563 564 if (fdt_regsize(ctrl, &gpio_ctrl, &size)) 565 return (ENXIO); 566 567 if (OF_getprop(ctrl, "pin-count", &pincnt, sizeof(pcell_t)) < 0) 568 return (ENXIO); 569 sc.pin_num = fdt32_to_cpu(pincnt); 570 571 /* 572 * Skip controller reference, since controller's phandle is given 573 * explicitly (in a function argument). 574 */ 575 inc = sizeof(ihandle_t) / sizeof(pcell_t); 576 gpios += inc; 577 578 for (t = 0; t < tuples; t++) { 579 pin = fdt32_to_cpu(gpios[0]); 580 dir = fdt32_to_cpu(gpios[1]); 581 flags = fdt32_to_cpu(gpios[2]); 582 583 mv_gpio_configure(pin, flags); 584 585 if (dir == 1) 586 /* Input. */ 587 mv_gpio_out_en(pin, 0); 588 else { 589 /* Output. */ 590 if (flags & MV_GPIO_OUT_OPEN_DRAIN) 591 mv_gpio_out(pin, 0, 1); 592 593 if (flags & MV_GPIO_OUT_OPEN_SRC) 594 mv_gpio_out(pin, 1, 1); 595 } 596 gpios += gpio_cells + inc; 597 } 598 599 return (0); 600} 601 602#define MAX_PINS_PER_NODE 5 603#define GPIOS_PROP_CELLS 4 604int 605platform_gpio_init(void) 606{ 607 phandle_t child, parent, root, ctrl; 608 pcell_t gpios[MAX_PINS_PER_NODE * GPIOS_PROP_CELLS]; 609 struct gpio_ctrl_entry *e; 610 int len, rv; 611 612 root = OF_finddevice("/"); 613 len = 0; 614 parent = root; 615 616 /* Traverse through entire tree to find nodes with 'gpios' prop */ 617 for (child = OF_child(parent); child != 0; child = OF_peer(child)) { 618 619 /* Find a 'leaf'. Start the search from this node. */ 620 while (OF_child(child)) { 621 parent = child; 622 child = OF_child(child); 623 } 624 if ((len = OF_getproplen(child, "gpios")) > 0) { 625 626 if (len > sizeof(gpios)) 627 return (ENXIO); 628 629 /* Get 'gpios' property. */ 630 OF_getprop(child, "gpios", &gpios, len); 631 632 e = (struct gpio_ctrl_entry *)&gpio_controllers; 633 634 /* Find and call a handler. */ 635 for (; e->compat; e++) { 636 /* 637 * First cell of 'gpios' property should 638 * contain a ref. to a node defining GPIO 639 * controller. 640 */ 641 ctrl = OF_xref_phandle(fdt32_to_cpu(gpios[0])); 642 643 if (fdt_is_compatible(ctrl, e->compat)) 644 /* Call a handler. */ 645 if ((rv = e->handler(ctrl, 646 (pcell_t *)&gpios, len))) 647 return (rv); 648 } 649 } 650 651 if (OF_peer(child) == 0) { 652 /* No more siblings. */ 653 child = parent; 654 parent = OF_parent(child); 655 } 656 } 657 return (0); 658} 659