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