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 void axp_setup_regulators(const void *fdt) 109 { 110 int node; 111 bool sw = false; 112 113 if (fdt == NULL) 114 return; 115 116 /* locate the PMIC DT node, bail out if not found */ 117 node = fdt_node_offset_by_compatible(fdt, -1, axp_compatible); 118 if (node < 0) { 119 WARN("PMIC: No PMIC DT node, skipping setup\n"); 120 return; 121 } 122 123 /* This applies to AXP803 only. */ 124 if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) { 125 axp_clrbits(0x8f, BIT(4)); 126 axp_setbits(0x30, BIT(2)); 127 INFO("PMIC: Enabling DRIVEVBUS\n"); 128 } 129 130 /* descend into the "regulators" subnode */ 131 node = fdt_subnode_offset(fdt, node, "regulators"); 132 if (node < 0) { 133 WARN("PMIC: No regulators DT node, skipping setup\n"); 134 return; 135 } 136 137 /* iterate over all regulators to find used ones */ 138 fdt_for_each_subnode(node, fdt, node) { 139 const struct axp_regulator *reg; 140 const char *name; 141 int length; 142 143 /* We only care if it's always on or referenced. */ 144 if (!should_enable_regulator(fdt, node)) 145 continue; 146 147 name = fdt_get_name(fdt, node, &length); 148 149 /* Enable the switch last to avoid overheating. */ 150 if (!strncmp(name, "dc1sw", length) || 151 !strncmp(name, "sw", length)) { 152 sw = true; 153 continue; 154 } 155 156 for (reg = axp_regulators; reg->dt_name; reg++) { 157 if (!strncmp(name, reg->dt_name, length)) { 158 setup_regulator(fdt, node, reg); 159 break; 160 } 161 } 162 } 163 164 /* 165 * On the AXP803, if DLDO2 is enabled after DC1SW, the PMIC overheats 166 * and shuts down. So always enable DC1SW as the very last regulator. 167 */ 168 if (sw) { 169 INFO("PMIC: Enabling DC SW\n"); 170 if (axp_chip_id == AXP803_CHIP_ID) 171 axp_setbits(0x12, BIT(7)); 172 if (axp_chip_id == AXP805_CHIP_ID) 173 axp_setbits(0x11, BIT(7)); 174 } 175 } 176