command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / drivers / power / axp209.c
index 98c214fa7ac6e783e5a0df8b16320263f8191d93..60f69ec27ac965912bae1adff6ab4a90f0b661b1 100644 (file)
@@ -1,24 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2012
  * Henrik Nordstrom <henrik@henriknordstrom.net>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
-#include <i2c.h>
-#include <asm/arch/gpio.h>
-#include <axp209.h>
-
-static int axp209_write(enum axp209_reg reg, u8 val)
-{
-       return i2c_write(0x34, reg, 1, &val, 1);
-}
-
-static int axp209_read(enum axp209_reg reg, u8 *val)
-{
-       return i2c_read(0x34, reg, 1, val, 1);
-}
+#include <command.h>
+#include <asm/arch/pmic_bus.h>
+#include <axp_pmic.h>
+
+#ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_08
+#  define AXP209_VRC_SLOPE AXP209_VRC_LDO3_800uV_uS
+#endif
+#ifdef CONFIG_AXP_ALDO3_VOLT_SLOPE_16
+#  define AXP209_VRC_SLOPE AXP209_VRC_LDO3_1600uV_uS
+#endif
+#if defined CONFIG_AXP_ALDO3_VOLT_SLOPE_NONE || !defined AXP209_VRC_SLOPE
+#  define AXP209_VRC_SLOPE 0x00
+#endif
 
 static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
 {
@@ -30,22 +29,30 @@ static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
        return (mvolt - min) / div;
 }
 
-int axp209_set_dcdc2(int mvolt)
+int axp_set_dcdc2(unsigned int mvolt)
 {
        int rc;
        u8 cfg, current;
 
+       if (mvolt == 0)
+               return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+                                       AXP209_OUTPUT_CTRL_DCDC2);
+
+       rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
+       if (rc)
+               return rc;
+
        cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
 
        /* Do we really need to be this gentle? It has built-in voltage slope */
-       while ((rc = axp209_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
+       while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
               current != cfg) {
                if (current < cfg)
                        current++;
                else
                        current--;
 
-               rc = axp209_write(AXP209_DCDC2_VOLTAGE, current);
+               rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
                if (rc)
                        break;
        }
@@ -53,169 +60,182 @@ int axp209_set_dcdc2(int mvolt)
        return rc;
 }
 
-int axp209_set_dcdc3(int mvolt)
+int axp_set_dcdc3(unsigned int mvolt)
 {
        u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
+       int rc;
 
-       return axp209_write(AXP209_DCDC3_VOLTAGE, cfg);
+       if (mvolt == 0)
+               return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+                                       AXP209_OUTPUT_CTRL_DCDC3);
+
+       rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
+       if (rc)
+               return rc;
+
+       return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
 }
 
-int axp209_set_ldo2(int mvolt)
+int axp_set_aldo2(unsigned int mvolt)
 {
        int rc;
        u8 cfg, reg;
 
+       if (mvolt == 0)
+               return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+                                       AXP209_OUTPUT_CTRL_LDO2);
+
        cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
 
-       rc = axp209_read(AXP209_LDO24_VOLTAGE, &reg);
+       rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
        if (rc)
                return rc;
 
-       /* LDO2 configuration is in upper 4 bits */
-       reg = (reg & 0x0f) | (cfg << 4);
-       return axp209_write(AXP209_LDO24_VOLTAGE, reg);
+       reg |= AXP209_LDO24_LDO2_SET(reg, cfg);
+       rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
+       if (rc)
+               return rc;
+
+       return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
 }
 
-int axp209_set_ldo3(int mvolt)
+int axp_set_aldo3(unsigned int mvolt)
 {
        u8 cfg;
+       int rc;
+
+       if (mvolt == 0)
+               return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+                                       AXP209_OUTPUT_CTRL_LDO3);
+
+       /*
+        * Some boards have trouble reaching the target voltage without causing
+        * great inrush currents. To prevent this, boards can enable a certain
+        * slope to ramp up voltage. Note, this only works when changing an
+        * already active power rail. When toggling power on, the AXP ramps up
+        * steeply at 0.0167 V/uS.
+        */
+       rc = pmic_bus_read(AXP209_VRC_DCDC2_LDO3, &cfg);
+       cfg = AXP209_VRC_LDO3_SLOPE_SET(cfg, AXP209_VRC_SLOPE);
+       rc |= pmic_bus_write(AXP209_VRC_DCDC2_LDO3, cfg);
 
-       if (mvolt == -1)
-               cfg = 0x80;     /* determined by LDO3IN pin */
-       else
+       if (rc)
+               return rc;
+
+#ifdef CONFIG_AXP_ALDO3_INRUSH_QUIRK
+       /*
+        * On some boards, LDO3 has a too big capacitor installed. When
+        * turning on LDO3, this causes the AXP209 to shutdown on
+        * voltages over 1.9 volt. As a workaround, we enable LDO3
+        * first with the lowest possible voltage. If this still causes
+        * high inrush currents, the voltage slope should be increased.
+        */
+       rc = pmic_bus_read(AXP209_OUTPUT_CTRL, &cfg);
+       if (rc)
+               return rc;
+
+       if (!(cfg & AXP209_OUTPUT_CTRL_LDO3)) {
+               rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, 0x0); /* 0.7 Volt */
+               mdelay(1);
+               rc |= pmic_bus_setbits(AXP209_OUTPUT_CTRL,
+                                      AXP209_OUTPUT_CTRL_LDO3);
+
+               if (rc)
+                       return rc;
+       }
+#endif
+
+       if (mvolt == -1) {
+               cfg = AXP209_LDO3_VOLTAGE_FROM_LDO3IN;
+       } else {
                cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
+               cfg = AXP209_LDO3_VOLTAGE_SET(cfg);
+       }
+
+       rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
+       if (rc)
+               return rc;
 
-       return axp209_write(AXP209_LDO3_VOLTAGE, cfg);
+       return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
 }
 
-int axp209_set_ldo4(int mvolt)
+int axp_set_aldo4(unsigned int mvolt)
 {
        int rc;
-       static const int vindex[] = {
+       static const unsigned int vindex[] = {
                1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
                2700, 2800, 3000, 3100, 3200, 3300
        };
        u8 cfg, reg;
 
+       if (mvolt == 0)
+               return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
+                                       AXP209_OUTPUT_CTRL_LDO4);
+
        /* Translate mvolt to register cfg value, requested <= selected */
        for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
 
-       rc = axp209_read(AXP209_LDO24_VOLTAGE, &reg);
+       rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
        if (rc)
                return rc;
 
-       /* LDO4 configuration is in lower 4 bits */
-       reg = (reg & 0xf0) | (cfg << 0);
-       return axp209_write(AXP209_LDO24_VOLTAGE, reg);
+       reg |= AXP209_LDO24_LDO4_SET(reg, cfg);
+       rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
+       if (rc)
+               return rc;
+
+       return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
 }
 
-int axp209_init(void)
+int axp_init(void)
 {
        u8 ver;
        int i, rc;
 
-       rc = axp209_read(AXP209_CHIP_VERSION, &ver);
+       rc = pmic_bus_init();
        if (rc)
                return rc;
 
-       /* Low 4 bits is chip version */
-       ver &= 0x0f;
+       rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
+       if (rc)
+               return rc;
 
-       if (ver != 0x1)
-               return -1;
+       if ((ver & AXP209_CHIP_VERSION_MASK) != 0x1)
+               return -EINVAL;
 
        /* Mask all interrupts */
        for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
-               rc = axp209_write(i, 0);
+               rc = pmic_bus_write(i, 0);
                if (rc)
                        return rc;
        }
 
-       return 0;
-}
-
-int axp209_poweron_by_dc(void)
-{
-       u8 v;
-
-       if (axp209_read(AXP209_POWER_STATUS, &v))
-               return 0;
-
-       return (v & AXP209_POWER_STATUS_ON_BY_DC);
-}
-
-int axp209_power_button(void)
-{
-       u8 v;
-
-       if (axp209_read(AXP209_IRQ_STATUS5, &v))
-               return 0;
+       /*
+        * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
+        * from android these are sometimes on.
+        */
+       rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
+       if (rc)
+               return rc;
 
-       axp209_write(AXP209_IRQ_STATUS5, AXP209_IRQ5_PEK_DOWN);
+       rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
+       if (rc)
+               return rc;
 
-       return v & AXP209_IRQ5_PEK_DOWN;
-}
+       rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
+       if (rc)
+               return rc;
 
-static u8 axp209_get_gpio_ctrl_reg(unsigned int pin)
-{
-       switch (pin) {
-       case 0: return AXP209_GPIO0_CTRL;
-       case 1: return AXP209_GPIO1_CTRL;
-       case 2: return AXP209_GPIO2_CTRL;
-       case 3: return AXP209_GPIO3_CTRL;
-       }
        return 0;
 }
 
-int axp_gpio_direction_input(struct udevice *dev, unsigned pin)
+int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 {
-       if (pin == SUNXI_GPIO_AXP0_VBUS_DETECT)
-               return 0;
+       pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
 
-       u8 reg = axp209_get_gpio_ctrl_reg(pin);
-       /* GPIO3 is "special" */
-       u8 val = (pin == 3) ? AXP209_GPIO3_INPUT : AXP209_GPIO_INPUT;
+       /* infinite loop during shutdown */
+       while (1) {}
 
-       return axp209_write(reg, val);
-}
-
-int axp_gpio_direction_output(struct udevice *dev, unsigned pin, int val)
-{
-       u8 reg = axp209_get_gpio_ctrl_reg(pin);
-
-       if (val) {
-               val = (pin == 3) ? AXP209_GPIO3_OUTPUT_HIGH :
-                                  AXP209_GPIO_OUTPUT_HIGH;
-       } else {
-               val = (pin == 3) ? AXP209_GPIO3_OUTPUT_LOW :
-                                  AXP209_GPIO_OUTPUT_LOW;
-       }
-
-       return axp209_write(reg, val);
-}
-
-int axp_gpio_get_value(struct udevice *dev, unsigned pin)
-{
-       u8 val, mask;
-       int rc;
-
-       if (pin == SUNXI_GPIO_AXP0_VBUS_DETECT) {
-               rc = axp209_read(AXP209_POWER_STATUS, &val);
-               mask = AXP209_POWER_STATUS_VBUS_USABLE;
-       } else if (pin == 3) {
-               rc = axp209_read(AXP209_GPIO3_CTRL, &val);
-               mask = 1;
-       } else {
-               rc = axp209_read(AXP209_GPIO_STATE, &val);
-               mask = 1 << (pin + 4);
-       }
-       if (rc)
-               return rc;
-
-       return (val & mask) ? 1 : 0;
-}
-
-int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val)
-{
-       return axp_gpio_direction_output(dev, pin, val);
+       /* not reached */
+       return 0;
 }