summaryrefslogtreecommitdiff
path: root/firmware/drivers/axp-pmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/axp-pmu.c')
-rw-r--r--firmware/drivers/axp-pmu.c146
1 files changed, 28 insertions, 118 deletions
diff --git a/firmware/drivers/axp-pmu.c b/firmware/drivers/axp-pmu.c
index ed284ee9c2..d59fbb2e3f 100644
--- a/firmware/drivers/axp-pmu.c
+++ b/firmware/drivers/axp-pmu.c
@@ -36,6 +36,8 @@ struct axp_adc_info {
36 uint8_t reg; 36 uint8_t reg;
37 uint8_t en_reg; 37 uint8_t en_reg;
38 uint8_t en_bit; 38 uint8_t en_bit;
39 int8_t num;
40 int8_t den;
39}; 41};
40 42
41struct axp_supply_info { 43struct axp_supply_info {
@@ -49,17 +51,16 @@ struct axp_supply_info {
49}; 51};
50 52
51static const struct axp_adc_info axp_adc_info[NUM_ADC_CHANNELS] = { 53static const struct axp_adc_info axp_adc_info[NUM_ADC_CHANNELS] = {
52 {0x56, AXP_REG_ADCENABLE1, 5}, /* ACIN_VOLTAGE */ 54 [ADC_ACIN_VOLTAGE] = {0x56, AXP_REG_ADCENABLE1, 1 << 5, 17, 10},
53 {0x58, AXP_REG_ADCENABLE1, 4}, /* ACIN_CURRENT */ 55 [ADC_ACIN_CURRENT] = {0x58, AXP_REG_ADCENABLE1, 1 << 4, 5, 8},
54 {0x5a, AXP_REG_ADCENABLE1, 3}, /* VBUS_VOLTAGE */ 56 [ADC_VBUS_VOLTAGE] = {0x5a, AXP_REG_ADCENABLE1, 1 << 3, 17, 10},
55 {0x5c, AXP_REG_ADCENABLE1, 2}, /* VBUS_CURRENT */ 57 [ADC_VBUS_CURRENT] = {0x5c, AXP_REG_ADCENABLE1, 1 << 2, 3, 8},
56 {0x5e, AXP_REG_ADCENABLE2, 7}, /* INTERNAL_TEMP */ 58 [ADC_INTERNAL_TEMP] = {0x5e, AXP_REG_ADCENABLE2, 1 << 7, 0, 0},
57 {0x62, AXP_REG_ADCENABLE1, 1}, /* TS_INPUT */ 59 [ADC_TS_INPUT] = {0x62, AXP_REG_ADCENABLE1, 1 << 1, 4, 5},
58 {0x78, AXP_REG_ADCENABLE1, 7}, /* BATTERY_VOLTAGE */ 60 [ADC_BATTERY_VOLTAGE] = {0x78, AXP_REG_ADCENABLE1, 1 << 7, 11, 10},
59 {0x7a, AXP_REG_ADCENABLE1, 6}, /* CHARGE_CURRENT */ 61 [ADC_CHARGE_CURRENT] = {0x7a, AXP_REG_ADCENABLE1, 1 << 6, 1, 2},
60 {0x7c, AXP_REG_ADCENABLE1, 6}, /* DISCHARGE_CURRENT */ 62 [ADC_DISCHARGE_CURRENT] = {0x7c, AXP_REG_ADCENABLE1, 1 << 6, 1, 2},
61 {0x7e, AXP_REG_ADCENABLE1, 1}, /* APS_VOLTAGE */ 63 [ADC_APS_VOLTAGE] = {0x7e, AXP_REG_ADCENABLE1, 1 << 1, 7, 5},
62 {0x70, 0xff, 0}, /* BATTERY_POWER */
63}; 64};
64 65
65static const struct axp_supply_info axp_supply_info[AXP_NUM_SUPPLIES] = { 66static const struct axp_supply_info axp_supply_info[AXP_NUM_SUPPLIES] = {
@@ -126,46 +127,8 @@ static const struct axp_supply_info axp_supply_info[AXP_NUM_SUPPLIES] = {
126#endif 127#endif
127}; 128};
128 129
129static struct axp_driver {
130 int adc_enable;
131} axp;
132
133static void axp_init_enabled_adcs(void)
134{
135 axp.adc_enable = 0;
136
137 /* Read enabled ADCs from the hardware */
138 uint8_t regs[2];
139 int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR,
140 AXP_REG_ADCENABLE1, 2, &regs[0]);
141 if(rc != I2C_STATUS_OK)
142 return;
143
144 /* Parse registers to set ADC enable bits */
145 const struct axp_adc_info* info = axp_adc_info;
146 for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
147 if(info[i].en_reg == 0xff)
148 continue;
149
150 if(regs[info[i].en_reg - AXP_REG_ADCENABLE1] & info[i].en_bit)
151 axp.adc_enable |= 1 << i;
152 }
153
154 /* Handle battery power ADC */
155 if((axp.adc_enable & (1 << ADC_BATTERY_VOLTAGE)) &&
156 (axp.adc_enable & (1 << ADC_DISCHARGE_CURRENT))) {
157 axp.adc_enable |= (1 << ADC_BATTERY_POWER);
158 }
159}
160
161void axp_init(void) 130void axp_init(void)
162{ 131{
163 axp_init_enabled_adcs();
164
165 /* We need discharge current ADC to reliably poll for a full battery */
166 int bits = axp.adc_enable;
167 bits |= (1 << ADC_DISCHARGE_CURRENT);
168 axp_adc_set_enabled(bits);
169} 132}
170 133
171void axp_supply_set_voltage(int supply, int voltage) 134void axp_supply_set_voltage(int supply, int voltage)
@@ -294,22 +257,15 @@ int axp_adc_read(int adc)
294 257
295int axp_adc_read_raw(int adc) 258int axp_adc_read_raw(int adc)
296{ 259{
297 /* Don't give a reading if the ADC is not enabled */
298 if((axp.adc_enable & (1 << adc)) == 0)
299 return INT_MIN;
300
301 /* Read the ADC */ 260 /* Read the ADC */
302 uint8_t buf[3]; 261 uint8_t buf[2];
303 int count = (adc == ADC_BATTERY_POWER) ? 3 : 2;
304 uint8_t reg = axp_adc_info[adc].reg; 262 uint8_t reg = axp_adc_info[adc].reg;
305 int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, reg, count, &buf[0]); 263 int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, reg, 2, &buf[0]);
306 if(rc != I2C_STATUS_OK) 264 if(rc != I2C_STATUS_OK)
307 return INT_MIN; 265 return INT_MIN;
308 266
309 /* Parse the value */ 267 /* Parse the value */
310 if(adc == ADC_BATTERY_POWER) 268 if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT)
311 return (buf[0] << 16) | (buf[1] << 8) | buf[2];
312 else if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT)
313 return (buf[0] << 5) | (buf[1] & 0x1f); 269 return (buf[0] << 5) | (buf[1] & 0x1f);
314 else 270 else
315 return (buf[0] << 4) | (buf[1] & 0xf); 271 return (buf[0] << 4) | (buf[1] & 0xf);
@@ -317,79 +273,33 @@ int axp_adc_read_raw(int adc)
317 273
318int axp_adc_conv_raw(int adc, int value) 274int axp_adc_conv_raw(int adc, int value)
319{ 275{
320 switch(adc) { 276 if(adc == ADC_INTERNAL_TEMP)
321 case ADC_ACIN_VOLTAGE:
322 case ADC_VBUS_VOLTAGE:
323 /* 0 mV ... 6.9615 mV, step 1.7 mV */
324 return value * 17 / 10;
325 case ADC_ACIN_CURRENT:
326 /* 0 mA ... 2.5594 A, step 0.625 mA */
327 return value * 5 / 8;
328 case ADC_VBUS_CURRENT:
329 /* 0 mA ... 1.5356 A, step 0.375 mA */
330 return value * 3 / 8;
331 case ADC_INTERNAL_TEMP:
332 /* -144.7 C ... 264.8 C, step 0.1 C */
333 return value - 1447; 277 return value - 1447;
334 case ADC_TS_INPUT: 278 else
335 /* 0 mV ... 3.276 V, step 0.8 mV */ 279 return axp_adc_info[adc].num * value / axp_adc_info[adc].den;
336 return value * 4 / 5;
337 case ADC_BATTERY_VOLTAGE:
338 /* 0 mV ... 4.5045 V, step 1.1 mV */
339 return value * 11 / 10;
340 case ADC_CHARGE_CURRENT:
341 case ADC_DISCHARGE_CURRENT:
342 /* 0 mA to 4.095 A, step 0.5 mA */
343 return value / 2;
344 case ADC_APS_VOLTAGE:
345 /* 0 mV to 5.733 V, step 1.4 mV */
346 return value * 7 / 5;
347 case ADC_BATTERY_POWER:
348 /* 0 uW to 23.6404 W, step 0.55 uW */
349 return value * 11 / 20;
350 default:
351 /* Shouldn't happen */
352 return INT_MIN;
353 }
354}
355
356int axp_adc_get_enabled(void)
357{
358 return axp.adc_enable;
359} 280}
360 281
361void axp_adc_set_enabled(int adc_bits) 282void axp_adc_set_enabled(int adc_bits)
362{ 283{
363 /* Ignore no-op */ 284 uint8_t xfer[3];
364 if(adc_bits == axp.adc_enable) 285 xfer[0] = 0;
365 return; 286 xfer[1] = AXP_REG_ADCENABLE2;
287 xfer[2] = 0;
366 288
367 /* Compute the new register values */ 289 /* Compute the new register values */
368 const struct axp_adc_info* info = axp_adc_info; 290 const struct axp_adc_info* info = axp_adc_info;
369 uint8_t regs[2] = {0, 0};
370 for(int i = 0; i < NUM_ADC_CHANNELS; ++i) { 291 for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
371 if(info[i].en_reg == 0xff) 292 if(!(adc_bits & (1 << i)))
372 continue; 293 continue;
373 294
374 if(adc_bits & (1 << i)) 295 if(info[i].en_reg == AXP_REG_ADCENABLE1)
375 regs[info[i].en_reg - 0x82] |= 1 << info[i].en_bit; 296 xfer[0] |= info[i].en_bit;
376 } 297 else
377 298 xfer[2] |= info[i].en_bit;
378 /* These ADCs share an enable bit */
379 if(adc_bits & ((1 << ADC_CHARGE_CURRENT)|(1 << ADC_DISCHARGE_CURRENT))) {
380 adc_bits |= (1 << ADC_CHARGE_CURRENT);
381 adc_bits |= (1 << ADC_DISCHARGE_CURRENT);
382 }
383
384 /* Enable required bits for battery power ADC */
385 if(adc_bits & (1 << ADC_BATTERY_POWER)) {
386 regs[0] |= 1 << info[ADC_DISCHARGE_CURRENT].en_bit;
387 regs[0] |= 1 << info[ADC_BATTERY_VOLTAGE].en_bit;
388 } 299 }
389 300
390 /* Update the configuration */ 301 /* Update the configuration */
391 i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCENABLE1, 2, &regs[0]); 302 i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCENABLE1, 3, &xfer[0]);
392 axp.adc_enable = adc_bits;
393} 303}
394 304
395int axp_adc_get_rate(void) 305int axp_adc_get_rate(void)