1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
25c7f10fdSOliver Schinagl /*
3bdcdf846SHans de Goede * AXP221 and AXP223 driver
4bdcdf846SHans de Goede *
5bdcdf846SHans de Goede * IMPORTANT when making changes to this file check that the registers
6bdcdf846SHans de Goede * used are the same for the axp221 and axp223.
7bdcdf846SHans de Goede *
8bdcdf846SHans de Goede * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com>
95c7f10fdSOliver Schinagl * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl>
105c7f10fdSOliver Schinagl */
115c7f10fdSOliver Schinagl
125c7f10fdSOliver Schinagl #include <common.h>
13fe4b71b2SHans de Goede #include <command.h>
145c7f10fdSOliver Schinagl #include <errno.h>
151d624a4fSHans de Goede #include <asm/arch/pmic_bus.h>
166944aff1SHans de Goede #include <axp_pmic.h>
175c7f10fdSOliver Schinagl
axp221_mvolt_to_cfg(int mvolt,int min,int max,int div)185c7f10fdSOliver Schinagl static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
195c7f10fdSOliver Schinagl {
205c7f10fdSOliver Schinagl if (mvolt < min)
215c7f10fdSOliver Schinagl mvolt = min;
225c7f10fdSOliver Schinagl else if (mvolt > max)
235c7f10fdSOliver Schinagl mvolt = max;
245c7f10fdSOliver Schinagl
255c7f10fdSOliver Schinagl return (mvolt - min) / div;
265c7f10fdSOliver Schinagl }
275c7f10fdSOliver Schinagl
axp_set_dcdc1(unsigned int mvolt)286944aff1SHans de Goede int axp_set_dcdc1(unsigned int mvolt)
295c7f10fdSOliver Schinagl {
305c7f10fdSOliver Schinagl int ret;
315c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
325c7f10fdSOliver Schinagl
3350e0d5e6SHans de Goede if (mvolt == 0)
341d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
3550e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC1_EN);
3650e0d5e6SHans de Goede
37bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
385c7f10fdSOliver Schinagl if (ret)
395c7f10fdSOliver Schinagl return ret;
405c7f10fdSOliver Schinagl
411d624a4fSHans de Goede ret = pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
4250e0d5e6SHans de Goede AXP221_OUTPUT_CTRL2_DCDC1SW_EN);
4350e0d5e6SHans de Goede if (ret)
4450e0d5e6SHans de Goede return ret;
4550e0d5e6SHans de Goede
461d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
4750e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC1_EN);
485c7f10fdSOliver Schinagl }
495c7f10fdSOliver Schinagl
axp_set_dcdc2(unsigned int mvolt)506944aff1SHans de Goede int axp_set_dcdc2(unsigned int mvolt)
515c7f10fdSOliver Schinagl {
5250e0d5e6SHans de Goede int ret;
535c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
545c7f10fdSOliver Schinagl
5550e0d5e6SHans de Goede if (mvolt == 0)
561d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
5750e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC2_EN);
5850e0d5e6SHans de Goede
5950e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
6050e0d5e6SHans de Goede if (ret)
6150e0d5e6SHans de Goede return ret;
6250e0d5e6SHans de Goede
631d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
6450e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC2_EN);
655c7f10fdSOliver Schinagl }
665c7f10fdSOliver Schinagl
axp_set_dcdc3(unsigned int mvolt)676944aff1SHans de Goede int axp_set_dcdc3(unsigned int mvolt)
685c7f10fdSOliver Schinagl {
6950e0d5e6SHans de Goede int ret;
705c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
715c7f10fdSOliver Schinagl
7250e0d5e6SHans de Goede if (mvolt == 0)
731d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
7450e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC3_EN);
7550e0d5e6SHans de Goede
7650e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
7750e0d5e6SHans de Goede if (ret)
7850e0d5e6SHans de Goede return ret;
7950e0d5e6SHans de Goede
801d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
8150e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC3_EN);
825c7f10fdSOliver Schinagl }
835c7f10fdSOliver Schinagl
axp_set_dcdc4(unsigned int mvolt)846944aff1SHans de Goede int axp_set_dcdc4(unsigned int mvolt)
855c7f10fdSOliver Schinagl {
8650e0d5e6SHans de Goede int ret;
875c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
885c7f10fdSOliver Schinagl
8950e0d5e6SHans de Goede if (mvolt == 0)
901d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
9150e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC4_EN);
9250e0d5e6SHans de Goede
9350e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
9450e0d5e6SHans de Goede if (ret)
9550e0d5e6SHans de Goede return ret;
9650e0d5e6SHans de Goede
971d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
9850e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC4_EN);
995c7f10fdSOliver Schinagl }
1005c7f10fdSOliver Schinagl
axp_set_dcdc5(unsigned int mvolt)1016944aff1SHans de Goede int axp_set_dcdc5(unsigned int mvolt)
1025c7f10fdSOliver Schinagl {
10350e0d5e6SHans de Goede int ret;
1045c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
1055c7f10fdSOliver Schinagl
10650e0d5e6SHans de Goede if (mvolt == 0)
1071d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
10850e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC5_EN);
10950e0d5e6SHans de Goede
11050e0d5e6SHans de Goede ret = pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
11150e0d5e6SHans de Goede if (ret)
11250e0d5e6SHans de Goede return ret;
11350e0d5e6SHans de Goede
1141d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
11550e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_DCDC5_EN);
1165c7f10fdSOliver Schinagl }
1175c7f10fdSOliver Schinagl
axp_set_aldo1(unsigned int mvolt)1186944aff1SHans de Goede int axp_set_aldo1(unsigned int mvolt)
1195c7f10fdSOliver Schinagl {
1205c7f10fdSOliver Schinagl int ret;
1215c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1225c7f10fdSOliver Schinagl
12350e0d5e6SHans de Goede if (mvolt == 0)
1241d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
12550e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_ALDO1_EN);
12650e0d5e6SHans de Goede
127bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
1285c7f10fdSOliver Schinagl if (ret)
1295c7f10fdSOliver Schinagl return ret;
1305c7f10fdSOliver Schinagl
1311d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
1325c7f10fdSOliver Schinagl AXP221_OUTPUT_CTRL1_ALDO1_EN);
1335c7f10fdSOliver Schinagl }
1345c7f10fdSOliver Schinagl
axp_set_aldo2(unsigned int mvolt)1356944aff1SHans de Goede int axp_set_aldo2(unsigned int mvolt)
1365c7f10fdSOliver Schinagl {
1375c7f10fdSOliver Schinagl int ret;
1385c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1395c7f10fdSOliver Schinagl
14050e0d5e6SHans de Goede if (mvolt == 0)
1411d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL1,
14250e0d5e6SHans de Goede AXP221_OUTPUT_CTRL1_ALDO2_EN);
14350e0d5e6SHans de Goede
144bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
1455c7f10fdSOliver Schinagl if (ret)
1465c7f10fdSOliver Schinagl return ret;
1475c7f10fdSOliver Schinagl
1481d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL1,
1495c7f10fdSOliver Schinagl AXP221_OUTPUT_CTRL1_ALDO2_EN);
1505c7f10fdSOliver Schinagl }
1515c7f10fdSOliver Schinagl
axp_set_aldo3(unsigned int mvolt)1526944aff1SHans de Goede int axp_set_aldo3(unsigned int mvolt)
1535c7f10fdSOliver Schinagl {
1545c7f10fdSOliver Schinagl int ret;
1555c7f10fdSOliver Schinagl u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1565c7f10fdSOliver Schinagl
15750e0d5e6SHans de Goede if (mvolt == 0)
1581d624a4fSHans de Goede return pmic_bus_clrbits(AXP221_OUTPUT_CTRL3,
15950e0d5e6SHans de Goede AXP221_OUTPUT_CTRL3_ALDO3_EN);
16050e0d5e6SHans de Goede
161bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
1625c7f10fdSOliver Schinagl if (ret)
1635c7f10fdSOliver Schinagl return ret;
1645c7f10fdSOliver Schinagl
1651d624a4fSHans de Goede return pmic_bus_setbits(AXP221_OUTPUT_CTRL3,
1665c7f10fdSOliver Schinagl AXP221_OUTPUT_CTRL3_ALDO3_EN);
1675c7f10fdSOliver Schinagl }
1685c7f10fdSOliver Schinagl
axp_set_dldo(int dldo_num,unsigned int mvolt)1693517a27dSChen-Yu Tsai int axp_set_dldo(int dldo_num, unsigned int mvolt)
1703517a27dSChen-Yu Tsai {
1713517a27dSChen-Yu Tsai u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1723517a27dSChen-Yu Tsai int ret;
1733517a27dSChen-Yu Tsai
1743517a27dSChen-Yu Tsai if (dldo_num < 1 || dldo_num > 4)
1753517a27dSChen-Yu Tsai return -EINVAL;
1763517a27dSChen-Yu Tsai
1773517a27dSChen-Yu Tsai if (mvolt == 0)
1783517a27dSChen-Yu Tsai return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
1793517a27dSChen-Yu Tsai AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
1803517a27dSChen-Yu Tsai
1813517a27dSChen-Yu Tsai ret = pmic_bus_write(AXP221_DLDO1_CTRL + (dldo_num - 1), cfg);
1823517a27dSChen-Yu Tsai if (ret)
1833517a27dSChen-Yu Tsai return ret;
1843517a27dSChen-Yu Tsai
1853517a27dSChen-Yu Tsai return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
1863517a27dSChen-Yu Tsai AXP221_OUTPUT_CTRL2_DLDO1_EN << (dldo_num - 1));
1873517a27dSChen-Yu Tsai }
1883517a27dSChen-Yu Tsai
axp_set_eldo(int eldo_num,unsigned int mvolt)1896944aff1SHans de Goede int axp_set_eldo(int eldo_num, unsigned int mvolt)
1906906df1aSSiarhei Siamashka {
1916906df1aSSiarhei Siamashka int ret;
1926906df1aSSiarhei Siamashka u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1936906df1aSSiarhei Siamashka
194aa23f539SChen-Yu Tsai if (eldo_num < 1 || eldo_num > 3)
1956906df1aSSiarhei Siamashka return -EINVAL;
1966906df1aSSiarhei Siamashka
1976906df1aSSiarhei Siamashka if (mvolt == 0)
198aa23f539SChen-Yu Tsai return pmic_bus_clrbits(AXP221_OUTPUT_CTRL2,
199aa23f539SChen-Yu Tsai AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
2006906df1aSSiarhei Siamashka
201aa23f539SChen-Yu Tsai ret = pmic_bus_write(AXP221_ELDO1_CTRL + (eldo_num - 1), cfg);
2026906df1aSSiarhei Siamashka if (ret)
2036906df1aSSiarhei Siamashka return ret;
2046906df1aSSiarhei Siamashka
205aa23f539SChen-Yu Tsai return pmic_bus_setbits(AXP221_OUTPUT_CTRL2,
206aa23f539SChen-Yu Tsai AXP221_OUTPUT_CTRL2_ELDO1_EN << (eldo_num - 1));
2076906df1aSSiarhei Siamashka }
2086906df1aSSiarhei Siamashka
axp_init(void)2096944aff1SHans de Goede int axp_init(void)
2105c7f10fdSOliver Schinagl {
2115c7f10fdSOliver Schinagl u8 axp_chip_id;
2125c7f10fdSOliver Schinagl int ret;
2135c7f10fdSOliver Schinagl
214bdcdf846SHans de Goede ret = pmic_bus_init();
2155c7f10fdSOliver Schinagl if (ret)
2165c7f10fdSOliver Schinagl return ret;
2175c7f10fdSOliver Schinagl
218bdcdf846SHans de Goede ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
2195c7f10fdSOliver Schinagl if (ret)
2205c7f10fdSOliver Schinagl return ret;
2215c7f10fdSOliver Schinagl
2225c7f10fdSOliver Schinagl if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
2235c7f10fdSOliver Schinagl return -ENODEV;
2245c7f10fdSOliver Schinagl
225253e62bfSHans de Goede /*
226253e62bfSHans de Goede * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
227253e62bfSHans de Goede * from android these are sometimes on.
228253e62bfSHans de Goede */
229253e62bfSHans de Goede ret = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
230253e62bfSHans de Goede if (ret)
231253e62bfSHans de Goede return ret;
232253e62bfSHans de Goede
233253e62bfSHans de Goede ret = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
234253e62bfSHans de Goede if (ret)
235253e62bfSHans de Goede return ret;
236253e62bfSHans de Goede
2375c7f10fdSOliver Schinagl return 0;
2385c7f10fdSOliver Schinagl }
239f3fba566SHans de Goede
axp_get_sid(unsigned int * sid)2406944aff1SHans de Goede int axp_get_sid(unsigned int *sid)
241f3fba566SHans de Goede {
242f3fba566SHans de Goede u8 *dest = (u8 *)sid;
243f3fba566SHans de Goede int i, ret;
244f3fba566SHans de Goede
2456944aff1SHans de Goede ret = pmic_bus_init();
246f3fba566SHans de Goede if (ret)
247f3fba566SHans de Goede return ret;
248f3fba566SHans de Goede
249bdcdf846SHans de Goede ret = pmic_bus_write(AXP221_PAGE, 1);
250f3fba566SHans de Goede if (ret)
251f3fba566SHans de Goede return ret;
252f3fba566SHans de Goede
253f3fba566SHans de Goede for (i = 0; i < 16; i++) {
254bdcdf846SHans de Goede ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
255f3fba566SHans de Goede if (ret)
256f3fba566SHans de Goede return ret;
257f3fba566SHans de Goede }
258f3fba566SHans de Goede
259bdcdf846SHans de Goede pmic_bus_write(AXP221_PAGE, 0);
260f3fba566SHans de Goede
261f3fba566SHans de Goede for (i = 0; i < 4; i++)
262f3fba566SHans de Goede sid[i] = be32_to_cpu(sid[i]);
263f3fba566SHans de Goede
264f3fba566SHans de Goede return 0;
265f3fba566SHans de Goede }
266fe4b71b2SHans de Goede
do_poweroff(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])267fe4b71b2SHans de Goede int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
268fe4b71b2SHans de Goede {
269fe4b71b2SHans de Goede pmic_bus_write(AXP221_SHUTDOWN, AXP221_SHUTDOWN_POWEROFF);
270fe4b71b2SHans de Goede
271fe4b71b2SHans de Goede /* infinite loop during shutdown */
272fe4b71b2SHans de Goede while (1) {}
273fe4b71b2SHans de Goede
274fe4b71b2SHans de Goede /* not reached */
275fe4b71b2SHans de Goede return 0;
276fe4b71b2SHans de Goede }
277