Path: blob/main/sys/arm64/nvidia/tegra210/max77620_gpio.c
48266 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright 2020 Michal Meloun <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#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>3435#include <machine/bus.h>3637#include <dev/fdt/fdt_common.h>38#include <dev/gpio/gpiobusvar.h>3940#include "max77620.h"4142MALLOC_DEFINE(M_MAX77620_GPIO, "MAX77620 gpio", "MAX77620 GPIO");4344#define NGPIO 84546#define GPIO_LOCK(_sc) sx_slock(&(_sc)->gpio_lock)47#define GPIO_UNLOCK(_sc) sx_unlock(&(_sc)->gpio_lock)48#define GPIO_ASSERT(_sc) sx_assert(&(_sc)->gpio_lock, SA_LOCKED)4950enum prop_id {51CFG_BIAS_PULL_UP,52CFG_BIAS_PULL_DOWN,53CFG_OPEN_DRAIN,54CFG_PUSH_PULL,5556CFG_ACTIVE_FPS_SRC,57CFG_ACTIVE_PWRUP_SLOT,58CFG_ACTIVE_PWRDOWN_SLOT,59CFG_SUSPEND_FPS_SRC,60CFG_SUSPEND_PWRUP_SLOT,61CFG_SUSPEND_PWRDOWN_SLOT,6263PROP_ID_MAX_ID64};6566static const struct {67const char *name;68enum prop_id id;69} max77620_prop_names[] = {70{"bias-pull-up", CFG_BIAS_PULL_UP},71{"bias-pull-down", CFG_BIAS_PULL_DOWN},72{"drive-open-drain", CFG_OPEN_DRAIN},73{"drive-push-pull", CFG_PUSH_PULL},74{"maxim,active-fps-source", CFG_ACTIVE_FPS_SRC},75{"maxim,active-fps-power-up-slot", CFG_ACTIVE_PWRUP_SLOT},76{"maxim,active-fps-power-down-slot", CFG_ACTIVE_PWRDOWN_SLOT},77{"maxim,suspend-fps-source", CFG_SUSPEND_FPS_SRC},78{"maxim,suspend-fps-power-up-slot", CFG_SUSPEND_PWRUP_SLOT},79{"maxim,suspend-fps-power-down-slot", CFG_SUSPEND_PWRDOWN_SLOT},80};8182/* Configuration for one pin group. */83struct max77620_pincfg {84bool alt_func;85int params[PROP_ID_MAX_ID];86};8788static char *altfnc_table[] = {89"lpm-control-in",90"fps-out",91"32k-out1",92"sd0-dvs-in",93"sd1-dvs-in",94"reference-out",95};9697struct max77620_gpio_pin {98int pin_caps;99char pin_name[GPIOMAXNAME];100uint8_t reg;101102/* Runtime data */103bool alt_func; /* GPIO or alternate function */104};105106/* --------------------------------------------------------------------------107*108* Pinmux functions.109*/110static int111max77620_pinmux_get_function(struct max77620_softc *sc, char *name,112struct max77620_pincfg *cfg)113{114int i;115116if (strcmp("gpio", name) == 0) {117cfg->alt_func = false;118return (0);119}120for (i = 0; i < nitems(altfnc_table); i++) {121if (strcmp(altfnc_table[i], name) == 0) {122cfg->alt_func = true;123return (0);124}125}126return (-1);127}128129static int130max77620_pinmux_set_fps(struct max77620_softc *sc, int pin_num,131struct max77620_gpio_pin *pin)132{133#if 0134struct max77620_fps_config *fps_config = &mpci->fps_config[pin];135int addr, ret;136int param_val;137int mask, shift;138139if ((pin < 1) || (pin > 3))140return (0);141142switch (param) {143case MAX77620_ACTIVE_FPS_SOURCE:144case MAX77620_SUSPEND_FPS_SOURCE:145mask = MAX77620_FPS_SRC_MASK;146shift = MAX77620_FPS_SRC_SHIFT;147param_val = fps_config->active_fps_src;148if (param == MAX77620_SUSPEND_FPS_SOURCE)149param_val = fps_config->suspend_fps_src;150break;151152case MAX77620_ACTIVE_FPS_POWER_ON_SLOTS:153case MAX77620_SUSPEND_FPS_POWER_ON_SLOTS:154mask = MAX77620_FPS_PU_PERIOD_MASK;155shift = MAX77620_FPS_PU_PERIOD_SHIFT;156param_val = fps_config->active_power_up_slots;157if (param == MAX77620_SUSPEND_FPS_POWER_ON_SLOTS)158param_val = fps_config->suspend_power_up_slots;159break;160161case MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS:162case MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS:163mask = MAX77620_FPS_PD_PERIOD_MASK;164shift = MAX77620_FPS_PD_PERIOD_SHIFT;165param_val = fps_config->active_power_down_slots;166if (param == MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS)167param_val = fps_config->suspend_power_down_slots;168break;169170default:171dev_err(mpci->dev, "Invalid parameter %d for pin %d\n",172param, pin);173return -EINVAL;174}175176if (param_val < 0)177return 0;178179ret = regmap_update_bits(mpci->rmap, addr, mask, param_val << shift);180if (ret < 0)181dev_err(mpci->dev, "Reg 0x%02x update failed %d\n", addr, ret);182183return ret;184#endif185return (0);186}187188static int189max77620_pinmux_config_node(struct max77620_softc *sc, char *pin_name,190struct max77620_pincfg *cfg)191{192struct max77620_gpio_pin *pin;193uint8_t reg;194int pin_num, rv;195196for (pin_num = 0; pin_num < sc->gpio_npins; pin_num++) {197if (strcmp(sc->gpio_pins[pin_num]->pin_name, pin_name) == 0)198break;199}200if (pin_num >= sc->gpio_npins) {201device_printf(sc->dev, "Unknown pin: %s\n", pin_name);202return (ENXIO);203}204pin = sc->gpio_pins[pin_num];205206rv = max77620_pinmux_set_fps(sc, pin_num, pin);207if (rv != 0)208return (rv);209210rv = RD1(sc, pin->reg, ®);211if (rv != 0) {212device_printf(sc->dev, "Cannot read GIPO_CFG register\n");213return (ENXIO);214}215216if (cfg->alt_func) {217pin->alt_func = true;218sc->gpio_reg_ame |= 1 << pin_num;219} else {220pin->alt_func = false;221sc->gpio_reg_ame &= ~(1 << pin_num);222}223224/* Pull up/down. */225switch (cfg->params[CFG_BIAS_PULL_UP]) {226case 1:227sc->gpio_reg_pue |= 1 << pin_num;228break;229case 0:230sc->gpio_reg_pue &= ~(1 << pin_num);231break;232default:233break;234}235236switch (cfg->params[CFG_BIAS_PULL_DOWN]) {237case 1:238sc->gpio_reg_pde |= 1 << pin_num;239break;240case 0:241sc->gpio_reg_pde &= ~(1 << pin_num);242break;243default:244break;245}246247/* Open drain/push-pull modes. */248if (cfg->params[CFG_OPEN_DRAIN] == 1) {249reg &= ~MAX77620_REG_GPIO_DRV(~0);250reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN);251}252253if (cfg->params[CFG_PUSH_PULL] == 1) {254reg &= ~MAX77620_REG_GPIO_DRV(~0);255reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_PUSHPULL);256}257258rv = WR1(sc, pin->reg, reg);259if (rv != 0) {260device_printf(sc->dev, "Cannot read GIPO_CFG register\n");261return (ENXIO);262}263264return (0);265}266267static int268max77620_pinmux_read_node(struct max77620_softc *sc, phandle_t node,269struct max77620_pincfg *cfg, char **pins, int *lpins)270{271char *function;272int rv, i;273274*lpins = OF_getprop_alloc(node, "pins", (void **)pins);275if (*lpins <= 0)276return (ENOENT);277278/* Read function (mux) settings. */279rv = OF_getprop_alloc(node, "function", (void **)&function);280if (rv > 0) {281rv = max77620_pinmux_get_function(sc, function, cfg);282if (rv == -1) {283device_printf(sc->dev,284"Unknown function %s\n", function);285OF_prop_free(function);286return (ENXIO);287}288}289290/* Read numeric properties. */291for (i = 0; i < PROP_ID_MAX_ID; i++) {292rv = OF_getencprop(node, max77620_prop_names[i].name,293&cfg->params[i], sizeof(cfg->params[i]));294if (rv <= 0)295cfg->params[i] = -1;296}297298OF_prop_free(function);299return (0);300}301302static int303max77620_pinmux_process_node(struct max77620_softc *sc, phandle_t node)304{305struct max77620_pincfg cfg;306char *pins, *pname;307int i, len, lpins, rv;308309rv = max77620_pinmux_read_node(sc, node, &cfg, &pins, &lpins);310if (rv != 0)311return (rv);312313len = 0;314pname = pins;315do {316i = strlen(pname) + 1;317rv = max77620_pinmux_config_node(sc, pname, &cfg);318if (rv != 0) {319device_printf(sc->dev,320"Cannot configure pin: %s: %d\n", pname, rv);321}322len += i;323pname += i;324} while (len < lpins);325326if (pins != NULL)327OF_prop_free(pins);328329return (rv);330}331332int max77620_pinmux_configure(device_t dev, phandle_t cfgxref)333{334struct max77620_softc *sc;335phandle_t node, cfgnode;336uint8_t old_reg_pue, old_reg_pde, old_reg_ame;337int rv;338339sc = device_get_softc(dev);340cfgnode = OF_node_from_xref(cfgxref);341342old_reg_pue = sc->gpio_reg_pue;343old_reg_pde = sc->gpio_reg_pde;344old_reg_ame = sc->gpio_reg_ame;345346for (node = OF_child(cfgnode); node != 0; node = OF_peer(node)) {347if (!ofw_bus_node_status_okay(node))348continue;349rv = max77620_pinmux_process_node(sc, node);350if (rv != 0)351device_printf(dev, "Failed to process pinmux");352353}354355if (old_reg_pue != sc->gpio_reg_pue) {356rv = WR1(sc, MAX77620_REG_PUE_GPIO, sc->gpio_reg_pue);357if (rv != 0) {358device_printf(sc->dev,359"Cannot update PUE_GPIO register\n");360return (ENXIO);361}362}363364if (old_reg_pde != sc->gpio_reg_pde) {365rv = WR1(sc, MAX77620_REG_PDE_GPIO, sc->gpio_reg_pde);366if (rv != 0) {367device_printf(sc->dev,368"Cannot update PDE_GPIO register\n");369return (ENXIO);370}371}372373if (old_reg_ame != sc->gpio_reg_ame) {374rv = WR1(sc, MAX77620_REG_AME_GPIO, sc->gpio_reg_ame);375if (rv != 0) {376device_printf(sc->dev,377"Cannot update PDE_GPIO register\n");378return (ENXIO);379}380}381382return (0);383}384385/* --------------------------------------------------------------------------386*387* GPIO388*/389device_t390max77620_gpio_get_bus(device_t dev)391{392struct max77620_softc *sc;393394sc = device_get_softc(dev);395return (sc->gpio_busdev);396}397398int399max77620_gpio_pin_max(device_t dev, int *maxpin)400{401402*maxpin = NGPIO - 1;403return (0);404}405406int407max77620_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)408{409struct max77620_softc *sc;410411sc = device_get_softc(dev);412if (pin >= sc->gpio_npins)413return (EINVAL);414GPIO_LOCK(sc);415*caps = sc->gpio_pins[pin]->pin_caps;416GPIO_UNLOCK(sc);417return (0);418}419420int421max77620_gpio_pin_getname(device_t dev, uint32_t pin, char *name)422{423struct max77620_softc *sc;424425sc = device_get_softc(dev);426if (pin >= sc->gpio_npins)427return (EINVAL);428GPIO_LOCK(sc);429memcpy(name, sc->gpio_pins[pin]->pin_name, GPIOMAXNAME);430GPIO_UNLOCK(sc);431return (0);432}433434static int435max77620_gpio_get_mode(struct max77620_softc *sc, uint32_t pin_num,436uint32_t *out_flags)437{438struct max77620_gpio_pin *pin;439uint8_t reg;440int rv;441442pin = sc->gpio_pins[pin_num];443*out_flags = 0;444445rv = RD1(sc, pin->reg, ®);446if (rv != 0) {447device_printf(sc->dev, "Cannot read GIPO_CFG register\n");448return (ENXIO);449}450451/* Pin function */452pin->alt_func = sc->gpio_reg_ame & (1 << pin_num);453454/* Pull up/down. */455if (sc->gpio_reg_pue & (1 << pin_num))456*out_flags |= GPIO_PIN_PULLUP;457if (sc->gpio_reg_pde & (1 << pin_num))458*out_flags |= GPIO_PIN_PULLDOWN;459460/* Open drain/push-pull modes. */461if (MAX77620_REG_GPIO_DRV_GET(reg) == MAX77620_REG_GPIO_DRV_PUSHPULL)462*out_flags |= GPIO_PIN_PUSHPULL;463else464*out_flags |= GPIO_PIN_OPENDRAIN;465466/* Input/output modes. */467if (MAX77620_REG_GPIO_DRV_GET(reg) == MAX77620_REG_GPIO_DRV_PUSHPULL)468*out_flags |= GPIO_PIN_OUTPUT;469else470*out_flags |= GPIO_PIN_OUTPUT | GPIO_PIN_INPUT;471return (0);472}473474int475max77620_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *out_flags)476{477struct max77620_softc *sc;478int rv;479480sc = device_get_softc(dev);481if (pin >= sc->gpio_npins)482return (EINVAL);483484GPIO_LOCK(sc);485#if 0 /* It colide with GPIO regulators */486/* Is pin in GPIO mode ? */487if (sc->gpio_pins[pin]->alt_func) {488GPIO_UNLOCK(sc);489return (ENXIO);490}491#endif492rv = max77620_gpio_get_mode(sc, pin, out_flags);493GPIO_UNLOCK(sc);494495return (rv);496}497498int499max77620_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)500{501struct max77620_softc *sc;502struct max77620_gpio_pin *pin;503uint8_t reg;504uint8_t old_reg_pue, old_reg_pde;505int rv;506507sc = device_get_softc(dev);508if (pin_num >= sc->gpio_npins)509return (EINVAL);510511pin = sc->gpio_pins[pin_num];512513GPIO_LOCK(sc);514515#if 0 /* It colide with GPIO regulators */516/* Is pin in GPIO mode ? */517if (pin->alt_func) {518GPIO_UNLOCK(sc);519return (ENXIO);520}521#endif522523old_reg_pue = sc->gpio_reg_pue;524old_reg_pde = sc->gpio_reg_pde;525526rv = RD1(sc, pin->reg, ®);527if (rv != 0) {528device_printf(sc->dev, "Cannot read GIPO_CFG register\n");529GPIO_UNLOCK(sc);530return (ENXIO);531}532533if (flags & GPIO_PIN_PULLUP)534sc->gpio_reg_pue |= 1 << pin_num;535else536sc->gpio_reg_pue &= ~(1 << pin_num);537538if (flags & GPIO_PIN_PULLDOWN)539sc->gpio_reg_pde |= 1 << pin_num;540else541sc->gpio_reg_pde &= ~(1 << pin_num);542543if (flags & GPIO_PIN_INPUT) {544reg &= ~MAX77620_REG_GPIO_DRV(~0);545reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN);546reg &= ~MAX77620_REG_GPIO_OUTPUT_VAL(~0);547reg |= MAX77620_REG_GPIO_OUTPUT_VAL(1);548549} else if (((flags & GPIO_PIN_OUTPUT) &&550(flags & GPIO_PIN_OPENDRAIN) == 0) ||551(flags & GPIO_PIN_PUSHPULL)) {552reg &= ~MAX77620_REG_GPIO_DRV(~0);553reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_PUSHPULL);554} else {555reg &= ~MAX77620_REG_GPIO_DRV(~0);556reg |= MAX77620_REG_GPIO_DRV(MAX77620_REG_GPIO_DRV_OPENDRAIN);557}558559rv = WR1(sc, pin->reg, reg);560if (rv != 0) {561device_printf(sc->dev, "Cannot read GIPO_CFG register\n");562return (ENXIO);563}564if (old_reg_pue != sc->gpio_reg_pue) {565rv = WR1(sc, MAX77620_REG_PUE_GPIO, sc->gpio_reg_pue);566if (rv != 0) {567device_printf(sc->dev,568"Cannot update PUE_GPIO register\n");569GPIO_UNLOCK(sc);570return (ENXIO);571}572}573574if (old_reg_pde != sc->gpio_reg_pde) {575rv = WR1(sc, MAX77620_REG_PDE_GPIO, sc->gpio_reg_pde);576if (rv != 0) {577device_printf(sc->dev,578"Cannot update PDE_GPIO register\n");579GPIO_UNLOCK(sc);580return (ENXIO);581}582}583584GPIO_UNLOCK(sc);585return (0);586}587588int589max77620_gpio_pin_set(device_t dev, uint32_t pin, uint32_t val)590{591struct max77620_softc *sc;592int rv;593594sc = device_get_softc(dev);595if (pin >= sc->gpio_npins)596return (EINVAL);597598GPIO_LOCK(sc);599rv = RM1(sc, sc->gpio_pins[pin]->reg, MAX77620_REG_GPIO_OUTPUT_VAL(~0),600MAX77620_REG_GPIO_OUTPUT_VAL(val));601GPIO_UNLOCK(sc);602return (rv);603}604605int606max77620_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *val)607{608struct max77620_softc *sc;609uint8_t tmp;610int rv;611612sc = device_get_softc(dev);613if (pin >= sc->gpio_npins)614return (EINVAL);615616GPIO_LOCK(sc);617rv = RD1(sc, sc->gpio_pins[pin]->reg, &tmp);618619if (MAX77620_REG_GPIO_DRV_GET(tmp) == MAX77620_REG_GPIO_DRV_PUSHPULL)620*val = MAX77620_REG_GPIO_OUTPUT_VAL_GET(tmp);621else622*val = MAX77620_REG_GPIO_INPUT_VAL_GET(tmp);623GPIO_UNLOCK(sc);624if (rv != 0)625return (rv);626627return (0);628}629630int631max77620_gpio_pin_toggle(device_t dev, uint32_t pin)632{633struct max77620_softc *sc;634uint8_t tmp;635int rv;636637sc = device_get_softc(dev);638if (pin >= sc->gpio_npins)639return (EINVAL);640641GPIO_LOCK(sc);642rv = RD1(sc, sc->gpio_pins[pin]->reg, &tmp);643if (rv != 0) {644GPIO_UNLOCK(sc);645return (rv);646}647tmp ^= MAX77620_REG_GPIO_OUTPUT_VAL(~0);648rv = RM1(sc, sc->gpio_pins[pin]->reg, MAX77620_REG_GPIO_OUTPUT_VAL(~0),649tmp);650GPIO_UNLOCK(sc);651return (0);652}653654int655max77620_gpio_map_gpios(device_t dev, phandle_t pdev, phandle_t gparent,656int gcells, pcell_t *gpios, uint32_t *pin, uint32_t *flags)657{658659if (gcells != 2)660return (ERANGE);661*pin = gpios[0];662*flags= gpios[1];663return (0);664}665666int667max77620_gpio_attach(struct max77620_softc *sc, phandle_t node)668{669struct max77620_gpio_pin *pin;670int i, rv;671672sx_init(&sc->gpio_lock, "MAX77620 GPIO lock");673674sc->gpio_busdev = gpiobus_add_bus(sc->dev);675if (sc->gpio_busdev == NULL)676return (ENXIO);677678rv = RD1(sc, MAX77620_REG_PUE_GPIO, &sc->gpio_reg_pue);679if (rv != 0) {680device_printf(sc->dev, "Cannot read PUE_GPIO register\n");681return (ENXIO);682}683684rv = RD1(sc, MAX77620_REG_PDE_GPIO, &sc->gpio_reg_pde);685if (rv != 0) {686device_printf(sc->dev, "Cannot read PDE_GPIO register\n");687return (ENXIO);688}689690rv = RD1(sc, MAX77620_REG_AME_GPIO, &sc->gpio_reg_ame);691if (rv != 0) {692device_printf(sc->dev, "Cannot read AME_GPIO register\n");693return (ENXIO);694}695696sc->gpio_npins = NGPIO;697sc->gpio_pins = malloc(sizeof(struct max77620_gpio_pin *) *698sc->gpio_npins, M_MAX77620_GPIO, M_WAITOK | M_ZERO);699for (i = 0; i < sc->gpio_npins; i++) {700sc->gpio_pins[i] = malloc(sizeof(struct max77620_gpio_pin),701M_MAX77620_GPIO, M_WAITOK | M_ZERO);702pin = sc->gpio_pins[i];703sprintf(pin->pin_name, "gpio%d", i);704pin->pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |705GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL |706GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;707pin->reg = MAX77620_REG_GPIO0 + i;708}709710return (0);711}712713714