summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/SOURCES4
-rw-r--r--firmware/drivers/axp-pmu.c670
-rw-r--r--firmware/drivers/axp192.c810
-rw-r--r--firmware/export/axp-pmu.h151
-rw-r--r--firmware/export/axp192-defs.h308
-rw-r--r--firmware/export/axp192.h131
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c10
-rw-r--r--firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c82
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c8
-rw-r--r--firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c80
-rw-r--r--firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c8
-rw-r--r--firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c70
12 files changed, 910 insertions, 1422 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 8868e4f21f..87db67d8fd 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -1947,8 +1947,8 @@ drivers/touchpad.c
1947#ifdef HAVE_I2C_ASYNC 1947#ifdef HAVE_I2C_ASYNC
1948drivers/i2c-async.c 1948drivers/i2c-async.c
1949#endif 1949#endif
1950#if defined(HAVE_AXP_PMU) && HAVE_AXP_PMU == 192 1950#ifdef HAVE_AXP_PMU
1951drivers/axp192.c 1951drivers/axp-pmu.c
1952#endif 1952#endif
1953#ifdef HAVE_FT6x06 1953#ifdef HAVE_FT6x06
1954drivers/ft6x06.c 1954drivers/ft6x06.c
diff --git a/firmware/drivers/axp-pmu.c b/firmware/drivers/axp-pmu.c
new file mode 100644
index 0000000000..fd1126dbbf
--- /dev/null
+++ b/firmware/drivers/axp-pmu.c
@@ -0,0 +1,670 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "axp-pmu.h"
23#include "power.h"
24#include "system.h"
25#include "i2c-async.h"
26#include <string.h>
27
28/* Headers for the debug menu */
29#ifndef BOOTLOADER
30# include "action.h"
31# include "list.h"
32# include <stdio.h>
33#endif
34
35struct axp_adc_info {
36 uint8_t reg;
37 uint8_t en_reg;
38 uint8_t en_bit;
39};
40
41struct axp_supply_info {
42 uint8_t volt_reg;
43 uint8_t volt_reg_mask;
44 uint8_t en_reg;
45 uint8_t en_bit;
46 int min_mV;
47 int max_mV;
48 int step_mV;
49};
50
51static const struct axp_adc_info axp_adc_info[NUM_ADC_CHANNELS] = {
52 {0x56, AXP_REG_ADCENABLE1, 5}, /* ACIN_VOLTAGE */
53 {0x58, AXP_REG_ADCENABLE1, 4}, /* ACIN_CURRENT */
54 {0x5a, AXP_REG_ADCENABLE1, 3}, /* VBUS_VOLTAGE */
55 {0x5c, AXP_REG_ADCENABLE1, 2}, /* VBUS_CURRENT */
56 {0x5e, AXP_REG_ADCENABLE2, 7}, /* INTERNAL_TEMP */
57 {0x62, AXP_REG_ADCENABLE1, 1}, /* TS_INPUT */
58 {0x78, AXP_REG_ADCENABLE1, 7}, /* BATTERY_VOLTAGE */
59 {0x7a, AXP_REG_ADCENABLE1, 6}, /* CHARGE_CURRENT */
60 {0x7c, AXP_REG_ADCENABLE1, 6}, /* DISCHARGE_CURRENT */
61 {0x7e, AXP_REG_ADCENABLE1, 1}, /* APS_VOLTAGE */
62 {0x70, 0xff, 0}, /* BATTERY_POWER */
63};
64
65static const struct axp_supply_info axp_supply_info[AXP_NUM_SUPPLIES] = {
66#if HAVE_AXP_PMU == 192
67 [AXP_SUPPLY_DCDC1] = {
68 .volt_reg = 0x26,
69 .volt_reg_mask = 0x7f,
70 .en_reg = 0x12,
71 .en_bit = 0,
72 .min_mV = 700,
73 .max_mV = 3500,
74 .step_mV = 25,
75 },
76 [AXP_SUPPLY_DCDC2] = {
77 .volt_reg = 0x23,
78 .volt_reg_mask = 0x3f,
79 .en_reg = 0x10,
80 .en_bit = 0,
81 .min_mV = 700,
82 .max_mV = 2275,
83 .step_mV = 25,
84 },
85 [AXP_SUPPLY_DCDC3] = {
86 .volt_reg = 0x27,
87 .volt_reg_mask = 0x7f,
88 .en_reg = 0x12,
89 .en_bit = 1,
90 .min_mV = 700,
91 .max_mV = 3500,
92 .step_mV = 25,
93 },
94 /*
95 * NOTE: LDO1 is always on, and we can't query it or change voltages
96 */
97 [AXP_SUPPLY_LDO2] = {
98 .volt_reg = 0x28,
99 .volt_reg_mask = 0xf0,
100 .en_reg = 0x12,
101 .en_bit = 2,
102 .min_mV = 1800,
103 .max_mV = 3300,
104 .step_mV = 100,
105 },
106 [AXP_SUPPLY_LDO3] = {
107 .volt_reg = 0x28,
108 .volt_reg_mask = 0x0f,
109 .en_reg = 0x12,
110 .en_bit = 3,
111 .min_mV = 1800,
112 .max_mV = 3300,
113 .step_mV = 100,
114 },
115 [AXP_SUPPLY_LDO_IO0] = {
116 .volt_reg = 0x91,
117 .volt_reg_mask = 0xf0,
118 .en_reg = 0x90,
119 .en_bit = 0xff, /* this one requires special handling */
120 .min_mV = 1800,
121 .max_mV = 3300,
122 .step_mV = 100,
123 },
124#else
125# error "Untested AXP chip"
126#endif
127};
128
129static struct axp_driver {
130 int adc_enable;
131 int chargecurrent_setting;
132 int chip_id;
133} axp;
134
135static void axp_init_enabled_adcs(void)
136{
137 axp.adc_enable = 0;
138
139 /* Read chip ID, so we can display it on the debug screen.
140 * This is undocumented but there's Linux driver code floating around
141 * which suggests this should work for many AXP chips. */
142 axp.chip_id = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHIP_ID);
143
144 /* Read enabled ADCs from the hardware */
145 uint8_t regs[2];
146 int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR,
147 AXP_REG_ADCENABLE1, 2, &regs[0]);
148 if(rc != I2C_STATUS_OK)
149 return;
150
151 /* Parse registers to set ADC enable bits */
152 const struct axp_adc_info* info = axp_adc_info;
153 for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
154 if(info[i].en_reg == 0xff)
155 continue;
156
157 if(regs[info[i].en_reg - AXP_REG_ADCENABLE1] & info[i].en_bit)
158 axp.adc_enable |= 1 << i;
159 }
160
161 /* Handle battery power ADC */
162 if((axp.adc_enable & (1 << ADC_BATTERY_VOLTAGE)) &&
163 (axp.adc_enable & (1 << ADC_DISCHARGE_CURRENT))) {
164 axp.adc_enable |= (1 << ADC_BATTERY_POWER);
165 }
166}
167
168void axp_init(void)
169{
170 axp_init_enabled_adcs();
171
172 /* We need discharge current ADC to reliably poll for a full battery */
173 int bits = axp.adc_enable;
174 bits |= (1 << ADC_DISCHARGE_CURRENT);
175 axp_adc_set_enabled(bits);
176
177 /* Read the maximum charging current */
178 int value = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHARGECONTROL1);
179 axp.chargecurrent_setting = (value < 0) ? -1 : (value & 0xf);
180}
181
182void axp_supply_set_voltage(int supply, int voltage)
183{
184 const struct axp_supply_info* info = &axp_supply_info[supply];
185 if(info->volt_reg == 0 || info->volt_reg_mask == 0)
186 return;
187
188 if(voltage > 0 && info->step_mV != 0) {
189 if(voltage < info->min_mV || voltage > info->max_mV)
190 return;
191
192 int regval = (voltage - info->min_mV) / info->step_mV;
193 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, info->volt_reg,
194 info->volt_reg_mask, regval, NULL);
195 }
196
197 if(info->en_bit != 0xff) {
198 i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
199 info->en_reg, info->en_bit,
200 voltage > 0 ? 1 : 0, NULL);
201 }
202}
203
204int axp_supply_get_voltage(int supply)
205{
206 const struct axp_supply_info* info = &axp_supply_info[supply];
207 if(info->volt_reg == 0)
208 return AXP_SUPPLY_NOT_PRESENT;
209
210 if(info->en_reg != 0) {
211 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, info->en_reg);
212 if(r < 0)
213 return AXP_SUPPLY_DISABLED;
214
215#if HAVE_AXP_PMU == 192
216 if(supply == AXP_SUPPLY_LDO_IO0) {
217 if((r & 7) != 2)
218 return AXP_SUPPLY_DISABLED;
219 } else
220#endif
221 {
222 if(r & (1 << info->en_bit) == 0)
223 return AXP_SUPPLY_DISABLED;
224 }
225 }
226
227 /* Hack, avoid undefined shift below. Can be useful too... */
228 if(info->volt_reg_mask == 0)
229 return info->min_mV;
230
231 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, info->volt_reg);
232 if(r < 0)
233 return 0;
234
235 int bit = find_first_set_bit(info->volt_reg_mask);
236 int val = (r & info->volt_reg_mask) >> bit;
237 return info->min_mV + (val * info->step_mV);
238}
239
240/* TODO: this can STILL indicate some false positives! */
241int axp_battery_status(void)
242{
243 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_POWERSTATUS);
244 if(r >= 0) {
245 /* Charging bit indicates we're currently charging */
246 if((r & 0x04) != 0)
247 return AXP_BATT_CHARGING;
248
249 /* Not plugged in means we're discharging */
250 if((r & 0xf0) == 0)
251 return AXP_BATT_DISCHARGING;
252 } else {
253 /* Report discharging if we can't find out power status */
254 return AXP_BATT_DISCHARGING;
255 }
256
257 /* If the battery is full and not in use, the charging bit will be 0,
258 * there will be an external power source, AND the discharge current
259 * will be zero. Seems to rule out all false positives. */
260 int d = axp_adc_read_raw(ADC_DISCHARGE_CURRENT);
261 if(d == 0)
262 return AXP_BATT_FULL;
263
264 return AXP_BATT_DISCHARGING;
265}
266
267int axp_input_status(void)
268{
269#ifdef HAVE_BATTERY_SWITCH
270 int input_status = 0;
271#else
272 int input_status = AXP_INPUT_BATTERY;
273#endif
274
275 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_POWERSTATUS);
276 if(r < 0)
277 return input_status;
278
279 /* Check for AC input */
280 if(r & 0x80)
281 input_status |= AXP_INPUT_AC;
282
283 /* Only report USB if ACIN and VBUS are not shorted */
284 if((r & 0x20) != 0 && (r & 0x02) == 0)
285 input_status |= AXP_INPUT_USB;
286
287#ifdef HAVE_BATTERY_SWITCH
288 /* Check for battery presence if target defines it as removable */
289 r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_CHARGESTATUS);
290 if(r >= 0 && (r & 0x20) != 0)
291 input_status |= AXP_INPUT_BATTERY;
292#endif
293
294 return input_status;
295}
296
297int axp_adc_read(int adc)
298{
299 int value = axp_adc_read_raw(adc);
300 if(value == INT_MIN)
301 return INT_MIN;
302
303 return axp_adc_conv_raw(adc, value);
304}
305
306int axp_adc_read_raw(int adc)
307{
308 /* Don't give a reading if the ADC is not enabled */
309 if((axp.adc_enable & (1 << adc)) == 0)
310 return INT_MIN;
311
312 /* Read the ADC */
313 uint8_t buf[3];
314 int count = (adc == ADC_BATTERY_POWER) ? 3 : 2;
315 uint8_t reg = axp_adc_info[adc].reg;
316 int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR, reg, count, &buf[0]);
317 if(rc != I2C_STATUS_OK)
318 return INT_MIN;
319
320 /* Parse the value */
321 if(adc == ADC_BATTERY_POWER)
322 return (buf[0] << 16) | (buf[1] << 8) | buf[2];
323 else if(adc == ADC_CHARGE_CURRENT || adc == ADC_DISCHARGE_CURRENT)
324 return (buf[0] << 5) | (buf[1] & 0x1f);
325 else
326 return (buf[0] << 4) | (buf[1] & 0xf);
327}
328
329int axp_adc_conv_raw(int adc, int value)
330{
331 switch(adc) {
332 case ADC_ACIN_VOLTAGE:
333 case ADC_VBUS_VOLTAGE:
334 /* 0 mV ... 6.9615 mV, step 1.7 mV */
335 return value * 17 / 10;
336 case ADC_ACIN_CURRENT:
337 /* 0 mA ... 2.5594 A, step 0.625 mA */
338 return value * 5 / 8;
339 case ADC_VBUS_CURRENT:
340 /* 0 mA ... 1.5356 A, step 0.375 mA */
341 return value * 3 / 8;
342 case ADC_INTERNAL_TEMP:
343 /* -144.7 C ... 264.8 C, step 0.1 C */
344 return value - 1447;
345 case ADC_TS_INPUT:
346 /* 0 mV ... 3.276 V, step 0.8 mV */
347 return value * 4 / 5;
348 case ADC_BATTERY_VOLTAGE:
349 /* 0 mV ... 4.5045 V, step 1.1 mV */
350 return value * 11 / 10;
351 case ADC_CHARGE_CURRENT:
352 case ADC_DISCHARGE_CURRENT:
353 /* 0 mA to 4.095 A, step 0.5 mA */
354 return value / 2;
355 case ADC_APS_VOLTAGE:
356 /* 0 mV to 5.733 V, step 1.4 mV */
357 return value * 7 / 5;
358 case ADC_BATTERY_POWER:
359 /* 0 uW to 23.6404 W, step 0.55 uW */
360 return value * 11 / 20;
361 default:
362 /* Shouldn't happen */
363 return INT_MIN;
364 }
365}
366
367int axp_adc_get_enabled(void)
368{
369 return axp.adc_enable;
370}
371
372void axp_adc_set_enabled(int adc_bits)
373{
374 /* Ignore no-op */
375 if(adc_bits == axp.adc_enable)
376 return;
377
378 /* Compute the new register values */
379 const struct axp_adc_info* info = axp_adc_info;
380 uint8_t regs[2] = {0, 0};
381 for(int i = 0; i < NUM_ADC_CHANNELS; ++i) {
382 if(info[i].en_reg == 0xff)
383 continue;
384
385 if(adc_bits & (1 << i))
386 regs[info[i].en_reg - 0x82] |= 1 << info[i].en_bit;
387 }
388
389 /* These ADCs share an enable bit */
390 if(adc_bits & ((1 << ADC_CHARGE_CURRENT)|(1 << ADC_DISCHARGE_CURRENT))) {
391 adc_bits |= (1 << ADC_CHARGE_CURRENT);
392 adc_bits |= (1 << ADC_DISCHARGE_CURRENT);
393 }
394
395 /* Enable required bits for battery power ADC */
396 if(adc_bits & (1 << ADC_BATTERY_POWER)) {
397 regs[0] |= 1 << info[ADC_DISCHARGE_CURRENT].en_bit;
398 regs[0] |= 1 << info[ADC_BATTERY_VOLTAGE].en_bit;
399 }
400
401 /* Update the configuration */
402 i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCENABLE1, 2, &regs[0]);
403 axp.adc_enable = adc_bits;
404}
405
406int axp_adc_get_rate(void)
407{
408 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCSAMPLERATE);
409 if(r < 0)
410 return AXP_ADC_RATE_100HZ; /* an arbitrary value */
411
412 return (r >> 6) & 3;
413}
414
415void axp_adc_set_rate(int rate)
416{
417 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCSAMPLERATE,
418 0xc0, (rate & 3) << 6, NULL);
419}
420
421static uint32_t axp_cc_parse(const uint8_t* buf)
422{
423 return ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
424}
425
426void axp_cc_read(uint32_t* charge, uint32_t* discharge)
427{
428 uint8_t buf[8];
429 int rc = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR,
430 AXP_REG_COULOMBCOUNTERBASE, 8, &buf[0]);
431 if(rc != I2C_STATUS_OK) {
432 if(charge)
433 *charge = 0;
434 if(discharge)
435 *discharge = 0;
436 return;
437 }
438
439 if(charge)
440 *charge = axp_cc_parse(&buf[0]);
441 if(discharge)
442 *discharge = axp_cc_parse(&buf[4]);
443}
444
445void axp_cc_clear(void)
446{
447 i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
448 AXP_REG_COULOMBCOUNTERCTRL, 5, 1, NULL);
449}
450
451void axp_cc_enable(bool en)
452{
453 i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
454 AXP_REG_COULOMBCOUNTERCTRL, 7, en ? 1 : 0, NULL);
455}
456
457bool axp_cc_is_enabled(void)
458{
459 int reg = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR,
460 AXP_REG_COULOMBCOUNTERCTRL);
461 return reg >= 0 && (reg & 0x40) != 0;
462}
463
464static const int chargecurrent_tbl[] = {
465 100, 190, 280, 360,
466 450, 550, 630, 700,
467 780, 880, 960, 1000,
468 1080, 1160, 1240, 1320,
469};
470
471static const int chargecurrent_tblsz = sizeof(chargecurrent_tbl)/sizeof(int);
472
473void axp_set_charge_current(int maxcurrent)
474{
475 /* Find the charge current just higher than maxcurrent */
476 int value = 0;
477 while(value < chargecurrent_tblsz &&
478 chargecurrent_tbl[value] <= maxcurrent)
479 ++value;
480
481 /* Select the next lower current, the greatest current <= maxcurrent */
482 if(value >= chargecurrent_tblsz)
483 value = chargecurrent_tblsz - 1;
484 else if(value > 0)
485 --value;
486
487 /* Don't issue i2c write if desired setting is already in use */
488 if(value == axp.chargecurrent_setting)
489 return;
490
491 /* Update register */
492 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
493 AXP_REG_CHARGECONTROL1, 0x0f, value, NULL);
494 axp.chargecurrent_setting = value;
495}
496
497int axp_get_charge_current(void)
498{
499 if(axp.chargecurrent_setting < 0)
500 return chargecurrent_tbl[0];
501 else
502 return chargecurrent_tbl[axp.chargecurrent_setting];
503}
504
505void axp_power_off(void)
506{
507 /* Set the shutdown bit */
508 i2c_reg_setbit1(AXP_PMU_BUS, AXP_PMU_ADDR,
509 AXP_REG_SHUTDOWNLEDCTRL, 7, 1, NULL);
510}
511
512#ifndef BOOTLOADER
513enum {
514 AXP_DEBUG_CHIP_ID,
515 AXP_DEBUG_BATTERY_STATUS,
516 AXP_DEBUG_INPUT_STATUS,
517 AXP_DEBUG_CHARGE_CURRENT,
518 AXP_DEBUG_COULOMB_COUNTERS,
519 AXP_DEBUG_ADC_RATE,
520 AXP_DEBUG_FIRST_ADC,
521 AXP_DEBUG_FIRST_SUPPLY = AXP_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS,
522 AXP_DEBUG_NUM_ENTRIES = AXP_DEBUG_FIRST_SUPPLY + AXP_NUM_SUPPLIES,
523};
524
525static int axp_debug_menu_cb(int action, struct gui_synclist* lists)
526{
527 (void)lists;
528
529 if(action == ACTION_NONE)
530 action = ACTION_REDRAW;
531
532 return action;
533}
534
535static const char* axp_debug_menu_get_name(int item, void* data,
536 char* buf, size_t buflen)
537{
538 (void)data;
539
540 static const char* const adc_names[] = {
541 "V_acin", "I_acin", "V_vbus", "I_vbus", "T_int",
542 "V_ts", "V_batt", "I_chrg", "I_dchg", "V_aps", "P_batt"
543 };
544
545 static const char* const adc_units[] = {
546 "mV", "mA", "mV", "mA", "C", "mV", "mV", "mA", "mA", "mV", "uW",
547 };
548
549 static const char* const supply_names[] = {
550 "DCDC1", "DCDC2", "DCDC3",
551 "LDO1", "LDO2", "LDO3", "LDO_IO0",
552 };
553
554 int adc = item - AXP_DEBUG_FIRST_ADC;
555 if(item >= AXP_DEBUG_FIRST_ADC && adc < NUM_ADC_CHANNELS) {
556 int raw_value = axp_adc_read_raw(adc);
557 if(raw_value == INT_MIN) {
558 snprintf(buf, buflen, "%s: [Disabled]", adc_names[adc]);
559 return buf;
560 }
561
562 int value = axp_adc_conv_raw(adc, raw_value);
563 if(adc == ADC_INTERNAL_TEMP) {
564 snprintf(buf, buflen, "%s: %d.%d %s", adc_names[adc],
565 value/10, value%10, adc_units[adc]);
566 } else {
567 snprintf(buf, buflen, "%s: %d %s", adc_names[adc],
568 value, adc_units[adc]);
569 }
570
571 return buf;
572 }
573
574 int supply = item - AXP_DEBUG_FIRST_SUPPLY;
575 if(item >= AXP_DEBUG_FIRST_SUPPLY && supply < AXP_NUM_SUPPLIES) {
576 int voltage = axp_supply_get_voltage(supply);
577 if(voltage == AXP_SUPPLY_NOT_PRESENT)
578 snprintf(buf, buflen, "%s: [Not Present]", supply_names[supply]);
579 else if(voltage == AXP_SUPPLY_DISABLED)
580 snprintf(buf, buflen, "%s: [Disabled]", supply_names[supply]);
581 else
582 snprintf(buf, buflen, "%s: %d mV", supply_names[supply], voltage);
583
584 return buf;
585 }
586
587 switch(item) {
588 case AXP_DEBUG_CHIP_ID: {
589 snprintf(buf, buflen, "Chip ID: %d (%02x) [Driver: AXP%d]",
590 axp.chip_id, axp.chip_id, HAVE_AXP_PMU);
591 return buf;
592 } break;
593
594 case AXP_DEBUG_BATTERY_STATUS: {
595 switch(axp_battery_status()) {
596 case AXP_BATT_FULL:
597 return "Battery: Full";
598 case AXP_BATT_CHARGING:
599 return "Battery: Charging";
600 case AXP_BATT_DISCHARGING:
601 return "Battery: Discharging";
602 default:
603 return "Battery: Unknown";
604 }
605 } break;
606
607 case AXP_DEBUG_INPUT_STATUS: {
608 int s = axp_input_status();
609 const char* ac = (s & AXP_INPUT_AC) ? " AC" : "";
610 const char* usb = (s & AXP_INPUT_USB) ? " USB" : "";
611 const char* batt = (s & AXP_INPUT_BATTERY) ? " Battery" : "";
612 snprintf(buf, buflen, "Inputs:%s%s%s", ac, usb, batt);
613 return buf;
614 } break;
615
616 case AXP_DEBUG_CHARGE_CURRENT: {
617 int current = axp_get_charge_current();
618 snprintf(buf, buflen, "Max charge current: %d mA", current);
619 return buf;
620 } break;
621
622 case AXP_DEBUG_COULOMB_COUNTERS: {
623 uint32_t charge, discharge;
624 axp_cc_read(&charge, &discharge);
625
626 snprintf(buf, buflen, "Coulomb counters: +%lu / -%lu",
627 (unsigned long)charge, (unsigned long)discharge);
628 return buf;
629 } break;
630
631 case AXP_DEBUG_ADC_RATE: {
632 int rate = 25 << axp_adc_get_rate();
633 snprintf(buf, buflen, "ADC sample rate: %d Hz", rate);
634 return buf;
635 } break;
636
637 default:
638 return "---";
639 }
640}
641
642bool axp_debug_menu(void)
643{
644 struct simplelist_info info;
645 simplelist_info_init(&info, "AXP debug", AXP_DEBUG_NUM_ENTRIES, NULL);
646 info.action_callback = axp_debug_menu_cb;
647 info.get_name = axp_debug_menu_get_name;
648 return simplelist_show_list(&info);
649}
650#endif /* !BOOTLOADER */
651
652/* This is basically the only valid implementation, so define it here */
653unsigned int power_input_status(void)
654{
655 unsigned int state = 0;
656 int input_status = axp_input_status();
657
658 if(input_status & AXP_INPUT_AC)
659 state |= POWER_INPUT_MAIN_CHARGER;
660
661 if(input_status & AXP_INPUT_USB)
662 state |= POWER_INPUT_USB_CHARGER;
663
664#ifdef HAVE_BATTERY_SWITCH
665 if(input_status & AXP_INPUT_BATTERY)
666 state |= POWER_INPUT_BATTERY;
667#endif
668
669 return state;
670}
diff --git a/firmware/drivers/axp192.c b/firmware/drivers/axp192.c
deleted file mode 100644
index 3c61d8c533..0000000000
--- a/firmware/drivers/axp192.c
+++ /dev/null
@@ -1,810 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "axp192.h"
23#include "system.h"
24#include "power.h"
25#include "i2c-async.h"
26#include "logf.h"
27
28/*
29 * Direct register access
30 */
31
32int axp_read(uint8_t reg)
33{
34 int ret = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, reg);
35 if(ret < 0)
36 logf("axp: read reg %02x err=%d", reg, ret);
37
38 return ret;
39}
40
41int axp_write(uint8_t reg, uint8_t value)
42{
43 int ret = i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, reg, value);
44 if(ret < 0)
45 logf("axp: write reg %02x err=%d", reg, ret);
46
47 return ret;
48}
49
50int axp_modify(uint8_t reg, uint8_t clr, uint8_t set)
51{
52 int ret = i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, reg, clr, set, NULL);
53 if(ret < 0)
54 logf("axp: modify reg %02x err=%d", reg, ret);
55
56 return ret;
57}
58
59/*
60 * Power supplies: enable/disable, set voltage
61 */
62
63struct axp_supplydata {
64 uint8_t en_reg;
65 uint8_t en_bit;
66 uint8_t volt_reg;
67 uint8_t volt_msb: 4;
68 uint8_t volt_lsb: 4;
69 short min_mV;
70 short step_mV;
71};
72
73static const struct axp_supplydata supplydata[] = {
74 [AXP_SUPPLY_EXTEN] = {
75 .en_reg = AXP_REG_PWRCTL1,
76 .en_bit = 1 << 2,
77 .volt_reg = 0xff, /* undefined */
78 .volt_msb = 0xf,
79 .volt_lsb = 0xf,
80 .min_mV = 0,
81 .step_mV = 0,
82 },
83 [AXP_SUPPLY_DCDC1] = {
84 .en_reg = AXP_REG_PWRCTL2,
85 .en_bit = 1 << 0,
86 .volt_reg = AXP_REG_DCDC1VOLT,
87 .volt_msb = 6,
88 .volt_lsb = 0,
89 .min_mV = 700,
90 .step_mV = 25,
91 },
92 [AXP_SUPPLY_DCDC2] = {
93 .en_reg = AXP_REG_PWRCTL1,
94 .en_bit = 1 << 0,
95 .volt_reg = AXP_REG_DCDC2VOLT,
96 .volt_msb = 5,
97 .volt_lsb = 0,
98 .min_mV = 700,
99 .step_mV = 25,
100 },
101 [AXP_SUPPLY_DCDC3] = {
102 .en_reg = AXP_REG_PWRCTL2,
103 .en_bit = 1 << 1,
104 .volt_reg = AXP_REG_DCDC3VOLT,
105 .volt_msb = 6,
106 .volt_lsb = 0,
107 .min_mV = 700,
108 .step_mV = 25,
109 },
110 [AXP_SUPPLY_LDO2] = {
111 .en_reg = AXP_REG_PWRCTL2,
112 .en_bit = 1 << 2,
113 .volt_reg = AXP_REG_LDO2LDO3VOLT,
114 .volt_msb = 7,
115 .volt_lsb = 4,
116 .min_mV = 1800,
117 .step_mV = 100,
118 },
119 [AXP_SUPPLY_LDO3] = {
120 .en_reg = AXP_REG_PWRCTL2,
121 .en_bit = 1 << 3,
122 .volt_reg = AXP_REG_LDO2LDO3VOLT,
123 .volt_msb = 3,
124 .volt_lsb = 0,
125 .min_mV = 1800,
126 .step_mV = 100,
127 },
128 [AXP_SUPPLY_LDOIO0] = {
129 .en_reg = 0xff, /* undefined */
130 .en_bit = 0,
131 .volt_reg = AXP_REG_GPIO0LDO,
132 .volt_msb = 7,
133 .volt_lsb = 4,
134 .min_mV = 1800,
135 .step_mV = 100,
136 },
137};
138
139void axp_enable_supply(int supply, bool enable)
140{
141 const struct axp_supplydata* data = &supplydata[supply];
142 axp_modify(data->en_reg, data->en_bit, enable ? data->en_bit : 0);
143}
144
145void axp_set_enabled_supplies(unsigned int supply_mask)
146{
147 uint8_t xfer[3];
148 xfer[0] = 0;
149 xfer[1] = AXP_REG_PWRCTL2;
150 xfer[2] = 0;
151
152 for(int i = 0; i < AXP_NUM_SUPPLIES; ++i) {
153 if(!(supply_mask & (1 << i)))
154 continue;
155
156 const struct axp_supplydata* data = &supplydata[i];
157 if(data->en_reg == AXP_REG_PWRCTL1) {
158 xfer[0] |= data->en_bit;
159 xfer[2] |= data->en_bit << 4; /* HACK: work around AXP quirk */
160 } else {
161 xfer[2] |= data->en_bit;
162 }
163 }
164
165 i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_PWRCTL1, 3, xfer);
166}
167
168void axp_set_supply_voltage(int supply, int output_mV)
169{
170 const struct axp_supplydata* data = &supplydata[supply];
171 uint8_t mask = (1 << (data->volt_msb - data->volt_lsb + 1)) - 1;
172 uint8_t value = (output_mV - data->min_mV) / data->step_mV;
173 axp_modify(data->volt_reg, mask << data->volt_lsb, value << data->volt_lsb);
174}
175
176/*
177 * ADC control: enable/disable, read
178 */
179
180struct axp_adcdata {
181 uint8_t data_reg;
182 uint8_t en_reg;
183 uint8_t en_bit;
184 int8_t num;
185 int8_t den;
186};
187
188static const struct axp_adcdata adcdata[] = {
189 [AXP_ADC_ACIN_VOLTAGE] = {0x56, AXP_REG_ADCEN1, 1 << 5, 17, 10},
190 [AXP_ADC_ACIN_CURRENT] = {0x58, AXP_REG_ADCEN1, 1 << 4, 5, 8},
191 [AXP_ADC_VBUS_VOLTAGE] = {0x5a, AXP_REG_ADCEN1, 1 << 3, 17, 10},
192 [AXP_ADC_VBUS_CURRENT] = {0x5c, AXP_REG_ADCEN1, 1 << 2, 3, 8},
193 [AXP_ADC_INTERNAL_TEMP] = {0x5e, AXP_REG_ADCEN2, 1 << 7, 0, 0},
194 [AXP_ADC_TS_INPUT] = {0x62, AXP_REG_ADCEN1, 1 << 0, 4, 5},
195 [AXP_ADC_GPIO0] = {0x64, AXP_REG_ADCEN2, 1 << 3, 1, 2},
196 [AXP_ADC_GPIO1] = {0x66, AXP_REG_ADCEN2, 1 << 2, 1, 2},
197 [AXP_ADC_GPIO2] = {0x68, AXP_REG_ADCEN2, 1 << 1, 1, 2},
198 [AXP_ADC_GPIO3] = {0x6a, AXP_REG_ADCEN2, 1 << 0, 1, 2},
199 [AXP_ADC_BATTERY_VOLTAGE] = {0x78, AXP_REG_ADCEN1, 1 << 7, 11, 10},
200 [AXP_ADC_CHARGE_CURRENT] = {0x7a, AXP_REG_ADCEN1, 1 << 6, 1, 2},
201 [AXP_ADC_DISCHARGE_CURRENT] = {0x7c, AXP_REG_ADCEN1, 1 << 6, 1, 2},
202 [AXP_ADC_APS_VOLTAGE] = {0x7e, AXP_REG_ADCEN1, 1 << 1, 7, 5},
203};
204
205void axp_enable_adc(int adc, bool enable)
206{
207 const struct axp_adcdata* data = &adcdata[adc];
208 axp_modify(data->en_reg, data->en_bit, enable ? data->en_bit : 0);
209}
210
211void axp_set_enabled_adcs(unsigned int adc_mask)
212{
213 uint8_t xfer[3];
214 xfer[0] = 0;
215 xfer[1] = AXP_REG_ADCEN2;
216 xfer[2] = 0;
217
218 for(int i = 0; i < AXP_NUM_ADCS; ++i) {
219 if(!(adc_mask & (1 << i)))
220 continue;
221
222 const struct axp_adcdata* data = &adcdata[i];
223 if(data->en_reg == AXP_REG_ADCEN1)
224 xfer[0] |= data->en_bit;
225 else
226 xfer[2] |= data->en_bit;
227 }
228
229 i2c_reg_write(AXP_PMU_BUS, AXP_PMU_ADDR, AXP_REG_ADCEN1, 3, xfer);
230}
231
232int axp_read_adc_raw(int adc)
233{
234 uint8_t data[2];
235 int ret = i2c_reg_read(AXP_PMU_BUS, AXP_PMU_ADDR,
236 adcdata[adc].data_reg, 2, data);
237 if(ret < 0) {
238 logf("axp: ADC read failed, err=%d", ret);
239 return INT_MIN;
240 }
241
242 if(adc == AXP_ADC_CHARGE_CURRENT || adc == AXP_ADC_DISCHARGE_CURRENT)
243 return (data[0] << 5) | data[1];
244 else
245 return (data[0] << 4) | data[1];
246}
247
248int axp_conv_adc(int adc, int value)
249{
250 const struct axp_adcdata* data = &adcdata[adc];
251 if(adc == AXP_ADC_INTERNAL_TEMP)
252 return value - 1447;
253 else
254 return data->num * value / data->den;
255}
256
257int axp_read_adc(int adc)
258{
259 int ret = axp_read_adc_raw(adc);
260 if(ret == INT_MIN)
261 return ret;
262
263 return axp_conv_adc(adc, ret);
264}
265
266/*
267 * GPIOs: set function, pull down control, get/set pin level
268 */
269
270struct axp_gpiodata {
271 uint8_t func_reg;
272 uint8_t func_msb: 4;
273 uint8_t func_lsb: 4;
274 uint8_t level_reg;
275 uint8_t level_out: 4;
276 uint8_t level_in: 4;
277};
278
279static const struct axp_gpiodata gpiodata[] = {
280 {AXP_REG_GPIO0FUNC, 2, 0, AXP_REG_GPIOLEVEL1, 0, 4},
281 {AXP_REG_GPIO1FUNC, 2, 0, AXP_REG_GPIOLEVEL1, 1, 5},
282 {AXP_REG_GPIO2FUNC, 2, 0, AXP_REG_GPIOLEVEL1, 2, 6},
283 {AXP_REG_GPIO3GPIO4FUNC, 1, 0, AXP_REG_GPIOLEVEL2, 0, 4},
284 {AXP_REG_GPIO3GPIO4FUNC, 3, 2, AXP_REG_GPIOLEVEL2, 1, 5},
285 {AXP_REG_NRSTO, 7, 6, AXP_REG_NRSTO, 4, 5},
286};
287
288static const uint8_t gpio34funcmap[8] = {
289 [AXP_GPIO_SPECIAL] = 0x0,
290 [AXP_GPIO_OPEN_DRAIN_OUTPUT] = 0x1,
291 [AXP_GPIO_INPUT] = 0x2,
292 [AXP_GPIO_ADC_IN] = 0x3,
293};
294
295static const uint8_t nrstofuncmap[8] = {
296 [AXP_GPIO_SPECIAL] = 0x0,
297 [AXP_GPIO_OPEN_DRAIN_OUTPUT] = 0x2,
298 [AXP_GPIO_INPUT] = 0x3,
299};
300
301void axp_set_gpio_function(int gpio, int function)
302{
303 const struct axp_gpiodata* data = &gpiodata[gpio];
304 int mask = (1 << (data->func_msb - data->func_lsb + 1)) - 1;
305
306 if(gpio == 5)
307 function = nrstofuncmap[function];
308 else if(gpio >= 3)
309 function = gpio34funcmap[function];
310
311 axp_modify(data->func_reg, mask << data->func_lsb, function << data->func_lsb);
312}
313
314void axp_set_gpio_pulldown(int gpio, bool enable)
315{
316 int bit = 1 << gpio;
317 axp_modify(AXP_REG_GPIOPULL, bit, enable ? bit : 0);
318}
319
320int axp_get_gpio(int gpio)
321{
322 const struct axp_gpiodata* data = &gpiodata[gpio];
323 return axp_read(data->level_reg) & (1 << data->level_in);
324}
325
326void axp_set_gpio(int gpio, bool enable)
327{
328 const struct axp_gpiodata* data = &gpiodata[gpio];
329 uint8_t bit = 1 << data->level_out;
330 axp_modify(data->level_reg, bit, enable ? bit : 0);
331}
332
333/*
334 * Charging: set charging current, query charging/input status
335 */
336
337static const short chargecurrent_tbl[] = {
338 100, 190, 280, 360,
339 450, 550, 630, 700,
340 780, 880, 960, 1000,
341 1080, 1160, 1240, 1320,
342};
343
344void axp_set_charge_current(int current_mA)
345{
346 /* find greatest charging current not exceeding requested current */
347 unsigned int index = 0;
348 while(index < ARRAYLEN(chargecurrent_tbl)-1 &&
349 chargecurrent_tbl[index+1] <= current_mA)
350 ++index;
351
352 axp_modify(AXP_REG_CHGCTL1, BM_AXP_CHGCTL1_CHARGE_CURRENT,
353 index << BP_AXP_CHGCTL1_CHARGE_CURRENT);
354}
355
356int axp_get_charge_current(void)
357{
358 int value = axp_read(AXP_REG_CHGCTL1);
359 if(value < 0)
360 value = 0;
361
362 value &= BM_AXP_CHGCTL1_CHARGE_CURRENT;
363 value >>= BP_AXP_CHGCTL1_CHARGE_CURRENT;
364 return chargecurrent_tbl[value];
365}
366
367void axp_set_vbus_limit(int mode)
368{
369 const int mask = BM_AXP_VBUSIPSOUT_VHOLD_LIM |
370 BM_AXP_VBUSIPSOUT_VBUS_LIM |
371 BM_AXP_VBUSIPSOUT_LIM_100mA;
372
373 axp_modify(AXP_REG_VBUSIPSOUT, mask, mode);
374}
375
376void axp_set_vhold_level(int vhold_mV)
377{
378 if(vhold_mV < 4000)
379 vhold_mV = 4000;
380 else if(vhold_mV > 4700)
381 vhold_mV = 4700;
382
383 int level = (vhold_mV - 4000) / 100;
384 axp_modify(AXP_REG_VBUSIPSOUT, BM_AXP_VBUSIPSOUT_VHOLD_LEV,
385 level << BP_AXP_VBUSIPSOUT_VHOLD_LEV);
386}
387
388bool axp_is_charging(void)
389{
390 int value = axp_read(AXP_REG_CHGSTS);
391 return (value >= 0) && (value & BM_AXP_CHGSTS_CHARGING);
392}
393
394unsigned int axp_power_input_status(void)
395{
396 unsigned int state = 0;
397 int value = axp_read(AXP_REG_PWRSTS);
398 if(value >= 0) {
399 /* ACIN is the main charger. Includes USB */
400 if(value & BM_AXP_PWRSTS_ACIN_VALID)
401 state |= POWER_INPUT_MAIN_CHARGER;
402
403 /* Report USB separately if discernable from ACIN */
404 if((value & BM_AXP_PWRSTS_VBUS_VALID) &&
405 !(value & BM_AXP_PWRSTS_PCB_SHORTED))
406 state |= POWER_INPUT_USB_CHARGER;
407 }
408
409#ifdef HAVE_BATTERY_SWITCH
410 /* If target allows switching batteries then report if the
411 * battery is present or not */
412 value = axp_read(AXP_REG_CHGSTS);
413 if(value >= 0 && (value & BM_AXP_CHGSTS_BATT_PRESENT))
414 state |= POWER_INPUT_BATTERY;
415#endif
416
417 return state;
418}
419
420/*
421 * Misc. functions
422 */
423
424void axp_power_off(void)
425{
426 axp_modify(AXP_REG_PWROFF, BM_AXP_PWROFF_SHUTDOWN, BM_AXP_PWROFF_SHUTDOWN);
427}
428
429/*
430 * Debug menu
431 */
432
433#ifndef BOOTLOADER
434#include "action.h"
435#include "list.h"
436#include "splash.h"
437#include <stdio.h>
438
439/* enable extra debug menus which are only useful for development,
440 * allow potentially dangerous operations and increase code size
441 * significantly */
442/*#define AXP_EXTRA_DEBUG*/
443
444enum {
445 MODE_ADC,
446#ifdef AXP_EXTRA_DEBUG
447 MODE_SUPPLY,
448 MODE_REGISTER,
449#endif
450 NUM_MODES,
451};
452
453static const char* const axp_modenames[NUM_MODES] = {
454 [MODE_ADC] = "ADCs",
455#ifdef AXP_EXTRA_DEBUG
456 [MODE_SUPPLY] = "Power supplies",
457 [MODE_REGISTER] = "Register viewer",
458#endif
459};
460
461struct axp_adcdebuginfo {
462 const char* name;
463 const char* unit;
464};
465
466static const struct axp_adcdebuginfo adc_debuginfo[AXP_NUM_ADCS] = {
467 [AXP_ADC_ACIN_VOLTAGE] = {"V_acin", "mV"},
468 [AXP_ADC_ACIN_CURRENT] = {"I_acin", "mA"},
469 [AXP_ADC_VBUS_VOLTAGE] = {"V_vbus", "mV"},
470 [AXP_ADC_VBUS_CURRENT] = {"I_vbus", "mA"},
471 [AXP_ADC_INTERNAL_TEMP] = {"T_int", "C"},
472 [AXP_ADC_TS_INPUT] = {"V_ts", "mV"},
473 [AXP_ADC_GPIO0] = {"V_gpio0", "mV"},
474 [AXP_ADC_GPIO1] = {"V_gpio1", "mV"},
475 [AXP_ADC_GPIO2] = {"V_gpio2", "mV"},
476 [AXP_ADC_GPIO3] = {"V_gpio3", "mV"},
477 [AXP_ADC_BATTERY_VOLTAGE] = {"V_batt", "mV"},
478 [AXP_ADC_CHARGE_CURRENT] = {"I_chrg", "mA"},
479 [AXP_ADC_DISCHARGE_CURRENT] = {"I_dchg", "mA"},
480 [AXP_ADC_APS_VOLTAGE] = {"V_aps", "mV"},
481};
482
483#ifdef AXP_EXTRA_DEBUG
484static const char* supply_names[AXP_NUM_SUPPLIES] = {
485 [AXP_SUPPLY_EXTEN] = "EXTEN",
486 [AXP_SUPPLY_DCDC1] = "DCDC1",
487 [AXP_SUPPLY_DCDC2] = "DCDC2",
488 [AXP_SUPPLY_DCDC3] = "DCDC3",
489 [AXP_SUPPLY_LDO2] = "LDO2",
490 [AXP_SUPPLY_LDO3] = "LDO3",
491 [AXP_SUPPLY_LDOIO0] = "LDOIO0",
492};
493
494struct axp_fieldinfo {
495 uint8_t rnum;
496 uint8_t msb: 4;
497 uint8_t lsb: 4;
498};
499
500enum {
501#define DEFREG(name, ...) AXP_RNUM_##name,
502#include "axp192-defs.h"
503 AXP_NUM_REGS,
504};
505
506enum {
507#define DEFFLD(regname, fldname, ...) AXP_FNUM_##regname##_##fldname,
508#include "axp192-defs.h"
509 AXP_NUM_FIELDS,
510};
511
512static const uint8_t axp_regaddr[AXP_NUM_REGS] = {
513#define DEFREG(name, addr) addr,
514#include "axp192-defs.h"
515};
516
517static const struct axp_fieldinfo axp_fieldinfo[AXP_NUM_FIELDS] = {
518#define DEFFLD(regname, fldname, _msb, _lsb, ...) \
519 {.rnum = AXP_RNUM_##regname, .msb = _msb, .lsb = _lsb},
520#include "axp192-defs.h"
521};
522
523static const char* const axp_regnames[AXP_NUM_REGS] = {
524#define DEFREG(name, ...) #name,
525#include "axp192-defs.h"
526};
527
528static const char* const axp_fldnames[AXP_NUM_FIELDS] = {
529#define DEFFLD(regname, fldname, ...) #fldname,
530#include "axp192-defs.h"
531};
532#endif /* AXP_EXTRA_DEBUG */
533
534struct axp_debug_menu_state {
535 int mode;
536#ifdef AXP_EXTRA_DEBUG
537 int reg_num;
538 int field_num;
539 int field_cnt;
540 uint8_t cache[AXP_NUM_REGS];
541 uint8_t is_cached[AXP_NUM_REGS];
542#endif
543};
544
545#ifdef AXP_EXTRA_DEBUG
546static void axp_debug_clear_cache(struct axp_debug_menu_state* state)
547{
548 memset(state->is_cached, 0, sizeof(state->is_cached));
549}
550
551static int axp_debug_get_rnum(uint8_t addr)
552{
553 for(int i = 0; i < AXP_NUM_REGS; ++i)
554 if(axp_regaddr[i] == addr)
555 return i;
556
557 return -1;
558}
559
560static uint8_t axp_debug_read(struct axp_debug_menu_state* state, int rnum)
561{
562 if(state->is_cached[rnum])
563 return state->cache[rnum];
564
565 int value = axp_read(axp_regaddr[rnum]);
566 if(value < 0)
567 return 0;
568
569 state->is_cached[rnum] = 1;
570 state->cache[rnum] = value;
571 return value;
572}
573
574static void axp_debug_get_sel(const struct axp_debug_menu_state* state,
575 int item, int* rnum, int* fnum)
576{
577 if(state->reg_num >= 0 && state->field_num >= 0) {
578 int i = item - state->reg_num;
579 if(i <= 0) {
580 /* preceding register is selected */
581 } else if(i <= state->field_cnt) {
582 /* field is selected */
583 *rnum = state->reg_num;
584 *fnum = i + state->field_num - 1;
585 return;
586 } else {
587 /* subsequent regiser is selected */
588 item -= state->field_cnt;
589 }
590 }
591
592 /* register is selected */
593 *rnum = item;
594 *fnum = -1;
595}
596
597static int axp_debug_set_sel(struct axp_debug_menu_state* state, int rnum)
598{
599 state->reg_num = rnum;
600 state->field_num = -1;
601 state->field_cnt = 0;
602
603 for(int i = 0; i < AXP_NUM_FIELDS; ++i) {
604 if(axp_fieldinfo[i].rnum != rnum)
605 continue;
606
607 state->field_num = i;
608 do {
609 state->field_cnt++;
610 i++;
611 } while(axp_fieldinfo[i].rnum == rnum);
612 break;
613 }
614
615 return rnum;
616}
617#endif /* AXP_EXTRA_DEBUG */
618
619static const char* axp_debug_menu_get_name(int item, void* data,
620 char* buf, size_t buflen)
621{
622 struct axp_debug_menu_state* state = data;
623 int value;
624
625 /* for safety */
626 buf[0] = '\0';
627
628 if(state->mode == MODE_ADC && item < AXP_NUM_ADCS)
629 {
630 const struct axp_adcdebuginfo* info = &adc_debuginfo[item];
631 value = axp_read_adc(item);
632 if(item == AXP_ADC_INTERNAL_TEMP) {
633 snprintf(buf, buflen, "%s: %d.%d %s",
634 info->name, value/10, value%10, info->unit);
635 } else {
636 snprintf(buf, buflen, "%s: %d %s", info->name, value, info->unit);
637 }
638 }
639#ifdef AXP_EXTRA_DEBUG
640 else if(state->mode == MODE_SUPPLY && item < AXP_NUM_SUPPLIES)
641 {
642 const struct axp_supplydata* data = &supplydata[item];
643 int en_rnum = axp_debug_get_rnum(data->en_reg);
644 int volt_rnum = axp_debug_get_rnum(data->volt_reg);
645 bool enabled = false;
646 int voltage = -1;
647
648 if(en_rnum >= 0) {
649 value = axp_debug_read(state, en_rnum);
650 if(value & data->en_bit)
651 enabled = true;
652 else
653 enabled = false;
654 } else if(item == AXP_SUPPLY_LDOIO0) {
655 value = axp_debug_read(state, AXP_RNUM_GPIO0FUNC);
656 if((value & 0x7) == AXP_GPIO_SPECIAL)
657 enabled = true;
658 else
659 enabled = false;
660 }
661
662 if(volt_rnum >= 0) {
663 voltage = axp_debug_read(state, volt_rnum);
664 voltage >>= data->volt_lsb;
665 voltage &= (1 << (data->volt_msb - data->volt_lsb + 1)) - 1;
666
667 /* convert to mV */
668 voltage = data->min_mV + voltage * data->step_mV;
669 }
670
671 if(enabled && voltage >= 0) {
672 snprintf(buf, buflen, "%s: %d mV",
673 supply_names[item], voltage);
674 } else {
675 snprintf(buf, buflen, "%s: %sabled",
676 supply_names[item], enabled ? "en" : "dis");
677 }
678 }
679 else if(state->mode == MODE_REGISTER)
680 {
681 int rnum, fnum;
682 axp_debug_get_sel(state, item, &rnum, &fnum);
683
684 if(fnum >= 0) {
685 const struct axp_fieldinfo* info = &axp_fieldinfo[fnum];
686 value = axp_debug_read(state, info->rnum);
687 value >>= info->lsb;
688 value &= (1 << (info->msb - info->lsb + 1)) - 1;
689 snprintf(buf, buflen, "\t%s: %d (0x%x)",
690 axp_fldnames[fnum], value, value);
691 } else if(rnum < AXP_NUM_REGS) {
692 value = axp_debug_read(state, rnum);
693 snprintf(buf, buflen, "%s: 0x%02x", axp_regnames[rnum], value);
694 }
695 }
696#endif /* AXP_EXTRA_DEBUG */
697
698 return buf;
699}
700
701static int axp_debug_menu_cb(int action, struct gui_synclist* lists)
702{
703 struct axp_debug_menu_state* state = lists->data;
704
705 if(state->mode == MODE_ADC)
706 {
707 /* update continuously */
708 if(action == ACTION_NONE)
709 action = ACTION_REDRAW;
710 }
711#ifdef AXP_EXTRA_DEBUG
712 else if(state->mode == MODE_REGISTER)
713 {
714 if(action == ACTION_STD_OK) {
715 /* expand a register to show its fields */
716 int rnum, fnum;
717 int sel_pos = gui_synclist_get_sel_pos(lists);
718 axp_debug_get_sel(state, sel_pos, &rnum, &fnum);
719 if(fnum < 0 && rnum < AXP_NUM_REGS) {
720 int delta_items = -state->field_cnt;
721 if(rnum != state->reg_num) {
722 if(rnum > state->reg_num)
723 sel_pos += delta_items;
724
725 axp_debug_set_sel(state, rnum);
726 delta_items += state->field_cnt;
727 } else {
728 state->reg_num = -1;
729 state->field_num = -1;
730 state->field_cnt = 0;
731 }
732
733 gui_synclist_set_nb_items(lists, lists->nb_items + delta_items);
734 gui_synclist_select_item(lists, sel_pos);
735 action = ACTION_REDRAW;
736 }
737 }
738 }
739 else if(state->mode == MODE_SUPPLY)
740 {
741 /* disable a supply... use with caution */
742 if(action == ACTION_STD_CONTEXT) {
743 int sel_pos = gui_synclist_get_sel_pos(lists);
744 axp_enable_supply(sel_pos, false);
745 }
746 }
747#endif
748
749#ifdef AXP_EXTRA_DEBUG
750 /* clear register cache to refresh values */
751 if(state->mode != MODE_ADC && action == ACTION_STD_CONTEXT) {
752 splashf(HZ/2, "Refreshed");
753 axp_debug_clear_cache(state);
754 action = ACTION_REDRAW;
755 }
756#endif
757
758 /* mode switching */
759 if(action == ACTION_STD_MENU) {
760 state->mode = (state->mode + 1) % NUM_MODES;
761 gui_synclist_set_title(lists, (char*)axp_modenames[state->mode], Icon_NOICON);
762 action = ACTION_REDRAW;
763
764 switch(state->mode) {
765 case MODE_ADC:
766 gui_synclist_set_nb_items(lists, AXP_NUM_ADCS);
767 gui_synclist_select_item(lists, 0);
768 break;
769
770#ifdef AXP_EXTRA_DEBUG
771 case MODE_SUPPLY:
772 axp_debug_clear_cache(state);
773 gui_synclist_set_nb_items(lists, AXP_NUM_SUPPLIES);
774 gui_synclist_select_item(lists, 0);
775 break;
776
777 case MODE_REGISTER:
778 state->reg_num = -1;
779 state->field_num = -1;
780 state->field_cnt = 0;
781 axp_debug_clear_cache(state);
782 gui_synclist_set_nb_items(lists, AXP_NUM_REGS);
783 gui_synclist_select_item(lists, 0);
784 break;
785#endif
786 }
787 }
788
789 return action;
790}
791
792bool axp_debug_menu(void)
793{
794 struct axp_debug_menu_state state;
795 state.mode = MODE_ADC;
796#ifdef AXP_EXTRA_DEBUG
797 state.reg_num = -1;
798 state.field_num = -1;
799 state.field_cnt = 0;
800 axp_debug_clear_cache(&state);
801#endif
802
803 struct simplelist_info info;
804 simplelist_info_init(&info, (char*)axp_modenames[state.mode],
805 AXP_NUM_ADCS, &state);
806 info.get_name = axp_debug_menu_get_name;
807 info.action_callback = axp_debug_menu_cb;
808 return simplelist_show_list(&info);
809}
810#endif
diff --git a/firmware/export/axp-pmu.h b/firmware/export/axp-pmu.h
new file mode 100644
index 0000000000..457f746e8c
--- /dev/null
+++ b/firmware/export/axp-pmu.h
@@ -0,0 +1,151 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __AXP_PMU_H__
23#define __AXP_PMU_H__
24
25#include "config.h"
26#include <stdbool.h>
27#include <stdint.h>
28
29/* ADC channels */
30#define ADC_ACIN_VOLTAGE 0
31#define ADC_ACIN_CURRENT 1
32#define ADC_VBUS_VOLTAGE 2
33#define ADC_VBUS_CURRENT 3
34#define ADC_INTERNAL_TEMP 4
35#define ADC_TS_INPUT 5
36#define ADC_BATTERY_VOLTAGE 6
37#define ADC_CHARGE_CURRENT 7
38#define ADC_DISCHARGE_CURRENT 8
39#define ADC_APS_VOLTAGE 9
40#define ADC_BATTERY_POWER 10
41#define NUM_ADC_CHANNELS 11
42
43/* ADC sampling rates */
44#define AXP_ADC_RATE_25HZ 0
45#define AXP_ADC_RATE_50HZ 1
46#define AXP_ADC_RATE_100HZ 2
47#define AXP_ADC_RATE_200HZ 3
48
49/* Return values of axp_battery_status() */
50#define AXP_BATT_DISCHARGING 0
51#define AXP_BATT_CHARGING 1
52#define AXP_BATT_FULL 2
53
54/* Bits returned by axp_input_status() */
55#define AXP_INPUT_AC (1 << 0)
56#define AXP_INPUT_USB (1 << 1)
57#define AXP_INPUT_BATTERY (1 << 2)
58#define AXP_INPUT_EXTERNAL (AXP_INPUT_AC|AXP_INPUT_USB)
59
60/* Power supplies known by this driver. Not every chip has all supplies! */
61#define AXP_SUPPLY_DCDC1 0
62#define AXP_SUPPLY_DCDC2 1
63#define AXP_SUPPLY_DCDC3 2
64#define AXP_SUPPLY_LDO1 3
65#define AXP_SUPPLY_LDO2 4
66#define AXP_SUPPLY_LDO3 5
67#define AXP_SUPPLY_LDO_IO0 6
68#define AXP_NUM_SUPPLIES 7
69
70/* Special values returned by axp_supply_get_voltage */
71#define AXP_SUPPLY_NOT_PRESENT INT_MIN
72#define AXP_SUPPLY_DISABLED (-1)
73
74/* Registers -- common to AXP173 and AXP192 (incomplete listing) */
75#define AXP_REG_POWERSTATUS 0x00
76#define AXP_REG_CHARGESTATUS 0x01
77#define AXP_REG_CHIP_ID 0x03
78#define AXP_REG_PWROUTPUTCTRL1 0x10
79#define AXP_REG_PWROUTPUTCTRL2 0x12
80#define AXP_REG_SHUTDOWNLEDCTRL 0x32
81#define AXP_REG_CHARGECONTROL1 0x33
82#define AXP_REG_DCDCWORKINGMODE 0x80
83#define AXP_REG_ADCENABLE1 0x82
84#define AXP_REG_ADCENABLE2 0x83
85#define AXP_REG_ADCSAMPLERATE 0x84
86#define AXP_REG_COULOMBCOUNTERBASE 0xb0
87#define AXP_REG_COULOMBCOUNTERCTRL 0xb8
88
89/* AXP192-only registers (incomplete listing) */
90#define AXP192_REG_GPIO0FUNCTION 0x90
91#define AXP192_REG_GPIO1FUNCTION 0x92
92#define AXP192_REG_GPIO2FUNCTION 0x93
93#define AXP192_REG_GPIOSTATE1 0x94
94
95/* Must be called from power_init() to initialize the driver state */
96extern void axp_init(void);
97
98/* - axp_supply_set_voltage(): set a supply voltage to the given value
99 * in millivolts. Pass a voltage of AXP_SUPPLY_DISABLED to shut off
100 * the supply. Any invalid supply or voltage will make the call a no-op.
101 *
102 * - axp_supply_get_voltage() returns a supply voltage in millivolts.
103 * If the supply is powered off, returns AXP_SUPPLY_DISABLED.
104 * If the chip does not have the supply, returns AXP_SUPPLY_NOT_PRESENT.
105 */
106extern void axp_supply_set_voltage(int supply, int voltage);
107extern int axp_supply_get_voltage(int supply);
108
109/* Basic battery and power supply status */
110extern int axp_battery_status(void);
111extern int axp_input_status(void);
112
113/* ADC access -- ADCs which are not enabled will return INT_MIN if read.
114 * The output of axp_adc_read() is normalized to appropriate units:
115 *
116 * - for voltages, the scale is millivolts
117 * - for currents, the scale is milliamps
118 * - for temperatures, the scale is tenths of a degree Celsius
119 * - for power, the scale is microwatts
120 *
121 * See the comment in axp_adc_conv_raw() for raw value precision/scale.
122 */
123extern int axp_adc_read(int adc);
124extern int axp_adc_read_raw(int adc);
125extern int axp_adc_conv_raw(int adc, int value);
126extern int axp_adc_get_enabled(void);
127extern void axp_adc_set_enabled(int adc_bits);
128extern int axp_adc_get_rate(void);
129extern void axp_adc_set_rate(int rate);
130
131/* - axp_cc_read() reads the coulomb counters
132 * - axp_cc_clear() resets both counters to zero
133 * - axp_cc_enable() will stop/start the counters running
134 * - axp_cc_is_enabled() returns true if the counters are running
135 */
136extern void axp_cc_read(uint32_t* charge, uint32_t* discharge);
137extern void axp_cc_clear(void);
138extern void axp_cc_enable(bool en);
139extern bool axp_cc_is_enabled(void);
140
141/* Set/get maximum charging current in milliamps */
142extern void axp_set_charge_current(int maxcurrent);
143extern int axp_get_charge_current(void);
144
145/* Set the shutdown bit */
146extern void axp_power_off(void);
147
148/* Debug menu */
149extern bool axp_debug_menu(void);
150
151#endif /* __AXP_PMU_H__ */
diff --git a/firmware/export/axp192-defs.h b/firmware/export/axp192-defs.h
deleted file mode 100644
index 13b465351b..0000000000
--- a/firmware/export/axp192-defs.h
+++ /dev/null
@@ -1,308 +0,0 @@
1/* Internal header for axp192 driver - not for general inclusion */
2
3#ifndef DEFREG
4# define DEFREG(...)
5#endif
6#ifndef DEFFLD
7# define DEFFLD(...)
8#endif
9
10#define DEFBIT(regname, fldname, bitpos, ...) \
11 DEFFLD(regname, fldname, bitpos, bitpos, __VA_ARGS__)
12
13DEFREG(PWRSTS, 0x00)
14DEFREG(CHGSTS, 0x01)
15DEFREG(CHIPID, 0x03)
16DEFREG(VBUSSTS, 0x04)
17DEFREG(DATA0, 0x06)
18DEFREG(DATA1, 0x07)
19DEFREG(DATA2, 0x08)
20DEFREG(DATA3, 0x09)
21DEFREG(DATA4, 0x0a)
22DEFREG(DATA5, 0x0b)
23DEFREG(PWRCTL1, 0x10)
24DEFREG(PWRCTL2, 0x12)
25DEFREG(DCDC2VOLT, 0x23)
26DEFREG(DCDC2RAMP, 0x25)
27DEFREG(DCDC1VOLT, 0x26)
28DEFREG(DCDC3VOLT, 0x27)
29DEFREG(LDO2LDO3VOLT, 0x28)
30DEFREG(VBUSIPSOUT, 0x30)
31DEFREG(VOFF, 0x31)
32DEFREG(PWROFF, 0x32)
33DEFREG(CHGCTL1, 0x33)
34DEFREG(CHGCTL2, 0x34)
35DEFREG(BKPCHGCTL, 0x35)
36DEFREG(PEKPARAM, 0x36)
37DEFREG(DCDCFREQ, 0x37)
38DEFREG(VLTFCHG, 0x38)
39DEFREG(VHTFCHG, 0x39)
40DEFREG(APSLOW1, 0x3a)
41DEFREG(APSLOW2, 0x3b)
42DEFREG(VLTFDCHG, 0x3c)
43DEFREG(VHTFDCHG, 0x3d)
44DEFREG(IRQEN1, 0x40)
45DEFREG(IRQEN2, 0x41)
46DEFREG(IRQEN3, 0x42)
47DEFREG(IRQEN4, 0x43)
48DEFREG(IRQSTS1, 0x44)
49DEFREG(IRQSTS2, 0x45)
50DEFREG(IRQSTS3, 0x46)
51DEFREG(IRQSTS4, 0x47)
52DEFREG(IRQEN5, 0x4a)
53DEFREG(IRQSTS5, 0x4d)
54DEFREG(DCDCMODE, 0x80)
55DEFREG(ADCEN1, 0x82)
56DEFREG(ADCEN2, 0x83)
57DEFREG(ADCCTL, 0x84)
58DEFREG(ADCRANGE, 0x85)
59DEFREG(TIMERCTL, 0x8a)
60DEFREG(VBUSSRP, 0x8b)
61DEFREG(OTPOWEROFF, 0x8f)
62DEFREG(GPIO0FUNC, 0x90)
63DEFREG(GPIO0LDO, 0x91)
64DEFREG(GPIO1FUNC, 0x92)
65DEFREG(GPIO2FUNC, 0x93)
66DEFREG(GPIOLEVEL1, 0x94)
67DEFREG(GPIO3GPIO4FUNC, 0x95)
68DEFREG(GPIOLEVEL2, 0x96)
69DEFREG(GPIOPULL, 0x97)
70DEFREG(PWM1X, 0x98)
71DEFREG(PWM1Y1, 0x99)
72DEFREG(PWM1Y2, 0x9a)
73DEFREG(PWM2X, 0x9b)
74DEFREG(PWM2Y1, 0x9c)
75DEFREG(PWM2Y2, 0x9d)
76DEFREG(NRSTO, 0x9e)
77DEFREG(CC_CTL, 0xb8)
78
79DEFBIT(PWRSTS, ACIN_PRESENT, 7)
80DEFBIT(PWRSTS, ACIN_VALID, 6)
81DEFBIT(PWRSTS, VBUS_PRESENT, 5)
82DEFBIT(PWRSTS, VBUS_VALID, 4)
83DEFBIT(PWRSTS, VBUS_VHOLD, 3)
84DEFBIT(PWRSTS, BATT_CURR_DIR, 2)
85DEFBIT(PWRSTS, PCB_SHORTED, 1)
86DEFBIT(PWRSTS, BOOT_TRIG, 0)
87
88DEFBIT(VBUSSTS, VALID, 2)
89DEFBIT(VBUSSTS, SESS_AB_VALID, 1)
90DEFBIT(VBUSSTS, SESS_END, 0)
91
92DEFBIT(CHGSTS, OVER_TEMP, 7)
93DEFBIT(CHGSTS, CHARGING, 6)
94DEFBIT(CHGSTS, BATT_PRESENT, 5)
95DEFBIT(CHGSTS, BATT_ERROR, 3)
96DEFBIT(CHGSTS, LOW_CHARGE, 2)
97
98/* NOTE: These two bits are mirrored in the upper nibble of PWRCTL2.
99 * Modifications through one register will immediately reflect in the
100 * other register. */
101DEFBIT(PWRCTL1, EXTEN_SW, 2)
102DEFBIT(PWRCTL1, DCDC2_SW, 0)
103
104DEFBIT(PWRCTL2, EXTEN_SW, 6)
105DEFBIT(PWRCTL2, DCDC2_SW, 4)
106DEFBIT(PWRCTL2, LDO3_SW, 3)
107DEFBIT(PWRCTL2, LDO2_SW, 2)
108DEFBIT(PWRCTL2, DCDC3_SW, 1)
109DEFBIT(PWRCTL2, DCDC1_SW, 0)
110
111DEFFLD(DCDC2VOLT, VALUE, 5, 0)
112
113DEFBIT(DCDC2RAMP, ENABLE, 2)
114DEFBIT(DCDC2RAMP, SLOPE, 0)
115
116DEFFLD(DCDC1VOLT, VALUE, 6, 0)
117DEFFLD(DCDC3VOLT, VALUE, 6, 0)
118
119DEFFLD(LDO2LDO3VOLT, LDO2_VALUE, 7, 4)
120DEFFLD(LDO2LDO3VOLT, LDO3_VALUE, 3, 0)
121
122DEFBIT(VBUSIPSOUT, ACCESS, 7)
123DEFBIT(VBUSIPSOUT, VHOLD_LIM, 6)
124DEFFLD(VBUSIPSOUT, VHOLD_LEV, 5, 3)
125DEFBIT(VBUSIPSOUT, VBUS_LIM, 1)
126DEFBIT(VBUSIPSOUT, LIM_100mA, 0)
127
128DEFFLD(VOFF, VALUE, 3, 0)
129
130DEFBIT(PWROFF, SHUTDOWN, 7)
131DEFBIT(PWROFF, MON_EN, 6)
132DEFFLD(PWROFF, LEDFUNC, 5, 4)
133DEFBIT(PWROFF, LEDCTL, 3)
134DEFBIT(PWROFF, DELAY, 1, 0)
135
136DEFBIT(CHGCTL1, CHARGE_EN, 7)
137DEFFLD(CHGCTL1, CHARGE_TGT, 6, 5)
138DEFBIT(CHGCTL1, CHARGE_ENDCURR, 4)
139DEFFLD(CHGCTL1, CHARGE_CURRENT, 3, 0)
140
141DEFFLD(CHGCTL2, PRECHARGE_OT, 7, 6)
142DEFFLD(CHGCTL2, EACCESS_CURRENT, 5, 3)
143DEFBIT(CHGCTL2, EACCESS_CHG_EN, 2)
144DEFFLD(CHGCTL2, CONST_CURR_OT, 1, 0)
145
146DEFBIT(BKPCHGCTL, ENABLE, 7)
147DEFFLD(BKPCHGCTL, TGT_VOLTAGE, 6, 5)
148DEFFLD(BKPCHGCTL, CHARGE_CURRENT, 1, 0)
149
150DEFFLD(PEKPARAM, POWER_ON_TIME, 7, 6)
151DEFFLD(PEKPARAM, LONG_TIME, 5, 4)
152DEFBIT(PEKPARAM, POWEROFF_EN, 3)
153DEFBIT(PEKPARAM, PWROK_DELAY, 2)
154DEFFLD(PEKPARAM, POWEROFF_TIME, 1, 0)
155
156DEFFLD(DCDCFREQ, VALUE, 3, 0)
157DEFFLD(VLTFCHG, VALUE, 7, 0)
158DEFFLD(VHTFCHG, VALUE, 7, 0)
159DEFFLD(APSLOW1, VALUE, 7, 0)
160DEFFLD(APSLOW2, VALUE, 7, 0)
161DEFFLD(VLTFDCHG, VALUE, 7, 0)
162DEFFLD(VHTFDCHG, VALUE, 7, 0)
163
164DEFBIT(IRQEN1, ACIN_OVER_VOLTAGE, 7)
165DEFBIT(IRQEN1, ACIN_INSERT, 6)
166DEFBIT(IRQEN1, ACIN_REMOVE, 5)
167DEFBIT(IRQEN1, VBUS_OVER_VOLTAGE, 4)
168DEFBIT(IRQEN1, VBUS_INSERT, 3)
169DEFBIT(IRQEN1, VBUS_REMOVE, 2)
170DEFBIT(IRQEN1, VBUS_BELOW_VHOLD, 1)
171DEFBIT(IRQEN2, BATTERY_INSERT, 7)
172DEFBIT(IRQEN2, BATTERY_REMOVE, 6)
173DEFBIT(IRQEN2, BATTERY_ERROR, 5)
174DEFBIT(IRQEN2, BATTERY_ERROR_CLR, 4)
175DEFBIT(IRQEN2, CHARGING_STARTED, 3)
176DEFBIT(IRQEN2, CHARGING_COMPLETE, 2)
177DEFBIT(IRQEN2, BATTERY_OVER_TEMP, 1)
178DEFBIT(IRQEN2, BATTERY_UNDER_TEMP, 0)
179DEFBIT(IRQEN3, INTERNAL_OVER_TEMP, 7)
180DEFBIT(IRQEN3, LOW_CHARGE_CURRENT, 6)
181DEFBIT(IRQEN3, DCDC1_UNDER_VOLT, 5)
182DEFBIT(IRQEN3, DCDC2_UNDER_VOLT, 4)
183DEFBIT(IRQEN3, DCDC3_UNDER_VOLT, 3)
184DEFBIT(IRQEN3, SHORT_PRESS, 1)
185DEFBIT(IRQEN3, LONG_PRESS, 0)
186DEFBIT(IRQEN4, POWER_ON_N_OE, 7)
187DEFBIT(IRQEN4, POWER_OFF_N_OE, 6)
188DEFBIT(IRQEN4, VBUS_VALID, 5)
189DEFBIT(IRQEN4, VBUS_INVALID, 4)
190DEFBIT(IRQEN4, VBUS_SESS_AB, 3)
191DEFBIT(IRQEN4, VBUS_SESS_END, 2)
192DEFBIT(IRQEN4, APS_UNDER_VOLT, 0)
193
194DEFBIT(IRQSTS1, ACIN_OVER_VOLTAGE, 7)
195DEFBIT(IRQSTS1, ACIN_INSERT, 6)
196DEFBIT(IRQSTS1, ACIN_REMOVE, 5)
197DEFBIT(IRQSTS1, VBUS_OVER_VOLTAGE, 4)
198DEFBIT(IRQSTS1, VBUS_INSERT, 3)
199DEFBIT(IRQSTS1, VBUS_REMOVE, 2)
200DEFBIT(IRQSTS1, VBUS_BELOW_VHOLD, 1)
201DEFBIT(IRQSTS2, BATTERY_INSERT, 7)
202DEFBIT(IRQSTS2, BATTERY_REMOVE, 6)
203DEFBIT(IRQSTS2, BATTERY_ERROR, 5)
204DEFBIT(IRQSTS2, BATTERY_ERROR_CLR, 4)
205DEFBIT(IRQSTS2, CHARGING_STARTED, 3)
206DEFBIT(IRQSTS2, CHARGING_STOPPED, 2)
207DEFBIT(IRQSTS2, BATTERY_OVER_TEMP, 1)
208DEFBIT(IRQSTS2, BATTERY_UNDER_TEMP, 0)
209DEFBIT(IRQSTS3, INTERNAL_OVER_TEMP, 7)
210DEFBIT(IRQSTS3, LOW_CHARGE_CURRENT, 6)
211DEFBIT(IRQSTS3, DCDC1_UNDER_VOLT, 5)
212DEFBIT(IRQSTS3, DCDC2_UNDER_VOLT, 4)
213DEFBIT(IRQSTS3, DCDC3_UNDER_VOLT, 3)
214DEFBIT(IRQSTS3, SHORT_PRESS, 1)
215DEFBIT(IRQSTS3, LONG_PRESS, 0)
216DEFBIT(IRQSTS4, POWER_ON_N_OE, 7)
217DEFBIT(IRQSTS4, POWER_OFF_N_OE, 6)
218DEFBIT(IRQSTS4, VBUS_VALID, 5)
219DEFBIT(IRQSTS4, VBUS_INVALID, 4)
220DEFBIT(IRQSTS4, VBUS_SESS_AB, 3)
221DEFBIT(IRQSTS4, VBUS_SESS_END, 2)
222DEFBIT(IRQSTS4, APS_UNDER_VOLT, 0)
223
224/* NOTE: IRQEN5 and IRQSTS5 are only listed on the Chinese datasheet. */
225DEFBIT(IRQEN5, TIME_OUT, 7)
226DEFBIT(IRQEN5, GPIO2_CHANGE, 2)
227DEFBIT(IRQEN5, GPIO1_CHANGE, 1)
228DEFBIT(IRQEN5, GPIO0_CHANGE, 0)
229
230DEFBIT(IRQSTS5, TIME_OUT, 7)
231DEFBIT(IRQSTS5, GPIO2_CHANGE, 2)
232DEFBIT(IRQSTS5, GPIO1_CHANGE, 1)
233DEFBIT(IRQSTS5, GPIO0_CHANGE, 0)
234
235DEFFLD(DCDCMODE, VALUE, 3, 1)
236
237DEFBIT(ADCEN1, BATTERY_VOLTAGE, 7)
238DEFBIT(ADCEN1, BATTERY_CURRENT, 6)
239DEFBIT(ADCEN1, ACIN_VOLTAGE, 5)
240DEFBIT(ADCEN1, ACIN_CURRENT, 4)
241DEFBIT(ADCEN1, VBUS_VOLTAGE, 3)
242DEFBIT(ADCEN1, VBUS_CURRENT, 2)
243DEFBIT(ADCEN1, APS_VOLTAGE, 1)
244DEFBIT(ADCEN1, TS_PIN, 0)
245
246DEFBIT(ADCEN2, INTERNAL_TEMP, 7)
247DEFBIT(ADCEN2, GPIO0, 3)
248DEFBIT(ADCEN2, GPIO1, 2)
249DEFBIT(ADCEN2, GPIO2, 1)
250DEFBIT(ADCEN2, GPIO3, 0)
251
252DEFFLD(ADCCTL, SAMPLE_RATE, 7, 6)
253DEFFLD(ADCCTL, TS_OUT_CURR, 5, 4)
254DEFBIT(ADCCTL, TS_FUNCTION, 2)
255DEFFLD(ADCCTL, TS_OUT_MODE, 1, 0)
256
257DEFBIT(ADCRANGE, GPIO3HIGH, 3)
258DEFBIT(ADCRANGE, GPIO2HIGH, 2)
259DEFBIT(ADCRANGE, GPIO1HIGH, 1)
260DEFBIT(ADCRANGE, GPIO0HIGH, 0)
261
262DEFBIT(TIMERCTL, TIMEOUT, 7)
263DEFFLD(TIMERCTL, DURATION, 6, 0)
264
265DEFFLD(VBUSSRP, VBUSVALID_VOLTAGE, 5, 4)
266DEFBIT(VBUSSRP, VBUSVALID_MONITOR, 3)
267DEFBIT(VBUSSRP, VBUS_SESS_MONITOR, 2)
268DEFBIT(VBUSSRP, VBUS_DCHG_RESISTOR, 1)
269DEFBIT(VBUSSRP, VBUS_CHG_RESISTOR, 0)
270
271DEFBIT(OTPOWEROFF, ENABLE, 2)
272
273DEFFLD(GPIO0FUNC, VALUE, 2, 0)
274DEFFLD(GPIO0LDO, VALUE, 7, 4)
275DEFFLD(GPIO1FUNC, VALUE, 2, 0)
276DEFFLD(GPIO2FUNC, VALUE, 2, 0)
277
278DEFBIT(GPIOLEVEL1, IN2, 6)
279DEFBIT(GPIOLEVEL1, IN1, 5)
280DEFBIT(GPIOLEVEL1, IN0, 4)
281DEFBIT(GPIOLEVEL1, OUT2, 2)
282DEFBIT(GPIOLEVEL1, OUT1, 1)
283DEFBIT(GPIOLEVEL1, OUT0, 0)
284
285DEFFLD(GPIO3GPIO4FUNC, FUNC3, 3, 2)
286DEFFLD(GPIO3GPIO4FUNC, FUNC4, 1, 0)
287
288DEFBIT(GPIOLEVEL2, IN4, 5)
289DEFBIT(GPIOLEVEL2, IN3, 4)
290DEFBIT(GPIOLEVEL2, OUT4, 1)
291DEFBIT(GPIOLEVEL2, OUT3, 0)
292
293DEFBIT(GPIOPULL, PULL2, 2)
294DEFBIT(GPIOPULL, PULL1, 1)
295DEFBIT(GPIOPULL, PULL0, 0)
296
297DEFBIT(NRSTO, FUNC, 7)
298DEFBIT(NRSTO, GPIO_DIR, 6)
299DEFBIT(NRSTO, GPIO_OUT, 5)
300DEFBIT(NRSTO, GPIO_IN, 4)
301
302DEFBIT(CC_CTL, OPEN, 7)
303DEFBIT(CC_CTL, PAUSE, 6)
304DEFBIT(CC_CTL, CLEAR, 5)
305
306#undef DEFBIT
307#undef DEFFLD
308#undef DEFREG
diff --git a/firmware/export/axp192.h b/firmware/export/axp192.h
deleted file mode 100644
index 6ed278d086..0000000000
--- a/firmware/export/axp192.h
+++ /dev/null
@@ -1,131 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __AXP192_H__
23#define __AXP192_H__
24
25#include <stdint.h>
26#include <stdbool.h>
27
28enum {
29#define DEFREG(regname, addr) AXP_REG_##regname = addr,
30#include "axp192-defs.h"
31};
32
33enum {
34#define DEFFLD(regname, fldname, msb, lsb, ...) \
35 BM_AXP_##regname##_##fldname = ((1 << ((msb) - (lsb) + 1)) - 1) << lsb, \
36 BP_AXP_##regname##_##fldname = lsb,
37#include "axp192-defs.h"
38};
39
40enum {
41 AXP_SUPPLY_EXTEN,
42 AXP_SUPPLY_DCDC1,
43 AXP_SUPPLY_DCDC2,
44 AXP_SUPPLY_DCDC3,
45 AXP_SUPPLY_LDO2,
46 AXP_SUPPLY_LDO3,
47 AXP_SUPPLY_LDOIO0,
48 AXP_NUM_SUPPLIES,
49};
50
51enum {
52 AXP_ADC_ACIN_VOLTAGE,
53 AXP_ADC_ACIN_CURRENT,
54 AXP_ADC_VBUS_VOLTAGE,
55 AXP_ADC_VBUS_CURRENT,
56 AXP_ADC_INTERNAL_TEMP,
57 AXP_ADC_TS_INPUT,
58 AXP_ADC_GPIO0,
59 AXP_ADC_GPIO1,
60 AXP_ADC_GPIO2,
61 AXP_ADC_GPIO3,
62 AXP_ADC_BATTERY_VOLTAGE,
63 AXP_ADC_CHARGE_CURRENT,
64 AXP_ADC_DISCHARGE_CURRENT,
65 AXP_ADC_APS_VOLTAGE,
66 AXP_NUM_ADCS,
67};
68
69enum {
70 AXP_GPIO_OPEN_DRAIN_OUTPUT = 0x0,
71 AXP_GPIO_INPUT = 0x1,
72 AXP_GPIO_SPECIAL = 0x2,
73 AXP_GPIO_ADC_IN = 0x4,
74 AXP_GPIO_LOW_OUTPUT = 0x5,
75 AXP_GPIO_FLOATING = 0x7,
76};
77
78enum {
79 /* Limit USB current consumption to 100 mA. */
80 AXP_VBUS_LIMIT_100mA = (1 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) |
81 (1 << BP_AXP_VBUSIPSOUT_VBUS_LIM) |
82 (1 << BP_AXP_VBUSIPSOUT_LIM_100mA),
83
84 /* Limit USB current consumption to 500 mA. */
85 AXP_VBUS_LIMIT_500mA = (1 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) |
86 (1 << BP_AXP_VBUSIPSOUT_VBUS_LIM) |
87 (0 << BP_AXP_VBUSIPSOUT_LIM_100mA),
88
89 /* No upper bound on USB current, but the current will still
90 * be reduced to maintain the bus voltage above V_hold. */
91 AXP_VBUS_UNLIMITED = (1 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) |
92 (0 << BP_AXP_VBUSIPSOUT_VBUS_LIM) |
93 (0 << BP_AXP_VBUSIPSOUT_LIM_100mA),
94
95 /* Unlimited USB current consumption. Voltage is allowed to drop
96 * below V_hold, which may interfere with normal USB operation.
97 * This mode is really only useful with AC charging adapters. */
98 AXP_VBUS_FULLY_UNLIMITED = (0 << BP_AXP_VBUSIPSOUT_VHOLD_LIM) |
99 (0 << BP_AXP_VBUSIPSOUT_VBUS_LIM) |
100 (0 << BP_AXP_VBUSIPSOUT_LIM_100mA),
101};
102
103extern int axp_read(uint8_t reg);
104extern int axp_write(uint8_t reg, uint8_t value);
105extern int axp_modify(uint8_t reg, uint8_t clr, uint8_t set);
106
107extern void axp_enable_supply(int supply, bool enable);
108extern void axp_set_enabled_supplies(unsigned int supply_mask);
109extern void axp_set_supply_voltage(int supply, int output_mV);
110
111extern void axp_enable_adc(int adc, bool enable);
112extern void axp_set_enabled_adcs(unsigned int adc_mask);
113extern int axp_read_adc_raw(int adc);
114extern int axp_conv_adc(int adc, int value);
115extern int axp_read_adc(int adc);
116
117extern void axp_set_gpio_function(int gpio, int function);
118extern void axp_set_gpio_pulldown(int gpio, bool enable);
119extern int axp_get_gpio(int gpio);
120extern void axp_set_gpio(int gpio, bool enable);
121
122extern void axp_set_charge_current(int current_mA);
123extern int axp_get_charge_current(void);
124extern void axp_set_vbus_limit(int vbus_limit);
125extern void axp_set_vhold_level(int vhold_mV);
126extern bool axp_is_charging(void);
127extern unsigned int axp_power_input_status(void);
128
129extern void axp_power_off(void);
130
131#endif /* __AXP192_H__ */
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c
index 64041795a3..1583db175a 100644
--- a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c
+++ b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c
@@ -24,7 +24,7 @@
24#include "backlight.h" 24#include "backlight.h"
25#include "powermgmt.h" 25#include "powermgmt.h"
26#include "panic.h" 26#include "panic.h"
27#include "axp192.h" 27#include "axp-pmu.h"
28#include "gpio-x1000.h" 28#include "gpio-x1000.h"
29#include "irq-x1000.h" 29#include "irq-x1000.h"
30#include "i2c-x1000.h" 30#include "i2c-x1000.h"
@@ -89,7 +89,7 @@ static int hp_detect_tmo_cb(struct timeout* tmo)
89static void hp_detect_init(void) 89static void hp_detect_init(void)
90{ 90{
91 static struct timeout tmo; 91 static struct timeout tmo;
92 static const uint8_t gpio_reg = AXP_REG_GPIOLEVEL1; 92 static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1;
93 static i2c_descriptor desc = { 93 static i2c_descriptor desc = {
94 .slave_addr = AXP_PMU_ADDR, 94 .slave_addr = AXP_PMU_ADDR,
95 .bus_cond = I2C_START | I2C_STOP, 95 .bus_cond = I2C_START | I2C_STOP,
@@ -105,11 +105,11 @@ static void hp_detect_init(void)
105 105
106 /* Headphone and LO detects are wired to AXP192 GPIOs 0 and 1, 106 /* Headphone and LO detects are wired to AXP192 GPIOs 0 and 1,
107 * set them to inputs. */ 107 * set them to inputs. */
108 axp_set_gpio_function(0, AXP_GPIO_INPUT); /* HP detect */ 108 i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO0FUNCTION, 0x01); /* HP detect */
109 axp_set_gpio_function(1, AXP_GPIO_INPUT); /* LO detect */ 109 i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO1FUNCTION, 0x01); /* LO detect */
110 110
111 /* Get an initial reading before startup */ 111 /* Get an initial reading before startup */
112 int r = axp_read(gpio_reg); 112 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg);
113 if(r >= 0) 113 if(r >= 0)
114 { 114 {
115 hp_detect_reg = r; 115 hp_detect_reg = r;
diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c
index 9cf64cee01..a1a4d2c2b2 100644
--- a/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c
+++ b/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c
@@ -28,7 +28,7 @@
28#ifdef HAVE_USB_CHARGING_ENABLE 28#ifdef HAVE_USB_CHARGING_ENABLE
29# include "usb_core.h" 29# include "usb_core.h"
30#endif 30#endif
31#include "axp192.h" 31#include "axp-pmu.h"
32#include "i2c-x1000.h" 32#include "i2c-x1000.h"
33 33
34const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = 34const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
@@ -56,35 +56,27 @@ const unsigned short percent_to_volt_charge[11] =
56 56
57void power_init(void) 57void power_init(void)
58{ 58{
59 /* Configure I2C bus */ 59 /* Initialize driver */
60 i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); 60 i2c_x1000_set_freq(2, I2C_FREQ_400K);
61 61 axp_init();
62 /* FIXME: Copy paste from M3K. Probably not necessary */ 62
63 axp_modify(AXP_REG_DCDCMODE, 0, 0xc0); 63 /* Set lowest sample rate */
64 64 axp_adc_set_rate(AXP_ADC_RATE_25HZ);
65 /* Power on required supplies 65
66 * TODO: This should be checked, though likely all but EXTEN are needed */ 66 /* Ensure battery voltage ADC is enabled */
67 axp_set_enabled_supplies( 67 int bits = axp_adc_get_enabled();
68 (1 << AXP_SUPPLY_EXTEN) | 68 bits |= (1 << ADC_BATTERY_VOLTAGE);
69 (1 << AXP_SUPPLY_DCDC1) | 69 axp_adc_set_enabled(bits);
70 (1 << AXP_SUPPLY_DCDC2) | 70
71 (1 << AXP_SUPPLY_DCDC3) | 71 /* Turn on all power outputs */
72 (1 << AXP_SUPPLY_LDO2) | 72 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
73 (1 << AXP_SUPPLY_LDO3)); 73 AXP_REG_PWROUTPUTCTRL2, 0, 0x5f, NULL);
74 74 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
75 /* Enable required ADCs */ 75 AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL);
76 axp_set_enabled_adcs( 76
77 (1 << AXP_ADC_BATTERY_VOLTAGE) | 77 /* Set the default charging current. This is the same as the
78 (1 << AXP_ADC_CHARGE_CURRENT) | 78 * OF's setting, although it's not strictly within the USB spec. */
79 (1 << AXP_ADC_DISCHARGE_CURRENT) | 79 axp_set_charge_current(780);
80 (1 << AXP_ADC_VBUS_VOLTAGE) |
81 (1 << AXP_ADC_VBUS_CURRENT) |
82 (1 << AXP_ADC_INTERNAL_TEMP) |
83 (1 << AXP_ADC_APS_VOLTAGE));
84
85 /* Configure USB charging */
86 axp_set_vhold_level(4400);
87 usb_charging_maxcurrent_change(100);
88 80
89 /* Delay to give power outputs time to stabilize. 81 /* Delay to give power outputs time to stabilize.
90 * With the power thread delay, this can apparently go as low as 50, 82 * With the power thread delay, this can apparently go as low as 50,
@@ -96,22 +88,7 @@ void power_init(void)
96#ifdef HAVE_USB_CHARGING_ENABLE 88#ifdef HAVE_USB_CHARGING_ENABLE
97void usb_charging_maxcurrent_change(int maxcurrent) 89void usb_charging_maxcurrent_change(int maxcurrent)
98{ 90{
99 int vbus_limit; 91 axp_set_charge_current(maxcurrent);
100 int charge_current;
101
102 /* Note that the charge current setting is a maximum: it will be
103 * reduced dynamically by the AXP192 so the combined load is less
104 * than the set VBUS current limit. */
105 if(maxcurrent <= 100) {
106 vbus_limit = AXP_VBUS_LIMIT_500mA;
107 charge_current = 100;
108 } else {
109 vbus_limit = AXP_VBUS_LIMIT_500mA;
110 charge_current = 550;
111 }
112
113 axp_set_vbus_limit(vbus_limit);
114 axp_set_charge_current(charge_current);
115} 92}
116#endif 93#endif
117 94
@@ -127,25 +104,20 @@ void power_off(void)
127 104
128bool charging_state(void) 105bool charging_state(void)
129{ 106{
130 return axp_is_charging(); 107 return axp_battery_status() == AXP_BATT_CHARGING;
131}
132
133unsigned int power_input_status(void)
134{
135 return axp_power_input_status();
136} 108}
137 109
138int _battery_voltage(void) 110int _battery_voltage(void)
139{ 111{
140 return axp_read_adc(AXP_ADC_BATTERY_VOLTAGE); 112 return axp_adc_read(ADC_BATTERY_VOLTAGE);
141} 113}
142 114
143#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE 115#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
144int _battery_current(void) 116int _battery_current(void)
145{ 117{
146 if(charging_state()) 118 if(charging_state())
147 return axp_read_adc(AXP_ADC_CHARGE_CURRENT); 119 return axp_adc_read(ADC_CHARGE_CURRENT);
148 else 120 else
149 return axp_read_adc(AXP_ADC_DISCHARGE_CURRENT); 121 return axp_adc_read(ADC_DISCHARGE_CURRENT);
150} 122}
151#endif 123#endif
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
index 0ef7bd2f64..24daf2ef69 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c
@@ -24,7 +24,7 @@
24#include "backlight.h" 24#include "backlight.h"
25#include "powermgmt.h" 25#include "powermgmt.h"
26#include "panic.h" 26#include "panic.h"
27#include "axp192.h" 27#include "axp-pmu.h"
28#include "ft6x06.h" 28#include "ft6x06.h"
29#include "gpio-x1000.h" 29#include "gpio-x1000.h"
30#include "irq-x1000.h" 30#include "irq-x1000.h"
@@ -393,7 +393,7 @@ static int hp_detect_tmo_cb(struct timeout* tmo)
393static void hp_detect_init(void) 393static void hp_detect_init(void)
394{ 394{
395 static struct timeout tmo; 395 static struct timeout tmo;
396 static const uint8_t gpio_reg = AXP_REG_GPIOLEVEL1; 396 static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1;
397 static i2c_descriptor desc = { 397 static i2c_descriptor desc = {
398 .slave_addr = AXP_PMU_ADDR, 398 .slave_addr = AXP_PMU_ADDR,
399 .bus_cond = I2C_START | I2C_STOP, 399 .bus_cond = I2C_START | I2C_STOP,
@@ -408,10 +408,10 @@ static void hp_detect_init(void)
408 }; 408 };
409 409
410 /* Headphone detect is wired to AXP192 GPIO: set it to input state */ 410 /* Headphone detect is wired to AXP192 GPIO: set it to input state */
411 axp_set_gpio_function(2, AXP_GPIO_INPUT); 411 i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01);
412 412
413 /* Get an initial reading before startup */ 413 /* Get an initial reading before startup */
414 int r = axp_read(gpio_reg); 414 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg);
415 if(r >= 0) 415 if(r >= 0)
416 hp_detect_reg = r; 416 hp_detect_reg = r;
417 417
diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
index b20bbd9e8c..2d28ad0975 100644
--- a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
+++ b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c
@@ -26,7 +26,7 @@
26#ifdef HAVE_USB_CHARGING_ENABLE 26#ifdef HAVE_USB_CHARGING_ENABLE
27# include "usb_core.h" 27# include "usb_core.h"
28#endif 28#endif
29#include "axp192.h" 29#include "axp-pmu.h"
30#include "i2c-x1000.h" 30#include "i2c-x1000.h"
31 31
32const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = 32const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
@@ -54,33 +54,27 @@ const unsigned short percent_to_volt_charge[11] =
54 54
55void power_init(void) 55void power_init(void)
56{ 56{
57 /* Configure I2C bus */ 57 /* Initialize driver */
58 i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); 58 i2c_x1000_set_freq(2, I2C_FREQ_400K);
59 59 axp_init();
60 /* Set DCDC1 and DCDC2 to fixed PWM mode to match OF settings. */ 60
61 axp_modify(AXP_REG_DCDCMODE, 0, 0x0c); 61 /* Set lowest sample rate */
62 62 axp_adc_set_rate(AXP_ADC_RATE_25HZ);
63 /* Power on required supplies */ 63
64 axp_set_enabled_supplies( 64 /* Ensure battery voltage ADC is enabled */
65 (1 << AXP_SUPPLY_DCDC1) | /* not sure (3.3 V) */ 65 int bits = axp_adc_get_enabled();
66 (1 << AXP_SUPPLY_DCDC2) | /* not sure (1.4 V) */ 66 bits |= (1 << ADC_BATTERY_VOLTAGE);
67 (1 << AXP_SUPPLY_DCDC3) | /* for CPU (1.8 V) */ 67 axp_adc_set_enabled(bits);
68 (1 << AXP_SUPPLY_LDO2) | /* LCD controller (3.3 V) */ 68
69 (1 << AXP_SUPPLY_LDO3)); /* SD bus (3.3 V) */ 69 /* Turn on all power outputs */
70 70 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
71 /* Enable required ADCs */ 71 AXP_REG_PWROUTPUTCTRL2, 0, 0x5f, NULL);
72 axp_set_enabled_adcs( 72 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
73 (1 << AXP_ADC_BATTERY_VOLTAGE) | 73 AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL);
74 (1 << AXP_ADC_CHARGE_CURRENT) | 74
75 (1 << AXP_ADC_DISCHARGE_CURRENT) | 75 /* Set the default charging current. This is the same as the
76 (1 << AXP_ADC_VBUS_VOLTAGE) | 76 * OF's setting, although it's not strictly within the USB spec. */
77 (1 << AXP_ADC_VBUS_CURRENT) | 77 axp_set_charge_current(780);
78 (1 << AXP_ADC_INTERNAL_TEMP) |
79 (1 << AXP_ADC_APS_VOLTAGE));
80
81 /* Configure USB charging */
82 axp_set_vhold_level(4400);
83 usb_charging_maxcurrent_change(100);
84 78
85 /* Short delay to give power outputs time to stabilize */ 79 /* Short delay to give power outputs time to stabilize */
86 mdelay(200); 80 mdelay(200);
@@ -89,22 +83,7 @@ void power_init(void)
89#ifdef HAVE_USB_CHARGING_ENABLE 83#ifdef HAVE_USB_CHARGING_ENABLE
90void usb_charging_maxcurrent_change(int maxcurrent) 84void usb_charging_maxcurrent_change(int maxcurrent)
91{ 85{
92 int vbus_limit; 86 axp_set_charge_current(maxcurrent);
93 int charge_current;
94
95 /* Note that the charge current setting is a maximum: it will be
96 * reduced dynamically by the AXP192 so the combined load is less
97 * than the set VBUS current limit. */
98 if(maxcurrent <= 100) {
99 vbus_limit = AXP_VBUS_LIMIT_500mA;
100 charge_current = 100;
101 } else {
102 vbus_limit = AXP_VBUS_LIMIT_500mA;
103 charge_current = 550;
104 }
105
106 axp_set_vbus_limit(vbus_limit);
107 axp_set_charge_current(charge_current);
108} 87}
109#endif 88#endif
110 89
@@ -120,25 +99,20 @@ void power_off(void)
120 99
121bool charging_state(void) 100bool charging_state(void)
122{ 101{
123 return axp_is_charging(); 102 return axp_battery_status() == AXP_BATT_CHARGING;
124}
125
126unsigned int power_input_status(void)
127{
128 return axp_power_input_status();
129} 103}
130 104
131int _battery_voltage(void) 105int _battery_voltage(void)
132{ 106{
133 return axp_read_adc(AXP_ADC_BATTERY_VOLTAGE); 107 return axp_adc_read(ADC_BATTERY_VOLTAGE);
134} 108}
135 109
136#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE 110#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
137int _battery_current(void) 111int _battery_current(void)
138{ 112{
139 if(charging_state()) 113 if(charging_state())
140 return axp_read_adc(AXP_ADC_CHARGE_CURRENT); 114 return axp_adc_read(ADC_CHARGE_CURRENT);
141 else 115 else
142 return axp_read_adc(AXP_ADC_DISCHARGE_CURRENT); 116 return axp_adc_read(ADC_DISCHARGE_CURRENT);
143} 117}
144#endif 118#endif
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
index 1976dde793..13b0cdd078 100644
--- a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
+++ b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
@@ -23,7 +23,7 @@
23#include "button.h" 23#include "button.h"
24#include "touchscreen.h" 24#include "touchscreen.h"
25#include "ft6x06.h" 25#include "ft6x06.h"
26#include "axp192.h" 26#include "axp-pmu.h"
27#include "kernel.h" 27#include "kernel.h"
28#include "backlight.h" 28#include "backlight.h"
29#include "powermgmt.h" 29#include "powermgmt.h"
@@ -57,7 +57,7 @@ static void hp_detect_init(void)
57{ 57{
58 /* TODO: replace this copy paste cruft with an API in axp-pmu */ 58 /* TODO: replace this copy paste cruft with an API in axp-pmu */
59 static struct timeout tmo; 59 static struct timeout tmo;
60 static const uint8_t gpio_reg = AXP_REG_GPIOLEVEL1; 60 static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1;
61 static i2c_descriptor desc = { 61 static i2c_descriptor desc = {
62 .slave_addr = AXP_PMU_ADDR, 62 .slave_addr = AXP_PMU_ADDR,
63 .bus_cond = I2C_START | I2C_STOP, 63 .bus_cond = I2C_START | I2C_STOP,
@@ -72,10 +72,10 @@ static void hp_detect_init(void)
72 }; 72 };
73 73
74 /* Headphone detect is wired to AXP192 GPIO: set it to input state */ 74 /* Headphone detect is wired to AXP192 GPIO: set it to input state */
75 axp_set_gpio_function(1, AXP_GPIO_INPUT); 75 i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO1FUNCTION, 0x01);
76 76
77 /* Get an initial reading before startup */ 77 /* Get an initial reading before startup */
78 int r = axp_read(gpio_reg); 78 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg);
79 if(r >= 0) 79 if(r >= 0)
80 hp_detect_reg = r; 80 hp_detect_reg = r;
81 81
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c
index 86ee84c37a..75f8031dd9 100644
--- a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c
+++ b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c
@@ -22,7 +22,7 @@
22#include "power.h" 22#include "power.h"
23#include "adc.h" 23#include "adc.h"
24#include "system.h" 24#include "system.h"
25#include "axp192.h" 25#include "axp-pmu.h"
26#ifdef HAVE_CW2015 26#ifdef HAVE_CW2015
27# include "cw2015.h" 27# include "cw2015.h"
28#endif 28#endif
@@ -73,34 +73,24 @@ const unsigned short percent_to_volt_charge[11] =
73void power_init(void) 73void power_init(void)
74{ 74{
75 i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K); 75 i2c_x1000_set_freq(AXP_PMU_BUS, I2C_FREQ_400K);
76 axp_init();
76#ifdef HAVE_CW2015 77#ifdef HAVE_CW2015
77 cw2015_init(); 78 cw2015_init();
78#endif 79#endif
79 80
80 /* Set DCDC2 to 1.2 V to match OF settings. */ 81 /* Change supply voltage from the default of 1250 mV to 1200 mV,
81 axp_set_supply_voltage(AXP_SUPPLY_DCDC2, 1200); 82 * this matches the original firmware's settings. Didn't observe
82 83 * any obviously bad behavior at 1250 mV, but better to be safe. */
83 /* Power on required supplies */ 84 axp_supply_set_voltage(AXP_SUPPLY_DCDC2, 1200);
84 axp_set_enabled_supplies( 85
85 (1 << AXP_SUPPLY_DCDC1) | /* SD bus (3.3 V) */ 86 /* For now, just turn everything on... definitely the touchscreen
86 (1 << AXP_SUPPLY_DCDC2) | /* LCD (1.2 V) */ 87 * is powered by one of the outputs */
87 (1 << AXP_SUPPLY_DCDC3) | /* CPU (1.8 V) */ 88 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
88 (1 << AXP_SUPPLY_LDO2) | /* Touchscreen (3.3 V) */ 89 AXP_REG_PWROUTPUTCTRL1, 0, 0x05, NULL);
89 (1 << AXP_SUPPLY_LDO3)); /* USB analog (2.5 V) */ 90 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
90 91 AXP_REG_PWROUTPUTCTRL2, 0, 0x0f, NULL);
91 /* Enable required ADCs */ 92 i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR,
92 axp_set_enabled_adcs( 93 AXP_REG_DCDCWORKINGMODE, 0, 0xc0, NULL);
93 (1 << AXP_ADC_BATTERY_VOLTAGE) |
94 (1 << AXP_ADC_CHARGE_CURRENT) |
95 (1 << AXP_ADC_DISCHARGE_CURRENT) |
96 (1 << AXP_ADC_VBUS_VOLTAGE) |
97 (1 << AXP_ADC_VBUS_CURRENT) |
98 (1 << AXP_ADC_INTERNAL_TEMP) |
99 (1 << AXP_ADC_APS_VOLTAGE));
100
101 /* Configure USB charging */
102 axp_set_vhold_level(4400);
103 usb_charging_maxcurrent_change(100);
104 94
105 /* Delay to give power output time to stabilize */ 95 /* Delay to give power output time to stabilize */
106 mdelay(20); 96 mdelay(20);
@@ -109,22 +99,7 @@ void power_init(void)
109#ifdef HAVE_USB_CHARGING_ENABLE 99#ifdef HAVE_USB_CHARGING_ENABLE
110void usb_charging_maxcurrent_change(int maxcurrent) 100void usb_charging_maxcurrent_change(int maxcurrent)
111{ 101{
112 int vbus_limit; 102 axp_set_charge_current(maxcurrent);
113 int charge_current;
114
115 /* Note that the charge current setting is a maximum: it will be
116 * reduced dynamically by the AXP192 so the combined load is less
117 * than the set VBUS current limit. */
118 if(maxcurrent <= 100) {
119 vbus_limit = AXP_VBUS_LIMIT_500mA;
120 charge_current = 100;
121 } else {
122 vbus_limit = AXP_VBUS_LIMIT_500mA;
123 charge_current = 550;
124 }
125
126 axp_set_vbus_limit(vbus_limit);
127 axp_set_charge_current(charge_current);
128} 103}
129#endif 104#endif
130 105
@@ -136,28 +111,23 @@ void power_off(void)
136 111
137bool charging_state(void) 112bool charging_state(void)
138{ 113{
139 return axp_is_charging(); 114 return axp_battery_status() == AXP_BATT_CHARGING;
140}
141
142unsigned int power_input_status(void)
143{
144 return axp_power_input_status();
145} 115}
146 116
147int _battery_voltage(void) 117int _battery_voltage(void)
148{ 118{
149 /* CW2015 can also read battery voltage, but the AXP consistently 119 /* CW2015 can also read battery voltage, but the AXP consistently
150 * reads ~20-30 mV higher so I suspect it's the "real" voltage. */ 120 * reads ~20-30 mV higher so I suspect it's the "real" voltage. */
151 return axp_read_adc(AXP_ADC_BATTERY_VOLTAGE); 121 return axp_adc_read(ADC_BATTERY_VOLTAGE);
152} 122}
153 123
154#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE 124#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE
155int _battery_current(void) 125int _battery_current(void)
156{ 126{
157 if(charging_state()) 127 if(charging_state())
158 return axp_read_adc(AXP_ADC_CHARGE_CURRENT); 128 return axp_adc_read(ADC_CHARGE_CURRENT);
159 else 129 else
160 return axp_read_adc(AXP_ADC_DISCHARGE_CURRENT); 130 return axp_adc_read(ADC_DISCHARGE_CURRENT);
161} 131}
162#endif 132#endif
163 133