uboot/drivers/gpio/axp_gpio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2015 Hans de Goede <hdegoede@redhat.com>
   4 *
   5 * X-Powers AXP Power Management ICs gpio driver
   6 */
   7
   8#include <common.h>
   9#include <asm/arch/gpio.h>
  10#include <asm/arch/pmic_bus.h>
  11#include <asm/gpio.h>
  12#include <axp_pmic.h>
  13#include <dm.h>
  14#include <dm/device-internal.h>
  15#include <dm/lists.h>
  16#include <dm/root.h>
  17#include <errno.h>
  18
  19static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val);
  20
  21static u8 axp_get_gpio_ctrl_reg(unsigned pin)
  22{
  23        switch (pin) {
  24        case 0: return AXP_GPIO0_CTRL;
  25        case 1: return AXP_GPIO1_CTRL;
  26#ifdef AXP_GPIO2_CTRL
  27        case 2: return AXP_GPIO2_CTRL;
  28#endif
  29#ifdef AXP_GPIO3_CTRL
  30        case 3: return AXP_GPIO3_CTRL;
  31#endif
  32        }
  33        return 0;
  34}
  35
  36static int axp_gpio_direction_input(struct udevice *dev, unsigned pin)
  37{
  38        u8 reg;
  39
  40        switch (pin) {
  41#ifndef CONFIG_AXP152_POWER /* NA on axp152 */
  42        case SUNXI_GPIO_AXP0_VBUS_DETECT:
  43                return 0;
  44#endif
  45        default:
  46                reg = axp_get_gpio_ctrl_reg(pin);
  47                if (reg == 0)
  48                        return -EINVAL;
  49
  50                return pmic_bus_write(reg, AXP_GPIO_CTRL_INPUT);
  51        }
  52}
  53
  54static int axp_gpio_direction_output(struct udevice *dev, unsigned pin,
  55                                     int val)
  56{
  57        __maybe_unused int ret;
  58        u8 reg;
  59
  60        switch (pin) {
  61#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
  62        /* Only available on later PMICs */
  63        case SUNXI_GPIO_AXP0_VBUS_ENABLE:
  64                ret = pmic_bus_clrbits(AXP_MISC_CTRL,
  65                                       AXP_MISC_CTRL_N_VBUSEN_FUNC);
  66                if (ret)
  67                        return ret;
  68
  69                return axp_gpio_set_value(dev, pin, val);
  70#endif
  71        default:
  72                reg = axp_get_gpio_ctrl_reg(pin);
  73                if (reg == 0)
  74                        return -EINVAL;
  75
  76                return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
  77                                                 AXP_GPIO_CTRL_OUTPUT_LOW);
  78        }
  79}
  80
  81static int axp_gpio_get_value(struct udevice *dev, unsigned pin)
  82{
  83        u8 reg, val, mask;
  84        int ret;
  85
  86        switch (pin) {
  87#ifndef CONFIG_AXP152_POWER /* NA on axp152 */
  88        case SUNXI_GPIO_AXP0_VBUS_DETECT:
  89                ret = pmic_bus_read(AXP_POWER_STATUS, &val);
  90                mask = AXP_POWER_STATUS_VBUS_PRESENT;
  91                break;
  92#endif
  93#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
  94        /* Only available on later PMICs */
  95        case SUNXI_GPIO_AXP0_VBUS_ENABLE:
  96                ret = pmic_bus_read(AXP_VBUS_IPSOUT, &val);
  97                mask = AXP_VBUS_IPSOUT_DRIVEBUS;
  98                break;
  99#endif
 100        default:
 101                reg = axp_get_gpio_ctrl_reg(pin);
 102                if (reg == 0)
 103                        return -EINVAL;
 104
 105                ret = pmic_bus_read(AXP_GPIO_STATE, &val);
 106                mask = 1 << (pin + AXP_GPIO_STATE_OFFSET);
 107        }
 108        if (ret)
 109                return ret;
 110
 111        return (val & mask) ? 1 : 0;
 112}
 113
 114static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val)
 115{
 116        u8 reg;
 117
 118        switch (pin) {
 119#ifdef AXP_MISC_CTRL_N_VBUSEN_FUNC
 120        /* Only available on later PMICs */
 121        case SUNXI_GPIO_AXP0_VBUS_ENABLE:
 122                if (val)
 123                        return pmic_bus_setbits(AXP_VBUS_IPSOUT,
 124                                                AXP_VBUS_IPSOUT_DRIVEBUS);
 125                else
 126                        return pmic_bus_clrbits(AXP_VBUS_IPSOUT,
 127                                                AXP_VBUS_IPSOUT_DRIVEBUS);
 128#endif
 129        default:
 130                reg = axp_get_gpio_ctrl_reg(pin);
 131                if (reg == 0)
 132                        return -EINVAL;
 133
 134                return pmic_bus_write(reg, val ? AXP_GPIO_CTRL_OUTPUT_HIGH :
 135                                                 AXP_GPIO_CTRL_OUTPUT_LOW);
 136        }
 137}
 138
 139static const struct dm_gpio_ops gpio_axp_ops = {
 140        .direction_input        = axp_gpio_direction_input,
 141        .direction_output       = axp_gpio_direction_output,
 142        .get_value              = axp_gpio_get_value,
 143        .set_value              = axp_gpio_set_value,
 144};
 145
 146static int gpio_axp_probe(struct udevice *dev)
 147{
 148        struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
 149
 150        /* Tell the uclass how many GPIOs we have */
 151        uc_priv->bank_name = strdup(SUNXI_GPIO_AXP0_PREFIX);
 152        uc_priv->gpio_count = SUNXI_GPIO_AXP0_GPIO_COUNT;
 153
 154        return 0;
 155}
 156
 157U_BOOT_DRIVER(gpio_axp) = {
 158        .name   = "gpio_axp",
 159        .id     = UCLASS_GPIO,
 160        .ops    = &gpio_axp_ops,
 161        .probe  = gpio_axp_probe,
 162};
 163
 164int axp_gpio_init(void)
 165{
 166        struct udevice *dev;
 167        int ret;
 168
 169        ret = pmic_bus_init();
 170        if (ret)
 171                return ret;
 172
 173        /* There is no devicetree support for the axp yet, so bind directly */
 174        ret = device_bind_driver(dm_root(), "gpio_axp", "AXP-gpio", &dev);
 175        if (ret)
 176                return ret;
 177
 178        return 0;
 179}
 180