1 /*- 2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/bus.h> 30 #include <sys/gpio.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/sx.h> 34 35 #include <machine/bus.h> 36 37 #include <dev/fdt/fdt_common.h> 38 #include <dev/gpio/gpiobusvar.h> 39 40 #include "as3722.h" 41 42 MALLOC_DEFINE(M_AS3722_GPIO, "AS3722 gpio", "AS3722 GPIO"); 43 44 /* AS3722_GPIOx_CONTROL MODE and IOSF definition. */ 45 #define AS3722_IOSF_GPIO 0x00 46 #define AS3722_IOSF_INTERRUPT_OUT 0x01 47 #define AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT 0x02 48 #define AS3722_IOSF_GPIO_IN_INTERRUPT 0x03 49 #define AS3722_IOSF_PWM_IN 0x04 50 #define AS3722_IOSF_VOLTAGE_IN_STANDBY 0x05 51 #define AS3722_IOSF_OC_PG_SD0 0x06 52 #define AS3722_IOSF_POWERGOOD_OUT 0x07 53 #define AS3722_IOSF_CLK32K_OUT 0x08 54 #define AS3722_IOSF_WATCHDOG_IN 0x09 55 #define AS3722_IOSF_SOFT_RESET_IN 0x0b 56 #define AS3722_IOSF_PWM_OUT 0x0c 57 #define AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT 0x0d 58 #define AS3722_IOSF_OC_PG_SD6 0x0e 59 60 #define AS3722_MODE_INPUT 0 61 #define AS3722_MODE_PUSH_PULL 1 62 #define AS3722_MODE_OPEN_DRAIN 2 63 #define AS3722_MODE_TRISTATE 3 64 #define AS3722_MODE_INPUT_PULL_UP_LV 4 65 #define AS3722_MODE_INPUT_PULL_DOWN 5 66 #define AS3722_MODE_OPEN_DRAIN_LV 6 67 #define AS3722_MODE_PUSH_PULL_LV 7 68 69 #define NGPIO 8 70 71 #define GPIO_LOCK(_sc) sx_slock(&(_sc)->gpio_lock) 72 #define GPIO_UNLOCK(_sc) sx_unlock(&(_sc)->gpio_lock) 73 #define GPIO_ASSERT(_sc) sx_assert(&(_sc)->gpio_lock, SA_LOCKED) 74 75 #define AS3722_CFG_BIAS_DISABLE 0x0001 76 #define AS3722_CFG_BIAS_PULL_UP 0x0002 77 #define AS3722_CFG_BIAS_PULL_DOWN 0x0004 78 #define AS3722_CFG_BIAS_HIGH_IMPEDANCE 0x0008 79 #define AS3722_CFG_OPEN_DRAIN 0x0010 80 81 static const struct { 82 const char *name; 83 int config; /* AS3722_CFG_ */ 84 } as3722_cfg_names[] = { 85 {"bias-disable", AS3722_CFG_BIAS_DISABLE}, 86 {"bias-pull-up", AS3722_CFG_BIAS_PULL_UP}, 87 {"bias-pull-down", AS3722_CFG_BIAS_PULL_DOWN}, 88 {"bias-high-impedance", AS3722_CFG_BIAS_HIGH_IMPEDANCE}, 89 {"drive-open-drain", AS3722_CFG_OPEN_DRAIN}, 90 }; 91 92 static struct { 93 const char *name; 94 int fnc_val; 95 } as3722_fnc_table[] = { 96 {"gpio", AS3722_IOSF_GPIO}, 97 {"interrupt-out", AS3722_IOSF_INTERRUPT_OUT}, 98 {"vsup-vbat-low-undebounce-out", AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT}, 99 {"gpio-in-interrupt", AS3722_IOSF_GPIO_IN_INTERRUPT}, 100 {"pwm-in", AS3722_IOSF_PWM_IN}, 101 {"voltage-in-standby", AS3722_IOSF_VOLTAGE_IN_STANDBY}, 102 {"oc-pg-sd0", AS3722_IOSF_OC_PG_SD0}, 103 {"powergood-out", AS3722_IOSF_POWERGOOD_OUT}, 104 {"clk32k-out", AS3722_IOSF_CLK32K_OUT}, 105 {"watchdog-in", AS3722_IOSF_WATCHDOG_IN}, 106 {"soft-reset-in", AS3722_IOSF_SOFT_RESET_IN}, 107 {"pwm-out", AS3722_IOSF_PWM_OUT}, 108 {"vsup-vbat-low-debounce-out", AS3722_IOSF_VSUP_VBAT_LOW_DEBOUNCE_OUT}, 109 {"oc-pg-sd6", AS3722_IOSF_OC_PG_SD6}, 110 }; 111 112 struct as3722_pincfg { 113 char *function; 114 int flags; 115 }; 116 117 struct as3722_gpio_pin { 118 int pin_caps; 119 uint8_t pin_ctrl_reg; 120 char pin_name[GPIOMAXNAME]; 121 int pin_cfg_flags; 122 }; 123 124 /* -------------------------------------------------------------------------- 125 * 126 * Pinmux functions. 127 */ 128 static int 129 as3722_pinmux_get_function(struct as3722_softc *sc, char *name) 130 { 131 int i; 132 133 for (i = 0; i < nitems(as3722_fnc_table); i++) { 134 if (strcmp(as3722_fnc_table[i].name, name) == 0) 135 return (as3722_fnc_table[i].fnc_val); 136 } 137 return (-1); 138 } 139 140 static int 141 as3722_pinmux_config_node(struct as3722_softc *sc, char *pin_name, 142 struct as3722_pincfg *cfg) 143 { 144 uint8_t ctrl; 145 int rv, fnc, pin; 146 147 for (pin = 0; pin < sc->gpio_npins; pin++) { 148 if (strcmp(sc->gpio_pins[pin]->pin_name, pin_name) == 0) 149 break; 150 } 151 if (pin >= sc->gpio_npins) { 152 device_printf(sc->dev, "Unknown pin: %s\n", pin_name); 153 return (ENXIO); 154 } 155 156 ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; 157 sc->gpio_pins[pin]->pin_cfg_flags = cfg->flags; 158 if (cfg->function != NULL) { 159 fnc = as3722_pinmux_get_function(sc, cfg->function); 160 if (fnc == -1) { 161 device_printf(sc->dev, 162 "Unknown function %s for pin %s\n", cfg->function, 163 sc->gpio_pins[pin]->pin_name); 164 return (ENXIO); 165 } 166 switch (fnc) { 167 case AS3722_IOSF_INTERRUPT_OUT: 168 case AS3722_IOSF_VSUP_VBAT_LOW_UNDEBOUNCE_OUT: 169 case AS3722_IOSF_OC_PG_SD0: 170 case AS3722_IOSF_POWERGOOD_OUT: 171 case AS3722_IOSF_CLK32K_OUT: 172 case AS3722_IOSF_PWM_OUT: 173 case AS3722_IOSF_OC_PG_SD6: 174 ctrl &= ~(AS3722_GPIO_MODE_MASK << 175 AS3722_GPIO_MODE_SHIFT); 176 ctrl |= AS3722_MODE_PUSH_PULL << AS3722_GPIO_MODE_SHIFT; 177 /* XXX Handle flags (OC + pullup) */ 178 break; 179 case AS3722_IOSF_GPIO_IN_INTERRUPT: 180 case AS3722_IOSF_PWM_IN: 181 case AS3722_IOSF_VOLTAGE_IN_STANDBY: 182 case AS3722_IOSF_WATCHDOG_IN: 183 case AS3722_IOSF_SOFT_RESET_IN: 184 ctrl &= ~(AS3722_GPIO_MODE_MASK << 185 AS3722_GPIO_MODE_SHIFT); 186 ctrl |= AS3722_MODE_INPUT << AS3722_GPIO_MODE_SHIFT; 187 /* XXX Handle flags (pulldown + pullup) */ 188 189 default: 190 break; 191 } 192 ctrl &= ~(AS3722_GPIO_IOSF_MASK << AS3722_GPIO_IOSF_SHIFT); 193 ctrl |= fnc << AS3722_GPIO_IOSF_SHIFT; 194 } 195 rv = 0; 196 if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) { 197 rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl); 198 sc->gpio_pins[pin]->pin_ctrl_reg = ctrl; 199 } 200 return (rv); 201 } 202 203 static int 204 as3722_pinmux_read_node(struct as3722_softc *sc, phandle_t node, 205 struct as3722_pincfg *cfg, char **pins, int *lpins) 206 { 207 int rv, i; 208 209 *lpins = OF_getprop_alloc(node, "pins", (void **)pins); 210 if (*lpins <= 0) 211 return (ENOENT); 212 213 /* Read function (mux) settings. */ 214 rv = OF_getprop_alloc(node, "function", (void **)&cfg->function); 215 if (rv <= 0) 216 cfg->function = NULL; 217 218 /* Read boolean properties. */ 219 for (i = 0; i < nitems(as3722_cfg_names); i++) { 220 if (OF_hasprop(node, as3722_cfg_names[i].name)) 221 cfg->flags |= as3722_cfg_names[i].config; 222 } 223 return (0); 224 } 225 226 static int 227 as3722_pinmux_process_node(struct as3722_softc *sc, phandle_t node) 228 { 229 struct as3722_pincfg cfg; 230 char *pins, *pname; 231 int i, len, lpins, rv; 232 233 rv = as3722_pinmux_read_node(sc, node, &cfg, &pins, &lpins); 234 if (rv != 0) 235 return (rv); 236 237 len = 0; 238 pname = pins; 239 do { 240 i = strlen(pname) + 1; 241 rv = as3722_pinmux_config_node(sc, pname, &cfg); 242 if (rv != 0) { 243 device_printf(sc->dev, 244 "Cannot configure pin: %s: %d\n", pname, rv); 245 } 246 len += i; 247 pname += i; 248 } while (len < lpins); 249 250 if (pins != NULL) 251 OF_prop_free(pins); 252 if (cfg.function != NULL) 253 OF_prop_free(cfg.function); 254 255 return (rv); 256 } 257 258 int as3722_pinmux_configure(device_t dev, phandle_t cfgxref) 259 { 260 struct as3722_softc *sc; 261 phandle_t node, cfgnode; 262 int rv; 263 264 sc = device_get_softc(dev); 265 cfgnode = OF_node_from_xref(cfgxref); 266 267 for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) { 268 if (!ofw_bus_node_status_okay(node)) 269 continue; 270 rv = as3722_pinmux_process_node(sc, node); 271 if (rv != 0) 272 device_printf(dev, "Failed to process pinmux"); 273 } 274 return (0); 275 } 276 277 /* -------------------------------------------------------------------------- 278 * 279 * GPIO 280 */ 281 device_t 282 as3722_gpio_get_bus(device_t dev) 283 { 284 struct as3722_softc *sc; 285 286 sc = device_get_softc(dev); 287 return (sc->gpio_busdev); 288 } 289 290 int 291 as3722_gpio_pin_max(device_t dev, int *maxpin) 292 { 293 294 *maxpin = NGPIO - 1; 295 return (0); 296 } 297 298 int 299 as3722_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 300 { 301 struct as3722_softc *sc; 302 303 sc = device_get_softc(dev); 304 if (pin >= sc->gpio_npins) 305 return (EINVAL); 306 GPIO_LOCK(sc); 307 *caps = sc->gpio_pins[pin]->pin_caps; 308 GPIO_UNLOCK(sc); 309 return (0); 310 } 311 312 int 313 as3722_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 314 { 315 struct as3722_softc *sc; 316 317 sc = device_get_softc(dev); 318 if (pin >= sc->gpio_npins) 319 return (EINVAL); 320 GPIO_LOCK(sc); 321 memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME); 322 GPIO_UNLOCK(sc); 323 return (0); 324 } 325 326 int 327 as3722_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags) 328 { 329 struct as3722_softc *sc; 330 uint8_t tmp, mode, iosf; 331 uint32_t flags; 332 bool inverted; 333 334 sc = device_get_softc(dev); 335 if (pin >= sc->gpio_npins) 336 return (EINVAL); 337 338 GPIO_LOCK(sc); 339 tmp = sc->gpio_pins[pin]->pin_ctrl_reg; 340 GPIO_UNLOCK(sc); 341 iosf = (tmp >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK; 342 mode = (tmp >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK; 343 inverted = (tmp & AS3722_GPIO_INVERT) != 0; 344 /* Is pin in GPIO mode ? */ 345 if (iosf != AS3722_IOSF_GPIO) 346 return (ENXIO); 347 348 flags = 0; 349 switch (mode) { 350 case AS3722_MODE_INPUT: 351 flags = GPIO_PIN_INPUT; 352 break; 353 case AS3722_MODE_PUSH_PULL: 354 case AS3722_MODE_PUSH_PULL_LV: 355 flags = GPIO_PIN_OUTPUT; 356 break; 357 case AS3722_MODE_OPEN_DRAIN: 358 case AS3722_MODE_OPEN_DRAIN_LV: 359 flags = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN; 360 break; 361 case AS3722_MODE_TRISTATE: 362 flags = GPIO_PIN_TRISTATE; 363 break; 364 case AS3722_MODE_INPUT_PULL_UP_LV: 365 flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP; 366 break; 367 368 case AS3722_MODE_INPUT_PULL_DOWN: 369 flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLDOWN; 370 break; 371 } 372 if (inverted) 373 flags |= GPIO_PIN_INVIN | GPIO_PIN_INVOUT; 374 *out_flags = flags; 375 return (0); 376 } 377 378 static int 379 as3722_gpio_get_mode(struct as3722_softc *sc, uint32_t pin, uint32_t gpio_flags) 380 { 381 int flags; 382 383 flags = sc->gpio_pins[pin]->pin_cfg_flags; 384 385 /* Tristate mode. */ 386 if (flags & AS3722_CFG_BIAS_HIGH_IMPEDANCE || 387 gpio_flags & GPIO_PIN_TRISTATE) 388 return (AS3722_MODE_TRISTATE); 389 390 /* Open drain modes. */ 391 if (flags & AS3722_CFG_OPEN_DRAIN || gpio_flags & GPIO_PIN_OPENDRAIN) { 392 /* Only pull up have effect */ 393 if (flags & AS3722_CFG_BIAS_PULL_UP || 394 gpio_flags & GPIO_PIN_PULLUP) 395 return (AS3722_MODE_OPEN_DRAIN_LV); 396 return (AS3722_MODE_OPEN_DRAIN); 397 } 398 /* Input modes. */ 399 if (gpio_flags & GPIO_PIN_INPUT) { 400 /* Accept pull up or pull down. */ 401 if (flags & AS3722_CFG_BIAS_PULL_UP || 402 gpio_flags & GPIO_PIN_PULLUP) 403 return (AS3722_MODE_INPUT_PULL_UP_LV); 404 405 if (flags & AS3722_CFG_BIAS_PULL_DOWN || 406 gpio_flags & GPIO_PIN_PULLDOWN) 407 return (AS3722_MODE_INPUT_PULL_DOWN); 408 return (AS3722_MODE_INPUT); 409 } 410 /* 411 * Output modes. 412 * Pull down is used as indicator of low voltage output. 413 */ 414 if (flags & AS3722_CFG_BIAS_PULL_DOWN || 415 gpio_flags & GPIO_PIN_PULLDOWN) 416 return (AS3722_MODE_PUSH_PULL_LV); 417 return (AS3722_MODE_PUSH_PULL); 418 } 419 420 int 421 as3722_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 422 { 423 struct as3722_softc *sc; 424 uint8_t ctrl, mode, iosf; 425 int rv; 426 427 sc = device_get_softc(dev); 428 if (pin >= sc->gpio_npins) 429 return (EINVAL); 430 431 GPIO_LOCK(sc); 432 ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; 433 iosf = (ctrl >> AS3722_GPIO_IOSF_SHIFT) & AS3722_GPIO_IOSF_MASK; 434 /* Is pin in GPIO mode ? */ 435 if (iosf != AS3722_IOSF_GPIO) { 436 GPIO_UNLOCK(sc); 437 return (ENXIO); 438 } 439 mode = as3722_gpio_get_mode(sc, pin, flags); 440 ctrl &= ~(AS3722_GPIO_MODE_MASK << AS3722_GPIO_MODE_SHIFT); 441 ctrl |= mode << AS3722_GPIO_MODE_SHIFT; 442 rv = 0; 443 if (ctrl != sc->gpio_pins[pin]->pin_ctrl_reg) { 444 rv = WR1(sc, AS3722_GPIO0_CONTROL + pin, ctrl); 445 sc->gpio_pins[pin]->pin_ctrl_reg = ctrl; 446 } 447 GPIO_UNLOCK(sc); 448 return (rv); 449 } 450 451 int 452 as3722_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val) 453 { 454 struct as3722_softc *sc; 455 uint8_t tmp; 456 int rv; 457 458 sc = device_get_softc(dev); 459 if (pin >= sc->gpio_npins) 460 return (EINVAL); 461 462 tmp = (val != 0) ? 1 : 0; 463 if (sc->gpio_pins[pin]->pin_ctrl_reg & AS3722_GPIO_INVERT) 464 tmp ^= 1; 465 466 GPIO_LOCK(sc); 467 rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), (tmp << pin)); 468 GPIO_UNLOCK(sc); 469 return (rv); 470 } 471 472 int 473 as3722_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val) 474 { 475 struct as3722_softc *sc; 476 uint8_t tmp, mode, ctrl; 477 int rv; 478 479 sc = device_get_softc(dev); 480 if (pin >= sc->gpio_npins) 481 return (EINVAL); 482 483 GPIO_LOCK(sc); 484 ctrl = sc->gpio_pins[pin]->pin_ctrl_reg; 485 mode = (ctrl >> AS3722_GPIO_MODE_SHIFT) & AS3722_GPIO_MODE_MASK; 486 if ((mode == AS3722_MODE_PUSH_PULL) || 487 (mode == AS3722_MODE_PUSH_PULL_LV)) 488 rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp); 489 else 490 rv = RD1(sc, AS3722_GPIO_SIGNAL_IN, &tmp); 491 GPIO_UNLOCK(sc); 492 if (rv != 0) 493 return (rv); 494 495 *val = tmp & (1 << pin) ? 1 : 0; 496 if (ctrl & AS3722_GPIO_INVERT) 497 *val ^= 1; 498 return (0); 499 } 500 501 int 502 as3722_gpio_pin_toggle(device_t dev, uint32_t pin) 503 { 504 struct as3722_softc *sc; 505 uint8_t tmp; 506 int rv; 507 508 sc = device_get_softc(dev); 509 if (pin >= sc->gpio_npins) 510 return (EINVAL); 511 512 GPIO_LOCK(sc); 513 rv = RD1(sc, AS3722_GPIO_SIGNAL_OUT, &tmp); 514 if (rv != 0) { 515 GPIO_UNLOCK(sc); 516 return (rv); 517 } 518 tmp ^= (1 <<pin); 519 rv = RM1(sc, AS3722_GPIO_SIGNAL_OUT, (1 << pin), tmp); 520 GPIO_UNLOCK(sc); 521 return (0); 522 } 523 524 int 525 as3722_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent, 526 int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) 527 { 528 529 if (gcells != 2) 530 return (ERANGE); 531 *pin = gpios[0]; 532 *flags= gpios[1]; 533 return (0); 534 } 535 536 int 537 as3722_gpio_attach(struct as3722_softc *sc, phandle_t node) 538 { 539 struct as3722_gpio_pin *pin; 540 int i, rv; 541 542 sx_init(&sc->gpio_lock, "AS3722 GPIO lock"); 543 sc->gpio_npins = NGPIO; 544 sc->gpio_pins = malloc(sizeof(struct as3722_gpio_pin *) * 545 sc->gpio_npins, M_AS3722_GPIO, M_WAITOK | M_ZERO); 546 547 sc->gpio_busdev = gpiobus_attach_bus(sc->dev); 548 if (sc->gpio_busdev == NULL) 549 return (ENXIO); 550 for (i = 0; i < sc->gpio_npins; i++) { 551 sc->gpio_pins[i] = malloc(sizeof(struct as3722_gpio_pin), 552 M_AS3722_GPIO, M_WAITOK | M_ZERO); 553 pin = sc->gpio_pins[i]; 554 sprintf(pin->pin_name, "gpio%d", i); 555 pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | 556 GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 557 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_PIN_INVIN | 558 GPIO_PIN_INVOUT; 559 rv = RD1(sc, AS3722_GPIO0_CONTROL + i, &pin->pin_ctrl_reg); 560 if (rv != 0) { 561 device_printf(sc->dev, 562 "Cannot read configuration for pin %s\n", 563 sc->gpio_pins[i]->pin_name); 564 } 565 } 566 return (0); 567 } 568