Hi, Attached code is a little program to decode AXP20x registers and present their values in a readable way.
By default it looks for AXP20x mfd driver's regmap in sysfs. Not all registers are being decoded yet (missing are e.g. GPIOs). Some undocumented registers are mentioned (e.g. OCV values, RDC). A nice bonus would be to add support for reading the regs directly via i2c (in order to easily display register status under 3.4 kernels). Bruno -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
/* * AXP20x register decoding utility * * Copyright 2014 Bruno Prémont <[email protected]> * * This file is subject to the terms and conditions of the GNU General * Public License. See the file "COPYING" in the main directory of this * archive for more details. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <dirent.h> #include <stdint.h> #include <sys/stat.h> struct { const char *b0; const char *b1; const char *b2; const char *b3; const char *b4; const char *b5; const char *b6; const char *b7; const char *bR; const char *rst; const char *inv; const char *bld; const char *h; const char *err; } c = { .b0 = "\033[48;5;1;30m", .b1 = "\033[48;5;2;30m", .b2 = "\033[48;5;3;30m", .b3 = "\033[48;5;4;30m", .b4 = "\033[48;5;5;30m", .b5 = "\033[48;5;6;30m", .b6 = "\033[48;5;10;30m", .b7 = "\033[48;5;12;30m", .bR = "\033[48;5;8;30m", .rst = "\033[0m", .inv = "\033[7m", .bld = "\033[1m", .h = "\033[34m", .err = "\033[31m", }; #define MASK_COLOR_0 0 #define MASK_COLOR_1 1 #define MASK_COLOR_2 2 #define MASK_COLOR_3 3 #define MASK_COLOR_4 4 #define MASK_COLOR_5 5 #define MASK_COLOR_6 6 #define MASK_COLOR_7 7 #define MASK_COLOR_R 8 #define MASK_COLOR(mc) ((const char *)(((void **)&c.b0)[mc])) struct mask_info { uint8_t mask; uint8_t color; const char *name; void (*print)(uint8_t reg, const uint8_t *values, const struct mask_info *mi); const char **data; }; void print_reg(uint8_t reg, const char *name, const uint8_t *values, const struct mask_info *masks) { int i, j; for (i = 7; i >= 0; i--) if (!masks) printf("%s%d", c.bR, (values[reg] & (1 << i)) ? 1 : 0); else for (j = 0; j < 8 && masks[j].mask; j++) if (masks[j].mask & (1 << i)) printf("%s%d", MASK_COLOR(masks[j].color), (values[reg] & (1 << i)) ? 1 : 0); printf("%s%s 0x%02hhx%s @ 0x%02hhx %s%s%s\n", c.inv, c.bR, values[reg], c.rst, reg, c.bld, name, c.rst); if (!masks) return; for (j = 0; j < 8 && masks[j].mask; j++) { if (!masks[j].name) continue; printf("%s%s", MASK_COLOR(masks[j].color), c.inv); for (i = 7; i >= 0; i--) if (masks[j].mask & (1 << i)) printf("%d", (values[reg] & (1 << i)) ? 1 : 0); else printf(" "); if (masks[j].print) { printf("%s %s: ", c.rst, masks[j].name); masks[j].print(reg, values, &masks[j]); printf("\n"); } else printf("%s %s\n", c.rst, masks[j].name); } } void print_reg_bool(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { if (values[reg] & mi->mask) printf("%s", mi->data ? mi->data[1] : "ON"); else printf("%s", mi->data ? mi->data[0] : "off"); } void print_reg_23(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%dmV", 700 + (values[reg] & mi->mask) * 25); } void print_reg_28a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%dmV", 1800 + ((values[reg] & mi->mask) >> 4) * 100); } void print_reg_28b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "1.25", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "2.0", "2.5", "2.7", "2.8", "3.0", "3.1", "3.2", "3.3" }; printf("%sV", labels[values[reg] & mi->mask]); } void print_reg_30a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%dmV", 4000 + ((values[reg] & mi->mask) >> 3) * 100); } void print_reg_30b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "900mA", "500mA", "100mA", "unlimited" }; printf("%s", labels[values[reg] & mi->mask]); } void print_reg_31(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%dmV", 2600 + (values[reg] & mi->mask) * 100); } void print_reg_32a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "high resistance", "25%, 1Hz flicker", "25%, 4Hz flicker", "Low level output" }; printf("%s", labels[(values[reg] & mi->mask) >> 4]); } void print_reg_32b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "128ms", "1s", "2s", "3s" }; printf("%s", labels[values[reg] & mi->mask]); } void print_reg_33a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "4.1V", "4.15V", "4.2V", "4.36V" }; printf("%s", labels[(values[reg] & mi->mask) >> 5]); } void print_reg_33b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%dmA", 300 + (values[reg] & mi->mask) * 100); } void print_reg_34a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "40min", "50min", "60min", "70min" }; printf("%s", labels[(values[reg] & mi->mask) >> 6]); } void print_reg_34b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "6hour", "8hour", "10hour", "12hour" }; printf("%s", labels[values[reg] & mi->mask]); } void print_reg_35a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "3.1V", "3.0V", "3.6V", "2.5V" }; printf("%s", labels[(values[reg] & mi->mask) >> 5]); } void print_reg_35b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "50µA", "100µA", "200µA", "400µA" }; printf("%s", labels[values[reg] & mi->mask]); } void print_reg_36a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "128ms", "3s", "1s", "2s" }; printf("%s", labels[(values[reg] & mi->mask) >> 6]); } void print_reg_36b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "1.0s", "1.5s", "2.0s", "2.5s" }; printf("%s", labels[(values[reg] & mi->mask) >> 4]); } void print_reg_36c(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "4s", "6s", "8s", "10s" }; printf("%s", labels[values[reg] & mi->mask]); } void print_reg_37(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%d.%03dMHz", 15 * (100 + (values[reg] & mi->mask) * 5) / 1000, 15 * (100 + (values[reg] & mi->mask) * 5) % 1000); } void print_reg_84a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "25Hz", "50Hz", "100Hz", "200Hz" }; printf("%s", labels[(values[reg] & mi->mask) >> 6]); } void print_reg_84b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "20µA", "40µA", "60µA", "80µA" }; printf("%s", labels[(values[reg] & mi->mask) >> 4]); } void print_reg_84c(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "disabled", "current while charging", "input while ADC sampling", "always-on" }; printf("%s", labels[values[reg] & mi->mask]); } void print_reg_8a(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%dmin", values[reg] & mi->mask); } void print_reg_8b(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { const char *labels[] = { "4.0V", "4.15V", "4.45V", "4.55V" }; printf("%s", labels[(values[reg] & mi->mask) >> 4]); } void print_reg_b9(uint8_t reg, const uint8_t *values, const struct mask_info *mi) { printf("%d%%", values[reg] & mi->mask); } const char *mask_info_presence[] = { "absent", "present" }; const char *mask_info_available[] = { "not available", "available" }; const char *mask_info_charging[] = { "discharging", "charging" }; const char *mask_info_shorted[] = { "independent", "shorted on PCB" }; const char *mask_info_powertrigger[] = { "other", "ACIN / VBUS powered" }; const char *mask_info_yes_no[] = { "no", "yes" }; const char *mask_info_over_ok[] = { "ok", "over" }; const char *mask_info_charge_idle[] = { "idle / charged", "charging" }; const char *mask_info_batt_activation[] = { "activation not started", "activation mode entered" }; const char *mask_info_chg_curr_match [] = { "charge current matches target", "charge current below target" }; const char *mask_info_v_rise_slope[] = { "25mV/15.625µs -> 1.6mV/µs", "25mV/31.250µs -> 0.8mV/µs" }; const char *mask_info_ldo3_mode[] = { "set by control value", "deteréined by LDO3IN" }; const char *mask_info_vbus_ipsout[] = { "enable permit if N_VBUSEN pin", "enable permitted" }; const char *mask_info_vbus_vlimit[] = { "not limited", "limited" }; const char *mask_info_cghled_ctrl[] = { "charing controller", "CHG-LED mode setting" }; const char *mask_info_pwoff_sync[] = { "Synchrnous disable", "Revers ordering of startup timing" }; const char *mask_info_chg_end_curr[] = { "End when below 10% of target", "End when below 15% of target" }; const char *mask_info_chg_led_chg_mode[] = { "Solid on", "Blinking on" }; const char *mask_info_pwrok_delay[] = { "8ms", "64ms" }; const char *mask_info_dcdc_workmode[] = { "PFM/PWM automatic switching", "fixed: PWM" }; const char *mask_info_ts_function[] = { "Battery temperature", "Independent signal" }; const char *mask_info_gpio_adc_range[] = { "0..2.0475V", "0.7..2.7475V" }; const char *mask_info_fuel_gauge[] = { "normal mode", "suspended" }; static struct mask_info AXP20x_00_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "ACIN presence", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "ACIN usable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "VBUS presence", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "VBUS usable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "VBUS > VHOLD", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "BATT current direction", .print = print_reg_bool, .data = mask_info_charging }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "ACIN/VBUS", .print = print_reg_bool, .data = mask_info_shorted }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "Power-on trigger", .print = print_reg_bool, .data = mask_info_powertrigger }, { } }; static struct mask_info AXP20x_01_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "AXP20x Temperature", .print = print_reg_bool, .data = mask_info_over_ok }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "BATT", .print = print_reg_bool, .data = mask_info_charge_idle }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "BATT presence", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "BATT", .print = print_reg_bool, .data = mask_info_batt_activation }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "BATT", .print = print_reg_bool, .data = mask_info_chg_curr_match }, { .mask = 0x13, .color = MASK_COLOR_R, .name = "Reserved" }, { } }; static struct mask_info AXP20x_02_masks[] = { { .mask = 0xf8, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "OTG valid", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "OTG session A/B valid", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "OTG session end", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_12_masks[] = { { .mask = 0xa0, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "LDO3 switch control", .print = print_reg_bool }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "DC-DC2 switch control", .print = print_reg_bool }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "LDO4 switch control", .print = print_reg_bool }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "LDO2 switch control", .print = print_reg_bool }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "DC-DC3 switch control", .print = print_reg_bool }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "EXTEN switch control", .print = print_reg_bool }, { } }; static struct mask_info AXP20x_23_masks[] = { { .mask = 0xc0, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x3f, .color = MASK_COLOR_2, .name = "DC-DC2 ouput voltage control", .print = print_reg_23 }, { } }; static struct mask_info AXP20x_25_masks[] = { { .mask = 0xf0, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "LDO3 VRC enabled", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "DC-DC2 VRC enabled", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "LDO3 VRC voltage rising slope", .print = print_reg_bool, .data = mask_info_v_rise_slope }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "DC-DC2 voltage rising slope", .print = print_reg_bool, .data = mask_info_v_rise_slope }, { } }; static struct mask_info AXP20x_27_masks[] = { { .mask = 0x80, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x7f, .color = MASK_COLOR_1, .name = "DC-DC3 ouput voltage control", .print = print_reg_23 }, { } }; static struct mask_info AXP20x_28_masks[] = { { .mask = 0xf0, .color = MASK_COLOR_0, .name = "LDO2 output voltage control", .print = print_reg_28a }, { .mask = 0x0f, .color = MASK_COLOR_4, .name = "LDO4 output voltage control", .print = print_reg_28b }, { } }; static struct mask_info AXP20x_29_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "LDO3 mode", .print = print_reg_bool, .data = mask_info_ldo3_mode }, { .mask = 0x7f, .color = MASK_COLOR_1, .name = "LDO3 ouput voltage control", .print = print_reg_23 }, { } }; static struct mask_info AXP20x_30_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "VBUS-IPSOUT path select", .print = print_reg_bool, .data = mask_info_vbus_ipsout }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "VBUS VHold voltage limit", .print = print_reg_bool, .data = mask_info_vbus_vlimit }, { .mask = 0x38, .color = MASK_COLOR_2, .name = "VHOLD limit voltage", .print = print_reg_30a }, { .mask = 0x04, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x03, .color = MASK_COLOR_7, .name = "VBUS current limit", .print = print_reg_30b }, { } }; static struct mask_info AXP20x_31_masks[] = { { .mask = 0xf0, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "PEK/GPIO wake from sleep", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x07, .color = MASK_COLOR_5, .name = "Voff setting", .print = print_reg_31 }, { } }; static struct mask_info AXP20x_32_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Shutdown control", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "Battery monitoring", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x30, .color = MASK_COLOR_2, .name = "CHG-LED mode", .print = print_reg_32a }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "CHG-LED pin control", .print = print_reg_bool, .data = mask_info_cghled_ctrl }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "Output disable timing", .print = print_reg_bool, .data = mask_info_pwoff_sync }, { .mask = 0x03, .color = MASK_COLOR_6, .name = "N_OE shutdown delay", .print = print_reg_32b }, { } }; static struct mask_info AXP20x_33_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Charging enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x60, .color = MASK_COLOR_1, .name = "Charging target voltage", .print = print_reg_33a }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "Charging end-current", .print = print_reg_bool, .data = mask_info_chg_end_curr }, { .mask = 0x0f, .color = MASK_COLOR_4, .name = "Charging target current", .print = print_reg_33b }, { } }; static struct mask_info AXP20x_34_masks[] = { { .mask = 0xc0, .color = MASK_COLOR_0, .name = "Pre-charge timeout", .print = print_reg_34a }, { .mask = 0x2c, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "CHG-LED charging mode", .print = print_reg_bool, .data = mask_info_chg_led_chg_mode }, { .mask = 0x03, .color = MASK_COLOR_6, .name = "Constant-current timeout", .print = print_reg_34b }, { } }; static struct mask_info AXP20x_35_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Backup battery charge enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x60, .color = MASK_COLOR_1, .name = "Backup battery charge target voltage", .print = print_reg_35a }, { .mask = 0x1c, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x03, .color = MASK_COLOR_6, .name = "Backup battery charge current", .print = print_reg_35b }, { } }; static struct mask_info AXP20x_36_masks[] = { { .mask = 0xc0, .color = MASK_COLOR_0, .name = "PEK Startup time", .print = print_reg_36a }, { .mask = 0x30, .color = MASK_COLOR_2, .name = "PEK Long-press time", .print = print_reg_36b }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "Force-shutdown on long press", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "PWROK signal delay", .print = print_reg_bool, .data = mask_info_pwrok_delay }, { .mask = 0x03, .color = MASK_COLOR_6, .name = "PEK shutdown press time", .print = print_reg_36c }, { } }; static struct mask_info AXP20x_37_masks[] = { { .mask = 0xf0, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x0f, .color = MASK_COLOR_4, .name = "DC-DC operating freq", .print = print_reg_37 }, { } }; static struct mask_info AXP20x_80_masks[] = { { .mask = 0xf9, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "DC-DC2 work mode", .print = print_reg_bool, .data = mask_info_dcdc_workmode }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "DC-DC3 work mode", .print = print_reg_bool, .data = mask_info_dcdc_workmode }, { } }; static struct mask_info AXP20x_82_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Battery voltage ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "Battery current ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "ACIN voltage ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "ACIN current ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "VBUS voltage ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "VBUS current ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "APS voltage ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "TS pin ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_83_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Internal temp ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x73, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "GPIO0 voltage ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "GPIO1 voltage ADC enable", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_84_masks[] = { { .mask = 0xc0, .color = MASK_COLOR_0, .name = "ADC sample rate", .print = print_reg_84a }, { .mask = 0x30, .color = MASK_COLOR_2, .name = "TS pin current setting", .print = print_reg_84b }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "Reserved" }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "TS pin function", .print = print_reg_bool, .data = mask_info_ts_function }, { .mask = 0x03, .color = MASK_COLOR_6, .name = "TS pin current out method", .print = print_reg_84c }, { } }; static struct mask_info AXP20x_85_masks[] = { { .mask = 0xfc, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "GPIO0 ADC input range", .print = print_reg_bool, .data = mask_info_gpio_adc_range }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "GPIO1 ADC input range", .print = print_reg_bool, .data = mask_info_gpio_adc_range }, { } }; static struct mask_info AXP20x_8a_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Timer timeout", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x7f, .color = MASK_COLOR_1, .name = "Timer interval", .print = print_reg_8a }, { } }; static struct mask_info AXP20x_8b_masks[] = { { .mask = 0xc0, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x30, .color = MASK_COLOR_2, .name = "VBUS valid voltage", .print = print_reg_8b }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "VBUS valid detect", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "VBUS session detect", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "VBUS discharge resistance", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "VBUS charge resistance", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_8f_masks[] = { { .mask = 0xfb, .color = MASK_COLOR_R, .name = "Reserved" }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "Shutdown on over-temp", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_40_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "IRQ: ACIN over-voltage", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "IRQ: ACIN connected", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "IRQ: ACIN removed", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "IRQ: VBUS over-voltage", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "IRQ: VBUS connected", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "IRQ: VBUS removed", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "IRQ: VBUS available but < Vhold", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_R, .name = "IRQ: reserved" }, { } }; static struct mask_info AXP20x_41_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "IRQ: Battery connected", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "IRQ: Battery removed", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "IRQ: Battery activate mode", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "IRQ: Battery activate exit", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "IRQ: Battery charging", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "IRQ: Battery charge done", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "IRQ: Battery over-temperature", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "IRQ: Battery low-temperature", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_42_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "IRQ: AXP over-temperature", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "IRQ: Charge current low", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_R, .name = "IRQ: Reserved" }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "IRQ: DC-DC2 voltage low", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "IRQ: DC-DC3 voltage low", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "IRQ: LDO3 voltage low", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "IRQ: PEK short press", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "IRQ: PEK long press", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_43_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "IRQ: N_OE startup", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "IRQ: N_OE shutdown", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "IRQ: VBUS valid", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "IRQ: VBUS invalid", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "IRQ: VBUS Session A/B", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "IRQ: VBUS Session end", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "IRQ: APS low-voltage (level 1)", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "IRQ: APS low-voltage (level 2)", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_44_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "IRQ: Timer timeout", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "IRQ: PEK press rising edge", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "IRQ: PEK press falling edge", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x10, .color = MASK_COLOR_3, .name = "IRQ: Reserved" }, { .mask = 0x08, .color = MASK_COLOR_4, .name = "IRQ: GPIO3 in edge trigger", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x04, .color = MASK_COLOR_5, .name = "IRQ: GPIO2 in edge trigger", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "IRQ: GPIO1 in edge trigger", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "IRQ: GPIO0 in edge trigger", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_b8_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Coulomb counter enable", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x40, .color = MASK_COLOR_1, .name = "Suspend coulomb counter", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x20, .color = MASK_COLOR_2, .name = "Clear coulomb counter", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x1c, .color = MASK_COLOR_3, .name = "Reserved" }, { .mask = 0x02, .color = MASK_COLOR_6, .name = "Decrypt start bit", .print = print_reg_bool, .data = mask_info_yes_no }, { .mask = 0x01, .color = MASK_COLOR_7, .name = "Decrypt finished", .print = print_reg_bool, .data = mask_info_yes_no }, { } }; static struct mask_info AXP20x_b9_masks[] = { { .mask = 0x80, .color = MASK_COLOR_0, .name = "Fuel gauge system", .print = print_reg_bool, .data = mask_info_fuel_gauge }, { .mask = 0x7f, .color = MASK_COLOR_1, .name = "Fuel gauge", .print = print_reg_b9 }, { } }; static struct mask_info AXP20x_ADC_HI_masks[] = { { .mask = 0xff, .color = MASK_COLOR_0 }, { } }; static struct mask_info AXP20x_ADC_LO4_masks[] = { { .mask = 0xf0, .color = MASK_COLOR_R }, { .mask = 0x0f, .color = MASK_COLOR_4 }, { } }; static struct mask_info AXP20x_ADC_LO5_masks[] = { { .mask = 0xe0, .color = MASK_COLOR_R }, { .mask = 0x1f, .color = MASK_COLOR_3 }, { } }; void axp20x_decode_reg(uint8_t reg, uint8_t val, const uint8_t *vals) { switch (reg) { case 0x00: /* RO - Power status */ print_reg(reg, "AXP20X_PWR_INPUT_STATUS", vals, AXP20x_00_masks); break; case 0x01: /* RO - Power mode / charge state */ print_reg(reg, "AXP20X_PWR_OP_MODE", vals, AXP20x_01_masks); break; case 0x02: /* RO - OTG VBUS state */ print_reg(reg, "AXP20X_USB_OTG_STATUS", vals, AXP20x_02_masks); break; case 0x04: /* RW - Data buffer */ case 0x05: /* RW - Data buffer */ case 0x06: /* RW - Data buffer */ case 0x07: /* RW - Data buffer */ case 0x08: /* RW - Data buffer */ case 0x09: /* RW - Data buffer */ case 0x0a: /* RW - Data buffer */ case 0x0b: /* RW - Data buffer */ case 0x0c: /* RW - Data buffer */ case 0x0d: /* RW - Data buffer */ case 0x0e: /* RW - Data buffer */ case 0x0f: /* RW - Data buffer */ print_reg(reg, "AXP20X_DATA_CACHE_<reg>", vals, NULL); break; case 0x12: /* RW - DC-DC2/3 & LDO2/3/4&EXTEN control */ print_reg(reg, "AXP20X_PWR_OUT_CTRL", vals, AXP20x_12_masks); break; case 0x23: /* RW - DC-DC2 voltage setting */ print_reg(reg, "AXP20X_DCDC2_V_OUT", vals, AXP20x_23_masks); break; case 0x25: /* RW - DC-DC2/LDO3 voltage ramp parameter etting */ print_reg(reg, "AXP20X_DCDC2_LDO3_V_SCAL", vals, AXP20x_25_masks); break; case 0x27: /* RW - DC-DC3 voltage setting */ print_reg(reg, "AXP20X_DCDC3_V_OUT", vals, AXP20x_27_masks); break; case 0x28: /* RW - LDO2/3 voltage setting */ print_reg(reg, "AXP20X_LDO24_V_OUT", vals, AXP20x_28_masks); break; case 0x29: /* not documented */ print_reg(reg, "AXP20X_LDO3_V_OUT", vals, AXP20x_29_masks); break; case 0x30: /* RW - VBUS-IPSOUT channel setting */ print_reg(reg, "AXP20X_VBUS_IPSOUT_MGMT", vals, AXP20x_30_masks); break; case 0x31: /* RW - Voff shutdown voltage setting */ print_reg(reg, "AXP20X_V_OFF", vals, AXP20x_31_masks); break; case 0x32: /* RW - Shutdown, battery detection, CHGLED control */ print_reg(reg, "AXP20X_OFF_CTRL", vals, AXP20x_32_masks); break; case 0x33: /* RW - Charge control 1 */ print_reg(reg, "AXP20X_CHRG_CTRL1", vals, AXP20x_33_masks); break; case 0x34: /* RW - Charge controle 2 */ print_reg(reg, "AXP20X_CHRG_CTRL2", vals, AXP20x_34_masks); break; case 0x35: /* RW - Backup battery charge control */ print_reg(reg, "AXP20X_CHRG_BAK_CTRL", vals, AXP20x_35_masks); break; case 0x36: /* RW - PEK parameter control */ print_reg(reg, "AXP20X_PEK_KEY", vals, AXP20x_36_masks); break; case 0x37: /* RW - DCDC converter work frequency setting */ print_reg(reg, "AXP20X_DCDC_FREQ", vals, AXP20x_37_masks); break; case 0x38: /* RW - Battery charge under-temperature warning setting */ print_reg(reg, "AXP20X_V_LTF_CHRG", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", vals[0x38] * 0x10 * 8 / 10000, vals[0x38] * 0x10 * 8 / 10 % 1000); break; case 0x39: /* RW - Battery charge over-temperature warning setting */ print_reg(reg, "AXP20X_V_HTF_CHRG", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", vals[0x39] * 0x10 * 8 / 10000, vals[0x39] * 0x10 * 8 / 10 % 1000); break; case 0x3a: /* RW - APS low-power level 1 setting */ print_reg(reg, "AXP20X_APS_WARN_L1", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", (28672 + 14 * vals[0x3a] * 4) / 10000, (28672 + 14 * vals[0x3a] * 4) / 10 % 1000); break; case 0x3b: /* RW - APS low-power level 2 setting */ print_reg(reg, "AXP20X_APS_WARN_L2", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", (28672 + 14 * vals[0x3b] * 4) / 10000, (28672 + 14 * vals[0x3b] * 4) / 10 % 1000); break; case 0x3c: /* RW - Battery discharge under-temperature warning setting */ print_reg(reg, "AXP20X_V_LTF_DISCHRG", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", vals[0x3c] * 0x10 * 8 / 10000, vals[0x3c] * 0x10 * 8 / 10 % 1000); break; case 0x3d: /* RW - Battery discharge over-temperature warning setting */ print_reg(reg, "AXP20X_V_HTF_DISCHRG", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", vals[0x3d] * 0x10 * 8 / 10000, vals[0x3d] * 0x10 * 8 / 10 % 1000); break; case 0x40: /* RW - IRQ enable control 1 */ print_reg(reg, "AXP20X_IRQ1_EN", vals, AXP20x_40_masks); break; case 0x41: /* RW - IRQ enable control 2 */ print_reg(reg, "AXP20X_IRQ2_EN", vals, AXP20x_41_masks); break; case 0x42: /* RW - IRQ enable control 3 */ print_reg(reg, "AXP20X_IRQ3_EN", vals, AXP20x_42_masks); break; case 0x43: /* RW - IRQ enable control 4 */ print_reg(reg, "AXP20X_IRQ4_EN", vals, AXP20x_43_masks); break; case 0x44: /* RW - IRQ enable control 5 */ print_reg(reg, "AXP20X_IRQ5_EN", vals, AXP20x_44_masks); break; case 0x48: /* RW - IRQ status 1 */ print_reg(reg, "AXP20X_IRQ1_STATE", vals, AXP20x_40_masks); break; case 0x49: /* RW - IRQ status 2 */ print_reg(reg, "AXP20X_IRQ2_STATE", vals, AXP20x_41_masks); break; case 0x4a: /* RW - IRQ status 3 */ print_reg(reg, "AXP20X_IRQ3_STATE", vals, AXP20x_42_masks); break; case 0x4b: /* RW - IRQ status 4 */ print_reg(reg, "AXP20X_IRQ4_STATE", vals, AXP20x_43_masks); break; case 0x4c: /* RW - IRQ status 5 */ print_reg(reg, "AXP20X_IRQ5_STATE", vals, AXP20x_44_masks); break; case 0x56: /* RO - ACIN Voltage HI */ print_reg(reg, "AXP20X_ACIN_V_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x57: /* RO - ACIN Voltage LO */ print_reg(reg, "AXP20X_ACIN_V_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dV\n", ((vals[0x56] << 4) | (vals[0x57] & 0x0f)) * 17 / 10000, ((vals[0x56] << 4) | (vals[0x57] & 0x0f)) * 17 / 10 % 1000); break; case 0x58: /* RO - ACIN Current HI */ print_reg(reg, "AXP20X_ACIN_I_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x59: /* RO - ACIN Current LO */ print_reg(reg, "AXP20X_ACIN_I_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dmA\n", ((vals[0x58] << 4) | (vals[0x59] & 0x0f)) * 625 / 1000, ((vals[0x58] << 4) | (vals[0x59] & 0x0f)) * 625 % 1000); break; case 0x5a: /* RO - VBUS Voltage HI */ print_reg(reg, "AXP20X_VBUS_V_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x5b: /* RO - VBUS Voltage LO */ print_reg(reg, "AXP20X_VBUS_V_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dV\n", ((vals[0x5a] << 4) | (vals[0x5b] & 0x0f)) * 17 / 10000, ((vals[0x5a] << 4) | (vals[0x5b] & 0x0f)) * 17 / 10 % 1000); break; case 0x5c: /* RO - VBUS Current HI */ print_reg(reg, "AXP20X_VBUS_I_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x5d: /* RO - VBUS Current LO */ print_reg(reg, "AXP20X_VBUS_I_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dmA\n", ((vals[0x5c] << 4) | (vals[0x5d] & 0x0f)) * 375 / 1000, ((vals[0x5c] << 4) | (vals[0x5d] & 0x0f)) * 375 % 1000); break; case 0x5e: /* RO - TEMP internal temperature HI */ print_reg(reg, "AXP20X_TEMP_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x5f: /* RO - TEMP internal temperature LO */ print_reg(reg, "AXP20X_TEMP_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%d°C\n", (((vals[0x5e] << 4) | (vals[0x5f] & 0x0f)) * 1 - 1447) / 10, (((vals[0x5e] << 4) | (vals[0x5f] & 0x0f)) * 1 - 1447) % 10); break; case 0x62: /* RO - TEMP Battery temperature sensor Voltage HI */ print_reg(reg, "AXP20X_TS_IN_H", vals, AXP20x_ADC_HI_masks); break; case 0x63: /* RO - TEMP Battery temperature sensor Voltage LO */ print_reg(reg, "AXP20X_TS_IN_L", vals, AXP20x_ADC_LO4_masks); printf(" %4dmV\n", ((vals[0x62] << 4) | (vals[0x63] & 0x0f)) * 8 / 10); break; case 0x64: /* RO - GPIO Voltage HI */ print_reg(reg, "AXP20X_GPIO0_V_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x65: /* RO - GPIO Voltage LO */ print_reg(reg, "AXP20X_GPIO0_V_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dV\n", ((vals[0x5a] << 4) | (vals[0x5b] & 0x0f)) * 17 / 10000, ((vals[0x5a] << 4) | (vals[0x5b] & 0x0f)) * 17 / 10 % 1000); break; case 0x66: /* RO - GPI1 Voltage HI */ print_reg(reg, "AXP20X_GPIO1_V_ADC_H", vals, AXP20x_ADC_HI_masks); break; case 0x67: /* RO - GPI1 Voltage HI */ print_reg(reg, "AXP20X_GPIO1_V_ADC_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dV\n", ((vals[0x5a] << 4) | (vals[0x5b] & 0x0f)) * 17 / 10000, ((vals[0x5a] << 4) | (vals[0x5b] & 0x0f)) * 17 / 10 % 1000); break; case 0x70: /* RO - BATT instant power HI */ print_reg(reg, "AXP20X_PWR_BATT_H", vals, AXP20x_ADC_HI_masks); break; case 0x71: /* RO - BATT instant power MI */ print_reg(reg, "AXP20X_PWR_BATT_M", vals, AXP20x_ADC_HI_masks); break; case 0x72: /* RO - BATT instant power LO */ print_reg(reg, "AXP20X_PWR_BATT_L", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dmW\n", 2 * ((vals[0x70] << 16) | (vals[0x71] << 8) | vals[0x72]) * 11 * 5 / 100000, 2 * ((vals[0x70] << 16) | (vals[0x71] << 8) | vals[0x72]) * 11 * 5 / 100 % 1000); break; case 0x78: /* RO - BATT Voltage HI */ print_reg(reg, "AXP20X_BATT_V_H", vals, AXP20x_ADC_HI_masks); break; case 0x79: /* RO - BATT Voltage LO */ print_reg(reg, "AXP20X_BATT_V_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dV\n", ((vals[0x78] << 4) | (vals[0x79] & 0x1f)) * 11 / 10000, ((vals[0x78] << 4) | (vals[0x79] & 0x1f)) * 11 / 10 % 1000); break; case 0x7a: /* RO - BATT charge Current HI */ print_reg(reg, "AXP20X_BATT_CHRG_I_H", vals, AXP20x_ADC_HI_masks); break; case 0x7b: /* RO - BATT charge Current LO */ print_reg(reg, "AXP20X_BATT_CHRG_I_L", vals, AXP20x_ADC_LO4_masks); printf(" %4dmA\n", ((vals[0x7a] << 4) | (vals[0x7b] & 0x1f)) * 5 / 10); break; case 0x7c: /* RO - BATT discharge Current HI */ print_reg(reg, "AXP20X_BATT_DISCHRG_I_H", vals, AXP20x_ADC_HI_masks); break; case 0x7d: /* RO - BATT discharge Current LO */ print_reg(reg, "AXP20X_BATT_DISCHRG_I_L", vals, AXP20x_ADC_LO5_masks); printf(" %4dmA\n", ((vals[0x7c] << 5) | (vals[0x7d] & 0x0f)) * 5 / 10); break; case 0x7e: /* RO - IPSOUT Voltage HI */ print_reg(reg, "AXP20X_IPSOUT_V_HIGH_H", vals, AXP20x_ADC_HI_masks); break; case 0x7f: /* RO - IPSOUT Voltage LO */ print_reg(reg, "AXP20X_IPSOUT_V_HIGH_L", vals, AXP20x_ADC_LO4_masks); printf(" %4d.%03dV\n", ((vals[0x7e] << 4) | (vals[0x7f] & 0x1f)) * 14 / 10000, ((vals[0x7e] << 4) | (vals[0x7f] & 0x1f)) * 14 / 10 % 1000); break; case 0x80: /* RW - DCDC work mode setting */ print_reg(reg, "AXP20X_DCDC_MODE", vals, AXP20x_80_masks); break; case 0x82: /* RW - ADC enable setting 1 */ print_reg(reg, "AXP20X_ADC_EN1", vals, AXP20x_82_masks); break; case 0x83: /* RW - ADC enable setting 2 */ print_reg(reg, "AXP20X_ADC_EN2", vals, AXP20x_83_masks); break; case 0x84: /* RW - ADC sample rate setting . TS pin control */ print_reg(reg, "AXP20X_ADC_RATE", vals, AXP20x_84_masks); break; case 0x85: /* RW - GPIO [1:0] input range setting */ print_reg(reg, "AXP20X_GPIO10_IN_RANGE", vals, AXP20x_85_masks); break; case 0x86: /* RW - GPIO1 ADC IRQ rising edge threshold setting */ print_reg(reg, "AXP20X_GPIO1_ADC_IRQ_RIS", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", (vals[0x86] * 8) / 1000, (vals[0x86] * 8) % 1000); break; case 0x87: /* RW - GPIO1 ADC IRQ falling edge threshold setting */ print_reg(reg, "AXP20X_GPIO1_ADC_IRQ_FAL", vals, AXP20x_ADC_HI_masks); printf(" %4d.%03dV\n", (vals[0x87] * 8) / 1000, (vals[0x87] * 8) % 1000); break; case 0x8a: /* RW - Timer control */ print_reg(reg, "AXP20X_TIMER_CTRL", vals, AXP20x_8a_masks); break; case 0x8b: /* RW - VBUS monitoring setting */ print_reg(reg, "AXP20X_VBUS_MON", vals, AXP20x_8b_masks); break; case 0x8f: /* RW - Over-temperature shutdown control */ print_reg(reg, "AXP20X_OVER_TMP", vals, AXP20x_8f_masks); break; case 0x90: /* RW - GPIO control */ print_reg(reg, "AXP20X_GPIO0_CTRL", vals, NULL); break; case 0x91: /* RW - LDO5 output voltage setting */ print_reg(reg, "AXP20X_LDO5_V_OUT", vals, NULL); break; case 0x92: /* RW - GPIO1 control */ print_reg(reg, "AXP20X_GPIO1_CTRL", vals, NULL); break; case 0x93: /* RW - GPIO2 control */ print_reg(reg, "AXP20X_GPIO2_CTRL", vals, NULL); break; case 0x94: /* RW - GPIO [2:0] signal status */ print_reg(reg, "AXP20X_GPIO20_SS", vals, NULL); break; case 0x95: /* RW - GPIO3 control */ print_reg(reg, "AXP20X_GPIO3_CTRL", vals, NULL); break; case 0xb0: /* RW - BATT charge coulomb counter HI */ print_reg(reg, "AXP20X_CHRG_CC_31_24", vals, AXP20x_ADC_HI_masks); break; case 0xb1: /* RW - BATT charge coulomb counter MH */ print_reg(reg, "AXP20X_CHRG_CC_23_16", vals, AXP20x_ADC_HI_masks); break; case 0xb2: /* RW - BATT charge coulomb counter ML */ print_reg(reg, "AXP20X_CHRG_CC_15_8", vals, AXP20x_ADC_HI_masks); break; case 0xb3: /* RW - BATT charge coulomb counter LO */ print_reg(reg, "AXP20X_CHRG_CC_7_0", vals, AXP20x_ADC_HI_masks); printf(" %uC\n", ((vals[0xb0] << 24) | (vals[0xb1] << 16) | (vals[0xb2] << 8) | vals[0xb3])); break; case 0xb4: /* RW - BATT discharge coulomb counter HI */ print_reg(reg, "AXP20X_DISCHRG_CC_31_24", vals, AXP20x_ADC_HI_masks); break; case 0xb5: /* RW - BATT discharge coulomb counter MH */ print_reg(reg, "AXP20X_DISCHRG_CC_23_16", vals, AXP20x_ADC_HI_masks); break; case 0xb6: /* RW - BATT discharge coulomb counter ML */ print_reg(reg, "AXP20X_DISCHRG_CC_15_8", vals, AXP20x_ADC_HI_masks); break; case 0xb7: /* RW - BATT discharge coulomb counter LO */ print_reg(reg, "AXP20X_DISCHRG_CC_7_0", vals, AXP20x_ADC_HI_masks); printf(" %uC\n", ((vals[0xb4] << 24) | (vals[0xb5] << 16) | (vals[0xb6] << 8) | vals[0xb7])); break; case 0xb8: /* RW - BATT coulomb counter control */ print_reg(reg, "AXP20X_CC_CTRL", vals, AXP20x_b8_masks); break; case 0xb9: /* RW - BATT FuelGauge result */ print_reg(reg, "AXP20X_FG_RES", vals, AXP20x_b9_masks); break; case 0xba: /* not documented */ print_reg(reg, "AXP20X_RDC_H", vals, AXP20x_ADC_HI_masks); break; case 0xbb: /*not documented */ print_reg(reg, "AXP20X_RDC_L", vals, AXP20x_ADC_LO4_masks); printf(" %dmΩ\n", ((((vals[0xba] & 0x1f) << 8) | vals[0xbb]) * 10742 - 5371) / 10000); break; case 0xc0: /* not documented */ case 0xc1: /* not documented */ case 0xc2: /* not documented */ case 0xc3: /* not documented */ case 0xc4: /* not documented */ case 0xc5: /* not documented */ case 0xc6: /* not documented */ case 0xc7: /* not documented */ case 0xc8: /* not documented */ case 0xc9: /* not documented */ case 0xca: /* not documented */ case 0xcb: /* not documented */ case 0xcc: /* not documented */ case 0xcd: /* not documented */ case 0xce: /* not documented */ case 0xcf: /* not documented */ print_reg(reg, "OCV param", vals, NULL); printf(" %d%%\n", vals[reg]); break; default: if (vals[reg] != 0x00) print_reg(reg, "<unknown>", vals, NULL); } } void axp20x_decode_regs(const char *name, const char *regs, size_t regs_sz) { uint8_t r, v; char *p; long int l; int i; uint8_t vals[256], has_reg[256]; memset(has_reg, 0, sizeof(has_reg)); memset(vals, 0, sizeof(vals)); while (regs_sz >=6) { l = strtol(regs, &p, 16); if (p != regs+2) break; if (*p != ':') break; p++; if (*p != ' ') break; p++; r = l; l = strtol(regs+4, &p, 16); if (p != regs+6) break; v = l; regs_sz -= 6; regs += 6; while (regs_sz > 0 && (*regs == ' ' || *regs == '\n')) { regs++; regs_sz--; } has_reg[r] = 1; vals[r] = v; } for (i = 0; i < 256; i++) if (has_reg[i]) axp20x_decode_reg(i, vals[i], vals); } int main(int argc, char **argv) { struct dirent *dent; struct stat st; DIR *d = opendir("/sys/kernel/debug/regmap/"); if (!d) { fprintf(stderr, "%sIs debugfs mounted?\nFailed to open /sys/kernel/debug/regmap/: %s%s\n", c.err, strerror(errno), c.rst); return 1; } if (!isatty(1) && (argc < 2 || strcmp(argv[1], "-c") != 0)) { c.b0 = ""; c.b1 = ""; c.b2 = ""; c.b3 = ""; c.b4 = ""; c.b5 = ""; c.b6 = ""; c.b7 = ""; c.bR = ""; c.rst = ""; c.inv = ""; c.bld = ""; c.err = ""; c.h = ""; } if (fstat(0, &st) == 0 && S_ISREG(st.st_mode)) { char fcontent[4096]; ssize_t r; size_t l; printf("%sFound an axp20x: %sstdin%s\n", c.h, c.bld, c.rst); l = 0; do { r = read(0, fcontent+l, sizeof(fcontent)-l); if (r == 0) break; else if (r > 0) l += r; else if (errno != EINTR) { fprintf(stderr, "%sFailed to read from stdin after %zu bytes: %s%s\n", c.err, l, strerror(errno), c.rst); l = 0; break; } } while (l < sizeof(fcontent)); if (l < sizeof(fcontent)) { fcontent[l] = '\0'; axp20x_decode_regs("stdin", fcontent, l); return 0; } else fprintf(stderr, "%sFound more than %zu bytes in stdin, too much for my little brain!%s\n", c.err, sizeof(fcontent), c.rst); } while ((dent = readdir(d))) { char buff[256], fcontent[4096]; int fd; ssize_t r; size_t l; if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) continue; snprintf(buff, sizeof(buff), "/sys/kernel/debug/regmap/%s/name", dent->d_name); fd = open(buff, O_RDONLY); if (fd == -1) { fprintf(stderr, "%sFailed to open '%s': %s%s\n", c.err, buff, strerror(errno), c.rst); continue; } l = 0; do { r = read(fd, fcontent+l, sizeof(fcontent)-l); if (r == 0) break; else if (r > 0) l += r; else if (errno != EINTR) { fprintf(stderr, "%sFailed to read from '%s' after %zu bytes: %s%s\n", c.err, buff, l, strerror(errno), c.rst); l = 0; break; } } while (l < sizeof(fcontent)); close(fd); if (l < sizeof(fcontent)) fcontent[l] = '\0'; else { fprintf(stderr, "%sFound more than %zu bytes in '%s', too much for my little brain!%s\n", c.err, sizeof(fcontent), buff, c.rst); continue; } if (strncmp(fcontent, "axp20x", 6) != 0 || strspn(fcontent+6, " \t\n\r") + 6 != l) { fprintf(stderr, "%s'%s' is '%s'%s\n", c.err, dent->d_name, fcontent, c.rst); continue; } printf("%sFound an axp20x: %s%s%s\n", c.h, c.bld, dent->d_name, c.rst); snprintf(buff, sizeof(buff), "/sys/kernel/debug/regmap/%s/registers", dent->d_name); fd = open(buff, O_RDONLY); if (fd == -1) continue; l = 0; do { r = read(fd, fcontent+l, sizeof(fcontent)-l); if (r == 0) break; else if (r > 0) l += r; else if (errno != EINTR) { fprintf(stderr, "%sFailed to read from '%s' after %zu bytes: %s%s\n", c.err, buff, l, strerror(errno), c.rst); l = 0; break; } } while (l < sizeof(fcontent)); close(fd); if (l < sizeof(fcontent)) fcontent[l] = '\0'; else { fprintf(stderr, "%sFound more than %zu bytes in '%s', too much for my little brain!%s\n", c.err, sizeof(fcontent), buff, c.rst); continue; } axp20x_decode_regs(dent->d_name, fcontent, l); } closedir(d); return 0; }
