xref: /arm-trusted-firmware/drivers/allwinner/axp/common.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <errno.h>
8*91f16700Schasinglulu 
9*91f16700Schasinglulu #include <libfdt.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <common/debug.h>
12*91f16700Schasinglulu #include <common/fdt_wrappers.h>
13*91f16700Schasinglulu #include <drivers/allwinner/axp.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu int axp_check_id(void)
16*91f16700Schasinglulu {
17*91f16700Schasinglulu 	int ret;
18*91f16700Schasinglulu 
19*91f16700Schasinglulu 	ret = axp_read(0x03);
20*91f16700Schasinglulu 	if (ret < 0)
21*91f16700Schasinglulu 		return ret;
22*91f16700Schasinglulu 
23*91f16700Schasinglulu 	ret &= 0xcf;
24*91f16700Schasinglulu 	if (ret != axp_chip_id) {
25*91f16700Schasinglulu 		ERROR("PMIC: Found unknown PMIC %02x\n", ret);
26*91f16700Schasinglulu 		return ret;
27*91f16700Schasinglulu 	}
28*91f16700Schasinglulu 
29*91f16700Schasinglulu 	return 0;
30*91f16700Schasinglulu }
31*91f16700Schasinglulu 
32*91f16700Schasinglulu int axp_clrsetbits(uint8_t reg, uint8_t clr_mask, uint8_t set_mask)
33*91f16700Schasinglulu {
34*91f16700Schasinglulu 	uint8_t val;
35*91f16700Schasinglulu 	int ret;
36*91f16700Schasinglulu 
37*91f16700Schasinglulu 	ret = axp_read(reg);
38*91f16700Schasinglulu 	if (ret < 0)
39*91f16700Schasinglulu 		return ret;
40*91f16700Schasinglulu 
41*91f16700Schasinglulu 	val = (ret & ~clr_mask) | set_mask;
42*91f16700Schasinglulu 
43*91f16700Schasinglulu 	return axp_write(reg, val);
44*91f16700Schasinglulu }
45*91f16700Schasinglulu 
46*91f16700Schasinglulu void axp_power_off(void)
47*91f16700Schasinglulu {
48*91f16700Schasinglulu 	/* Set "power disable control" bit */
49*91f16700Schasinglulu 	axp_setbits(0x32, BIT(7));
50*91f16700Schasinglulu }
51*91f16700Schasinglulu 
52*91f16700Schasinglulu #if SUNXI_SETUP_REGULATORS == 1
53*91f16700Schasinglulu /*
54*91f16700Schasinglulu  * Retrieve the voltage from a given regulator DTB node.
55*91f16700Schasinglulu  * Both the regulator-{min,max}-microvolt properties must be present and
56*91f16700Schasinglulu  * have the same value. Return that value in millivolts.
57*91f16700Schasinglulu  */
58*91f16700Schasinglulu static int fdt_get_regulator_millivolt(const void *fdt, int node)
59*91f16700Schasinglulu {
60*91f16700Schasinglulu 	const fdt32_t *prop;
61*91f16700Schasinglulu 	uint32_t min_volt;
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 	prop = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL);
64*91f16700Schasinglulu 	if (prop == NULL)
65*91f16700Schasinglulu 		return -EINVAL;
66*91f16700Schasinglulu 	min_volt = fdt32_to_cpu(*prop);
67*91f16700Schasinglulu 
68*91f16700Schasinglulu 	prop = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL);
69*91f16700Schasinglulu 	if (prop == NULL)
70*91f16700Schasinglulu 		return -EINVAL;
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	if (fdt32_to_cpu(*prop) != min_volt)
73*91f16700Schasinglulu 		return -EINVAL;
74*91f16700Schasinglulu 
75*91f16700Schasinglulu 	return min_volt / 1000;
76*91f16700Schasinglulu }
77*91f16700Schasinglulu 
78*91f16700Schasinglulu static int setup_regulator(const void *fdt, int node,
79*91f16700Schasinglulu 			   const struct axp_regulator *reg)
80*91f16700Schasinglulu {
81*91f16700Schasinglulu 	uint8_t val;
82*91f16700Schasinglulu 	int mvolt;
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	mvolt = fdt_get_regulator_millivolt(fdt, node);
85*91f16700Schasinglulu 	if (mvolt < reg->min_volt || mvolt > reg->max_volt)
86*91f16700Schasinglulu 		return -EINVAL;
87*91f16700Schasinglulu 
88*91f16700Schasinglulu 	val = (mvolt / reg->step) - (reg->min_volt / reg->step);
89*91f16700Schasinglulu 	if (val > reg->split)
90*91f16700Schasinglulu 		val = ((val - reg->split) / 2) + reg->split;
91*91f16700Schasinglulu 
92*91f16700Schasinglulu 	axp_write(reg->volt_reg, val);
93*91f16700Schasinglulu 	axp_setbits(reg->switch_reg, BIT(reg->switch_bit));
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 	INFO("PMIC: %s voltage: %d.%03dV\n", reg->dt_name,
96*91f16700Schasinglulu 	     mvolt / 1000, mvolt % 1000);
97*91f16700Schasinglulu 
98*91f16700Schasinglulu 	return 0;
99*91f16700Schasinglulu }
100*91f16700Schasinglulu 
101*91f16700Schasinglulu static bool should_enable_regulator(const void *fdt, int node)
102*91f16700Schasinglulu {
103*91f16700Schasinglulu 	if (!fdt_node_is_enabled(fdt, node)) {
104*91f16700Schasinglulu 		return false;
105*91f16700Schasinglulu 	}
106*91f16700Schasinglulu 	if (fdt_getprop(fdt, node, "phandle", NULL) != NULL) {
107*91f16700Schasinglulu 		return true;
108*91f16700Schasinglulu 	}
109*91f16700Schasinglulu 	if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL) {
110*91f16700Schasinglulu 		return true;
111*91f16700Schasinglulu 	}
112*91f16700Schasinglulu 	return false;
113*91f16700Schasinglulu }
114*91f16700Schasinglulu 
115*91f16700Schasinglulu static bool board_uses_usb0_host_mode(const void *fdt)
116*91f16700Schasinglulu {
117*91f16700Schasinglulu 	int node, length;
118*91f16700Schasinglulu 	const char *prop;
119*91f16700Schasinglulu 
120*91f16700Schasinglulu 	node = fdt_node_offset_by_compatible(fdt, -1,
121*91f16700Schasinglulu 					     "allwinner,sun8i-a33-musb");
122*91f16700Schasinglulu 	if (node < 0) {
123*91f16700Schasinglulu 		return false;
124*91f16700Schasinglulu 	}
125*91f16700Schasinglulu 
126*91f16700Schasinglulu 	prop = fdt_getprop(fdt, node, "dr_mode", &length);
127*91f16700Schasinglulu 	if (!prop) {
128*91f16700Schasinglulu 		return false;
129*91f16700Schasinglulu 	}
130*91f16700Schasinglulu 
131*91f16700Schasinglulu 	return !strncmp(prop, "host", length);
132*91f16700Schasinglulu }
133*91f16700Schasinglulu 
134*91f16700Schasinglulu void axp_setup_regulators(const void *fdt)
135*91f16700Schasinglulu {
136*91f16700Schasinglulu 	int node;
137*91f16700Schasinglulu 	bool sw = false;
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 	if (fdt == NULL)
140*91f16700Schasinglulu 		return;
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	/* locate the PMIC DT node, bail out if not found */
143*91f16700Schasinglulu 	node = fdt_node_offset_by_compatible(fdt, -1, axp_compatible);
144*91f16700Schasinglulu 	if (node < 0) {
145*91f16700Schasinglulu 		WARN("PMIC: No PMIC DT node, skipping setup\n");
146*91f16700Schasinglulu 		return;
147*91f16700Schasinglulu 	}
148*91f16700Schasinglulu 
149*91f16700Schasinglulu 	/* This applies to AXP803 only. */
150*91f16700Schasinglulu 	if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL) &&
151*91f16700Schasinglulu 	    board_uses_usb0_host_mode(fdt)) {
152*91f16700Schasinglulu 		axp_clrbits(0x8f, BIT(4));
153*91f16700Schasinglulu 		axp_setbits(0x30, BIT(2));
154*91f16700Schasinglulu 		INFO("PMIC: Enabling DRIVEVBUS\n");
155*91f16700Schasinglulu 	}
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	/* descend into the "regulators" subnode */
158*91f16700Schasinglulu 	node = fdt_subnode_offset(fdt, node, "regulators");
159*91f16700Schasinglulu 	if (node < 0) {
160*91f16700Schasinglulu 		WARN("PMIC: No regulators DT node, skipping setup\n");
161*91f16700Schasinglulu 		return;
162*91f16700Schasinglulu 	}
163*91f16700Schasinglulu 
164*91f16700Schasinglulu 	/* iterate over all regulators to find used ones */
165*91f16700Schasinglulu 	fdt_for_each_subnode(node, fdt, node) {
166*91f16700Schasinglulu 		const struct axp_regulator *reg;
167*91f16700Schasinglulu 		const char *name;
168*91f16700Schasinglulu 		int length;
169*91f16700Schasinglulu 
170*91f16700Schasinglulu 		/* We only care if it's always on or referenced. */
171*91f16700Schasinglulu 		if (!should_enable_regulator(fdt, node))
172*91f16700Schasinglulu 			continue;
173*91f16700Schasinglulu 
174*91f16700Schasinglulu 		name = fdt_get_name(fdt, node, &length);
175*91f16700Schasinglulu 
176*91f16700Schasinglulu 		/* Enable the switch last to avoid overheating. */
177*91f16700Schasinglulu 		if (!strncmp(name, "dc1sw", length) ||
178*91f16700Schasinglulu 		    !strncmp(name, "sw", length)) {
179*91f16700Schasinglulu 			sw = true;
180*91f16700Schasinglulu 			continue;
181*91f16700Schasinglulu 		}
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 		for (reg = axp_regulators; reg->dt_name; reg++) {
184*91f16700Schasinglulu 			if (!strncmp(name, reg->dt_name, length)) {
185*91f16700Schasinglulu 				setup_regulator(fdt, node, reg);
186*91f16700Schasinglulu 				break;
187*91f16700Schasinglulu 			}
188*91f16700Schasinglulu 		}
189*91f16700Schasinglulu 	}
190*91f16700Schasinglulu 
191*91f16700Schasinglulu 	/*
192*91f16700Schasinglulu 	 * On the AXP803, if DLDO2 is enabled after DC1SW, the PMIC overheats
193*91f16700Schasinglulu 	 * and shuts down. So always enable DC1SW as the very last regulator.
194*91f16700Schasinglulu 	 */
195*91f16700Schasinglulu 	if (sw) {
196*91f16700Schasinglulu 		INFO("PMIC: Enabling DC SW\n");
197*91f16700Schasinglulu 		if (axp_chip_id == AXP803_CHIP_ID)
198*91f16700Schasinglulu 			axp_setbits(0x12, BIT(7));
199*91f16700Schasinglulu 		if (axp_chip_id == AXP805_CHIP_ID)
200*91f16700Schasinglulu 			axp_setbits(0x11, BIT(7));
201*91f16700Schasinglulu 	}
202*91f16700Schasinglulu }
203*91f16700Schasinglulu #endif	/* SUNXI_SETUP_REGULATORS */
204