1e9034789SMichal Meloun /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3e9034789SMichal Meloun * 4e9034789SMichal Meloun * Copyright 2020 Michal Meloun <mmel@FreeBSD.org> 5e9034789SMichal Meloun * 6e9034789SMichal Meloun * Redistribution and use in source and binary forms, with or without 7e9034789SMichal Meloun * modification, are permitted provided that the following conditions 8e9034789SMichal Meloun * are met: 9e9034789SMichal Meloun * 1. Redistributions of source code must retain the above copyright 10e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer. 11e9034789SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 12e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer in the 13e9034789SMichal Meloun * documentation and/or other materials provided with the distribution. 14e9034789SMichal Meloun * 15e9034789SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e9034789SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e9034789SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e9034789SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e9034789SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e9034789SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e9034789SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e9034789SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e9034789SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e9034789SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e9034789SMichal Meloun * SUCH DAMAGE. 26e9034789SMichal Meloun */ 27e9034789SMichal Meloun 28e9034789SMichal Meloun #include <sys/param.h> 29e9034789SMichal Meloun #include <sys/systm.h> 30e9034789SMichal Meloun #include <sys/bus.h> 31e9034789SMichal Meloun #include <sys/gpio.h> 32e9034789SMichal Meloun #include <sys/kernel.h> 33e9034789SMichal Meloun #include <sys/malloc.h> 34e9034789SMichal Meloun #include <sys/sx.h> 35e9034789SMichal Meloun 36e9034789SMichal Meloun #include <machine/bus.h> 37e9034789SMichal Meloun 38e9034789SMichal Meloun #include <dev/fdt/fdt_common.h> 39e9034789SMichal Meloun #include <dev/gpio/gpiobusvar.h> 40e9034789SMichal Meloun 41e9034789SMichal Meloun #include "max77620.h" 42e9034789SMichal Meloun 43e9034789SMichal Meloun MALLOC_DEFINE(M_MAX77620_GPIO, "MAX77620 gpio", "MAX77620 GPIO"); 44e9034789SMichal Meloun 45e9034789SMichal Meloun #define NGPIO 8 46e9034789SMichal Meloun 47e9034789SMichal Meloun #define GPIO_LOCK(_sc) sx_slock(&(_sc)->gpio_lock) 48e9034789SMichal Meloun #define GPIO_UNLOCK(_sc) sx_unlock(&(_sc)->gpio_lock) 49e9034789SMichal Meloun #define GPIO_ASSERT(_sc) sx_assert(&(_sc)->gpio_lock, SA_LOCKED) 50e9034789SMichal Meloun 51e9034789SMichal Meloun enum prop_id { 52e9034789SMichal Meloun CFG_BIAS_PULL_UP, 53e9034789SMichal Meloun CFG_BIAS_PULL_DOWN, 54e9034789SMichal Meloun CFG_OPEN_DRAIN, 55e9034789SMichal Meloun CFG_PUSH_PULL, 56e9034789SMichal Meloun 57e9034789SMichal Meloun CFG_ACTIVE_FPS_SRC, 58e9034789SMichal Meloun CFG_ACTIVE_PWRUP_SLOT, 59e9034789SMichal Meloun CFG_ACTIVE_PWRDOWN_SLOT, 60e9034789SMichal Meloun CFG_SUSPEND_FPS_SRC, 61e9034789SMichal Meloun CFG_SUSPEND_PWRUP_SLOT, 62e9034789SMichal Meloun CFG_SUSPEND_PWRDOWN_SLOT, 63e9034789SMichal Meloun 64e9034789SMichal Meloun PROP_ID_MAX_ID 65e9034789SMichal Meloun }; 66e9034789SMichal Meloun 67e9034789SMichal Meloun static const struct { 68e9034789SMichal Meloun const char *name; 69e9034789SMichal Meloun enum prop_id id; 70e9034789SMichal Meloun } max77620_prop_names[] = { 71e9034789SMichal Meloun {"bias-pull-up", CFG_BIAS_PULL_UP}, 72e9034789SMichal Meloun {"bias-pull-down", CFG_BIAS_PULL_DOWN}, 73e9034789SMichal Meloun {"drive-open-drain", CFG_OPEN_DRAIN}, 74e9034789SMichal Meloun {"drive-push-pull", CFG_PUSH_PULL}, 75e9034789SMichal Meloun {"maxim,active-fps-source", CFG_ACTIVE_FPS_SRC}, 76e9034789SMichal Meloun {"maxim,active-fps-power-up-slot", CFG_ACTIVE_PWRUP_SLOT}, 77e9034789SMichal Meloun {"maxim,active-fps-power-down-slot", CFG_ACTIVE_PWRDOWN_SLOT}, 78e9034789SMichal Meloun {"maxim,suspend-fps-source", CFG_SUSPEND_FPS_SRC}, 79e9034789SMichal Meloun {"maxim,suspend-fps-power-up-slot", CFG_SUSPEND_PWRUP_SLOT}, 80e9034789SMichal Meloun {"maxim,suspend-fps-power-down-slot", CFG_SUSPEND_PWRDOWN_SLOT}, 81e9034789SMichal Meloun }; 82e9034789SMichal Meloun 83e9034789SMichal Meloun /* Configuration for one pin group. */ 84e9034789SMichal Meloun struct max77620_pincfg { 85e9034789SMichal Meloun bool alt_func; 86e9034789SMichal Meloun int params[PROP_ID_MAX_ID]; 87e9034789SMichal Meloun }; 88e9034789SMichal Meloun 89e9034789SMichal Meloun static char *altfnc_table[] = { 90e9034789SMichal Meloun "lpm-control-in", 91e9034789SMichal Meloun "fps-out", 92e9034789SMichal Meloun "32k-out1", 93e9034789SMichal Meloun "sd0-dvs-in", 94e9034789SMichal Meloun "sd1-dvs-in", 95e9034789SMichal Meloun "reference-out", 96e9034789SMichal Meloun }; 97e9034789SMichal Meloun 98e9034789SMichal Meloun struct max77620_gpio_pin { 99e9034789SMichal Meloun int pin_caps; 100e9034789SMichal Meloun char pin_name[GPIOMAXNAME]; 101e9034789SMichal Meloun uint8_t reg; 102e9034789SMichal Meloun 103e9034789SMichal Meloun /* Runtime data */ 104e9034789SMichal Meloun bool alt_func; /* GPIO or alternate function */ 105e9034789SMichal Meloun }; 106e9034789SMichal Meloun 107e9034789SMichal Meloun /* -------------------------------------------------------------------------- 108e9034789SMichal Meloun * 109e9034789SMichal Meloun * Pinmux functions. 110e9034789SMichal Meloun */ 111e9034789SMichal Meloun static int 112e9034789SMichal Meloun max77620_pinmux_get_function(struct max77620_softc *sc, char *name, 113e9034789SMichal Meloun struct max77620_pincfg *cfg) 114e9034789SMichal Meloun { 115e9034789SMichal Meloun int i; 116e9034789SMichal Meloun 117e9034789SMichal Meloun if (strcmp("gpio", name) == 0) { 118e9034789SMichal Meloun cfg->alt_func = false; 119e9034789SMichal Meloun return (0); 120e9034789SMichal Meloun } 121e9034789SMichal Meloun for (i = 0; i < nitems(altfnc_table); i++) { 122e9034789SMichal Meloun if (strcmp(altfnc_table[i], name) == 0) { 123e9034789SMichal Meloun cfg->alt_func = true; 124e9034789SMichal Meloun return (0); 125e9034789SMichal Meloun } 126e9034789SMichal Meloun } 127e9034789SMichal Meloun return (-1); 128e9034789SMichal Meloun } 129e9034789SMichal Meloun 130e9034789SMichal Meloun static int 131e9034789SMichal Meloun max77620_pinmux_set_fps(struct max77620_softc *sc, int pin_num, 132e9034789SMichal Meloun struct max77620_gpio_pin *pin) 133e9034789SMichal Meloun { 134e9034789SMichal Meloun #if 0 135e9034789SMichal Meloun struct max77620_fps_config *fps_config = &mpci->fps_config[pin]; 136e9034789SMichal Meloun int addr, ret; 137e9034789SMichal Meloun int param_val; 138e9034789SMichal Meloun int mask, shift; 139e9034789SMichal Meloun 140e9034789SMichal Meloun if ((pin < 1) || (pin > 3)) 141e9034789SMichal Meloun return (0); 142e9034789SMichal Meloun 143e9034789SMichal Meloun switch (param) { 144e9034789SMichal Meloun case MAX77620_ACTIVE_FPS_SOURCE: 145e9034789SMichal Meloun case MAX77620_SUSPEND_FPS_SOURCE: 146e9034789SMichal Meloun mask = MAX77620_FPS_SRC_MASK; 147e9034789SMichal Meloun shift = MAX77620_FPS_SRC_SHIFT; 148e9034789SMichal Meloun param_val = fps_config->active_fps_src; 149e9034789SMichal Meloun if (param == MAX77620_SUSPEND_FPS_SOURCE) 150e9034789SMichal Meloun param_val = fps_config->suspend_fps_src; 151e9034789SMichal Meloun break; 152e9034789SMichal Meloun 153e9034789SMichal Meloun case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS: 154e9034789SMichal Meloun case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS: 155e9034789SMichal Meloun mask = MAX77620_FPS_PU_PERIOD_MASK; 156e9034789SMichal Meloun shift = MAX77620_FPS_PU_PERIOD_SHIFT; 157e9034789SMichal Meloun param_val = fps_config->active_power_up_slots; 158e9034789SMichal Meloun if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS) 159e9034789SMichal Meloun param_val = fps_config->suspend_power_up_slots; 160e9034789SMichal Meloun break; 161e9034789SMichal Meloun 162e9034789SMichal Meloun case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS: 163e9034789SMichal Meloun case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS: 164e9034789SMichal Meloun mask = MAX77620_FPS_PD_PERIOD_MASK; 165e9034789SMichal Meloun shift = MAX77620_FPS_PD_PERIOD_SHIFT; 166e9034789SMichal Meloun param_val = fps_config->active_power_down_slots; 167e9034789SMichal Meloun if (param == MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS) 168e9034789SMichal Meloun param_val = fps_config->suspend_power_down_slots; 169e9034789SMichal Meloun break; 170e9034789SMichal Meloun 171e9034789SMichal Meloun default: 172e9034789SMichal Meloun dev_err(mpci->dev, "Invalid parameter %d for pin %d\n", 173e9034789SMichal Meloun param, pin); 174e9034789SMichal Meloun return -EINVAL; 175e9034789SMichal Meloun } 176e9034789SMichal Meloun 177e9034789SMichal Meloun if (param_val < 0) 178e9034789SMichal Meloun return 0; 179e9034789SMichal Meloun 180e9034789SMichal Meloun ret = regmap_update_bits(mpci->rmap, addr, mask, param_val << shift); 181e9034789SMichal Meloun if (ret < 0) 182e9034789SMichal Meloun dev_err(mpci->dev, "Reg 0x%02x update failed %d\n", addr, ret); 183e9034789SMichal Meloun 184e9034789SMichal Meloun return ret; 185e9034789SMichal Meloun #endif 186e9034789SMichal Meloun return (0); 187e9034789SMichal Meloun } 188e9034789SMichal Meloun 189e9034789SMichal Meloun static int 190e9034789SMichal Meloun max77620_pinmux_config_node(struct max77620_softc *sc, char *pin_name, 191e9034789SMichal Meloun struct max77620_pincfg *cfg) 192e9034789SMichal Meloun { 193e9034789SMichal Meloun struct max77620_gpio_pin *pin; 194e9034789SMichal Meloun uint8_t reg; 195e9034789SMichal Meloun int pin_num, rv; 196e9034789SMichal Meloun 197e9034789SMichal Meloun for (pin_num = 0; pin_num < sc->gpio_npins; pin_num++) { 198e9034789SMichal Meloun if (strcmp(sc->gpio_pins[pin_num]->pin_name, pin_name) == 0) 199e9034789SMichal Meloun break; 200e9034789SMichal Meloun } 201e9034789SMichal Meloun if (pin_num >= sc->gpio_npins) { 202e9034789SMichal Meloun device_printf(sc->dev, "Unknown pin: %s\n", pin_name); 203e9034789SMichal Meloun return (ENXIO); 204e9034789SMichal Meloun } 205e9034789SMichal Meloun pin = sc->gpio_pins[pin_num]; 206e9034789SMichal Meloun 207e9034789SMichal Meloun rv = max77620_pinmux_set_fps(sc, pin_num, pin); 208e9034789SMichal Meloun if (rv != 0) 209e9034789SMichal Meloun return (rv); 210e9034789SMichal Meloun 211e9034789SMichal Meloun rv = RD1(sc, pin->reg, ®); 212e9034789SMichal Meloun if (rv != 0) { 213e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n"); 214e9034789SMichal Meloun return (ENXIO); 215e9034789SMichal Meloun } 216e9034789SMichal Meloun 217e9034789SMichal Meloun if (cfg->alt_func) { 218e9034789SMichal Meloun pin->alt_func = true; 219e9034789SMichal Meloun sc->gpio_reg_ame |= 1 << pin_num; 220e9034789SMichal Meloun } else { 221e9034789SMichal Meloun pin->alt_func = false; 222e9034789SMichal Meloun sc->gpio_reg_ame &= ~(1 << pin_num); 223e9034789SMichal Meloun } 224e9034789SMichal Meloun 225e9034789SMichal Meloun /* Pull up/down. */ 226e9034789SMichal Meloun switch (cfg->params[CFG_BIAS_PULL_UP]) { 227e9034789SMichal Meloun case 1: 228e9034789SMichal Meloun sc->gpio_reg_pue |= 1 << pin_num; 229e9034789SMichal Meloun break; 230e9034789SMichal Meloun case 0: 231e9034789SMichal Meloun sc->gpio_reg_pue &= ~(1 << pin_num); 232e9034789SMichal Meloun break; 233e9034789SMichal Meloun default: 234e9034789SMichal Meloun break; 235e9034789SMichal Meloun } 236e9034789SMichal Meloun 237e9034789SMichal Meloun switch (cfg->params[CFG_BIAS_PULL_DOWN]) { 238e9034789SMichal Meloun case 1: 239e9034789SMichal Meloun sc->gpio_reg_pde |= 1 << pin_num; 240e9034789SMichal Meloun break; 241e9034789SMichal Meloun case 0: 242e9034789SMichal Meloun sc->gpio_reg_pde &= ~(1 << pin_num); 243e9034789SMichal Meloun break; 244e9034789SMichal Meloun default: 245e9034789SMichal Meloun break; 246e9034789SMichal Meloun } 247e9034789SMichal Meloun 248e9034789SMichal Meloun /* Open drain/push-pull modes. */ 249e9034789SMichal Meloun if (cfg->params[CFG_OPEN_DRAIN] == 1) { 250e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0); 251e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN); 252e9034789SMichal Meloun } 253e9034789SMichal Meloun 254e9034789SMichal Meloun if (cfg->params[CFG_PUSH_PULL] == 1) { 255e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0); 256e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_PUSHPULL); 257e9034789SMichal Meloun } 258e9034789SMichal Meloun 259e9034789SMichal Meloun rv = WR1(sc, pin->reg, reg); 260e9034789SMichal Meloun if (rv != 0) { 261e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n"); 262e9034789SMichal Meloun return (ENXIO); 263e9034789SMichal Meloun } 264e9034789SMichal Meloun 265e9034789SMichal Meloun return (0); 266e9034789SMichal Meloun } 267e9034789SMichal Meloun 268e9034789SMichal Meloun static int 269e9034789SMichal Meloun max77620_pinmux_read_node(struct max77620_softc *sc, phandle_t node, 270e9034789SMichal Meloun struct max77620_pincfg *cfg, char **pins, int *lpins) 271e9034789SMichal Meloun { 272e9034789SMichal Meloun char *function; 273e9034789SMichal Meloun int rv, i; 274e9034789SMichal Meloun 275e9034789SMichal Meloun *lpins = OF_getprop_alloc(node, "pins", (void **)pins); 276e9034789SMichal Meloun if (*lpins <= 0) 277e9034789SMichal Meloun return (ENOENT); 278e9034789SMichal Meloun 279e9034789SMichal Meloun /* Read function (mux) settings. */ 280e9034789SMichal Meloun rv = OF_getprop_alloc(node, "function", (void **)&function); 281e9034789SMichal Meloun if (rv > 0) { 282e9034789SMichal Meloun rv = max77620_pinmux_get_function(sc, function, cfg); 283e9034789SMichal Meloun if (rv == -1) { 284e9034789SMichal Meloun device_printf(sc->dev, 285e9034789SMichal Meloun "Unknown function %s\n", function); 286e9034789SMichal Meloun OF_prop_free(function); 287e9034789SMichal Meloun return (ENXIO); 288e9034789SMichal Meloun } 289e9034789SMichal Meloun } 290e9034789SMichal Meloun 291e9034789SMichal Meloun /* Read numeric properties. */ 292e9034789SMichal Meloun for (i = 0; i < PROP_ID_MAX_ID; i++) { 293e9034789SMichal Meloun rv = OF_getencprop(node, max77620_prop_names[i].name, 294e9034789SMichal Meloun &cfg->params[i], sizeof(cfg->params[i])); 295e9034789SMichal Meloun if (rv <= 0) 296e9034789SMichal Meloun cfg->params[i] = -1; 297e9034789SMichal Meloun } 298e9034789SMichal Meloun 299e9034789SMichal Meloun OF_prop_free(function); 300e9034789SMichal Meloun return (0); 301e9034789SMichal Meloun } 302e9034789SMichal Meloun 303e9034789SMichal Meloun static int 304e9034789SMichal Meloun max77620_pinmux_process_node(struct max77620_softc *sc, phandle_t node) 305e9034789SMichal Meloun { 306e9034789SMichal Meloun struct max77620_pincfg cfg; 307e9034789SMichal Meloun char *pins, *pname; 308e9034789SMichal Meloun int i, len, lpins, rv; 309e9034789SMichal Meloun 310e9034789SMichal Meloun rv = max77620_pinmux_read_node(sc, node, &cfg, &pins, &lpins); 311e9034789SMichal Meloun if (rv != 0) 312e9034789SMichal Meloun return (rv); 313e9034789SMichal Meloun 314e9034789SMichal Meloun len = 0; 315e9034789SMichal Meloun pname = pins; 316e9034789SMichal Meloun do { 317e9034789SMichal Meloun i = strlen(pname) + 1; 318e9034789SMichal Meloun rv = max77620_pinmux_config_node(sc, pname, &cfg); 319e9034789SMichal Meloun if (rv != 0) { 320e9034789SMichal Meloun device_printf(sc->dev, 321e9034789SMichal Meloun "Cannot configure pin: %s: %d\n", pname, rv); 322e9034789SMichal Meloun } 323e9034789SMichal Meloun len += i; 324e9034789SMichal Meloun pname += i; 325e9034789SMichal Meloun } while (len < lpins); 326e9034789SMichal Meloun 327e9034789SMichal Meloun if (pins != NULL) 328e9034789SMichal Meloun OF_prop_free(pins); 329e9034789SMichal Meloun 330e9034789SMichal Meloun return (rv); 331e9034789SMichal Meloun } 332e9034789SMichal Meloun 333e9034789SMichal Meloun int max77620_pinmux_configure(device_t dev, phandle_t cfgxref) 334e9034789SMichal Meloun { 335e9034789SMichal Meloun struct max77620_softc *sc; 336e9034789SMichal Meloun phandle_t node, cfgnode; 337e9034789SMichal Meloun uint8_t old_reg_pue, old_reg_pde, old_reg_ame; 338e9034789SMichal Meloun int rv; 339e9034789SMichal Meloun 340e9034789SMichal Meloun sc = device_get_softc(dev); 341e9034789SMichal Meloun cfgnode = OF_node_from_xref(cfgxref); 342e9034789SMichal Meloun 343e9034789SMichal Meloun old_reg_pue = sc->gpio_reg_pue; 344e9034789SMichal Meloun old_reg_pde = sc->gpio_reg_pde; 345e9034789SMichal Meloun old_reg_ame = sc->gpio_reg_ame; 346e9034789SMichal Meloun 347e9034789SMichal Meloun for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) { 348e9034789SMichal Meloun if (!ofw_bus_node_status_okay(node)) 349e9034789SMichal Meloun continue; 350e9034789SMichal Meloun rv = max77620_pinmux_process_node(sc, node); 351e9034789SMichal Meloun if (rv != 0) 352e9034789SMichal Meloun device_printf(dev, "Failed to process pinmux"); 353e9034789SMichal Meloun 354e9034789SMichal Meloun } 355e9034789SMichal Meloun 356e9034789SMichal Meloun if (old_reg_pue != sc->gpio_reg_pue) { 357e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PUE_GPIO, sc->gpio_reg_pue); 358e9034789SMichal Meloun if (rv != 0) { 359e9034789SMichal Meloun device_printf(sc->dev, 360e9034789SMichal Meloun "Cannot update PUE_GPIO register\n"); 361e9034789SMichal Meloun return (ENXIO); 362e9034789SMichal Meloun } 363e9034789SMichal Meloun } 364e9034789SMichal Meloun 365e9034789SMichal Meloun if (old_reg_pde != sc->gpio_reg_pde) { 366e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PDE_GPIO, sc->gpio_reg_pde); 367e9034789SMichal Meloun if (rv != 0) { 368e9034789SMichal Meloun device_printf(sc->dev, 369e9034789SMichal Meloun "Cannot update PDE_GPIO register\n"); 370e9034789SMichal Meloun return (ENXIO); 371e9034789SMichal Meloun } 372e9034789SMichal Meloun } 373e9034789SMichal Meloun 374e9034789SMichal Meloun if (old_reg_ame != sc->gpio_reg_ame) { 375e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_AME_GPIO, sc->gpio_reg_ame); 376e9034789SMichal Meloun if (rv != 0) { 377e9034789SMichal Meloun device_printf(sc->dev, 378e9034789SMichal Meloun "Cannot update PDE_GPIO register\n"); 379e9034789SMichal Meloun return (ENXIO); 380e9034789SMichal Meloun } 381e9034789SMichal Meloun } 382e9034789SMichal Meloun 383e9034789SMichal Meloun return (0); 384e9034789SMichal Meloun } 385e9034789SMichal Meloun 386e9034789SMichal Meloun /* -------------------------------------------------------------------------- 387e9034789SMichal Meloun * 388e9034789SMichal Meloun * GPIO 389e9034789SMichal Meloun */ 390e9034789SMichal Meloun device_t 391e9034789SMichal Meloun max77620_gpio_get_bus(device_t dev) 392e9034789SMichal Meloun { 393e9034789SMichal Meloun struct max77620_softc *sc; 394e9034789SMichal Meloun 395e9034789SMichal Meloun sc = device_get_softc(dev); 396e9034789SMichal Meloun return (sc->gpio_busdev); 397e9034789SMichal Meloun } 398e9034789SMichal Meloun 399e9034789SMichal Meloun int 400e9034789SMichal Meloun max77620_gpio_pin_max(device_t dev, int *maxpin) 401e9034789SMichal Meloun { 402e9034789SMichal Meloun 403e9034789SMichal Meloun *maxpin = NGPIO - 1; 404e9034789SMichal Meloun return (0); 405e9034789SMichal Meloun } 406e9034789SMichal Meloun 407e9034789SMichal Meloun int 408e9034789SMichal Meloun max77620_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 409e9034789SMichal Meloun { 410e9034789SMichal Meloun struct max77620_softc *sc; 411e9034789SMichal Meloun 412e9034789SMichal Meloun sc = device_get_softc(dev); 413e9034789SMichal Meloun if (pin >= sc->gpio_npins) 414e9034789SMichal Meloun return (EINVAL); 415e9034789SMichal Meloun GPIO_LOCK(sc); 416e9034789SMichal Meloun *caps = sc->gpio_pins[pin]->pin_caps; 417e9034789SMichal Meloun GPIO_UNLOCK(sc); 418e9034789SMichal Meloun return (0); 419e9034789SMichal Meloun } 420e9034789SMichal Meloun 421e9034789SMichal Meloun int 422e9034789SMichal Meloun max77620_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 423e9034789SMichal Meloun { 424e9034789SMichal Meloun struct max77620_softc *sc; 425e9034789SMichal Meloun 426e9034789SMichal Meloun sc = device_get_softc(dev); 427e9034789SMichal Meloun if (pin >= sc->gpio_npins) 428e9034789SMichal Meloun return (EINVAL); 429e9034789SMichal Meloun GPIO_LOCK(sc); 430e9034789SMichal Meloun memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME); 431e9034789SMichal Meloun GPIO_UNLOCK(sc); 432e9034789SMichal Meloun return (0); 433e9034789SMichal Meloun } 434e9034789SMichal Meloun 435e9034789SMichal Meloun static int 436e9034789SMichal Meloun max77620_gpio_get_mode(struct max77620_softc *sc, uint32_t pin_num, 437e9034789SMichal Meloun uint32_t *out_flags) 438e9034789SMichal Meloun { 439e9034789SMichal Meloun struct max77620_gpio_pin *pin; 440e9034789SMichal Meloun uint8_t reg; 441e9034789SMichal Meloun int rv; 442e9034789SMichal Meloun 443e9034789SMichal Meloun pin = sc->gpio_pins[pin_num]; 444e9034789SMichal Meloun *out_flags = 0; 445e9034789SMichal Meloun 446e9034789SMichal Meloun rv = RD1(sc, pin->reg, ®); 447e9034789SMichal Meloun if (rv != 0) { 448e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n"); 449e9034789SMichal Meloun return (ENXIO); 450e9034789SMichal Meloun } 451e9034789SMichal Meloun 452e9034789SMichal Meloun /* Pin function */ 453e9034789SMichal Meloun pin->alt_func = sc->gpio_reg_ame & (1 << pin_num); 454e9034789SMichal Meloun 455e9034789SMichal Meloun /* Pull up/down. */ 456e9034789SMichal Meloun if (sc->gpio_reg_pue & (1 << pin_num)) 457e9034789SMichal Meloun *out_flags |= GPIO_PIN_PULLUP; 458e9034789SMichal Meloun if (sc->gpio_reg_pde & (1 << pin_num)) 459e9034789SMichal Meloun *out_flags |= GPIO_PIN_PULLDOWN; 460e9034789SMichal Meloun 461e9034789SMichal Meloun /* Open drain/push-pull modes. */ 462e9034789SMichal Meloun if (MAX77620_REG_GPIO_DRV_GET(reg) == MAX77620_REG_GPIO_DRV_PUSHPULL) 463e9034789SMichal Meloun *out_flags |= GPIO_PIN_PUSHPULL; 464e9034789SMichal Meloun else 465e9034789SMichal Meloun *out_flags |= GPIO_PIN_OPENDRAIN; 466e9034789SMichal Meloun 467e9034789SMichal Meloun /* Input/output modes. */ 468e9034789SMichal Meloun if (MAX77620_REG_GPIO_DRV_GET(reg) == MAX77620_REG_GPIO_DRV_PUSHPULL) 469e9034789SMichal Meloun *out_flags |= GPIO_PIN_OUTPUT; 470e9034789SMichal Meloun else 471e9034789SMichal Meloun *out_flags |= GPIO_PIN_OUTPUT | GPIO_PIN_INPUT; 472e9034789SMichal Meloun return (0); 473e9034789SMichal Meloun } 474e9034789SMichal Meloun 475e9034789SMichal Meloun int 476e9034789SMichal Meloun max77620_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags) 477e9034789SMichal Meloun { 478e9034789SMichal Meloun struct max77620_softc *sc; 479e9034789SMichal Meloun int rv; 480e9034789SMichal Meloun 481e9034789SMichal Meloun sc = device_get_softc(dev); 482e9034789SMichal Meloun if (pin >= sc->gpio_npins) 483e9034789SMichal Meloun return (EINVAL); 484e9034789SMichal Meloun 485e9034789SMichal Meloun GPIO_LOCK(sc); 486e9034789SMichal Meloun #if 0 /* It colide with GPIO regulators */ 487e9034789SMichal Meloun /* Is pin in GPIO mode ? */ 488e9034789SMichal Meloun if (sc->gpio_pins[pin]->alt_func) { 489e9034789SMichal Meloun GPIO_UNLOCK(sc); 490e9034789SMichal Meloun return (ENXIO); 491e9034789SMichal Meloun } 492e9034789SMichal Meloun #endif 493e9034789SMichal Meloun rv = max77620_gpio_get_mode(sc, pin, out_flags); 494e9034789SMichal Meloun GPIO_UNLOCK(sc); 495e9034789SMichal Meloun 496e9034789SMichal Meloun return (rv); 497e9034789SMichal Meloun } 498e9034789SMichal Meloun 499e9034789SMichal Meloun int 500e9034789SMichal Meloun max77620_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) 501e9034789SMichal Meloun { 502e9034789SMichal Meloun struct max77620_softc *sc; 503e9034789SMichal Meloun struct max77620_gpio_pin *pin; 504e9034789SMichal Meloun uint8_t reg; 505e9034789SMichal Meloun uint8_t old_reg_pue, old_reg_pde; 506e9034789SMichal Meloun int rv; 507e9034789SMichal Meloun 508e9034789SMichal Meloun sc = device_get_softc(dev); 509e9034789SMichal Meloun if (pin_num >= sc->gpio_npins) 510e9034789SMichal Meloun return (EINVAL); 511e9034789SMichal Meloun 512e9034789SMichal Meloun pin = sc->gpio_pins[pin_num]; 513e9034789SMichal Meloun 514e9034789SMichal Meloun GPIO_LOCK(sc); 515e9034789SMichal Meloun 516e9034789SMichal Meloun #if 0 /* It colide with GPIO regulators */ 517e9034789SMichal Meloun /* Is pin in GPIO mode ? */ 518e9034789SMichal Meloun if (pin->alt_func) { 519e9034789SMichal Meloun GPIO_UNLOCK(sc); 520e9034789SMichal Meloun return (ENXIO); 521e9034789SMichal Meloun } 522e9034789SMichal Meloun #endif 523e9034789SMichal Meloun 524e9034789SMichal Meloun old_reg_pue = sc->gpio_reg_pue; 525e9034789SMichal Meloun old_reg_pde = sc->gpio_reg_pde; 526e9034789SMichal Meloun 527e9034789SMichal Meloun rv = RD1(sc, pin->reg, ®); 528e9034789SMichal Meloun if (rv != 0) { 529e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n"); 530e9034789SMichal Meloun GPIO_UNLOCK(sc); 531e9034789SMichal Meloun return (ENXIO); 532e9034789SMichal Meloun } 533e9034789SMichal Meloun 534e9034789SMichal Meloun if (flags & GPIO_PIN_PULLUP) 535e9034789SMichal Meloun sc->gpio_reg_pue |= 1 << pin_num; 536e9034789SMichal Meloun else 537e9034789SMichal Meloun sc->gpio_reg_pue &= ~(1 << pin_num); 538e9034789SMichal Meloun 539e9034789SMichal Meloun if (flags & GPIO_PIN_PULLDOWN) 540e9034789SMichal Meloun sc->gpio_reg_pde |= 1 << pin_num; 541e9034789SMichal Meloun else 542e9034789SMichal Meloun sc->gpio_reg_pde &= ~(1 << pin_num); 543e9034789SMichal Meloun 544e9034789SMichal Meloun if (flags & GPIO_PIN_INPUT) { 545e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0); 546e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN); 547e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_OUTPUT_VAL(~0); 548e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_OUTPUT_VAL(1); 549e9034789SMichal Meloun 550e9034789SMichal Meloun } else if (((flags & GPIO_PIN_OUTPUT) && 551e9034789SMichal Meloun (flags & GPIO_PIN_OPENDRAIN) == 0) || 552e9034789SMichal Meloun (flags & GPIO_PIN_PUSHPULL)) { 553e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0); 554e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_PUSHPULL); 555e9034789SMichal Meloun } else { 556e9034789SMichal Meloun reg &= ~MAX77620_REG_GPIO_DRV(~0); 557e9034789SMichal Meloun reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN); 558e9034789SMichal Meloun } 559e9034789SMichal Meloun 560e9034789SMichal Meloun rv = WR1(sc, pin->reg, reg); 561e9034789SMichal Meloun if (rv != 0) { 562e9034789SMichal Meloun device_printf(sc->dev, "Cannot read GIPO_CFG register\n"); 563e9034789SMichal Meloun return (ENXIO); 564e9034789SMichal Meloun } 565e9034789SMichal Meloun if (old_reg_pue != sc->gpio_reg_pue) { 566e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PUE_GPIO, sc->gpio_reg_pue); 567e9034789SMichal Meloun if (rv != 0) { 568e9034789SMichal Meloun device_printf(sc->dev, 569e9034789SMichal Meloun "Cannot update PUE_GPIO register\n"); 570e9034789SMichal Meloun GPIO_UNLOCK(sc); 571e9034789SMichal Meloun return (ENXIO); 572e9034789SMichal Meloun } 573e9034789SMichal Meloun } 574e9034789SMichal Meloun 575e9034789SMichal Meloun if (old_reg_pde != sc->gpio_reg_pde) { 576e9034789SMichal Meloun rv = WR1(sc, MAX77620_REG_PDE_GPIO, sc->gpio_reg_pde); 577e9034789SMichal Meloun if (rv != 0) { 578e9034789SMichal Meloun device_printf(sc->dev, 579e9034789SMichal Meloun "Cannot update PDE_GPIO register\n"); 580e9034789SMichal Meloun GPIO_UNLOCK(sc); 581e9034789SMichal Meloun return (ENXIO); 582e9034789SMichal Meloun } 583e9034789SMichal Meloun } 584e9034789SMichal Meloun 585e9034789SMichal Meloun GPIO_UNLOCK(sc); 586e9034789SMichal Meloun return (0); 587e9034789SMichal Meloun } 588e9034789SMichal Meloun 589e9034789SMichal Meloun int 590e9034789SMichal Meloun max77620_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val) 591e9034789SMichal Meloun { 592e9034789SMichal Meloun struct max77620_softc *sc; 593e9034789SMichal Meloun int rv; 594e9034789SMichal Meloun 595e9034789SMichal Meloun sc = device_get_softc(dev); 596e9034789SMichal Meloun if (pin >= sc->gpio_npins) 597e9034789SMichal Meloun return (EINVAL); 598e9034789SMichal Meloun 599e9034789SMichal Meloun GPIO_LOCK(sc); 600e9034789SMichal Meloun rv = RM1(sc, sc->gpio_pins[pin]->reg, MAX77620_REG_GPIO_OUTPUT_VAL(~0), 601e9034789SMichal Meloun MAX77620_REG_GPIO_OUTPUT_VAL(val)); 602e9034789SMichal Meloun GPIO_UNLOCK(sc); 603e9034789SMichal Meloun return (rv); 604e9034789SMichal Meloun } 605e9034789SMichal Meloun 606e9034789SMichal Meloun int 607e9034789SMichal Meloun max77620_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val) 608e9034789SMichal Meloun { 609e9034789SMichal Meloun struct max77620_softc *sc; 610e9034789SMichal Meloun uint8_t tmp; 611e9034789SMichal Meloun int rv; 612e9034789SMichal Meloun 613e9034789SMichal Meloun sc = device_get_softc(dev); 614e9034789SMichal Meloun if (pin >= sc->gpio_npins) 615e9034789SMichal Meloun return (EINVAL); 616e9034789SMichal Meloun 617e9034789SMichal Meloun GPIO_LOCK(sc); 618e9034789SMichal Meloun rv = RD1(sc, sc->gpio_pins[pin]->reg, &tmp); 619e9034789SMichal Meloun 620e9034789SMichal Meloun if (MAX77620_REG_GPIO_DRV_GET(tmp) == MAX77620_REG_GPIO_DRV_PUSHPULL) 621e9034789SMichal Meloun *val = MAX77620_REG_GPIO_OUTPUT_VAL_GET(tmp); 622e9034789SMichal Meloun else 623e9034789SMichal Meloun *val = MAX77620_REG_GPIO_INPUT_VAL_GET(tmp); 624e9034789SMichal Meloun GPIO_UNLOCK(sc); 625e9034789SMichal Meloun if (rv != 0) 626e9034789SMichal Meloun return (rv); 627e9034789SMichal Meloun 628e9034789SMichal Meloun return (0); 629e9034789SMichal Meloun } 630e9034789SMichal Meloun 631e9034789SMichal Meloun int 632e9034789SMichal Meloun max77620_gpio_pin_toggle(device_t dev, uint32_t pin) 633e9034789SMichal Meloun { 634e9034789SMichal Meloun struct max77620_softc *sc; 635e9034789SMichal Meloun uint8_t tmp; 636e9034789SMichal Meloun int rv; 637e9034789SMichal Meloun 638e9034789SMichal Meloun sc = device_get_softc(dev); 639e9034789SMichal Meloun if (pin >= sc->gpio_npins) 640e9034789SMichal Meloun return (EINVAL); 641e9034789SMichal Meloun 642e9034789SMichal Meloun GPIO_LOCK(sc); 643e9034789SMichal Meloun rv = RD1(sc, sc->gpio_pins[pin]->reg, &tmp); 644e9034789SMichal Meloun if (rv != 0) { 645e9034789SMichal Meloun GPIO_UNLOCK(sc); 646e9034789SMichal Meloun return (rv); 647e9034789SMichal Meloun } 648e9034789SMichal Meloun tmp ^= MAX77620_REG_GPIO_OUTPUT_VAL(~0); 649e9034789SMichal Meloun rv = RM1(sc, sc->gpio_pins[pin]->reg, MAX77620_REG_GPIO_OUTPUT_VAL(~0), 650e9034789SMichal Meloun tmp); 651e9034789SMichal Meloun GPIO_UNLOCK(sc); 652e9034789SMichal Meloun return (0); 653e9034789SMichal Meloun } 654e9034789SMichal Meloun 655e9034789SMichal Meloun int 656e9034789SMichal Meloun max77620_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent, 657e9034789SMichal Meloun int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags) 658e9034789SMichal Meloun { 659e9034789SMichal Meloun 660e9034789SMichal Meloun if (gcells != 2) 661e9034789SMichal Meloun return (ERANGE); 662e9034789SMichal Meloun *pin = gpios[0]; 663e9034789SMichal Meloun *flags= gpios[1]; 664e9034789SMichal Meloun return (0); 665e9034789SMichal Meloun } 666e9034789SMichal Meloun 667e9034789SMichal Meloun int 668e9034789SMichal Meloun max77620_gpio_attach(struct max77620_softc *sc, phandle_t node) 669e9034789SMichal Meloun { 670e9034789SMichal Meloun struct max77620_gpio_pin *pin; 671e9034789SMichal Meloun int i, rv; 672e9034789SMichal Meloun 673e9034789SMichal Meloun sx_init(&sc->gpio_lock, "MAX77620 GPIO lock"); 674e9034789SMichal Meloun 675e9034789SMichal Meloun sc->gpio_busdev = gpiobus_attach_bus(sc->dev); 676e9034789SMichal Meloun if (sc->gpio_busdev == NULL) 677e9034789SMichal Meloun return (ENXIO); 678e9034789SMichal Meloun 679e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_PUE_GPIO, &sc->gpio_reg_pue); 680e9034789SMichal Meloun if (rv != 0) { 681e9034789SMichal Meloun device_printf(sc->dev, "Cannot read PUE_GPIO register\n"); 682e9034789SMichal Meloun return (ENXIO); 683e9034789SMichal Meloun } 684e9034789SMichal Meloun 685e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_PDE_GPIO, &sc->gpio_reg_pde); 686e9034789SMichal Meloun if (rv != 0) { 687e9034789SMichal Meloun device_printf(sc->dev, "Cannot read PDE_GPIO register\n"); 688e9034789SMichal Meloun return (ENXIO); 689e9034789SMichal Meloun } 690e9034789SMichal Meloun 691e9034789SMichal Meloun rv = RD1(sc, MAX77620_REG_AME_GPIO, &sc->gpio_reg_ame); 692e9034789SMichal Meloun if (rv != 0) { 693e9034789SMichal Meloun device_printf(sc->dev, "Cannot read AME_GPIO register\n"); 694e9034789SMichal Meloun return (ENXIO); 695e9034789SMichal Meloun } 696e9034789SMichal Meloun 697e9034789SMichal Meloun sc->gpio_npins = NGPIO; 698e9034789SMichal Meloun sc->gpio_pins = malloc(sizeof(struct max77620_gpio_pin *) * 699e9034789SMichal Meloun sc->gpio_npins, M_MAX77620_GPIO, M_WAITOK | M_ZERO); 700e9034789SMichal Meloun for (i = 0; i < sc->gpio_npins; i++) { 701e9034789SMichal Meloun sc->gpio_pins[i] = malloc(sizeof(struct max77620_gpio_pin), 702e9034789SMichal Meloun M_MAX77620_GPIO, M_WAITOK | M_ZERO); 703e9034789SMichal Meloun pin = sc->gpio_pins[i]; 704e9034789SMichal Meloun sprintf(pin->pin_name, "gpio%d", i); 705e9034789SMichal Meloun pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | 706e9034789SMichal Meloun GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | 707e9034789SMichal Meloun GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN; 708e9034789SMichal Meloun pin->reg = MAX77620_REG_GPIO0 + i; 709e9034789SMichal Meloun } 710e9034789SMichal Meloun 711e9034789SMichal Meloun return (0); 712e9034789SMichal Meloun } 713