34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/malloc.h> 41#include <sys/rman.h> 42#include <sys/timeet.h> 43#include <sys/timetc.h> 44#include <sys/watchdog.h> 45#include <sys/mutex.h> 46#include <sys/gpio.h> 47 48#include <dev/ofw/openfirm.h> 49#include <dev/ofw/ofw_bus.h> 50#include <dev/ofw/ofw_bus_subr.h> 51 52#include <machine/bus.h> 53#include <machine/cpu.h> 54#include <machine/intr.h> 55 56#include "gpio_if.h" 57 58#include <arm/samsung/exynos/exynos5_combiner.h> 59#include <arm/samsung/exynos/exynos5_pad.h> 60 61#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 62#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 63 64#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 65 66#define MAX_PORTS 5 67#define MAX_NGPIO 253 68 69#define N_EXT_INTS 16 70 71#define EXYNOS5250 1 72#define EXYNOS5420 2 73 74#define PIN_IN 0 75#define PIN_OUT 1 76 77#define READ4(_sc, _port, _reg) \ 78 bus_space_read_4(_sc->bst[_port], _sc->bsh[_port], _reg) 79#define WRITE4(_sc, _port, _reg, _val) \ 80 bus_space_write_4(_sc->bst[_port], _sc->bsh[_port], _reg, _val) 81 82/* 83 * GPIO interface 84 */ 85static int pad_pin_max(device_t, int *); 86static int pad_pin_getcaps(device_t, uint32_t, uint32_t *); 87static int pad_pin_getname(device_t, uint32_t, char *); 88static int pad_pin_getflags(device_t, uint32_t, uint32_t *); 89static int pad_pin_setflags(device_t, uint32_t, uint32_t); 90static int pad_pin_set(device_t, uint32_t, unsigned int); 91static int pad_pin_get(device_t, uint32_t, unsigned int *); 92static int pad_pin_toggle(device_t, uint32_t pin); 93 94struct gpio_bank { 95 char *name; 96 uint32_t port; 97 uint32_t con; 98 uint32_t ngpio; 99 uint32_t ext_con; 100 uint32_t ext_flt_con; 101 uint32_t mask; 102 uint32_t pend; 103}; 104 105struct pad_softc { 106 struct resource *res[MAX_PORTS * 2]; 107 bus_space_tag_t bst[MAX_PORTS]; 108 bus_space_handle_t bsh[MAX_PORTS]; 109 struct mtx sc_mtx; 110 int gpio_npins; 111 struct gpio_pin gpio_pins[MAX_NGPIO]; 112 void *gpio_ih[MAX_PORTS]; 113 device_t dev; 114 int model; 115 struct resource_spec *pad_spec; 116 struct gpio_bank *gpio_map; 117 struct interrupt_entry *interrupt_table; 118 int nports; 119}; 120 121struct pad_softc *gpio_sc; 122 123static struct resource_spec pad_spec_5250[] = { 124 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 125 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 126 { SYS_RES_MEMORY, 2, RF_ACTIVE }, 127 { SYS_RES_MEMORY, 3, RF_ACTIVE }, 128 { SYS_RES_IRQ, 0, RF_ACTIVE }, 129 { SYS_RES_IRQ, 1, RF_ACTIVE }, 130 { SYS_RES_IRQ, 2, RF_ACTIVE }, 131 { SYS_RES_IRQ, 3, RF_ACTIVE }, 132 { -1, 0 } 133}; 134 135static struct resource_spec pad_spec_5420[] = { 136 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 137 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 138 { SYS_RES_MEMORY, 2, RF_ACTIVE }, 139 { SYS_RES_MEMORY, 3, RF_ACTIVE }, 140 { SYS_RES_MEMORY, 4, RF_ACTIVE }, 141 { SYS_RES_IRQ, 0, RF_ACTIVE }, 142 { SYS_RES_IRQ, 1, RF_ACTIVE }, 143 { SYS_RES_IRQ, 2, RF_ACTIVE }, 144 { SYS_RES_IRQ, 3, RF_ACTIVE }, 145 { SYS_RES_IRQ, 4, RF_ACTIVE }, 146 { -1, 0 } 147}; 148 149static struct ofw_compat_data compat_data[] = { 150 {"samsung,exynos5420-padctrl", EXYNOS5420}, 151 {"samsung,exynos5250-padctrl", EXYNOS5250}, 152 {NULL, 0} 153}; 154 155struct pad_intr { 156 uint32_t enabled; 157 void (*ih) (void *); 158 void *ih_user; 159}; 160 161static struct pad_intr intr_map[MAX_NGPIO]; 162 163struct interrupt_entry { 164 int gpio_number; 165 char *combiner_source_name; 166}; 167 168struct interrupt_entry interrupt_table_5250[N_EXT_INTS] = { 169 { 147, "EINT[15]" }, 170 { 146, "EINT[14]" }, 171 { 145, "EINT[13]" }, 172 { 144, "EINT[12]" }, 173 { 143, "EINT[11]" }, 174 { 142, "EINT[10]" }, 175 { 141, "EINT[9]" }, 176 { 140, "EINT[8]" }, 177 { 139, "EINT[7]" }, 178 { 138, "EINT[6]" }, 179 { 137, "EINT[5]" }, 180 { 136, "EINT[4]" }, 181 { 135, "EINT[3]" }, 182 { 134, "EINT[2]" }, 183 { 133, "EINT[1]" }, 184 { 132, "EINT[0]" }, 185}; 186 187struct interrupt_entry interrupt_table_5420[N_EXT_INTS] = { 188 { 23, "EINT[15]" }, 189 { 22, "EINT[14]" }, 190 { 21, "EINT[13]" }, 191 { 20, "EINT[12]" }, 192 { 19, "EINT[11]" }, 193 { 18, "EINT[10]" }, 194 { 17, "EINT[9]" }, 195 { 16, "EINT[8]" }, 196 { 15, "EINT[7]" }, 197 { 14, "EINT[6]" }, 198 { 13, "EINT[5]" }, 199 { 12, "EINT[4]" }, 200 { 11, "EINT[3]" }, 201 { 10, "EINT[2]" }, 202 { 9, "EINT[1]" }, 203 { 8, "EINT[0]" }, 204}; 205 206/* 207 * 253 multi-functional input/output ports 208 */ 209 210static struct gpio_bank gpio_map_5250[] = { 211 /* first 132 gpio */ 212 { "gpa0", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 213 { "gpa1", 0, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 }, 214 { "gpa2", 0, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 }, 215 { "gpb0", 0, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C }, 216 { "gpb1", 0, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 }, 217 { "gpb2", 0, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 }, 218 { "gpb3", 0, 0x0C0, 4, 0x718, 0x830, 0x918, 0xA18 }, 219 { "gpc0", 0, 0x0E0, 7, 0x71C, 0x838, 0x91C, 0xA1C }, 220 { "gpc1", 0, 0x100, 4, 0x720, 0x840, 0x920, 0xA20 }, 221 { "gpc2", 0, 0x120, 7, 0x724, 0x848, 0x924, 0xA24 }, 222 { "gpc3", 0, 0x140, 7, 0x728, 0x850, 0x928, 0xA28 }, 223 { "gpd0", 0, 0x160, 4, 0x72C, 0x858, 0x92C, 0xA2C }, 224 { "gpd1", 0, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 }, 225 { "gpy0", 0, 0x1A0, 6, 0, 0, 0, 0 }, 226 { "gpy1", 0, 0x1C0, 4, 0, 0, 0, 0 }, 227 { "gpy2", 0, 0x1E0, 6, 0, 0, 0, 0 }, 228 { "gpy3", 0, 0x200, 8, 0, 0, 0, 0 }, 229 { "gpy4", 0, 0x220, 8, 0, 0, 0, 0 }, 230 { "gpy5", 0, 0x240, 8, 0, 0, 0, 0 }, 231 { "gpy6", 0, 0x260, 8, 0, 0, 0, 0 }, 232 { "gpc4", 0, 0x2E0, 7, 0x734, 0x868, 0x934, 0xA34 }, 233 234 /* next 32 */ 235 { "gpx0", 0, 0xC00, 8, 0xE00, 0xE80, 0xF00, 0xF40 }, 236 { "gpx1", 0, 0xC20, 8, 0xE04, 0xE88, 0xF04, 0xF44 }, 237 { "gpx2", 0, 0xC40, 8, 0xE08, 0xE90, 0xF08, 0xF48 }, 238 { "gpx3", 0, 0xC60, 8, 0xE0C, 0xE98, 0xF0C, 0xF4C }, 239 240 { "gpe0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 241 { "gpe1", 1, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 }, 242 { "gpf0", 1, 0x040, 4, 0x708, 0x810, 0x908, 0xA08 }, 243 { "gpf1", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C }, 244 { "gpg0", 1, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 }, 245 { "gpg1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 }, 246 { "gpg2", 1, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 }, 247 { "gph0", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C }, 248 { "gph1", 1, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 }, 249 250 { "gpv0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 251 { "gpv1", 2, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 }, 252 { "gpv2", 2, 0x060, 8, 0x708, 0x810, 0x908, 0xA08 }, 253 { "gpv3", 2, 0x080, 8, 0x70C, 0x818, 0x90C, 0xA0C }, 254 { "gpv4", 2, 0x0C0, 2, 0x710, 0x820, 0x910, 0xA10 }, 255 256 { "gpz", 3, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 }, 257 258 { NULL, -1, -1, -1, -1, -1, -1, -1 }, 259}; 260 261static struct gpio_bank gpio_map_5420[] = { 262 /* First 40 */ 263 { "gpy7", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 264 { "gpx0", 0, 0xC00, 8, 0x704, 0xE80, 0xF00, 0xF40 }, 265 { "gpx1", 0, 0xC20, 8, 0x708, 0xE88, 0xF04, 0xF44 }, 266 { "gpx2", 0, 0xC40, 8, 0x70C, 0xE90, 0xF08, 0xF48 }, 267 { "gpx3", 0, 0xC60, 8, 0x710, 0xE98, 0xF0C, 0xF4C }, 268 269 /* Next 85 */ 270 { "gpc0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 271 { "gpc1", 1, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 }, 272 { "gpc2", 1, 0x040, 7, 0x708, 0x810, 0x908, 0xA08 }, 273 { "gpc3", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C }, 274 { "gpc4", 1, 0x080, 2, 0x710, 0x820, 0x910, 0xA10 }, 275 { "gpd1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 }, 276 { "gpy0", 1, 0x0C0, 6, 0x718, 0x830, 0x918, 0xA18 }, 277 { "gpy1", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C }, 278 { "gpy2", 1, 0x100, 6, 0x720, 0x840, 0x920, 0xA20 }, 279 { "gpy3", 1, 0x120, 8, 0x724, 0x848, 0x924, 0xA24 }, 280 { "gpy4", 1, 0x140, 8, 0x728, 0x850, 0x928, 0xA28 }, 281 { "gpy5", 1, 0x160, 8, 0x72C, 0x858, 0x92C, 0xA2C }, 282 { "gpy6", 1, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 }, 283 284 /* Next 46 */ 285 { "gpe0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 286 { "gpe1", 2, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 }, 287 { "gpf0", 2, 0x040, 6, 0x708, 0x810, 0x908, 0xA08 }, 288 { "gpf1", 2, 0x060, 8, 0x70C, 0x818, 0x90C, 0xA0C }, 289 { "gpg0", 2, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 }, 290 { "gpg1", 2, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 }, 291 { "gpg2", 2, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 }, 292 { "gpj4", 2, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C }, 293 294 /* Next 54 */ 295 { "gpa0", 3, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 296 { "gpa1", 3, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 }, 297 { "gpa2", 3, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 }, 298 { "gpb0", 3, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C }, 299 { "gpb1", 3, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 }, 300 { "gpb2", 3, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 }, 301 { "gpb3", 3, 0x0C0, 8, 0x718, 0x830, 0x918, 0xA18 }, 302 { "gpb4", 3, 0x0E0, 2, 0x71C, 0x838, 0x91C, 0xA1C }, 303 { "gph0", 3, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 }, 304 305 /* Last 7 */ 306 { "gpz", 4, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 }, 307 308 { NULL, -1, -1, -1, -1, -1, -1, -1 }, 309}; 310 311static int 312get_bank(struct pad_softc *sc, int gpio_number, 313 struct gpio_bank *bank, int *pin_shift) 314{ 315 int ngpio; 316 int i; 317 int n; 318 319 n = 0; 320 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) { 321 ngpio = sc->gpio_map[i].ngpio; 322 323 if ((n + ngpio) > gpio_number) { 324 *bank = sc->gpio_map[i]; 325 *pin_shift = (gpio_number - n); 326 return (0); 327 }; 328 329 n += ngpio; 330 }; 331 332 return (-1); 333} 334 335static int 336port_intr(void *arg) 337{ 338 struct port_softc *sc; 339 340 sc = arg; 341 342 return (FILTER_HANDLED); 343} 344 345static void 346ext_intr(void *arg) 347{ 348 struct pad_softc *sc; 349 void (*ih) (void *); 350 void *ih_user; 351 int ngpio; 352 int found; 353 int reg; 354 int i,j; 355 int n,k; 356 357 sc = arg; 358 359 n = 0; 360 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) { 361 found = 0; 362 ngpio = sc->gpio_map[i].ngpio; 363 364 if (sc->gpio_map[i].pend == 0) { 365 n += ngpio; 366 continue; 367 } 368 369 reg = READ4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend); 370 371 for (j = 0; j < ngpio; j++) { 372 if (reg & (1 << j)) { 373 found = 1; 374 375 k = (n + j); 376 if (intr_map[k].enabled == 1) { 377 ih = intr_map[k].ih; 378 ih_user = intr_map[k].ih_user; 379 ih(ih_user); 380 } 381 } 382 } 383 384 if (found) { 385 /* ACK */ 386 WRITE4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend, reg); 387 } 388 389 n += ngpio; 390 } 391} 392 393int 394pad_setup_intr(int gpio_number, void (*ih)(void *), void *ih_user) 395{ 396 struct interrupt_entry *entry; 397 struct pad_intr *pad_irq; 398 struct gpio_bank bank; 399 struct pad_softc *sc; 400 int pin_shift; 401 int reg; 402 int i; 403 404 sc = gpio_sc; 405 406 if (sc == NULL) { 407 device_printf(sc->dev, "Error: pad is not attached\n"); 408 return (-1); 409 } 410 411 if (get_bank(sc, gpio_number, &bank, &pin_shift) != 0) 412 return (-1); 413 414 entry = NULL; 415 for (i = 0; i < N_EXT_INTS; i++) 416 if (sc->interrupt_table[i].gpio_number == gpio_number) 417 entry = &(sc->interrupt_table[i]); 418 419 if (entry == NULL) { 420 device_printf(sc->dev, "Cant find interrupt source for %d\n", 421 gpio_number); 422 return (-1); 423 } 424 425#if 0 426 printf("Request interrupt name %s\n", entry->combiner_source_name); 427#endif 428 429 pad_irq = &intr_map[gpio_number]; 430 pad_irq->enabled = 1; 431 pad_irq->ih = ih; 432 pad_irq->ih_user = ih_user; 433 434 /* Setup port as external interrupt source */ 435 reg = READ4(sc, bank.port, bank.con); 436 reg |= (0xf << (pin_shift * 4)); 437#if 0 438 printf("writing 0x%08x to 0x%08x\n", reg, bank.con); 439#endif 440 WRITE4(sc, bank.port, bank.con, reg); 441 442 /* 443 * Configure interrupt pin 444 * 445 * 0x0 = Sets Low level 446 * 0x1 = Sets High level 447 * 0x2 = Triggers Falling edge 448 * 0x3 = Triggers Rising edge 449 * 0x4 = Triggers Both edge 450 * 451 * TODO: add parameter. For now configure as 0x0 452 */ 453 reg = READ4(sc, bank.port, bank.ext_con); 454 reg &= ~(0x7 << (pin_shift * 4)); 455 WRITE4(sc, bank.port, bank.ext_con, reg); 456 457 /* Unmask */ 458 reg = READ4(sc, bank.port, bank.mask); 459 reg &= ~(1 << pin_shift); 460 WRITE4(sc, bank.port, bank.mask, reg); 461 462 combiner_setup_intr(entry->combiner_source_name, ext_intr, sc); 463 464 return (0); 465} 466 467static int 468pad_probe(device_t dev) 469{ 470 471 if (!ofw_bus_status_okay(dev)) 472 return (ENXIO); 473 474 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 475 device_set_desc(dev, "Exynos Pad Control"); 476 return (BUS_PROBE_DEFAULT); 477 } 478 479 return (ENXIO); 480} 481 482static int 483pad_attach(device_t dev) 484{ 485 struct gpio_bank bank; 486 struct pad_softc *sc; 487 int pin_shift; 488 int reg; 489 int i; 490 491 sc = device_get_softc(dev); 492 493 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 494 495 sc->model = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 496 switch (sc->model) { 497 case EXYNOS5250: 498 sc->pad_spec = pad_spec_5250; 499 sc->gpio_map = gpio_map_5250; 500 sc->interrupt_table = interrupt_table_5250; 501 sc->gpio_npins = 253; 502 sc->nports = 4; 503 break; 504 case EXYNOS5420: 505 sc->pad_spec = pad_spec_5420; 506 sc->gpio_map = gpio_map_5420; 507 sc->interrupt_table = interrupt_table_5420; 508 sc->gpio_npins = 232; 509 sc->nports = 5; 510 break; 511 default: 512 return (-1); 513 }; 514 515 if (bus_alloc_resources(dev, sc->pad_spec, sc->res)) { 516 device_printf(dev, "could not allocate resources\n"); 517 return (ENXIO); 518 } 519 520 /* Memory interface */ 521 522 for (i = 0; i < sc->nports; i++) { 523 sc->bst[i] = rman_get_bustag(sc->res[i]); 524 sc->bsh[i] = rman_get_bushandle(sc->res[i]); 525 }; 526 527 sc->dev = dev; 528 529 gpio_sc = sc; 530 531 for (i = 0; i < sc->nports; i++) { 532 if ((bus_setup_intr(dev, sc->res[sc->nports + i], 533 INTR_TYPE_BIO | INTR_MPSAFE, port_intr, 534 NULL, sc, &sc->gpio_ih[i]))) { 535 device_printf(dev, 536 "ERROR: Unable to register interrupt handler\n"); 537 return (ENXIO); 538 } 539 }; 540 541 for (i = 0; i < sc->gpio_npins; i++) { 542 sc->gpio_pins[i].gp_pin = i; 543 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 544 545 if (get_bank(sc, i, &bank, &pin_shift) != 0) 546 continue; 547 548 pin_shift *= 4; 549 550 reg = READ4(sc, bank.port, bank.con); 551 if (reg & (PIN_OUT << pin_shift)) 552 sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT; 553 else 554 sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT; 555 556 /* TODO: add other pin statuses */ 557 558 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 559 "pad%d.%d", device_get_unit(dev), i); 560 } 561 562 device_add_child(dev, "gpioc", -1); 563 device_add_child(dev, "gpiobus", -1); 564 565 return (bus_generic_attach(dev)); 566} 567 568static int 569pad_pin_max(device_t dev, int *maxpin) 570{ 571 struct pad_softc *sc; 572 573 sc = device_get_softc(dev); 574 575 *maxpin = sc->gpio_npins - 1; 576 return (0); 577} 578 579static int 580pad_pin_getname(device_t dev, uint32_t pin, char *name) 581{ 582 struct pad_softc *sc; 583 int i; 584 585 sc = device_get_softc(dev); 586 for (i = 0; i < sc->gpio_npins; i++) { 587 if (sc->gpio_pins[i].gp_pin == pin) 588 break; 589 } 590 591 if (i >= sc->gpio_npins) 592 return (EINVAL); 593 594 GPIO_LOCK(sc); 595 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 596 GPIO_UNLOCK(sc); 597 598 return (0); 599} 600 601static int 602pad_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 603{ 604 struct pad_softc *sc; 605 int i; 606 607 sc = device_get_softc(dev); 608 for (i = 0; i < sc->gpio_npins; i++) { 609 if (sc->gpio_pins[i].gp_pin == pin) 610 break; 611 } 612 613 if (i >= sc->gpio_npins) 614 return (EINVAL); 615 616 GPIO_LOCK(sc); 617 *caps = sc->gpio_pins[i].gp_caps; 618 GPIO_UNLOCK(sc); 619 620 return (0); 621} 622 623static int 624pad_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 625{ 626 struct pad_softc *sc; 627 int i; 628 629 sc = device_get_softc(dev); 630 for (i = 0; i < sc->gpio_npins; i++) { 631 if (sc->gpio_pins[i].gp_pin == pin) 632 break; 633 } 634 635 if (i >= sc->gpio_npins) 636 return (EINVAL); 637 638 GPIO_LOCK(sc); 639 *flags = sc->gpio_pins[i].gp_flags; 640 GPIO_UNLOCK(sc); 641 642 return (0); 643} 644 645static int 646pad_pin_get(device_t dev, uint32_t pin, unsigned int *val) 647{ 648 struct gpio_bank bank; 649 struct pad_softc *sc; 650 int pin_shift; 651 int i; 652 653 sc = device_get_softc(dev); 654 for (i = 0; i < sc->gpio_npins; i++) { 655 if (sc->gpio_pins[i].gp_pin == pin) 656 break; 657 } 658 659 if (i >= sc->gpio_npins) 660 return (EINVAL); 661 662 if (get_bank(sc, pin, &bank, &pin_shift) != 0) 663 return (EINVAL); 664 665 GPIO_LOCK(sc); 666 if (READ4(sc, bank.port, bank.con + 0x4) & (1 << pin_shift)) 667 *val = 1; 668 else 669 *val = 0; 670 GPIO_UNLOCK(sc); 671 672 return (0); 673} 674 675static int 676pad_pin_toggle(device_t dev, uint32_t pin) 677{ 678 struct gpio_bank bank; 679 struct pad_softc *sc; 680 int pin_shift; 681 int reg; 682 int i; 683 684 sc = device_get_softc(dev); 685 for (i = 0; i < sc->gpio_npins; i++) { 686 if (sc->gpio_pins[i].gp_pin == pin) 687 break; 688 } 689 690 if (i >= sc->gpio_npins) 691 return (EINVAL); 692 693 if (get_bank(sc, pin, &bank, &pin_shift) != 0) 694 return (EINVAL); 695 696 GPIO_LOCK(sc); 697 reg = READ4(sc, bank.port, bank.con + 0x4); 698 if (reg & (1 << pin_shift)) 699 reg &= ~(1 << pin_shift); 700 else 701 reg |= (1 << pin_shift); 702 WRITE4(sc, bank.port, bank.con + 0x4, reg); 703 GPIO_UNLOCK(sc); 704 705 return (0); 706} 707 708 709static void 710pad_pin_configure(struct pad_softc *sc, struct gpio_pin *pin, 711 unsigned int flags) 712{ 713 struct gpio_bank bank; 714 int pin_shift; 715 int reg; 716 717 GPIO_LOCK(sc); 718 719 /* 720 * Manage input/output 721 */ 722 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 723 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 724 725 if (get_bank(sc, pin->gp_pin, &bank, &pin_shift) != 0) 726 return; 727 728 pin_shift *= 4; 729 730#if 0 731 printf("bank is 0x%08x pin_shift %d\n", bank.con, pin_shift); 732#endif 733 734 if (flags & GPIO_PIN_OUTPUT) { 735 pin->gp_flags |= GPIO_PIN_OUTPUT; 736 reg = READ4(sc, bank.port, bank.con); 737 reg &= ~(0xf << pin_shift); 738 reg |= (PIN_OUT << pin_shift); 739 WRITE4(sc, bank.port, bank.con, reg); 740 } else { 741 pin->gp_flags |= GPIO_PIN_INPUT; 742 reg = READ4(sc, bank.port, bank.con); 743 reg &= ~(0xf << pin_shift); 744 WRITE4(sc, bank.port, bank.con, reg); 745 } 746 } 747 748 GPIO_UNLOCK(sc); 749} 750 751 752static int 753pad_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 754{ 755 struct pad_softc *sc; 756 int i; 757 758 sc = device_get_softc(dev); 759 for (i = 0; i < sc->gpio_npins; i++) { 760 if (sc->gpio_pins[i].gp_pin == pin) 761 break; 762 } 763 764 if (i >= sc->gpio_npins) 765 return (EINVAL); 766
| 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/malloc.h> 41#include <sys/rman.h> 42#include <sys/timeet.h> 43#include <sys/timetc.h> 44#include <sys/watchdog.h> 45#include <sys/mutex.h> 46#include <sys/gpio.h> 47 48#include <dev/ofw/openfirm.h> 49#include <dev/ofw/ofw_bus.h> 50#include <dev/ofw/ofw_bus_subr.h> 51 52#include <machine/bus.h> 53#include <machine/cpu.h> 54#include <machine/intr.h> 55 56#include "gpio_if.h" 57 58#include <arm/samsung/exynos/exynos5_combiner.h> 59#include <arm/samsung/exynos/exynos5_pad.h> 60 61#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 62#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 63 64#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 65 66#define MAX_PORTS 5 67#define MAX_NGPIO 253 68 69#define N_EXT_INTS 16 70 71#define EXYNOS5250 1 72#define EXYNOS5420 2 73 74#define PIN_IN 0 75#define PIN_OUT 1 76 77#define READ4(_sc, _port, _reg) \ 78 bus_space_read_4(_sc->bst[_port], _sc->bsh[_port], _reg) 79#define WRITE4(_sc, _port, _reg, _val) \ 80 bus_space_write_4(_sc->bst[_port], _sc->bsh[_port], _reg, _val) 81 82/* 83 * GPIO interface 84 */ 85static int pad_pin_max(device_t, int *); 86static int pad_pin_getcaps(device_t, uint32_t, uint32_t *); 87static int pad_pin_getname(device_t, uint32_t, char *); 88static int pad_pin_getflags(device_t, uint32_t, uint32_t *); 89static int pad_pin_setflags(device_t, uint32_t, uint32_t); 90static int pad_pin_set(device_t, uint32_t, unsigned int); 91static int pad_pin_get(device_t, uint32_t, unsigned int *); 92static int pad_pin_toggle(device_t, uint32_t pin); 93 94struct gpio_bank { 95 char *name; 96 uint32_t port; 97 uint32_t con; 98 uint32_t ngpio; 99 uint32_t ext_con; 100 uint32_t ext_flt_con; 101 uint32_t mask; 102 uint32_t pend; 103}; 104 105struct pad_softc { 106 struct resource *res[MAX_PORTS * 2]; 107 bus_space_tag_t bst[MAX_PORTS]; 108 bus_space_handle_t bsh[MAX_PORTS]; 109 struct mtx sc_mtx; 110 int gpio_npins; 111 struct gpio_pin gpio_pins[MAX_NGPIO]; 112 void *gpio_ih[MAX_PORTS]; 113 device_t dev; 114 int model; 115 struct resource_spec *pad_spec; 116 struct gpio_bank *gpio_map; 117 struct interrupt_entry *interrupt_table; 118 int nports; 119}; 120 121struct pad_softc *gpio_sc; 122 123static struct resource_spec pad_spec_5250[] = { 124 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 125 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 126 { SYS_RES_MEMORY, 2, RF_ACTIVE }, 127 { SYS_RES_MEMORY, 3, RF_ACTIVE }, 128 { SYS_RES_IRQ, 0, RF_ACTIVE }, 129 { SYS_RES_IRQ, 1, RF_ACTIVE }, 130 { SYS_RES_IRQ, 2, RF_ACTIVE }, 131 { SYS_RES_IRQ, 3, RF_ACTIVE }, 132 { -1, 0 } 133}; 134 135static struct resource_spec pad_spec_5420[] = { 136 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 137 { SYS_RES_MEMORY, 1, RF_ACTIVE }, 138 { SYS_RES_MEMORY, 2, RF_ACTIVE }, 139 { SYS_RES_MEMORY, 3, RF_ACTIVE }, 140 { SYS_RES_MEMORY, 4, RF_ACTIVE }, 141 { SYS_RES_IRQ, 0, RF_ACTIVE }, 142 { SYS_RES_IRQ, 1, RF_ACTIVE }, 143 { SYS_RES_IRQ, 2, RF_ACTIVE }, 144 { SYS_RES_IRQ, 3, RF_ACTIVE }, 145 { SYS_RES_IRQ, 4, RF_ACTIVE }, 146 { -1, 0 } 147}; 148 149static struct ofw_compat_data compat_data[] = { 150 {"samsung,exynos5420-padctrl", EXYNOS5420}, 151 {"samsung,exynos5250-padctrl", EXYNOS5250}, 152 {NULL, 0} 153}; 154 155struct pad_intr { 156 uint32_t enabled; 157 void (*ih) (void *); 158 void *ih_user; 159}; 160 161static struct pad_intr intr_map[MAX_NGPIO]; 162 163struct interrupt_entry { 164 int gpio_number; 165 char *combiner_source_name; 166}; 167 168struct interrupt_entry interrupt_table_5250[N_EXT_INTS] = { 169 { 147, "EINT[15]" }, 170 { 146, "EINT[14]" }, 171 { 145, "EINT[13]" }, 172 { 144, "EINT[12]" }, 173 { 143, "EINT[11]" }, 174 { 142, "EINT[10]" }, 175 { 141, "EINT[9]" }, 176 { 140, "EINT[8]" }, 177 { 139, "EINT[7]" }, 178 { 138, "EINT[6]" }, 179 { 137, "EINT[5]" }, 180 { 136, "EINT[4]" }, 181 { 135, "EINT[3]" }, 182 { 134, "EINT[2]" }, 183 { 133, "EINT[1]" }, 184 { 132, "EINT[0]" }, 185}; 186 187struct interrupt_entry interrupt_table_5420[N_EXT_INTS] = { 188 { 23, "EINT[15]" }, 189 { 22, "EINT[14]" }, 190 { 21, "EINT[13]" }, 191 { 20, "EINT[12]" }, 192 { 19, "EINT[11]" }, 193 { 18, "EINT[10]" }, 194 { 17, "EINT[9]" }, 195 { 16, "EINT[8]" }, 196 { 15, "EINT[7]" }, 197 { 14, "EINT[6]" }, 198 { 13, "EINT[5]" }, 199 { 12, "EINT[4]" }, 200 { 11, "EINT[3]" }, 201 { 10, "EINT[2]" }, 202 { 9, "EINT[1]" }, 203 { 8, "EINT[0]" }, 204}; 205 206/* 207 * 253 multi-functional input/output ports 208 */ 209 210static struct gpio_bank gpio_map_5250[] = { 211 /* first 132 gpio */ 212 { "gpa0", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 213 { "gpa1", 0, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 }, 214 { "gpa2", 0, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 }, 215 { "gpb0", 0, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C }, 216 { "gpb1", 0, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 }, 217 { "gpb2", 0, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 }, 218 { "gpb3", 0, 0x0C0, 4, 0x718, 0x830, 0x918, 0xA18 }, 219 { "gpc0", 0, 0x0E0, 7, 0x71C, 0x838, 0x91C, 0xA1C }, 220 { "gpc1", 0, 0x100, 4, 0x720, 0x840, 0x920, 0xA20 }, 221 { "gpc2", 0, 0x120, 7, 0x724, 0x848, 0x924, 0xA24 }, 222 { "gpc3", 0, 0x140, 7, 0x728, 0x850, 0x928, 0xA28 }, 223 { "gpd0", 0, 0x160, 4, 0x72C, 0x858, 0x92C, 0xA2C }, 224 { "gpd1", 0, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 }, 225 { "gpy0", 0, 0x1A0, 6, 0, 0, 0, 0 }, 226 { "gpy1", 0, 0x1C0, 4, 0, 0, 0, 0 }, 227 { "gpy2", 0, 0x1E0, 6, 0, 0, 0, 0 }, 228 { "gpy3", 0, 0x200, 8, 0, 0, 0, 0 }, 229 { "gpy4", 0, 0x220, 8, 0, 0, 0, 0 }, 230 { "gpy5", 0, 0x240, 8, 0, 0, 0, 0 }, 231 { "gpy6", 0, 0x260, 8, 0, 0, 0, 0 }, 232 { "gpc4", 0, 0x2E0, 7, 0x734, 0x868, 0x934, 0xA34 }, 233 234 /* next 32 */ 235 { "gpx0", 0, 0xC00, 8, 0xE00, 0xE80, 0xF00, 0xF40 }, 236 { "gpx1", 0, 0xC20, 8, 0xE04, 0xE88, 0xF04, 0xF44 }, 237 { "gpx2", 0, 0xC40, 8, 0xE08, 0xE90, 0xF08, 0xF48 }, 238 { "gpx3", 0, 0xC60, 8, 0xE0C, 0xE98, 0xF0C, 0xF4C }, 239 240 { "gpe0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 241 { "gpe1", 1, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 }, 242 { "gpf0", 1, 0x040, 4, 0x708, 0x810, 0x908, 0xA08 }, 243 { "gpf1", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C }, 244 { "gpg0", 1, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 }, 245 { "gpg1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 }, 246 { "gpg2", 1, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 }, 247 { "gph0", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C }, 248 { "gph1", 1, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 }, 249 250 { "gpv0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 251 { "gpv1", 2, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 }, 252 { "gpv2", 2, 0x060, 8, 0x708, 0x810, 0x908, 0xA08 }, 253 { "gpv3", 2, 0x080, 8, 0x70C, 0x818, 0x90C, 0xA0C }, 254 { "gpv4", 2, 0x0C0, 2, 0x710, 0x820, 0x910, 0xA10 }, 255 256 { "gpz", 3, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 }, 257 258 { NULL, -1, -1, -1, -1, -1, -1, -1 }, 259}; 260 261static struct gpio_bank gpio_map_5420[] = { 262 /* First 40 */ 263 { "gpy7", 0, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 264 { "gpx0", 0, 0xC00, 8, 0x704, 0xE80, 0xF00, 0xF40 }, 265 { "gpx1", 0, 0xC20, 8, 0x708, 0xE88, 0xF04, 0xF44 }, 266 { "gpx2", 0, 0xC40, 8, 0x70C, 0xE90, 0xF08, 0xF48 }, 267 { "gpx3", 0, 0xC60, 8, 0x710, 0xE98, 0xF0C, 0xF4C }, 268 269 /* Next 85 */ 270 { "gpc0", 1, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 271 { "gpc1", 1, 0x020, 8, 0x704, 0x808, 0x904, 0xA04 }, 272 { "gpc2", 1, 0x040, 7, 0x708, 0x810, 0x908, 0xA08 }, 273 { "gpc3", 1, 0x060, 4, 0x70C, 0x818, 0x90C, 0xA0C }, 274 { "gpc4", 1, 0x080, 2, 0x710, 0x820, 0x910, 0xA10 }, 275 { "gpd1", 1, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 }, 276 { "gpy0", 1, 0x0C0, 6, 0x718, 0x830, 0x918, 0xA18 }, 277 { "gpy1", 1, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C }, 278 { "gpy2", 1, 0x100, 6, 0x720, 0x840, 0x920, 0xA20 }, 279 { "gpy3", 1, 0x120, 8, 0x724, 0x848, 0x924, 0xA24 }, 280 { "gpy4", 1, 0x140, 8, 0x728, 0x850, 0x928, 0xA28 }, 281 { "gpy5", 1, 0x160, 8, 0x72C, 0x858, 0x92C, 0xA2C }, 282 { "gpy6", 1, 0x180, 8, 0x730, 0x860, 0x930, 0xA30 }, 283 284 /* Next 46 */ 285 { "gpe0", 2, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 286 { "gpe1", 2, 0x020, 2, 0x704, 0x808, 0x904, 0xA04 }, 287 { "gpf0", 2, 0x040, 6, 0x708, 0x810, 0x908, 0xA08 }, 288 { "gpf1", 2, 0x060, 8, 0x70C, 0x818, 0x90C, 0xA0C }, 289 { "gpg0", 2, 0x080, 8, 0x710, 0x820, 0x910, 0xA10 }, 290 { "gpg1", 2, 0x0A0, 8, 0x714, 0x828, 0x914, 0xA14 }, 291 { "gpg2", 2, 0x0C0, 2, 0x718, 0x830, 0x918, 0xA18 }, 292 { "gpj4", 2, 0x0E0, 4, 0x71C, 0x838, 0x91C, 0xA1C }, 293 294 /* Next 54 */ 295 { "gpa0", 3, 0x000, 8, 0x700, 0x800, 0x900, 0xA00 }, 296 { "gpa1", 3, 0x020, 6, 0x704, 0x808, 0x904, 0xA04 }, 297 { "gpa2", 3, 0x040, 8, 0x708, 0x810, 0x908, 0xA08 }, 298 { "gpb0", 3, 0x060, 5, 0x70C, 0x818, 0x90C, 0xA0C }, 299 { "gpb1", 3, 0x080, 5, 0x710, 0x820, 0x910, 0xA10 }, 300 { "gpb2", 3, 0x0A0, 4, 0x714, 0x828, 0x914, 0xA14 }, 301 { "gpb3", 3, 0x0C0, 8, 0x718, 0x830, 0x918, 0xA18 }, 302 { "gpb4", 3, 0x0E0, 2, 0x71C, 0x838, 0x91C, 0xA1C }, 303 { "gph0", 3, 0x100, 8, 0x720, 0x840, 0x920, 0xA20 }, 304 305 /* Last 7 */ 306 { "gpz", 4, 0x000, 7, 0x700, 0x800, 0x900, 0xA00 }, 307 308 { NULL, -1, -1, -1, -1, -1, -1, -1 }, 309}; 310 311static int 312get_bank(struct pad_softc *sc, int gpio_number, 313 struct gpio_bank *bank, int *pin_shift) 314{ 315 int ngpio; 316 int i; 317 int n; 318 319 n = 0; 320 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) { 321 ngpio = sc->gpio_map[i].ngpio; 322 323 if ((n + ngpio) > gpio_number) { 324 *bank = sc->gpio_map[i]; 325 *pin_shift = (gpio_number - n); 326 return (0); 327 }; 328 329 n += ngpio; 330 }; 331 332 return (-1); 333} 334 335static int 336port_intr(void *arg) 337{ 338 struct port_softc *sc; 339 340 sc = arg; 341 342 return (FILTER_HANDLED); 343} 344 345static void 346ext_intr(void *arg) 347{ 348 struct pad_softc *sc; 349 void (*ih) (void *); 350 void *ih_user; 351 int ngpio; 352 int found; 353 int reg; 354 int i,j; 355 int n,k; 356 357 sc = arg; 358 359 n = 0; 360 for (i = 0; sc->gpio_map[i].ngpio != -1; i++) { 361 found = 0; 362 ngpio = sc->gpio_map[i].ngpio; 363 364 if (sc->gpio_map[i].pend == 0) { 365 n += ngpio; 366 continue; 367 } 368 369 reg = READ4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend); 370 371 for (j = 0; j < ngpio; j++) { 372 if (reg & (1 << j)) { 373 found = 1; 374 375 k = (n + j); 376 if (intr_map[k].enabled == 1) { 377 ih = intr_map[k].ih; 378 ih_user = intr_map[k].ih_user; 379 ih(ih_user); 380 } 381 } 382 } 383 384 if (found) { 385 /* ACK */ 386 WRITE4(sc, sc->gpio_map[i].port, sc->gpio_map[i].pend, reg); 387 } 388 389 n += ngpio; 390 } 391} 392 393int 394pad_setup_intr(int gpio_number, void (*ih)(void *), void *ih_user) 395{ 396 struct interrupt_entry *entry; 397 struct pad_intr *pad_irq; 398 struct gpio_bank bank; 399 struct pad_softc *sc; 400 int pin_shift; 401 int reg; 402 int i; 403 404 sc = gpio_sc; 405 406 if (sc == NULL) { 407 device_printf(sc->dev, "Error: pad is not attached\n"); 408 return (-1); 409 } 410 411 if (get_bank(sc, gpio_number, &bank, &pin_shift) != 0) 412 return (-1); 413 414 entry = NULL; 415 for (i = 0; i < N_EXT_INTS; i++) 416 if (sc->interrupt_table[i].gpio_number == gpio_number) 417 entry = &(sc->interrupt_table[i]); 418 419 if (entry == NULL) { 420 device_printf(sc->dev, "Cant find interrupt source for %d\n", 421 gpio_number); 422 return (-1); 423 } 424 425#if 0 426 printf("Request interrupt name %s\n", entry->combiner_source_name); 427#endif 428 429 pad_irq = &intr_map[gpio_number]; 430 pad_irq->enabled = 1; 431 pad_irq->ih = ih; 432 pad_irq->ih_user = ih_user; 433 434 /* Setup port as external interrupt source */ 435 reg = READ4(sc, bank.port, bank.con); 436 reg |= (0xf << (pin_shift * 4)); 437#if 0 438 printf("writing 0x%08x to 0x%08x\n", reg, bank.con); 439#endif 440 WRITE4(sc, bank.port, bank.con, reg); 441 442 /* 443 * Configure interrupt pin 444 * 445 * 0x0 = Sets Low level 446 * 0x1 = Sets High level 447 * 0x2 = Triggers Falling edge 448 * 0x3 = Triggers Rising edge 449 * 0x4 = Triggers Both edge 450 * 451 * TODO: add parameter. For now configure as 0x0 452 */ 453 reg = READ4(sc, bank.port, bank.ext_con); 454 reg &= ~(0x7 << (pin_shift * 4)); 455 WRITE4(sc, bank.port, bank.ext_con, reg); 456 457 /* Unmask */ 458 reg = READ4(sc, bank.port, bank.mask); 459 reg &= ~(1 << pin_shift); 460 WRITE4(sc, bank.port, bank.mask, reg); 461 462 combiner_setup_intr(entry->combiner_source_name, ext_intr, sc); 463 464 return (0); 465} 466 467static int 468pad_probe(device_t dev) 469{ 470 471 if (!ofw_bus_status_okay(dev)) 472 return (ENXIO); 473 474 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 475 device_set_desc(dev, "Exynos Pad Control"); 476 return (BUS_PROBE_DEFAULT); 477 } 478 479 return (ENXIO); 480} 481 482static int 483pad_attach(device_t dev) 484{ 485 struct gpio_bank bank; 486 struct pad_softc *sc; 487 int pin_shift; 488 int reg; 489 int i; 490 491 sc = device_get_softc(dev); 492 493 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 494 495 sc->model = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 496 switch (sc->model) { 497 case EXYNOS5250: 498 sc->pad_spec = pad_spec_5250; 499 sc->gpio_map = gpio_map_5250; 500 sc->interrupt_table = interrupt_table_5250; 501 sc->gpio_npins = 253; 502 sc->nports = 4; 503 break; 504 case EXYNOS5420: 505 sc->pad_spec = pad_spec_5420; 506 sc->gpio_map = gpio_map_5420; 507 sc->interrupt_table = interrupt_table_5420; 508 sc->gpio_npins = 232; 509 sc->nports = 5; 510 break; 511 default: 512 return (-1); 513 }; 514 515 if (bus_alloc_resources(dev, sc->pad_spec, sc->res)) { 516 device_printf(dev, "could not allocate resources\n"); 517 return (ENXIO); 518 } 519 520 /* Memory interface */ 521 522 for (i = 0; i < sc->nports; i++) { 523 sc->bst[i] = rman_get_bustag(sc->res[i]); 524 sc->bsh[i] = rman_get_bushandle(sc->res[i]); 525 }; 526 527 sc->dev = dev; 528 529 gpio_sc = sc; 530 531 for (i = 0; i < sc->nports; i++) { 532 if ((bus_setup_intr(dev, sc->res[sc->nports + i], 533 INTR_TYPE_BIO | INTR_MPSAFE, port_intr, 534 NULL, sc, &sc->gpio_ih[i]))) { 535 device_printf(dev, 536 "ERROR: Unable to register interrupt handler\n"); 537 return (ENXIO); 538 } 539 }; 540 541 for (i = 0; i < sc->gpio_npins; i++) { 542 sc->gpio_pins[i].gp_pin = i; 543 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 544 545 if (get_bank(sc, i, &bank, &pin_shift) != 0) 546 continue; 547 548 pin_shift *= 4; 549 550 reg = READ4(sc, bank.port, bank.con); 551 if (reg & (PIN_OUT << pin_shift)) 552 sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT; 553 else 554 sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT; 555 556 /* TODO: add other pin statuses */ 557 558 snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, 559 "pad%d.%d", device_get_unit(dev), i); 560 } 561 562 device_add_child(dev, "gpioc", -1); 563 device_add_child(dev, "gpiobus", -1); 564 565 return (bus_generic_attach(dev)); 566} 567 568static int 569pad_pin_max(device_t dev, int *maxpin) 570{ 571 struct pad_softc *sc; 572 573 sc = device_get_softc(dev); 574 575 *maxpin = sc->gpio_npins - 1; 576 return (0); 577} 578 579static int 580pad_pin_getname(device_t dev, uint32_t pin, char *name) 581{ 582 struct pad_softc *sc; 583 int i; 584 585 sc = device_get_softc(dev); 586 for (i = 0; i < sc->gpio_npins; i++) { 587 if (sc->gpio_pins[i].gp_pin == pin) 588 break; 589 } 590 591 if (i >= sc->gpio_npins) 592 return (EINVAL); 593 594 GPIO_LOCK(sc); 595 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 596 GPIO_UNLOCK(sc); 597 598 return (0); 599} 600 601static int 602pad_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 603{ 604 struct pad_softc *sc; 605 int i; 606 607 sc = device_get_softc(dev); 608 for (i = 0; i < sc->gpio_npins; i++) { 609 if (sc->gpio_pins[i].gp_pin == pin) 610 break; 611 } 612 613 if (i >= sc->gpio_npins) 614 return (EINVAL); 615 616 GPIO_LOCK(sc); 617 *caps = sc->gpio_pins[i].gp_caps; 618 GPIO_UNLOCK(sc); 619 620 return (0); 621} 622 623static int 624pad_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 625{ 626 struct pad_softc *sc; 627 int i; 628 629 sc = device_get_softc(dev); 630 for (i = 0; i < sc->gpio_npins; i++) { 631 if (sc->gpio_pins[i].gp_pin == pin) 632 break; 633 } 634 635 if (i >= sc->gpio_npins) 636 return (EINVAL); 637 638 GPIO_LOCK(sc); 639 *flags = sc->gpio_pins[i].gp_flags; 640 GPIO_UNLOCK(sc); 641 642 return (0); 643} 644 645static int 646pad_pin_get(device_t dev, uint32_t pin, unsigned int *val) 647{ 648 struct gpio_bank bank; 649 struct pad_softc *sc; 650 int pin_shift; 651 int i; 652 653 sc = device_get_softc(dev); 654 for (i = 0; i < sc->gpio_npins; i++) { 655 if (sc->gpio_pins[i].gp_pin == pin) 656 break; 657 } 658 659 if (i >= sc->gpio_npins) 660 return (EINVAL); 661 662 if (get_bank(sc, pin, &bank, &pin_shift) != 0) 663 return (EINVAL); 664 665 GPIO_LOCK(sc); 666 if (READ4(sc, bank.port, bank.con + 0x4) & (1 << pin_shift)) 667 *val = 1; 668 else 669 *val = 0; 670 GPIO_UNLOCK(sc); 671 672 return (0); 673} 674 675static int 676pad_pin_toggle(device_t dev, uint32_t pin) 677{ 678 struct gpio_bank bank; 679 struct pad_softc *sc; 680 int pin_shift; 681 int reg; 682 int i; 683 684 sc = device_get_softc(dev); 685 for (i = 0; i < sc->gpio_npins; i++) { 686 if (sc->gpio_pins[i].gp_pin == pin) 687 break; 688 } 689 690 if (i >= sc->gpio_npins) 691 return (EINVAL); 692 693 if (get_bank(sc, pin, &bank, &pin_shift) != 0) 694 return (EINVAL); 695 696 GPIO_LOCK(sc); 697 reg = READ4(sc, bank.port, bank.con + 0x4); 698 if (reg & (1 << pin_shift)) 699 reg &= ~(1 << pin_shift); 700 else 701 reg |= (1 << pin_shift); 702 WRITE4(sc, bank.port, bank.con + 0x4, reg); 703 GPIO_UNLOCK(sc); 704 705 return (0); 706} 707 708 709static void 710pad_pin_configure(struct pad_softc *sc, struct gpio_pin *pin, 711 unsigned int flags) 712{ 713 struct gpio_bank bank; 714 int pin_shift; 715 int reg; 716 717 GPIO_LOCK(sc); 718 719 /* 720 * Manage input/output 721 */ 722 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 723 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 724 725 if (get_bank(sc, pin->gp_pin, &bank, &pin_shift) != 0) 726 return; 727 728 pin_shift *= 4; 729 730#if 0 731 printf("bank is 0x%08x pin_shift %d\n", bank.con, pin_shift); 732#endif 733 734 if (flags & GPIO_PIN_OUTPUT) { 735 pin->gp_flags |= GPIO_PIN_OUTPUT; 736 reg = READ4(sc, bank.port, bank.con); 737 reg &= ~(0xf << pin_shift); 738 reg |= (PIN_OUT << pin_shift); 739 WRITE4(sc, bank.port, bank.con, reg); 740 } else { 741 pin->gp_flags |= GPIO_PIN_INPUT; 742 reg = READ4(sc, bank.port, bank.con); 743 reg &= ~(0xf << pin_shift); 744 WRITE4(sc, bank.port, bank.con, reg); 745 } 746 } 747 748 GPIO_UNLOCK(sc); 749} 750 751 752static int 753pad_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 754{ 755 struct pad_softc *sc; 756 int i; 757 758 sc = device_get_softc(dev); 759 for (i = 0; i < sc->gpio_npins; i++) { 760 if (sc->gpio_pins[i].gp_pin == pin) 761 break; 762 } 763 764 if (i >= sc->gpio_npins) 765 return (EINVAL); 766
|