114bc66bdSHenrik Nordstrom /*
214bc66bdSHenrik Nordstrom * (C) Copyright 2012
314bc66bdSHenrik Nordstrom * Henrik Nordstrom <henrik@henriknordstrom.net>
414bc66bdSHenrik Nordstrom *
514bc66bdSHenrik Nordstrom * SPDX-License-Identifier: GPL-2.0+
614bc66bdSHenrik Nordstrom */
714bc66bdSHenrik Nordstrom
814bc66bdSHenrik Nordstrom #include <common.h>
9467e92b3SMichael van Slingerland #include <command.h>
1030490b52SHans de Goede #include <asm/arch/pmic_bus.h>
116944aff1SHans de Goede #include <axp_pmic.h>
1214bc66bdSHenrik Nordstrom
axp209_mvolt_to_cfg(int mvolt,int min,int max,int div)1314bc66bdSHenrik Nordstrom static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
1414bc66bdSHenrik Nordstrom {
1514bc66bdSHenrik Nordstrom if (mvolt < min)
1614bc66bdSHenrik Nordstrom mvolt = min;
1714bc66bdSHenrik Nordstrom else if (mvolt > max)
1814bc66bdSHenrik Nordstrom mvolt = max;
1914bc66bdSHenrik Nordstrom
2014bc66bdSHenrik Nordstrom return (mvolt - min) / div;
2114bc66bdSHenrik Nordstrom }
2214bc66bdSHenrik Nordstrom
axp_set_dcdc2(unsigned int mvolt)236944aff1SHans de Goede int axp_set_dcdc2(unsigned int mvolt)
2414bc66bdSHenrik Nordstrom {
2514bc66bdSHenrik Nordstrom int rc;
2614bc66bdSHenrik Nordstrom u8 cfg, current;
2714bc66bdSHenrik Nordstrom
28beba401fSHans de Goede if (mvolt == 0)
29beba401fSHans de Goede return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
30beba401fSHans de Goede AXP209_OUTPUT_CTRL_DCDC2);
31beba401fSHans de Goede
32beba401fSHans de Goede rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
33beba401fSHans de Goede if (rc)
34beba401fSHans de Goede return rc;
35beba401fSHans de Goede
3614bc66bdSHenrik Nordstrom cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
3714bc66bdSHenrik Nordstrom
3814bc66bdSHenrik Nordstrom /* Do we really need to be this gentle? It has built-in voltage slope */
3930490b52SHans de Goede while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, ¤t)) == 0 &&
4014bc66bdSHenrik Nordstrom current != cfg) {
4114bc66bdSHenrik Nordstrom if (current < cfg)
4214bc66bdSHenrik Nordstrom current++;
4314bc66bdSHenrik Nordstrom else
4414bc66bdSHenrik Nordstrom current--;
4514bc66bdSHenrik Nordstrom
4630490b52SHans de Goede rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
4714bc66bdSHenrik Nordstrom if (rc)
4814bc66bdSHenrik Nordstrom break;
4914bc66bdSHenrik Nordstrom }
5014bc66bdSHenrik Nordstrom
5114bc66bdSHenrik Nordstrom return rc;
5214bc66bdSHenrik Nordstrom }
5314bc66bdSHenrik Nordstrom
axp_set_dcdc3(unsigned int mvolt)546944aff1SHans de Goede int axp_set_dcdc3(unsigned int mvolt)
5514bc66bdSHenrik Nordstrom {
5614bc66bdSHenrik Nordstrom u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
57beba401fSHans de Goede int rc;
5814bc66bdSHenrik Nordstrom
59beba401fSHans de Goede if (mvolt == 0)
60beba401fSHans de Goede return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
61beba401fSHans de Goede AXP209_OUTPUT_CTRL_DCDC3);
62beba401fSHans de Goede
63beba401fSHans de Goede rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
64beba401fSHans de Goede if (rc)
65beba401fSHans de Goede return rc;
66beba401fSHans de Goede
67beba401fSHans de Goede return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
6814bc66bdSHenrik Nordstrom }
6914bc66bdSHenrik Nordstrom
axp_set_aldo2(unsigned int mvolt)706944aff1SHans de Goede int axp_set_aldo2(unsigned int mvolt)
7114bc66bdSHenrik Nordstrom {
7214bc66bdSHenrik Nordstrom int rc;
7314bc66bdSHenrik Nordstrom u8 cfg, reg;
7414bc66bdSHenrik Nordstrom
75beba401fSHans de Goede if (mvolt == 0)
76beba401fSHans de Goede return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
77beba401fSHans de Goede AXP209_OUTPUT_CTRL_LDO2);
78beba401fSHans de Goede
7914bc66bdSHenrik Nordstrom cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
8014bc66bdSHenrik Nordstrom
8130490b52SHans de Goede rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, ®);
8214bc66bdSHenrik Nordstrom if (rc)
8314bc66bdSHenrik Nordstrom return rc;
8414bc66bdSHenrik Nordstrom
8514bc66bdSHenrik Nordstrom /* LDO2 configuration is in upper 4 bits */
8614bc66bdSHenrik Nordstrom reg = (reg & 0x0f) | (cfg << 4);
87beba401fSHans de Goede rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
88beba401fSHans de Goede if (rc)
89beba401fSHans de Goede return rc;
90beba401fSHans de Goede
91beba401fSHans de Goede return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
9214bc66bdSHenrik Nordstrom }
9314bc66bdSHenrik Nordstrom
axp_set_aldo3(unsigned int mvolt)946944aff1SHans de Goede int axp_set_aldo3(unsigned int mvolt)
9514bc66bdSHenrik Nordstrom {
9614bc66bdSHenrik Nordstrom u8 cfg;
97beba401fSHans de Goede int rc;
98beba401fSHans de Goede
99beba401fSHans de Goede if (mvolt == 0)
100beba401fSHans de Goede return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
101beba401fSHans de Goede AXP209_OUTPUT_CTRL_LDO3);
10214bc66bdSHenrik Nordstrom
10314bc66bdSHenrik Nordstrom if (mvolt == -1)
10414bc66bdSHenrik Nordstrom cfg = 0x80; /* determined by LDO3IN pin */
10514bc66bdSHenrik Nordstrom else
10699deda1dSIain Paton cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
10714bc66bdSHenrik Nordstrom
108beba401fSHans de Goede rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
109beba401fSHans de Goede if (rc)
110beba401fSHans de Goede return rc;
111beba401fSHans de Goede
112beba401fSHans de Goede return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
11314bc66bdSHenrik Nordstrom }
11414bc66bdSHenrik Nordstrom
axp_set_aldo4(unsigned int mvolt)1156944aff1SHans de Goede int axp_set_aldo4(unsigned int mvolt)
11614bc66bdSHenrik Nordstrom {
11714bc66bdSHenrik Nordstrom int rc;
1186944aff1SHans de Goede static const unsigned int vindex[] = {
11914bc66bdSHenrik Nordstrom 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
12014bc66bdSHenrik Nordstrom 2700, 2800, 3000, 3100, 3200, 3300
12114bc66bdSHenrik Nordstrom };
12214bc66bdSHenrik Nordstrom u8 cfg, reg;
12314bc66bdSHenrik Nordstrom
124beba401fSHans de Goede if (mvolt == 0)
125beba401fSHans de Goede return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
126beba401fSHans de Goede AXP209_OUTPUT_CTRL_LDO4);
127beba401fSHans de Goede
12814bc66bdSHenrik Nordstrom /* Translate mvolt to register cfg value, requested <= selected */
12914bc66bdSHenrik Nordstrom for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
13014bc66bdSHenrik Nordstrom
13130490b52SHans de Goede rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, ®);
13214bc66bdSHenrik Nordstrom if (rc)
13314bc66bdSHenrik Nordstrom return rc;
13414bc66bdSHenrik Nordstrom
13514bc66bdSHenrik Nordstrom /* LDO4 configuration is in lower 4 bits */
13614bc66bdSHenrik Nordstrom reg = (reg & 0xf0) | (cfg << 0);
137beba401fSHans de Goede rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
138beba401fSHans de Goede if (rc)
139beba401fSHans de Goede return rc;
140beba401fSHans de Goede
141beba401fSHans de Goede return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
14214bc66bdSHenrik Nordstrom }
14314bc66bdSHenrik Nordstrom
axp_init(void)1446944aff1SHans de Goede int axp_init(void)
14514bc66bdSHenrik Nordstrom {
14614bc66bdSHenrik Nordstrom u8 ver;
1479dcf68faSHans de Goede int i, rc;
14814bc66bdSHenrik Nordstrom
14930490b52SHans de Goede rc = pmic_bus_init();
15030490b52SHans de Goede if (rc)
15130490b52SHans de Goede return rc;
15230490b52SHans de Goede
15330490b52SHans de Goede rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
15414bc66bdSHenrik Nordstrom if (rc)
15514bc66bdSHenrik Nordstrom return rc;
15614bc66bdSHenrik Nordstrom
15714bc66bdSHenrik Nordstrom /* Low 4 bits is chip version */
15814bc66bdSHenrik Nordstrom ver &= 0x0f;
15914bc66bdSHenrik Nordstrom
16014bc66bdSHenrik Nordstrom if (ver != 0x1)
161*505cf475SJaehoon Chung return -EINVAL;
16214bc66bdSHenrik Nordstrom
1639dcf68faSHans de Goede /* Mask all interrupts */
1649dcf68faSHans de Goede for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
16530490b52SHans de Goede rc = pmic_bus_write(i, 0);
1669dcf68faSHans de Goede if (rc)
1679dcf68faSHans de Goede return rc;
1689dcf68faSHans de Goede }
1699dcf68faSHans de Goede
170253e62bfSHans de Goede /*
171253e62bfSHans de Goede * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
172253e62bfSHans de Goede * from android these are sometimes on.
173253e62bfSHans de Goede */
174253e62bfSHans de Goede rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
175253e62bfSHans de Goede if (rc)
176253e62bfSHans de Goede return rc;
177253e62bfSHans de Goede
178253e62bfSHans de Goede rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
179253e62bfSHans de Goede if (rc)
180253e62bfSHans de Goede return rc;
181253e62bfSHans de Goede
182253e62bfSHans de Goede rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
183253e62bfSHans de Goede if (rc)
184253e62bfSHans de Goede return rc;
185253e62bfSHans de Goede
18614bc66bdSHenrik Nordstrom return 0;
18714bc66bdSHenrik Nordstrom }
188467e92b3SMichael van Slingerland
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])189467e92b3SMichael van Slingerland int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
190467e92b3SMichael van Slingerland {
191467e92b3SMichael van Slingerland pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
192467e92b3SMichael van Slingerland
193467e92b3SMichael van Slingerland /* infinite loop during shutdown */
194467e92b3SMichael van Slingerland while (1) {}
195467e92b3SMichael van Slingerland
196467e92b3SMichael van Slingerland /* not reached */
197467e92b3SMichael van Slingerland return 0;
198467e92b3SMichael van Slingerland }
199