15c7f10fdSOliver Schinagl /*
2bdcdf846SHans de Goede * AXP221 and AXP223 driver
3bdcdf846SHans de Goede *
4bdcdf846SHans de Goede * IMPORTANT when making changes to this file check that the registers
5bdcdf846SHans de Goede * used are the same for the axp221 and axp223.
6bdcdf846SHans de Goede *
7bdcdf846SHans de Goede * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
85c7f10fdSOliver Schinagl * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
95c7f10fdSOliver Schinagl *
105c7f10fdSOliver Schinagl * SPDX-License-Identifier: GPL-2.0+
115c7f10fdSOliver Schinagl */
125c7f10fdSOliver Schinagl
135c7f10fdSOliver Schinagl #include <common.h>
14fe4b71b2SHans de Goede #include <command.h>
155c7f10fdSOliver Schinagl #include <errno.h>
161d624a4fSHans de Goede #include <asm/arch/pmic_bus.h>
176944aff1SHans de Goede #include <axp_pmic.h>
185c7f10fdSOliver Schinagl
axp221_mvolt_to_cfg(int mvolt,int min,int max,int div)195c7f10fdSOliver Schinagl static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
205c7f10fdSOliver Schinagl {
215c7f10fdSOliver Schinagl if (mvolt < min)
225c7f10fdSOliver Schinagl mvolt = min;
235c7f10fdSOliver Schinagl else if (mvolt > max)
245c7f10fdSOliver Schinagl mvolt = max;
255c7f10fdSOliver Schinagl
265c7f10fdSOliver Schinagl return (mvolt - min) / div;
275c7f10fdSOliver Schinagl }
285c7f10fdSOliver Schinagl
axp_set_dcdc1(unsigned int mvolt)296944aff1SHans de Goede int axp_set_dcdc1(unsigned int mvolt)
305c7f10fdSOliver Schinagl {
315c7f10fdSOliver Schinagl int ret;
325c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
335c7f10fdSOliver Schinagl
3450e0d5e6SHans de Goede if (mvolt == 0)
351d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
3650e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC1_EN);
3750e0d5e6SHans de Goede
38bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
395c7f10fdSOliver Schinagl if (ret)
405c7f10fdSOliver Schinagl return ret;
415c7f10fdSOliver Schinagl
421d624a4fSHans de Goede ret = pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
4350e0d5e6SHans de Goede AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
4450e0d5e6SHans de Goede if (ret)
4550e0d5e6SHans de Goede return ret;
4650e0d5e6SHans de Goede
471d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
4850e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC1_EN);
495c7f10fdSOliver Schinagl }
505c7f10fdSOliver Schinagl
axp_set_dcdc2(unsigned int mvolt)516944aff1SHans de Goede int axp_set_dcdc2(unsigned int mvolt)
525c7f10fdSOliver Schinagl {
5350e0d5e6SHans de Goede int ret;
545c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
555c7f10fdSOliver Schinagl
5650e0d5e6SHans de Goede if (mvolt == 0)
571d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
5850e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC2_EN);
5950e0d5e6SHans de Goede
6050e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
6150e0d5e6SHans de Goede if (ret)
6250e0d5e6SHans de Goede return ret;
6350e0d5e6SHans de Goede
641d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
6550e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC2_EN);
665c7f10fdSOliver Schinagl }
675c7f10fdSOliver Schinagl
axp_set_dcdc3(unsigned int mvolt)686944aff1SHans de Goede int axp_set_dcdc3(unsigned int mvolt)
695c7f10fdSOliver Schinagl {
7050e0d5e6SHans de Goede int ret;
715c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
725c7f10fdSOliver Schinagl
7350e0d5e6SHans de Goede if (mvolt == 0)
741d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
7550e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC3_EN);
7650e0d5e6SHans de Goede
7750e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
7850e0d5e6SHans de Goede if (ret)
7950e0d5e6SHans de Goede return ret;
8050e0d5e6SHans de Goede
811d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
8250e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC3_EN);
835c7f10fdSOliver Schinagl }
845c7f10fdSOliver Schinagl
axp_set_dcdc4(unsigned int mvolt)856944aff1SHans de Goede int axp_set_dcdc4(unsigned int mvolt)
865c7f10fdSOliver Schinagl {
8750e0d5e6SHans de Goede int ret;
885c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
895c7f10fdSOliver Schinagl
9050e0d5e6SHans de Goede if (mvolt == 0)
911d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
9250e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC4_EN);
9350e0d5e6SHans de Goede
9450e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
9550e0d5e6SHans de Goede if (ret)
9650e0d5e6SHans de Goede return ret;
9750e0d5e6SHans de Goede
981d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
9950e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC4_EN);
1005c7f10fdSOliver Schinagl }
1015c7f10fdSOliver Schinagl
axp_set_dcdc5(unsigned int mvolt)1026944aff1SHans de Goede int axp_set_dcdc5(unsigned int mvolt)
1035c7f10fdSOliver Schinagl {
10450e0d5e6SHans de Goede int ret;
1055c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
1065c7f10fdSOliver Schinagl
10750e0d5e6SHans de Goede if (mvolt == 0)
1081d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
10950e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC5_EN);
11050e0d5e6SHans de Goede
11150e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
11250e0d5e6SHans de Goede if (ret)
11350e0d5e6SHans de Goede return ret;
11450e0d5e6SHans de Goede
1151d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
11650e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC5_EN);
1175c7f10fdSOliver Schinagl }
1185c7f10fdSOliver Schinagl
axp_set_aldo1(unsigned int mvolt)1196944aff1SHans de Goede int axp_set_aldo1(unsigned int mvolt)
1205c7f10fdSOliver Schinagl {
1215c7f10fdSOliver Schinagl int ret;
1225c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1235c7f10fdSOliver Schinagl
12450e0d5e6SHans de Goede if (mvolt == 0)
1251d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
12650e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_ALDO1_EN);
12750e0d5e6SHans de Goede
128bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
1295c7f10fdSOliver Schinagl if (ret)
1305c7f10fdSOliver Schinagl return ret;
1315c7f10fdSOliver Schinagl
1321d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
1335c7f10fdSOliver Schinagl AXP221_OUTPUT_CTRL1_ALDO1_EN);
1345c7f10fdSOliver Schinagl }
1355c7f10fdSOliver Schinagl
axp_set_aldo2(unsigned int mvolt)1366944aff1SHans de Goede int axp_set_aldo2(unsigned int mvolt)
1375c7f10fdSOliver Schinagl {
1385c7f10fdSOliver Schinagl int ret;
1395c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1405c7f10fdSOliver Schinagl
14150e0d5e6SHans de Goede if (mvolt == 0)
1421d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
14350e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_ALDO2_EN);
14450e0d5e6SHans de Goede
145bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
1465c7f10fdSOliver Schinagl if (ret)
1475c7f10fdSOliver Schinagl return ret;
1485c7f10fdSOliver Schinagl
1491d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
1505c7f10fdSOliver Schinagl AXP221_OUTPUT_CTRL1_ALDO2_EN);
1515c7f10fdSOliver Schinagl }
1525c7f10fdSOliver Schinagl
axp_set_aldo3(unsigned int mvolt)1536944aff1SHans de Goede int axp_set_aldo3(unsigned int mvolt)
1545c7f10fdSOliver Schinagl {
1555c7f10fdSOliver Schinagl int ret;
1565c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1575c7f10fdSOliver Schinagl
15850e0d5e6SHans de Goede if (mvolt == 0)
1591d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL3,
16050e0d5e6SHans de Goede AXP221_OUTPUT_CTRL3_ALDO3_EN);
16150e0d5e6SHans de Goede
162bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
1635c7f10fdSOliver Schinagl if (ret)
1645c7f10fdSOliver Schinagl return ret;
1655c7f10fdSOliver Schinagl
1661d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL3,
1675c7f10fdSOliver Schinagl AXP221_OUTPUT_CTRL3_ALDO3_EN);
1685c7f10fdSOliver Schinagl }
1695c7f10fdSOliver Schinagl
axp_set_dldo(int dldo_num,unsigned int mvolt)1703517a27dSChen-Yu Tsai int axp_set_dldo(int dldo_num, unsigned int mvolt)
1713517a27dSChen-Yu Tsai {
1723517a27dSChen-Yu Tsai u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1733517a27dSChen-Yu Tsai int ret;
1743517a27dSChen-Yu Tsai
1753517a27dSChen-Yu Tsai if (dldo_num < 1 || dldo_num > 4)
1763517a27dSChen-Yu Tsai return -EINVAL;
1773517a27dSChen-Yu Tsai
1783517a27dSChen-Yu Tsai if (mvolt == 0)
1793517a27dSChen-Yu Tsai return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
1803517a27dSChen-Yu Tsai AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
1813517a27dSChen-Yu Tsai
1823517a27dSChen-Yu Tsai ret = pmic_bus_write(AXP221_DLDO1_CTRL + (dldo_num - 1), cfg);
1833517a27dSChen-Yu Tsai if (ret)
1843517a27dSChen-Yu Tsai return ret;
1853517a27dSChen-Yu Tsai
1863517a27dSChen-Yu Tsai return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
1873517a27dSChen-Yu Tsai AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
1883517a27dSChen-Yu Tsai }
1893517a27dSChen-Yu Tsai
axp_set_eldo(int eldo_num,unsigned int mvolt)1906944aff1SHans de Goede int axp_set_eldo(int eldo_num, unsigned int mvolt)
1916906df1aSSiarhei Siamashka {
1926906df1aSSiarhei Siamashka int ret;
1936906df1aSSiarhei Siamashka u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1946906df1aSSiarhei Siamashka
195aa23f539SChen-Yu Tsai if (eldo_num < 1 || eldo_num > 3)
1966906df1aSSiarhei Siamashka return -EINVAL;
1976906df1aSSiarhei Siamashka
1986906df1aSSiarhei Siamashka if (mvolt == 0)
199aa23f539SChen-Yu Tsai return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
200aa23f539SChen-Yu Tsai AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
2016906df1aSSiarhei Siamashka
202aa23f539SChen-Yu Tsai ret = pmic_bus_write(AXP221_ELDO1_CTRL + (eldo_num - 1), cfg);
2036906df1aSSiarhei Siamashka if (ret)
2046906df1aSSiarhei Siamashka return ret;
2056906df1aSSiarhei Siamashka
206aa23f539SChen-Yu Tsai return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
207aa23f539SChen-Yu Tsai AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
2086906df1aSSiarhei Siamashka }
2096906df1aSSiarhei Siamashka
axp_init(void)2106944aff1SHans de Goede int axp_init(void)
2115c7f10fdSOliver Schinagl {
2125c7f10fdSOliver Schinagl u8 axp_chip_id;
2135c7f10fdSOliver Schinagl int ret;
2145c7f10fdSOliver Schinagl
215bdcdf846SHans de Goede ret = pmic_bus_init();
2165c7f10fdSOliver Schinagl if (ret)
2175c7f10fdSOliver Schinagl return ret;
2185c7f10fdSOliver Schinagl
219bdcdf846SHans de Goede ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
2205c7f10fdSOliver Schinagl if (ret)
2215c7f10fdSOliver Schinagl return ret;
2225c7f10fdSOliver Schinagl
2235c7f10fdSOliver Schinagl if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
2245c7f10fdSOliver Schinagl return -ENODEV;
2255c7f10fdSOliver Schinagl
226*253e62bfSHans de Goede /*
227*253e62bfSHans de Goede * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
228*253e62bfSHans de Goede * from android these are sometimes on.
229*253e62bfSHans de Goede */
230*253e62bfSHans de Goede ret = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
231*253e62bfSHans de Goede if (ret)
232*253e62bfSHans de Goede return ret;
233*253e62bfSHans de Goede
234*253e62bfSHans de Goede ret = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
235*253e62bfSHans de Goede if (ret)
236*253e62bfSHans de Goede return ret;
237*253e62bfSHans de Goede
2385c7f10fdSOliver Schinagl return 0;
2395c7f10fdSOliver Schinagl }
240f3fba566SHans de Goede
axp_get_sid(unsigned int * sid)2416944aff1SHans de Goede int axp_get_sid(unsigned int *sid)
242f3fba566SHans de Goede {
243f3fba566SHans de Goede u8 *dest = (u8 *)sid;
244f3fba566SHans de Goede int i, ret;
245f3fba566SHans de Goede
2466944aff1SHans de Goede ret = pmic_bus_init();
247f3fba566SHans de Goede if (ret)
248f3fba566SHans de Goede return ret;
249f3fba566SHans de Goede
250bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_PAGE, 1);
251f3fba566SHans de Goede if (ret)
252f3fba566SHans de Goede return ret;
253f3fba566SHans de Goede
254f3fba566SHans de Goede for (i = 0; i < 16; i++) {
255bdcdf846SHans de Goede ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
256f3fba566SHans de Goede if (ret)
257f3fba566SHans de Goede return ret;
258f3fba566SHans de Goede }
259f3fba566SHans de Goede
260bdcdf846SHans de Goede pmic_bus_write(AXP221_PAGE, 0);
261f3fba566SHans de Goede
262f3fba566SHans de Goede for (i = 0; i < 4; i++)
263f3fba566SHans de Goede sid[i] = be32_to_cpu(sid[i]);
264f3fba566SHans de Goede
265f3fba566SHans de Goede return 0;
266f3fba566SHans de Goede }
267fe4b71b2SHans de Goede
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])268fe4b71b2SHans de Goede int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
269fe4b71b2SHans de Goede {
270fe4b71b2SHans de Goede pmic_bus_write(AXP221_SHUTDOWN, AXP221_SHUTDOWN_POWEROFF);
271fe4b71b2SHans de Goede
272fe4b71b2SHans de Goede /* infinite loop during shutdown */
273fe4b71b2SHans de Goede while (1) {}
274fe4b71b2SHans de Goede
275fe4b71b2SHans de Goede /* not reached */
276fe4b71b2SHans de Goede return 0;
277fe4b71b2SHans de Goede }
278