From 088ebb5fac02932178fe0da31dd8966472225bdf Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Wed, 21 Apr 2021 01:45:34 +0100 Subject: Minor enhancements to axp173 driver - Added register names to reduce usage of magic numbers - Added function to control max charging current, needed for USB - Corrected comment about axp173, since FiiO M3K has an axp192 Change-Id: I6604ce8d44e5a2ee84061cf042d17ccc4734ac57 --- firmware/drivers/axp173.c | 105 ++++++++++++++++----- firmware/export/axp173.h | 24 +++++ .../mips/ingenic_x1000/fiiom3k/button-fiiom3k.c | 10 +- .../mips/ingenic_x1000/fiiom3k/power-fiiom3k.c | 13 ++- 4 files changed, 120 insertions(+), 32 deletions(-) diff --git a/firmware/drivers/axp173.c b/firmware/drivers/axp173.c index 22417650fc..0c9b9c81a4 100644 --- a/firmware/drivers/axp173.c +++ b/firmware/drivers/axp173.c @@ -35,21 +35,22 @@ static const struct axp173_adc_info { uint8_t en_reg; uint8_t en_bit; } axp173_adc_info[NUM_ADC_CHANNELS] = { - {0x56, 0x82, 5}, /* ACIN_VOLTAGE */ - {0x58, 0x82, 4}, /* ACIN_CURRENT */ - {0x5a, 0x82, 3}, /* VBUS_VOLTAGE */ - {0x5c, 0x82, 2}, /* VBUS_CURRENT */ - {0x5e, 0x83, 7}, /* INTERNAL_TEMP */ - {0x62, 0x82, 1}, /* TS_INPUT */ - {0x78, 0x82, 7}, /* BATTERY_VOLTAGE */ - {0x7a, 0x82, 6}, /* CHARGE_CURRENT */ - {0x7c, 0x82, 6}, /* DISCHARGE_CURRENT */ - {0x7e, 0x82, 1}, /* APS_VOLTAGE */ - {0x70, 0xff, 0}, /* BATTERY_POWER */ + {0x56, AXP173_REG_ADCENABLE1, 5}, /* ACIN_VOLTAGE */ + {0x58, AXP173_REG_ADCENABLE1, 4}, /* ACIN_CURRENT */ + {0x5a, AXP173_REG_ADCENABLE1, 3}, /* VBUS_VOLTAGE */ + {0x5c, AXP173_REG_ADCENABLE1, 2}, /* VBUS_CURRENT */ + {0x5e, AXP173_REG_ADCENABLE2, 7}, /* INTERNAL_TEMP */ + {0x62, AXP173_REG_ADCENABLE1, 1}, /* TS_INPUT */ + {0x78, AXP173_REG_ADCENABLE1, 7}, /* BATTERY_VOLTAGE */ + {0x7a, AXP173_REG_ADCENABLE1, 6}, /* CHARGE_CURRENT */ + {0x7c, AXP173_REG_ADCENABLE1, 6}, /* DISCHARGE_CURRENT */ + {0x7e, AXP173_REG_ADCENABLE1, 1}, /* APS_VOLTAGE */ + {0x70, 0xff, 0}, /* BATTERY_POWER */ }; static struct axp173 { int adc_enable; + int chargecurrent_setting; } axp173; static void axp173_init_enabled_adcs(void) @@ -58,7 +59,8 @@ static void axp173_init_enabled_adcs(void) /* Read enabled ADCs from the hardware */ uint8_t regs[2]; - int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, 0x82, 2, ®s[0]); + int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, + AXP173_REG_ADCENABLE1, 2, ®s[0]); if(rc != I2C_STATUS_OK) return; @@ -68,7 +70,7 @@ static void axp173_init_enabled_adcs(void) if(info[i].en_reg == 0xff) continue; - if(regs[info[i].en_reg - 0x82] & info[i].en_bit) + if(regs[info[i].en_reg - AXP173_REG_ADCENABLE1] & info[i].en_bit) axp173.adc_enable |= 1 << i; } @@ -87,12 +89,16 @@ void axp173_init(void) int bits = axp173.adc_enable; bits |= (1 << ADC_DISCHARGE_CURRENT); axp173_adc_set_enabled(bits); + + /* Read the maximum charging current */ + int value = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_CHARGECONTROL1); + axp173.chargecurrent_setting = (value < 0) ? -1 : value; } /* TODO: this can STILL indicate some false positives! */ int axp173_battery_status(void) { - int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x00); + int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_POWERSTATUS); if(r >= 0) { /* Charging bit indicates we're currently charging */ if((r & 0x04) != 0) @@ -124,7 +130,7 @@ int axp173_input_status(void) int input_status = AXP173_INPUT_BATTERY; #endif - int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x00); + int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_POWERSTATUS); if(r < 0) return input_status; @@ -138,7 +144,7 @@ int axp173_input_status(void) #ifdef HAVE_BATTERY_SWITCH /* Check for battery presence if target defines it as removable */ - r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x01); + r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_CHARGESTATUS); if(r >= 0 && (r & 0x20) != 0) input_status |= AXP173_INPUT_BATTERY; #endif @@ -251,13 +257,13 @@ void axp173_adc_set_enabled(int adc_bits) } /* Update the configuration */ - i2c_reg_write(AXP173_BUS, AXP173_ADDR, 0x82, 2, ®s[0]); + i2c_reg_write(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCENABLE1, 2, ®s[0]); axp173.adc_enable = adc_bits; } int axp173_adc_get_rate(void) { - int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, 0x84); + int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCSAMPLERATE); if(r < 0) return AXP173_ADC_RATE_100HZ; /* an arbitrary value */ @@ -266,7 +272,7 @@ int axp173_adc_get_rate(void) void axp173_adc_set_rate(int rate) { - i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x84, + i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, AXP173_REG_ADCSAMPLERATE, 0xc0, (rate & 3) << 6, NULL); } @@ -278,7 +284,8 @@ static uint32_t axp173_cc_parse(const uint8_t* buf) void axp173_cc_read(uint32_t* charge, uint32_t* discharge) { uint8_t buf[8]; - int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, 0xb0, 8, &buf[0]); + int rc = i2c_reg_read(AXP173_BUS, AXP173_ADDR, + AXP173_REG_COULOMBCOUNTERBASE, 8, &buf[0]); if(rc != I2C_STATUS_OK) { if(charge) *charge = 0; @@ -295,19 +302,63 @@ void axp173_cc_read(uint32_t* charge, uint32_t* discharge) void axp173_cc_clear(void) { - i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0xb8, 5, 1, NULL); + i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, + AXP173_REG_COULOMBCOUNTERCTRL, 5, 1, NULL); } void axp173_cc_enable(bool en) { - i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0xb8, 7, en ? 1 : 0, NULL); + i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, + AXP173_REG_COULOMBCOUNTERCTRL, 7, en ? 1 : 0, NULL); +} + +static const int chargecurrent_tbl[] = { + 100, 190, 280, 360, + 450, 550, 630, 700, + 780, 880, 960, 1000, + 1080, 1160, 1240, 1320, +}; + +static const int chargecurrent_tblsz = sizeof(chargecurrent_tbl)/sizeof(int); + +void axp173_set_charge_current(int maxcurrent) +{ + /* Find the charge current just higher than maxcurrent */ + int value = 0; + while(value < chargecurrent_tblsz && + chargecurrent_tbl[value] <= maxcurrent) + ++value; + + /* Select the next lower current, the greatest current <= maxcurrent */ + if(value >= chargecurrent_tblsz) + value = chargecurrent_tblsz - 1; + else if(value > 0) + --value; + + /* Don't issue i2c write if desired setting is already in use */ + if(value == axp173.chargecurrent_setting) + return; + + /* Update register */ + i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, + AXP173_REG_CHARGECONTROL1, 0x0f, value, NULL); + axp173.chargecurrent_setting = value; +} + +int axp173_get_charge_current(void) +{ + if(axp173.chargecurrent_setting < 0) + return chargecurrent_tbl[0]; + else + return chargecurrent_tbl[axp173.chargecurrent_setting]; } #ifndef BOOTLOADER #define AXP173_DEBUG_BATTERY_STATUS 0 #define AXP173_DEBUG_INPUT_STATUS 1 -#define AXP173_DEBUG_ADC_RATE 2 -#define AXP173_DEBUG_FIRST_ADC 3 +#define AXP173_DEBUG_CHARGE_CURRENT 2 +#define AXP173_DEBUG_ADC_RATE 3 +#define AXP173_DEBUG_FIRST_ADC 4 #define AXP173_DEBUG_ENTRIES (AXP173_DEBUG_FIRST_ADC + NUM_ADC_CHANNELS) static int axp173_debug_menu_cb(int action, struct gui_synclist* lists) @@ -377,6 +428,12 @@ static const char* axp173_debug_menu_get_name(int item, void* data, return buf; } break; + case AXP173_DEBUG_CHARGE_CURRENT: { + int current = axp173_get_charge_current(); + snprintf(buf, buflen, "Max charge current: %d mA", current); + return buf; + } break; + case AXP173_DEBUG_ADC_RATE: { int rate = 25 << axp173_adc_get_rate(); snprintf(buf, buflen, "ADC sample rate: %d Hz", rate); diff --git a/firmware/export/axp173.h b/firmware/export/axp173.h index 60519138e1..34f0c2ec19 100644 --- a/firmware/export/axp173.h +++ b/firmware/export/axp173.h @@ -25,6 +25,7 @@ #include #include +/* ADC channels */ #define ADC_ACIN_VOLTAGE 0 #define ADC_ACIN_CURRENT 1 #define ADC_VBUS_VOLTAGE 2 @@ -55,6 +56,25 @@ #define AXP173_INPUT_BATTERY (1 << 2) #define AXP173_INPUT_EXTERNAL (AXP173_INPUT_AC|AXP173_INPUT_USB) +/* Registers -- common to AXP173 and AXP192 (incomplete listing) */ +#define AXP173_REG_POWERSTATUS 0x00 +#define AXP173_REG_CHARGESTATUS 0x01 +#define AXP173_REG_PWROUTPUTCTRL 0x12 +#define AXP173_REG_SHUTDOWNLEDCTRL 0x32 +#define AXP173_REG_CHARGECONTROL1 0x33 +#define AXP173_REG_DCDCWORKINGMODE 0x80 +#define AXP173_REG_ADCENABLE1 0x82 +#define AXP173_REG_ADCENABLE2 0x83 +#define AXP173_REG_ADCSAMPLERATE 0x84 +#define AXP173_REG_COULOMBCOUNTERBASE 0xb0 +#define AXP173_REG_COULOMBCOUNTERCTRL 0xb8 + +/* AXP192-only registers (incomplete listing) */ +#define AXP192_REG_GPIO0FUNCTION 0x90 +#define AXP192_REG_GPIO1FUNCTION 0x92 +#define AXP192_REG_GPIO2FUNCTION 0x93 +#define AXP192_REG_GPIOSTATE1 0x94 + /* Must be called from power_init() to initialize the driver state */ extern void axp173_init(void); @@ -88,6 +108,10 @@ extern void axp173_cc_read(uint32_t* charge, uint32_t* discharge); extern void axp173_cc_clear(void); extern void axp173_cc_enable(bool en); +/* Set/get maximum charging current in milliamps */ +extern void axp173_set_charge_current(int maxcurrent); +extern int axp173_get_charge_current(void); + /* Debug menu */ extern bool axp173_debug_menu(void); diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c index db5ece10b0..e27e0be464 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/button-fiiom3k.c @@ -23,13 +23,14 @@ #include "kernel.h" #include "backlight.h" #include "panic.h" -#include "lcd.h" +#include "axp173.h" #include "gpio-x1000.h" #include "i2c-x1000.h" #include #include #ifndef BOOTLOADER +# include "lcd.h" # include "font.h" #endif @@ -409,7 +410,7 @@ static int hp_detect_tmo_cb(struct timeout* tmo) static void hp_detect_init(void) { static struct timeout tmo; - static const uint8_t gpio_reg = 0x94; + static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1; static i2c_descriptor desc = { .slave_addr = AXP173_ADDR, .bus_cond = I2C_START | I2C_STOP, @@ -423,9 +424,8 @@ static void hp_detect_init(void) .next = NULL, }; - /* Headphone detect is wired to an undocumented GPIO on the AXP173. - * This sets it to input mode so we can see the pin state. */ - i2c_reg_write1(AXP173_BUS, AXP173_ADDR, 0x93, 0x01); + /* Headphone detect is wired to AXP192 GPIO: set it to input state */ + i2c_reg_write1(AXP173_BUS, AXP173_ADDR, AXP192_REG_GPIO2FUNCTION, 0x01); /* Get an initial reading before startup */ int r = i2c_reg_read1(AXP173_BUS, AXP173_ADDR, gpio_reg); diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c index b4923835aa..a3760d145a 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c @@ -68,8 +68,14 @@ void power_init(void) axp173_adc_set_enabled(bits); /* Turn on all power outputs */ - i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x12, 0, 0x5f, NULL); - i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, 0x80, 0, 0xc0, NULL); + i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, + AXP173_REG_PWROUTPUTCTRL, 0, 0x5f, NULL); + i2c_reg_modify1(AXP173_BUS, AXP173_ADDR, + AXP173_REG_DCDCWORKINGMODE, 0, 0xc0, NULL); + + /* Set the default charging current. This is the same as the + * OF's setting, although it's not strictly within the USB spec. */ + axp173_set_charge_current(780); /* Short delay to give power outputs time to stabilize */ mdelay(5); @@ -82,7 +88,8 @@ void adc_init(void) void power_off(void) { /* Set the shutdown bit */ - i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, 0x32, 7, 1, NULL); + i2c_reg_setbit1(AXP173_BUS, AXP173_ADDR, + AXP173_REG_SHUTDOWNLEDCTRL, 7, 1, NULL); while(1); } -- cgit v1.2.3