xref: /openbmc/u-boot/drivers/power/axp221.c (revision bdcdf846)
15c7f10fdSOliver Schinagl /*
2*bdcdf846SHans de Goede  * AXP221 and AXP223 driver
3*bdcdf846SHans de Goede  *
4*bdcdf846SHans de Goede  * IMPORTANT when making changes to this file check that the registers
5*bdcdf846SHans de Goede  * used are the same for the axp221 and axp223.
6*bdcdf846SHans de Goede  *
7*bdcdf846SHans 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>
145c7f10fdSOliver Schinagl #include <errno.h>
155c7f10fdSOliver Schinagl #include <asm/arch/p2wi.h>
16*bdcdf846SHans de Goede #include <asm/arch/rsb.h>
175c7f10fdSOliver Schinagl #include <axp221.h>
185c7f10fdSOliver Schinagl 
19*bdcdf846SHans de Goede /*
20*bdcdf846SHans de Goede  * The axp221 uses the p2wi bus, the axp223 is identical (for all registers
21*bdcdf846SHans de Goede  * used sofar) but uses the rsb bus. These functions abstract this.
22*bdcdf846SHans de Goede  */
23*bdcdf846SHans de Goede static int pmic_bus_init(void)
24*bdcdf846SHans de Goede {
25*bdcdf846SHans de Goede #ifdef CONFIG_MACH_SUN6I
26*bdcdf846SHans de Goede 	p2wi_init();
27*bdcdf846SHans de Goede 	return p2wi_change_to_p2wi_mode(AXP221_CHIP_ADDR, AXP221_CTRL_ADDR,
28*bdcdf846SHans de Goede 					AXP221_INIT_DATA);
29*bdcdf846SHans de Goede #else
30*bdcdf846SHans de Goede 	int ret;
31*bdcdf846SHans de Goede 
32*bdcdf846SHans de Goede 	rsb_init();
33*bdcdf846SHans de Goede 
34*bdcdf846SHans de Goede 	ret = rsb_set_device_mode(AXP223_DEVICE_MODE_DATA);
35*bdcdf846SHans de Goede 	if (ret)
36*bdcdf846SHans de Goede 		return ret;
37*bdcdf846SHans de Goede 
38*bdcdf846SHans de Goede 	return rsb_set_device_address(AXP223_DEVICE_ADDR, AXP223_RUNTIME_ADDR);
39*bdcdf846SHans de Goede #endif
40*bdcdf846SHans de Goede }
41*bdcdf846SHans de Goede 
42*bdcdf846SHans de Goede static int pmic_bus_read(const u8 addr, u8 *data)
43*bdcdf846SHans de Goede {
44*bdcdf846SHans de Goede #ifdef CONFIG_MACH_SUN6I
45*bdcdf846SHans de Goede 	return p2wi_read(addr, data);
46*bdcdf846SHans de Goede #else
47*bdcdf846SHans de Goede 	return rsb_read(AXP223_RUNTIME_ADDR, addr, data);
48*bdcdf846SHans de Goede #endif
49*bdcdf846SHans de Goede }
50*bdcdf846SHans de Goede 
51*bdcdf846SHans de Goede static int pmic_bus_write(const u8 addr, u8 data)
52*bdcdf846SHans de Goede {
53*bdcdf846SHans de Goede #ifdef CONFIG_MACH_SUN6I
54*bdcdf846SHans de Goede 	return p2wi_write(addr, data);
55*bdcdf846SHans de Goede #else
56*bdcdf846SHans de Goede 	return rsb_write(AXP223_RUNTIME_ADDR, addr, data);
57*bdcdf846SHans de Goede #endif
58*bdcdf846SHans de Goede }
59*bdcdf846SHans de Goede 
605c7f10fdSOliver Schinagl static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div)
615c7f10fdSOliver Schinagl {
625c7f10fdSOliver Schinagl 	if (mvolt < min)
635c7f10fdSOliver Schinagl 		mvolt = min;
645c7f10fdSOliver Schinagl 	else if (mvolt > max)
655c7f10fdSOliver Schinagl 		mvolt = max;
665c7f10fdSOliver Schinagl 
675c7f10fdSOliver Schinagl 	return (mvolt - min) / div;
685c7f10fdSOliver Schinagl }
695c7f10fdSOliver Schinagl 
705c7f10fdSOliver Schinagl static int axp221_setbits(u8 reg, u8 bits)
715c7f10fdSOliver Schinagl {
725c7f10fdSOliver Schinagl 	int ret;
735c7f10fdSOliver Schinagl 	u8 val;
745c7f10fdSOliver Schinagl 
75*bdcdf846SHans de Goede 	ret = pmic_bus_read(reg, &val);
765c7f10fdSOliver Schinagl 	if (ret)
775c7f10fdSOliver Schinagl 		return ret;
785c7f10fdSOliver Schinagl 
795c7f10fdSOliver Schinagl 	val |= bits;
80*bdcdf846SHans de Goede 	return pmic_bus_write(reg, val);
815c7f10fdSOliver Schinagl }
825c7f10fdSOliver Schinagl 
835c7f10fdSOliver Schinagl int axp221_set_dcdc1(unsigned int mvolt)
845c7f10fdSOliver Schinagl {
855c7f10fdSOliver Schinagl 	int ret;
865c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100);
875c7f10fdSOliver Schinagl 
88*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_DCDC1_CTRL, cfg);
895c7f10fdSOliver Schinagl 	if (ret)
905c7f10fdSOliver Schinagl 		return ret;
915c7f10fdSOliver Schinagl 
925c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
935c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL2_DCDC1_EN);
945c7f10fdSOliver Schinagl }
955c7f10fdSOliver Schinagl 
965c7f10fdSOliver Schinagl int axp221_set_dcdc2(unsigned int mvolt)
975c7f10fdSOliver Schinagl {
985c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
995c7f10fdSOliver Schinagl 
100*bdcdf846SHans de Goede 	return pmic_bus_write(AXP221_DCDC2_CTRL, cfg);
1015c7f10fdSOliver Schinagl }
1025c7f10fdSOliver Schinagl 
1035c7f10fdSOliver Schinagl int axp221_set_dcdc3(unsigned int mvolt)
1045c7f10fdSOliver Schinagl {
1055c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20);
1065c7f10fdSOliver Schinagl 
107*bdcdf846SHans de Goede 	return pmic_bus_write(AXP221_DCDC3_CTRL, cfg);
1085c7f10fdSOliver Schinagl }
1095c7f10fdSOliver Schinagl 
1105c7f10fdSOliver Schinagl int axp221_set_dcdc4(unsigned int mvolt)
1115c7f10fdSOliver Schinagl {
1125c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20);
1135c7f10fdSOliver Schinagl 
114*bdcdf846SHans de Goede 	return pmic_bus_write(AXP221_DCDC4_CTRL, cfg);
1155c7f10fdSOliver Schinagl }
1165c7f10fdSOliver Schinagl 
1175c7f10fdSOliver Schinagl int axp221_set_dcdc5(unsigned int mvolt)
1185c7f10fdSOliver Schinagl {
1195c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50);
1205c7f10fdSOliver Schinagl 
121*bdcdf846SHans de Goede 	return pmic_bus_write(AXP221_DCDC5_CTRL, cfg);
1225c7f10fdSOliver Schinagl }
1235c7f10fdSOliver Schinagl 
1245c7f10fdSOliver Schinagl int axp221_set_dldo1(unsigned int mvolt)
1255c7f10fdSOliver Schinagl {
1265c7f10fdSOliver Schinagl 	int ret;
1275c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1285c7f10fdSOliver Schinagl 
129*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_DLDO1_CTRL, cfg);
1305c7f10fdSOliver Schinagl 	if (ret)
1315c7f10fdSOliver Schinagl 		return ret;
1325c7f10fdSOliver Schinagl 
1335c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
1345c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL2_DLDO1_EN);
1355c7f10fdSOliver Schinagl }
1365c7f10fdSOliver Schinagl 
1375c7f10fdSOliver Schinagl int axp221_set_dldo2(unsigned int mvolt)
1385c7f10fdSOliver Schinagl {
1395c7f10fdSOliver Schinagl 	int ret;
1405c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1415c7f10fdSOliver Schinagl 
142*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_DLDO2_CTRL, cfg);
1435c7f10fdSOliver Schinagl 	if (ret)
1445c7f10fdSOliver Schinagl 		return ret;
1455c7f10fdSOliver Schinagl 
1465c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
1475c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL2_DLDO2_EN);
1485c7f10fdSOliver Schinagl }
1495c7f10fdSOliver Schinagl 
1505c7f10fdSOliver Schinagl int axp221_set_dldo3(unsigned int mvolt)
1515c7f10fdSOliver Schinagl {
1525c7f10fdSOliver Schinagl 	int ret;
1535c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1545c7f10fdSOliver Schinagl 
155*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_DLDO3_CTRL, cfg);
1565c7f10fdSOliver Schinagl 	if (ret)
1575c7f10fdSOliver Schinagl 		return ret;
1585c7f10fdSOliver Schinagl 
1595c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
1605c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL2_DLDO3_EN);
1615c7f10fdSOliver Schinagl }
1625c7f10fdSOliver Schinagl 
1635c7f10fdSOliver Schinagl int axp221_set_dldo4(unsigned int mvolt)
1645c7f10fdSOliver Schinagl {
1655c7f10fdSOliver Schinagl 	int ret;
1665c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1675c7f10fdSOliver Schinagl 
168*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_DLDO4_CTRL, cfg);
1695c7f10fdSOliver Schinagl 	if (ret)
1705c7f10fdSOliver Schinagl 		return ret;
1715c7f10fdSOliver Schinagl 
1725c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL2,
1735c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL2_DLDO4_EN);
1745c7f10fdSOliver Schinagl }
1755c7f10fdSOliver Schinagl 
1765c7f10fdSOliver Schinagl int axp221_set_aldo1(unsigned int mvolt)
1775c7f10fdSOliver Schinagl {
1785c7f10fdSOliver Schinagl 	int ret;
1795c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1805c7f10fdSOliver Schinagl 
181*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_ALDO1_CTRL, cfg);
1825c7f10fdSOliver Schinagl 	if (ret)
1835c7f10fdSOliver Schinagl 		return ret;
1845c7f10fdSOliver Schinagl 
1855c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
1865c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL1_ALDO1_EN);
1875c7f10fdSOliver Schinagl }
1885c7f10fdSOliver Schinagl 
1895c7f10fdSOliver Schinagl int axp221_set_aldo2(unsigned int mvolt)
1905c7f10fdSOliver Schinagl {
1915c7f10fdSOliver Schinagl 	int ret;
1925c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
1935c7f10fdSOliver Schinagl 
194*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_ALDO2_CTRL, cfg);
1955c7f10fdSOliver Schinagl 	if (ret)
1965c7f10fdSOliver Schinagl 		return ret;
1975c7f10fdSOliver Schinagl 
1985c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL1,
1995c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL1_ALDO2_EN);
2005c7f10fdSOliver Schinagl }
2015c7f10fdSOliver Schinagl 
2025c7f10fdSOliver Schinagl int axp221_set_aldo3(unsigned int mvolt)
2035c7f10fdSOliver Schinagl {
2045c7f10fdSOliver Schinagl 	int ret;
2055c7f10fdSOliver Schinagl 	u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100);
2065c7f10fdSOliver Schinagl 
207*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_ALDO3_CTRL, cfg);
2085c7f10fdSOliver Schinagl 	if (ret)
2095c7f10fdSOliver Schinagl 		return ret;
2105c7f10fdSOliver Schinagl 
2115c7f10fdSOliver Schinagl 	return axp221_setbits(AXP221_OUTPUT_CTRL3,
2125c7f10fdSOliver Schinagl 			      AXP221_OUTPUT_CTRL3_ALDO3_EN);
2135c7f10fdSOliver Schinagl }
2145c7f10fdSOliver Schinagl 
2155c7f10fdSOliver Schinagl int axp221_init(void)
2165c7f10fdSOliver Schinagl {
2175c7f10fdSOliver Schinagl 	u8 axp_chip_id;
2185c7f10fdSOliver Schinagl 	int ret;
2195c7f10fdSOliver Schinagl 
220*bdcdf846SHans de Goede 	ret = pmic_bus_init();
2215c7f10fdSOliver Schinagl 	if (ret)
2225c7f10fdSOliver Schinagl 		return ret;
2235c7f10fdSOliver Schinagl 
224*bdcdf846SHans de Goede 	ret = pmic_bus_read(AXP221_CHIP_ID, &axp_chip_id);
2255c7f10fdSOliver Schinagl 	if (ret)
2265c7f10fdSOliver Schinagl 		return ret;
2275c7f10fdSOliver Schinagl 
2285c7f10fdSOliver Schinagl 	if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17))
2295c7f10fdSOliver Schinagl 		return -ENODEV;
2305c7f10fdSOliver Schinagl 
2315c7f10fdSOliver Schinagl 	return 0;
2325c7f10fdSOliver Schinagl }
233f3fba566SHans de Goede 
234f3fba566SHans de Goede int axp221_get_sid(unsigned int *sid)
235f3fba566SHans de Goede {
236f3fba566SHans de Goede 	u8 *dest = (u8 *)sid;
237f3fba566SHans de Goede 	int i, ret;
238f3fba566SHans de Goede 
239f3fba566SHans de Goede 	ret = axp221_init();
240f3fba566SHans de Goede 	if (ret)
241f3fba566SHans de Goede 		return ret;
242f3fba566SHans de Goede 
243*bdcdf846SHans de Goede 	ret = pmic_bus_write(AXP221_PAGE, 1);
244f3fba566SHans de Goede 	if (ret)
245f3fba566SHans de Goede 		return ret;
246f3fba566SHans de Goede 
247f3fba566SHans de Goede 	for (i = 0; i < 16; i++) {
248*bdcdf846SHans de Goede 		ret = pmic_bus_read(AXP221_SID + i, &dest[i]);
249f3fba566SHans de Goede 		if (ret)
250f3fba566SHans de Goede 			return ret;
251f3fba566SHans de Goede 	}
252f3fba566SHans de Goede 
253*bdcdf846SHans de Goede 	pmic_bus_write(AXP221_PAGE, 0);
254f3fba566SHans de Goede 
255f3fba566SHans de Goede 	for (i = 0; i < 4; i++)
256f3fba566SHans de Goede 		sid[i] = be32_to_cpu(sid[i]);
257f3fba566SHans de Goede 
258f3fba566SHans de Goede 	return 0;
259f3fba566SHans de Goede }
260