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