1 /* $OpenBSD: amlpinctrl.c,v 1.5 2019/10/06 16:17:06 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/ofw_gpio.h> 28 #include <dev/ofw/ofw_pinctrl.h> 29 #include <dev/ofw/fdt.h> 30 31 #define BIAS_DISABLE 0x00 32 #define BIAS_PULL_UP 0x01 33 #define BIAS_PULL_DOWN 0x02 34 35 #define GPIOZ_0 0 36 #define GPIOZ_1 1 37 #define GPIOZ_7 7 38 #define GPIOZ_8 8 39 #define GPIOZ_14 14 40 #define GPIOZ_15 15 41 #define GPIOH_0 16 42 #define GPIOH_1 17 43 #define GPIOH_2 18 44 #define GPIOH_3 19 45 #define GPIOH_6 22 46 #define GPIOH_7 23 47 #define BOOT_0 25 48 #define BOOT_1 26 49 #define BOOT_2 27 50 #define BOOT_3 28 51 #define BOOT_4 29 52 #define BOOT_5 30 53 #define BOOT_6 31 54 #define BOOT_7 32 55 #define BOOT_8 33 56 #define BOOT_10 35 57 #define BOOT_13 38 58 #define GPIOC_0 41 59 #define GPIOC_1 42 60 #define GPIOC_2 43 61 #define GPIOC_3 44 62 #define GPIOC_4 45 63 #define GPIOC_5 46 64 #define GPIOC_6 47 65 #define GPIOA_0 49 66 #define GPIOA_14 63 67 #define GPIOA_15 64 68 #define GPIOX_0 65 69 #define GPIOX_10 75 70 #define GPIOX_11 76 71 #define GPIOX_17 82 72 #define GPIOX_18 83 73 74 #define PERIPHS_PIN_MUX_0 0xb0 75 #define PERIPHS_PIN_MUX_3 0xb3 76 #define PERIPHS_PIN_MUX_6 0xb6 77 #define PERIPHS_PIN_MUX_9 0xb9 78 #define PERIPHS_PIN_MUX_B 0xbb 79 #define PERIPHS_PIN_MUX_D 0xbd 80 #define PREG_PAD_GPIO0_EN_N 0x10 81 #define PREG_PAD_GPIO1_EN_N 0x13 82 #define PREG_PAD_GPIO2_EN_N 0x16 83 #define PREG_PAD_GPIO3_EN_N 0x19 84 #define PREG_PAD_GPIO4_EN_N 0x1c 85 #define PREG_PAD_GPIO5_EN_N 0x20 86 #define PAD_PULL_UP_EN_0 0x48 87 #define PAD_PULL_UP_EN_1 0x49 88 #define PAD_PULL_UP_EN_2 0x4a 89 #define PAD_PULL_UP_EN_3 0x4b 90 #define PAD_PULL_UP_EN_4 0x4c 91 #define PAD_PULL_UP_EN_5 0x4d 92 #define PAD_PULL_UP_0 0x3a 93 #define PAD_PULL_UP_1 0x3b 94 #define PAD_PULL_UP_2 0x3c 95 #define PAD_PULL_UP_3 0x3d 96 #define PAD_PULL_UP_4 0x3e 97 #define PAD_PULL_UP_5 0x3f 98 #define PAD_DS_0A 0xd0 99 #define PAD_DS_1A 0xd1 100 #define PAD_DS_2A 0xd2 101 #define PAD_DS_3A 0xd4 102 #define PAD_DS_4A 0xd5 103 #define PAD_DS_5A 0xd6 104 105 struct aml_gpio_bank { 106 uint8_t first_pin, num_pins; 107 uint8_t mux_reg; 108 uint8_t gpio_reg; 109 uint8_t pull_reg; 110 uint8_t pull_en_reg; 111 uint8_t ds_reg; 112 }; 113 114 struct aml_pin_group { 115 const char *name; 116 uint8_t pin; 117 uint8_t func; 118 const char *function; 119 }; 120 121 struct aml_gpio_bank aml_g12a_gpio_banks[] = { 122 /* BOOT */ 123 { BOOT_0, 16, PERIPHS_PIN_MUX_0 - PERIPHS_PIN_MUX_0, 124 PREG_PAD_GPIO0_EN_N - PREG_PAD_GPIO0_EN_N, 125 PAD_PULL_UP_0 - PAD_PULL_UP_0, 126 PAD_PULL_UP_EN_0 - PAD_PULL_UP_EN_0, PAD_DS_0A - PAD_DS_0A }, 127 128 /* GPIOC */ 129 { GPIOC_0, 8, PERIPHS_PIN_MUX_9 - PERIPHS_PIN_MUX_0, 130 PREG_PAD_GPIO1_EN_N - PREG_PAD_GPIO0_EN_N, 131 PAD_PULL_UP_1 - PAD_PULL_UP_0, 132 PAD_PULL_UP_EN_1 - PAD_PULL_UP_EN_0, PAD_DS_1A - PAD_DS_0A }, 133 134 /* GPIOX */ 135 { GPIOX_0, 20, PERIPHS_PIN_MUX_3 - PERIPHS_PIN_MUX_0, 136 PREG_PAD_GPIO2_EN_N - PREG_PAD_GPIO0_EN_N, 137 PAD_PULL_UP_2 - PAD_PULL_UP_0, 138 PAD_PULL_UP_EN_2 - PAD_PULL_UP_EN_0, PAD_DS_2A - PAD_DS_0A }, 139 140 /* GPIOH */ 141 { GPIOH_0, 9, PERIPHS_PIN_MUX_B - PERIPHS_PIN_MUX_0, 142 PREG_PAD_GPIO3_EN_N - PREG_PAD_GPIO0_EN_N, 143 PAD_PULL_UP_3 - PAD_PULL_UP_0, 144 PAD_PULL_UP_EN_3 - PAD_PULL_UP_EN_0, PAD_DS_3A - PAD_DS_0A }, 145 146 /* GPIOZ */ 147 { GPIOZ_0, 16, PERIPHS_PIN_MUX_6 - PERIPHS_PIN_MUX_0, 148 PREG_PAD_GPIO4_EN_N - PREG_PAD_GPIO0_EN_N, 149 PAD_PULL_UP_4 - PAD_PULL_UP_0, 150 PAD_PULL_UP_EN_4 - PAD_PULL_UP_EN_0, PAD_DS_4A - PAD_DS_0A }, 151 152 /* GPIOA */ 153 { GPIOA_0, 16, PERIPHS_PIN_MUX_D - PERIPHS_PIN_MUX_0, 154 PREG_PAD_GPIO5_EN_N - PREG_PAD_GPIO0_EN_N, 155 PAD_PULL_UP_5 - PAD_PULL_UP_0, 156 PAD_PULL_UP_EN_5 - PAD_PULL_UP_EN_0, PAD_DS_5A - PAD_DS_0A }, 157 158 { } 159 }; 160 161 struct aml_pin_group aml_g12a_pin_groups[] = { 162 /* GPIOZ */ 163 { "i2c0_sda_z0", GPIOZ_0, 4, "i2c0" }, 164 { "i2c0_sck_z1", GPIOZ_1, 4, "i2c0" }, 165 { "i2c0_sda_z7", GPIOZ_7, 7, "i2c0" }, 166 { "i2c0_sck_z8", GPIOZ_8, 7, "i2c0" }, 167 { "i2c2_sda_z", GPIOZ_14, 3, "i2c2" }, 168 { "i2c2_sck_z", GPIOZ_15, 3, "i2c2" }, 169 170 /* GPIOA */ 171 { "i2c3_sda_a", GPIOA_14, 2, "i2c3" }, 172 { "i2c3_sck_a", GPIOA_15, 2, "i2c3" }, 173 174 /* BOOT */ 175 { "emmc_nand_d0", BOOT_0, 1, "emmc" }, 176 { "emmc_nand_d1", BOOT_1, 1, "emmc" }, 177 { "emmc_nand_d2", BOOT_2, 1, "emmc" }, 178 { "emmc_nand_d3", BOOT_3, 1, "emmc" }, 179 { "emmc_nand_d4", BOOT_4, 1, "emmc" }, 180 { "emmc_nand_d5", BOOT_5, 1, "emmc" }, 181 { "emmc_nand_d6", BOOT_6, 1, "emmc" }, 182 { "emmc_nand_d7", BOOT_7, 1, "emmc" }, 183 { "BOOT_8", BOOT_8, 0, "gpio_periphs" }, 184 { "emmc_clk", BOOT_8, 1, "emmc" }, 185 { "emmc_cmd", BOOT_10, 1, "emmc" }, 186 { "emmc_nand_ds", BOOT_13, 1, "emmc" }, 187 188 /* GPIOC */ 189 { "sdcard_d0_c", GPIOC_0, 1, "sdcard" }, 190 { "sdcard_d1_c", GPIOC_1, 1, "sdcard" }, 191 { "sdcard_d2_c", GPIOC_2, 1, "sdcard" }, 192 { "sdcard_d3_c", GPIOC_3, 1, "sdcard" }, 193 { "GPIOC_4", GPIOC_4, 0, "gpio_periphs" }, 194 { "sdcard_clk_c", GPIOC_4, 1, "sdcard" }, 195 { "sdcard_cmd_c", GPIOC_5, 1, "sdcard" }, 196 { "i2c0_sda_c", GPIOC_5, 3, "i2c0" }, 197 { "i2c0_sck_c", GPIOC_6, 3, "i2c0" }, 198 199 /* GPIOX */ 200 { "i2c1_sda_x", GPIOX_10, 5, "i2c1" }, 201 { "i2c1_sck_x", GPIOX_11, 5, "i2c1" }, 202 { "i2c2_sda_x", GPIOX_17, 1, "i2c2" }, 203 { "i2c2_sck_x", GPIOX_18, 1, "i2c2" }, 204 205 /* GPIOH */ 206 { "i2c3_sda_h", GPIOH_0, 2, "i2c3" }, 207 { "i2c3_sck_h", GPIOH_1, 2, "i2c3" }, 208 { "i2c1_sda_h2", GPIOH_2, 2, "i2c1" }, 209 { "i2c1_sck_h3", GPIOH_3, 2, "i2c1" }, 210 { "i2c1_sda_h6", GPIOH_6, 4, "i2c1" }, 211 { "i2c1_sck_h7", GPIOH_7, 4, "i2c1" }, 212 213 { } 214 }; 215 216 struct amlpinctrl_softc { 217 struct device sc_dev; 218 bus_space_tag_t sc_iot; 219 bus_space_handle_t sc_gpio_ioh; 220 bus_space_handle_t sc_pull_ioh; 221 bus_space_handle_t sc_pull_en_ioh; 222 bus_space_handle_t sc_mux_ioh; 223 bus_space_handle_t sc_ds_ioh; 224 225 struct aml_gpio_bank *sc_gpio_banks; 226 struct aml_pin_group *sc_pin_groups; 227 228 struct gpio_controller sc_gc; 229 }; 230 231 int amlpinctrl_match(struct device *, void *, void *); 232 void amlpinctrl_attach(struct device *, struct device *, void *); 233 234 struct cfattach amlpinctrl_ca = { 235 sizeof(struct amlpinctrl_softc), amlpinctrl_match, amlpinctrl_attach 236 }; 237 238 struct cfdriver amlpinctrl_cd = { 239 NULL, "amlpinctrl", DV_DULL 240 }; 241 242 int amlpinctrl_pinctrl(uint32_t, void *); 243 void amlpinctrl_config_pin(void *, uint32_t *, int); 244 int amlpinctrl_get_pin(void *, uint32_t *); 245 void amlpinctrl_set_pin(void *, uint32_t *, int); 246 247 int 248 amlpinctrl_match(struct device *parent, void *match, void *aux) 249 { 250 struct fdt_attach_args *faa = aux; 251 int node = faa->fa_node; 252 253 return OF_is_compatible(node, "amlogic,meson-g12a-periphs-pinctrl"); 254 } 255 256 void 257 amlpinctrl_attach(struct device *parent, struct device *self, void *aux) 258 { 259 struct amlpinctrl_softc *sc = (struct amlpinctrl_softc *)self; 260 struct fdt_attach_args *faa = aux; 261 uint64_t addr[5], size[5]; 262 uint32_t *cell; 263 uint32_t acells, scells; 264 uint32_t reg[20]; 265 int node = faa->fa_node; 266 int child; 267 int i, len, line; 268 269 for (child = OF_child(node); child; child = OF_peer(child)) { 270 if (OF_getproplen(child, "gpio-controller") == 0) 271 break; 272 } 273 if (child == 0) { 274 printf(": no register banks\n"); 275 return; 276 } 277 278 acells = OF_getpropint(node, "#address-cells", faa->fa_acells); 279 scells = OF_getpropint(node, "#size-cells", faa->fa_scells); 280 len = OF_getproplen(child, "reg"); 281 line = (acells + scells) * sizeof(uint32_t); 282 if (acells < 1 || acells > 2 || scells < 1 || scells > 2 || 283 len > sizeof(reg) || (len / line) > nitems(addr)) { 284 printf(": unexpected register layout\n"); 285 return; 286 } 287 288 OF_getpropintarray(child, "reg", reg, len); 289 for (i = 0, cell = reg; i < len / line; i++) { 290 addr[i] = cell[0]; 291 if (acells > 1) 292 addr[i] = (addr[i] << 32) | cell[1]; 293 cell += acells; 294 size[i] = cell[0]; 295 if (scells > 1) 296 size[i] = (size[i] << 32) | cell[1]; 297 cell += scells; 298 } 299 300 sc->sc_iot = faa->fa_iot; 301 if (bus_space_map(sc->sc_iot, addr[0], size[0], 0, &sc->sc_gpio_ioh)) { 302 printf(": can't map gpio registers\n"); 303 return; 304 } 305 if (bus_space_map(sc->sc_iot, addr[1], size[1], 0, &sc->sc_pull_ioh)) { 306 printf(": can't map pull registers\n"); 307 return; 308 } 309 if (bus_space_map(sc->sc_iot, addr[2], size[2], 0, &sc->sc_pull_en_ioh)) { 310 printf(": can't map pull-enable registers\n"); 311 return; 312 } 313 if (bus_space_map(sc->sc_iot, addr[3], size[3], 0, &sc->sc_mux_ioh)) { 314 printf(": can't map mux registers\n"); 315 return; 316 } 317 if (bus_space_map(sc->sc_iot, addr[4], size[4], 0, &sc->sc_ds_ioh)) { 318 printf(": can't map ds registers\n"); 319 return; 320 } 321 322 printf("\n"); 323 324 sc->sc_gpio_banks = aml_g12a_gpio_banks; 325 sc->sc_pin_groups = aml_g12a_pin_groups; 326 327 pinctrl_register(faa->fa_node, amlpinctrl_pinctrl, sc); 328 329 sc->sc_gc.gc_node = child; 330 sc->sc_gc.gc_cookie = sc; 331 sc->sc_gc.gc_config_pin = amlpinctrl_config_pin; 332 sc->sc_gc.gc_get_pin = amlpinctrl_get_pin; 333 sc->sc_gc.gc_set_pin = amlpinctrl_set_pin; 334 gpio_controller_register(&sc->sc_gc); 335 } 336 337 struct aml_gpio_bank * 338 amlpinctrl_lookup_bank(struct amlpinctrl_softc *sc, uint32_t pin) 339 { 340 struct aml_gpio_bank *bank; 341 342 for (bank = sc->sc_gpio_banks; bank->num_pins > 0; bank++) { 343 if (pin >= bank->first_pin && 344 pin < bank->first_pin + bank->num_pins) 345 return bank; 346 } 347 348 return NULL; 349 } 350 351 struct aml_pin_group * 352 amlpinctrl_lookup_group(struct amlpinctrl_softc *sc, const char *name) 353 { 354 struct aml_pin_group *group; 355 356 for (group = sc->sc_pin_groups; group->name; group++) { 357 if (strcmp(name, group->name) == 0) 358 return group; 359 } 360 361 return NULL; 362 } 363 364 void 365 amlpinctrl_config_func(struct amlpinctrl_softc *sc, const char *name, 366 const char *function, int bias, int ds) 367 { 368 struct aml_pin_group *group; 369 struct aml_gpio_bank *bank; 370 bus_addr_t off; 371 uint32_t pin; 372 uint32_t reg; 373 374 group = amlpinctrl_lookup_group(sc, name); 375 if (group == NULL) { 376 printf("%s: %s\n", __func__, name); 377 return; 378 } 379 if (strcmp(function, group->function) != 0) { 380 printf("%s: mismatched function %s\n", __func__, function); 381 return; 382 } 383 384 bank = amlpinctrl_lookup_bank(sc, group->pin); 385 KASSERT(bank); 386 387 pin = group->pin - bank->first_pin; 388 389 /* mux */ 390 off = (bank->mux_reg + pin / 8) << 2; 391 reg = bus_space_read_4(sc->sc_iot, sc->sc_mux_ioh, off); 392 reg &= ~(0xf << ((pin % 8) * 4)); 393 reg |= (group->func << ((pin % 8) * 4)); 394 bus_space_write_4(sc->sc_iot, sc->sc_mux_ioh, off, reg); 395 396 /* pull */ 397 off = bank->pull_reg << 2; 398 reg = bus_space_read_4(sc->sc_iot, sc->sc_pull_ioh, off); 399 if (bias == BIAS_PULL_UP) 400 reg |= (1 << pin); 401 else 402 reg &= ~(1 << pin); 403 bus_space_write_4(sc->sc_iot, sc->sc_pull_ioh, off, reg); 404 405 /* pull-enable */ 406 off = bank->pull_en_reg << 2; 407 reg = bus_space_read_4(sc->sc_iot, sc->sc_pull_en_ioh, off); 408 if (bias != BIAS_DISABLE) 409 reg |= (1 << pin); 410 else 411 reg &= ~(1 << pin); 412 bus_space_write_4(sc->sc_iot, sc->sc_pull_en_ioh, off, reg); 413 414 if (ds < 0) 415 return; 416 else if (ds <= 500) 417 ds = 0; 418 else if (ds <= 2500) 419 ds = 1; 420 else if (ds <= 3000) 421 ds = 2; 422 else if (ds <= 4000) 423 ds = 3; 424 else { 425 printf("%s: invalid drive-strength %d\n", __func__, ds); 426 ds = 3; 427 } 428 429 /* ds */ 430 off = (bank->ds_reg + pin / 16) << 2; 431 reg = bus_space_read_4(sc->sc_iot, sc->sc_ds_ioh, off); 432 reg &= ~(0x3 << ((pin % 16) * 2)); 433 reg |= (ds << ((pin % 16) * 2)); 434 bus_space_write_4(sc->sc_iot, sc->sc_ds_ioh, off, reg); 435 } 436 437 int 438 amlpinctrl_pinctrl(uint32_t phandle, void *cookie) 439 { 440 struct amlpinctrl_softc *sc = cookie; 441 int node, child; 442 443 node = OF_getnodebyphandle(phandle); 444 if (node == 0) 445 return -1; 446 447 for (child = OF_child(node); child; child = OF_peer(child)) { 448 char function[16]; 449 char *groups; 450 char *group; 451 int bias, ds; 452 int len; 453 454 memset(function, 0, sizeof(function)); 455 OF_getprop(child, "function", function, sizeof(function)); 456 function[sizeof(function) - 1] = 0; 457 458 /* Bias */ 459 if (OF_getproplen(child, "bias-pull-up") == 0) 460 bias = BIAS_PULL_UP; 461 else if (OF_getproplen(child, "bias-pull-down") == 0) 462 bias = BIAS_PULL_DOWN; 463 else 464 bias = BIAS_DISABLE; 465 466 /* Drive-strength */ 467 ds = OF_getpropint(child, "drive-strength-microamp", -1); 468 469 len = OF_getproplen(child, "groups"); 470 if (len <= 0) { 471 printf("%s: 0x%08x\n", __func__, phandle); 472 continue; 473 } 474 475 groups = malloc(len, M_TEMP, M_WAITOK); 476 OF_getprop(child, "groups", groups, len); 477 478 group = groups; 479 while (group < groups + len) { 480 amlpinctrl_config_func(sc, group, function, bias, ds); 481 group += strlen(group) + 1; 482 } 483 484 free(groups, M_TEMP, len); 485 } 486 487 return 0; 488 } 489 490 void 491 amlpinctrl_config_pin(void *cookie, uint32_t *cells, int config) 492 { 493 struct amlpinctrl_softc *sc = cookie; 494 struct aml_gpio_bank *bank; 495 bus_addr_t off; 496 uint32_t pin = cells[0]; 497 uint32_t reg; 498 499 bank = amlpinctrl_lookup_bank(sc, pin); 500 if (bank == NULL) { 501 printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]); 502 return; 503 } 504 505 pin = pin - bank->first_pin; 506 507 /* mux */ 508 off = (bank->mux_reg + pin / 8) << 2; 509 reg = bus_space_read_4(sc->sc_iot, sc->sc_mux_ioh, off); 510 reg &= ~(0xf << ((pin % 8) * 4)); 511 bus_space_write_4(sc->sc_iot, sc->sc_mux_ioh, off, reg); 512 513 /* gpio */ 514 off = bank->gpio_reg << 2; 515 reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off); 516 if (config & GPIO_CONFIG_OUTPUT) 517 reg &= ~(1 << pin); 518 else 519 reg |= (1 << pin); 520 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg); 521 } 522 523 int 524 amlpinctrl_get_pin(void *cookie, uint32_t *cells) 525 { 526 struct amlpinctrl_softc *sc = cookie; 527 struct aml_gpio_bank *bank; 528 bus_addr_t off; 529 uint32_t pin = cells[0]; 530 uint32_t flags = cells[1]; 531 uint32_t reg; 532 int val; 533 534 bank = amlpinctrl_lookup_bank(sc, pin); 535 if (bank == NULL) { 536 printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]); 537 return 0; 538 } 539 540 pin = pin - bank->first_pin; 541 542 /* gpio */ 543 off = (bank->gpio_reg + 2) << 2; 544 reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off); 545 val = (reg >> pin) & 1; 546 if (flags & GPIO_ACTIVE_LOW) 547 val = !val; 548 549 return val; 550 } 551 552 void 553 amlpinctrl_set_pin(void *cookie, uint32_t *cells, int val) 554 { 555 struct amlpinctrl_softc *sc = cookie; 556 struct aml_gpio_bank *bank; 557 bus_addr_t off; 558 uint32_t pin = cells[0]; 559 uint32_t flags = cells[1]; 560 int reg; 561 562 bank = amlpinctrl_lookup_bank(sc, pin); 563 if (bank == NULL) { 564 printf("%s: 0x%08x 0x%08x\n", __func__, cells[0], cells[1]); 565 return; 566 } 567 568 if (flags & GPIO_ACTIVE_LOW) 569 val = !val; 570 571 pin = pin - bank->first_pin; 572 573 /* gpio */ 574 off = (bank->gpio_reg + 1) << 2; 575 reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, off); 576 if (val) 577 reg |= (1 << pin); 578 else 579 reg &= ~(1 << pin); 580 bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, off, reg); 581 } 582