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