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