uboot/drivers/power/axp221.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * AXP221 and AXP223 driver
   4 *
   5 * IMPORTANT when making changes to this file check that the registers
   6 * used are the same for the axp221 and axp223.
   7 *
   8 * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
   9 * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
  10 */
  11
  12#include <common.h>
  13#include <command.h>
  14#include <errno.h>
  15#include <asm/arch/pmic_bus.h>
  16#include <axp_pmic.h>
  17
  18static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
  19{
  20        if (mvolt < min)
  21                mvolt = min;
  22        else if (mvolt > max)
  23                mvolt = max;
  24
  25        return (mvolt - min) / div;
  26}
  27
  28int axp_set_dcdc1(unsigned int mvolt)
  29{
  30        int ret;
  31        u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
  32
  33        if (mvolt == 0)
  34                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
  35                                        AXP221_OUTPUT_CTRL1_DCDC1_EN);
  36
  37        ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
  38        if (ret)
  39                return ret;
  40
  41        ret = pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
  42                               AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
  43        if (ret)
  44                return ret;
  45
  46        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
  47                                AXP221_OUTPUT_CTRL1_DCDC1_EN);
  48}
  49
  50int axp_set_dcdc2(unsigned int mvolt)
  51{
  52        int ret;
  53        u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
  54
  55        if (mvolt == 0)
  56                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
  57                                        AXP221_OUTPUT_CTRL1_DCDC2_EN);
  58
  59        ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
  60        if (ret)
  61                return ret;
  62
  63        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
  64                                AXP221_OUTPUT_CTRL1_DCDC2_EN);
  65}
  66
  67int axp_set_dcdc3(unsigned int mvolt)
  68{
  69        int ret;
  70        u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
  71
  72        if (mvolt == 0)
  73                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
  74                                        AXP221_OUTPUT_CTRL1_DCDC3_EN);
  75
  76        ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
  77        if (ret)
  78                return ret;
  79
  80        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
  81                                AXP221_OUTPUT_CTRL1_DCDC3_EN);
  82}
  83
  84int axp_set_dcdc4(unsigned int mvolt)
  85{
  86        int ret;
  87        u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
  88
  89        if (mvolt == 0)
  90                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
  91                                        AXP221_OUTPUT_CTRL1_DCDC4_EN);
  92
  93        ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
  94        if (ret)
  95                return ret;
  96
  97        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
  98                                AXP221_OUTPUT_CTRL1_DCDC4_EN);
  99}
 100
 101int axp_set_dcdc5(unsigned int mvolt)
 102{
 103        int ret;
 104        u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
 105
 106        if (mvolt == 0)
 107                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
 108                                        AXP221_OUTPUT_CTRL1_DCDC5_EN);
 109
 110        ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
 111        if (ret)
 112                return ret;
 113
 114        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
 115                                AXP221_OUTPUT_CTRL1_DCDC5_EN);
 116}
 117
 118int axp_set_aldo1(unsigned int mvolt)
 119{
 120        int ret;
 121        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 122
 123        if (mvolt == 0)
 124                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
 125                                        AXP221_OUTPUT_CTRL1_ALDO1_EN);
 126
 127        ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
 128        if (ret)
 129                return ret;
 130
 131        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
 132                                AXP221_OUTPUT_CTRL1_ALDO1_EN);
 133}
 134
 135int axp_set_aldo2(unsigned int mvolt)
 136{
 137        int ret;
 138        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 139
 140        if (mvolt == 0)
 141                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
 142                                        AXP221_OUTPUT_CTRL1_ALDO2_EN);
 143
 144        ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
 145        if (ret)
 146                return ret;
 147
 148        return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
 149                                AXP221_OUTPUT_CTRL1_ALDO2_EN);
 150}
 151
 152int axp_set_aldo3(unsigned int mvolt)
 153{
 154        int ret;
 155        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 156
 157        if (mvolt == 0)
 158                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL3,
 159                                        AXP221_OUTPUT_CTRL3_ALDO3_EN);
 160
 161        ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
 162        if (ret)
 163                return ret;
 164
 165        return pmic_bus_setbits(AXP221_OUTPUT_CTRL3,
 166                                AXP221_OUTPUT_CTRL3_ALDO3_EN);
 167}
 168
 169int axp_set_dldo(int dldo_num, unsigned int mvolt)
 170{
 171        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 172        int ret;
 173
 174        if (dldo_num < 1 || dldo_num > 4)
 175                return -EINVAL;
 176
 177        if (mvolt == 0)
 178                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
 179                                AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
 180
 181        ret = pmic_bus_write(AXP221_DLDO1_CTRL + (dldo_num - 1), cfg);
 182        if (ret)
 183                return ret;
 184
 185        return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
 186                                AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
 187}
 188
 189int axp_set_eldo(int eldo_num, unsigned int mvolt)
 190{
 191        int ret;
 192        u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
 193
 194        if (eldo_num < 1 || eldo_num > 3)
 195                return -EINVAL;
 196
 197        if (mvolt == 0)
 198                return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
 199                                AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
 200
 201        ret = pmic_bus_write(AXP221_ELDO1_CTRL + (eldo_num - 1), cfg);
 202        if (ret)
 203                return ret;
 204
 205        return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
 206                                AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
 207}
 208
 209int axp_init(void)
 210{
 211        u8 axp_chip_id;
 212        int ret;
 213
 214        ret = pmic_bus_init();
 215        if (ret)
 216                return ret;
 217
 218        ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
 219        if (ret)
 220                return ret;
 221
 222        if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
 223                return -ENODEV;
 224
 225        /*
 226         * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
 227         * from android these are sometimes on.
 228         */
 229        ret = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
 230        if (ret)
 231                return ret;
 232
 233        ret = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
 234        if (ret)
 235                return ret;
 236
 237        return 0;
 238}
 239
 240int axp_get_sid(unsigned int *sid)
 241{
 242        u8 *dest = (u8 *)sid;
 243        int i, ret;
 244
 245        ret = pmic_bus_init();
 246        if (ret)
 247                return ret;
 248
 249        ret = pmic_bus_write(AXP221_PAGE, 1);
 250        if (ret)
 251                return ret;
 252
 253        for (i = 0; i < 16; i++) {
 254                ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
 255                if (ret)
 256                        return ret;
 257        }
 258
 259        pmic_bus_write(AXP221_PAGE, 0);
 260
 261        for (i = 0; i < 4; i++)
 262                sid[i] = be32_to_cpu(sid[i]);
 263
 264        return 0;
 265}
 266
 267#if !IS_ENABLED(CONFIG_SYSRESET_CMD_POWEROFF)
 268int do_poweroff(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
 269{
 270        pmic_bus_write(AXP221_SHUTDOWN, AXP221_SHUTDOWN_POWEROFF);
 271
 272        /* infinite loop during shutdown */
 273        while (1) {}
 274
 275        /* not reached */
 276        return 0;
 277}
 278#endif
 279