Home | History | Annotate | Download | only in power
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2012
      4  * Henrik Nordstrom <henrik (at) henriknordstrom.net>
      5  */
      6 
      7 #include <common.h>
      8 #include <command.h>
      9 #include <asm/arch/pmic_bus.h>
     10 #include <axp_pmic.h>
     11 
     12 static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div)
     13 {
     14 	if (mvolt < min)
     15 		mvolt = min;
     16 	else if (mvolt > max)
     17 		mvolt = max;
     18 
     19 	return (mvolt - min) / div;
     20 }
     21 
     22 int axp_set_dcdc2(unsigned int mvolt)
     23 {
     24 	int rc;
     25 	u8 cfg, current;
     26 
     27 	if (mvolt == 0)
     28 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
     29 					AXP209_OUTPUT_CTRL_DCDC2);
     30 
     31 	rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2);
     32 	if (rc)
     33 		return rc;
     34 
     35 	cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25);
     36 
     37 	/* Do we really need to be this gentle? It has built-in voltage slope */
     38 	while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, &current)) == 0 &&
     39 	       current != cfg) {
     40 		if (current < cfg)
     41 			current++;
     42 		else
     43 			current--;
     44 
     45 		rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current);
     46 		if (rc)
     47 			break;
     48 	}
     49 
     50 	return rc;
     51 }
     52 
     53 int axp_set_dcdc3(unsigned int mvolt)
     54 {
     55 	u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
     56 	int rc;
     57 
     58 	if (mvolt == 0)
     59 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
     60 					AXP209_OUTPUT_CTRL_DCDC3);
     61 
     62 	rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg);
     63 	if (rc)
     64 		return rc;
     65 
     66 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3);
     67 }
     68 
     69 int axp_set_aldo2(unsigned int mvolt)
     70 {
     71 	int rc;
     72 	u8 cfg, reg;
     73 
     74 	if (mvolt == 0)
     75 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
     76 					AXP209_OUTPUT_CTRL_LDO2);
     77 
     78 	cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100);
     79 
     80 	rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
     81 	if (rc)
     82 		return rc;
     83 
     84 	/* LDO2 configuration is in upper 4 bits */
     85 	reg = (reg & 0x0f) | (cfg << 4);
     86 	rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
     87 	if (rc)
     88 		return rc;
     89 
     90 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2);
     91 }
     92 
     93 int axp_set_aldo3(unsigned int mvolt)
     94 {
     95 	u8 cfg;
     96 	int rc;
     97 
     98 	if (mvolt == 0)
     99 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
    100 					AXP209_OUTPUT_CTRL_LDO3);
    101 
    102 	if (mvolt == -1)
    103 		cfg = 0x80;	/* determined by LDO3IN pin */
    104 	else
    105 		cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25);
    106 
    107 	rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg);
    108 	if (rc)
    109 		return rc;
    110 
    111 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3);
    112 }
    113 
    114 int axp_set_aldo4(unsigned int mvolt)
    115 {
    116 	int rc;
    117 	static const unsigned int vindex[] = {
    118 		1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500,
    119 		2700, 2800, 3000, 3100, 3200, 3300
    120 	};
    121 	u8 cfg, reg;
    122 
    123 	if (mvolt == 0)
    124 		return pmic_bus_clrbits(AXP209_OUTPUT_CTRL,
    125 					AXP209_OUTPUT_CTRL_LDO4);
    126 
    127 	/* Translate mvolt to register cfg value, requested <= selected */
    128 	for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--);
    129 
    130 	rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, &reg);
    131 	if (rc)
    132 		return rc;
    133 
    134 	/* LDO4 configuration is in lower 4 bits */
    135 	reg = (reg & 0xf0) | (cfg << 0);
    136 	rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg);
    137 	if (rc)
    138 		return rc;
    139 
    140 	return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4);
    141 }
    142 
    143 int axp_init(void)
    144 {
    145 	u8 ver;
    146 	int i, rc;
    147 
    148 	rc = pmic_bus_init();
    149 	if (rc)
    150 		return rc;
    151 
    152 	rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver);
    153 	if (rc)
    154 		return rc;
    155 
    156 	/* Low 4 bits is chip version */
    157 	ver &= 0x0f;
    158 
    159 	if (ver != 0x1)
    160 		return -EINVAL;
    161 
    162 	/* Mask all interrupts */
    163 	for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) {
    164 		rc = pmic_bus_write(i, 0);
    165 		if (rc)
    166 			return rc;
    167 	}
    168 
    169 	/*
    170 	 * Turn off LDOIO regulators / tri-state GPIO pins, when rebooting
    171 	 * from android these are sometimes on.
    172 	 */
    173 	rc = pmic_bus_write(AXP_GPIO0_CTRL, AXP_GPIO_CTRL_INPUT);
    174 	if (rc)
    175 		return rc;
    176 
    177 	rc = pmic_bus_write(AXP_GPIO1_CTRL, AXP_GPIO_CTRL_INPUT);
    178 	if (rc)
    179 		return rc;
    180 
    181 	rc = pmic_bus_write(AXP_GPIO2_CTRL, AXP_GPIO_CTRL_INPUT);
    182 	if (rc)
    183 		return rc;
    184 
    185 	return 0;
    186 }
    187 
    188 int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
    189 {
    190 	pmic_bus_write(AXP209_SHUTDOWN, AXP209_POWEROFF);
    191 
    192 	/* infinite loop during shutdown */
    193 	while (1) {}
    194 
    195 	/* not reached */
    196 	return 0;
    197 }
    198