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