xref: /openbmc/u-boot/drivers/power/axp221.c (revision e8f80a5a)
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