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