1 /* 2 * (C) Copyright 2012 3 * Henrik Nordstrom <henrik@henriknordstrom.net> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <i2c.h> 10 #include <axp209.h> 11 12 enum axp209_reg { 13 AXP209_POWER_STATUS = 0x00, 14 AXP209_CHIP_VERSION = 0x03, 15 AXP209_DCDC2_VOLTAGE = 0x23, 16 AXP209_DCDC3_VOLTAGE = 0x27, 17 AXP209_LDO24_VOLTAGE = 0x28, 18 AXP209_LDO3_VOLTAGE = 0x29, 19 AXP209_IRQ_STATUS5 = 0x4c, 20 AXP209_SHUTDOWN = 0x32, 21 AXP209_GPIO0_CTRL = 0x90, 22 AXP209_GPIO1_CTRL = 0x92, 23 AXP209_GPIO2_CTRL = 0x93, 24 AXP209_GPIO_STATE = 0x94, 25 AXP209_GPIO3_CTRL = 0x95, 26 }; 27 28 #define AXP209_POWER_STATUS_ON_BY_DC (1 << 0) 29 30 #define AXP209_IRQ5_PEK_UP (1 << 6) 31 #define AXP209_IRQ5_PEK_DOWN (1 << 5) 32 33 #define AXP209_POWEROFF (1 << 7) 34 35 #define AXP209_GPIO_OUTPUT_LOW 0x00 /* Drive pin low */ 36 #define AXP209_GPIO_OUTPUT_HIGH 0x01 /* Drive pin high */ 37 #define AXP209_GPIO_INPUT 0x02 /* Float pin */ 38 39 /* GPIO3 is different from the others */ 40 #define AXP209_GPIO3_OUTPUT_LOW 0x00 /* Drive pin low, Output mode */ 41 #define AXP209_GPIO3_OUTPUT_HIGH 0x02 /* Float pin, Output mode */ 42 #define AXP209_GPIO3_INPUT 0x06 /* Float pin, Input mode */ 43 44 static int axp209_write(enum axp209_reg reg, u8 val) 45 { 46 return i2c_write(0x34, reg, 1, &val, 1); 47 } 48 49 static int axp209_read(enum axp209_reg reg, u8 *val) 50 { 51 return i2c_read(0x34, reg, 1, val, 1); 52 } 53 54 static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div) 55 { 56 if (mvolt < min) 57 mvolt = min; 58 else if (mvolt > max) 59 mvolt = max; 60 61 return (mvolt - min) / div; 62 } 63 64 int axp209_set_dcdc2(int mvolt) 65 { 66 int rc; 67 u8 cfg, current; 68 69 cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25); 70 71 /* Do we really need to be this gentle? It has built-in voltage slope */ 72 while ((rc = axp209_read(AXP209_DCDC2_VOLTAGE, ¤t)) == 0 && 73 current != cfg) { 74 if (current < cfg) 75 current++; 76 else 77 current--; 78 79 rc = axp209_write(AXP209_DCDC2_VOLTAGE, current); 80 if (rc) 81 break; 82 } 83 84 return rc; 85 } 86 87 int axp209_set_dcdc3(int mvolt) 88 { 89 u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25); 90 91 return axp209_write(AXP209_DCDC3_VOLTAGE, cfg); 92 } 93 94 int axp209_set_ldo2(int mvolt) 95 { 96 int rc; 97 u8 cfg, reg; 98 99 cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100); 100 101 rc = axp209_read(AXP209_LDO24_VOLTAGE, ®); 102 if (rc) 103 return rc; 104 105 /* LDO2 configuration is in upper 4 bits */ 106 reg = (reg & 0x0f) | (cfg << 4); 107 return axp209_write(AXP209_LDO24_VOLTAGE, reg); 108 } 109 110 int axp209_set_ldo3(int mvolt) 111 { 112 u8 cfg; 113 114 if (mvolt == -1) 115 cfg = 0x80; /* determined by LDO3IN pin */ 116 else 117 cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25); 118 119 return axp209_write(AXP209_LDO3_VOLTAGE, cfg); 120 } 121 122 int axp209_set_ldo4(int mvolt) 123 { 124 int rc; 125 static const int vindex[] = { 126 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500, 127 2700, 2800, 3000, 3100, 3200, 3300 128 }; 129 u8 cfg, reg; 130 131 /* Translate mvolt to register cfg value, requested <= selected */ 132 for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--); 133 134 rc = axp209_read(AXP209_LDO24_VOLTAGE, ®); 135 if (rc) 136 return rc; 137 138 /* LDO4 configuration is in lower 4 bits */ 139 reg = (reg & 0xf0) | (cfg << 0); 140 return axp209_write(AXP209_LDO24_VOLTAGE, reg); 141 } 142 143 int axp209_init(void) 144 { 145 u8 ver; 146 int rc; 147 148 rc = axp209_read(AXP209_CHIP_VERSION, &ver); 149 if (rc) 150 return rc; 151 152 /* Low 4 bits is chip version */ 153 ver &= 0x0f; 154 155 if (ver != 0x1) 156 return -1; 157 158 return 0; 159 } 160 161 int axp209_poweron_by_dc(void) 162 { 163 u8 v; 164 165 if (axp209_read(AXP209_POWER_STATUS, &v)) 166 return 0; 167 168 return (v & AXP209_POWER_STATUS_ON_BY_DC); 169 } 170 171 int axp209_power_button(void) 172 { 173 u8 v; 174 175 if (axp209_read(AXP209_IRQ_STATUS5, &v)) 176 return 0; 177 178 axp209_write(AXP209_IRQ_STATUS5, AXP209_IRQ5_PEK_DOWN); 179 180 return v & AXP209_IRQ5_PEK_DOWN; 181 } 182 183 static u8 axp209_get_gpio_ctrl_reg(unsigned int pin) 184 { 185 switch (pin) { 186 case 0: return AXP209_GPIO0_CTRL; 187 case 1: return AXP209_GPIO1_CTRL; 188 case 2: return AXP209_GPIO2_CTRL; 189 case 3: return AXP209_GPIO3_CTRL; 190 } 191 return 0; 192 } 193 194 int axp_gpio_direction_input(unsigned int pin) 195 { 196 u8 reg = axp209_get_gpio_ctrl_reg(pin); 197 /* GPIO3 is "special" */ 198 u8 val = (pin == 3) ? AXP209_GPIO3_INPUT : AXP209_GPIO_INPUT; 199 200 return axp209_write(reg, val); 201 } 202 203 int axp_gpio_direction_output(unsigned int pin, unsigned int val) 204 { 205 u8 reg = axp209_get_gpio_ctrl_reg(pin); 206 207 if (val) { 208 val = (pin == 3) ? AXP209_GPIO3_OUTPUT_HIGH : 209 AXP209_GPIO_OUTPUT_HIGH; 210 } else { 211 val = (pin == 3) ? AXP209_GPIO3_OUTPUT_LOW : 212 AXP209_GPIO_OUTPUT_LOW; 213 } 214 215 return axp209_write(reg, val); 216 } 217 218 int axp_gpio_get_value(unsigned int pin) 219 { 220 u8 val, mask; 221 int rc; 222 223 if (pin == 3) { 224 rc = axp209_read(AXP209_GPIO3_CTRL, &val); 225 mask = 1; 226 } else { 227 rc = axp209_read(AXP209_GPIO_STATE, &val); 228 mask = 1 << (pin + 4); 229 } 230 if (rc) 231 return rc; 232 233 return (val & mask) ? 1 : 0; 234 } 235 236 int axp_gpio_set_value(unsigned int pin, unsigned int val) 237 { 238 return axp_gpio_direction_output(pin, val); 239 } 240