diff options
Diffstat (limited to 'driver/battery')
-rw-r--r-- | driver/battery/max17055.c | 208 | ||||
-rw-r--r-- | driver/battery/max17055.h | 19 |
2 files changed, 208 insertions, 19 deletions
diff --git a/driver/battery/max17055.c b/driver/battery/max17055.c index b022b24655..28a2ba1038 100644 --- a/driver/battery/max17055.c +++ b/driver/battery/max17055.c @@ -346,16 +346,191 @@ int battery_wait_for_stable(void) return EC_SUCCESS; } -/* Configured MAX17055 with the battery parameters for optimal performance. */ -static int max17055_load_batt_model(void) +static int max17055_poll_flag_clear(int regno, int mask, int timeout) +{ + int reg; + + do { + if (max17055_read(regno, ®)) + return EC_ERROR_UNKNOWN; + + if (!(mask & reg)) + return EC_SUCCESS; + + msleep(10); + timeout -= 10; + } while (timeout > 0); + + return EC_ERROR_TIMEOUT; +} + +static int max17055_load_ocv_table(const struct max17055_batt_profile *config) +{ + int i; + int reg; + int retries = 3; + + /* Unlock ocv table */ + if (max17055_write(REG_LOCK1, 0x0059) || + max17055_write(REG_LOCK2, 0x00c4)) + return EC_ERROR_UNKNOWN; + + ASSERT(config->ocv_table); + + /* Write ocv data */ + for (i = 0; i < MAX17055_OCV_TABLE_SIZE; i++) { + if (max17055_write(REG_OCV_TABLE_START + i, + config->ocv_table[i])) + return EC_ERROR_UNKNOWN; + } + + /* Read and compare ocv data */ + for (i = 0; i < MAX17055_OCV_TABLE_SIZE; i++) { + if (max17055_read(REG_OCV_TABLE_START + i, ®) || + reg != config->ocv_table[i]) + return EC_ERROR_UNKNOWN; + } + + while (--retries) { + /* Lock ocv table */ + if (max17055_write(REG_LOCK1, 0x0000) || + max17055_write(REG_LOCK2, 0x0000)) + return EC_ERROR_UNKNOWN; + + /* + * If the ocv table remains unlocked, the MAX17055 cannot + * monitor the capacity of the battery. Therefore, it is very + * critical that the ocv table is locked. To verify it is + * locked, simply read back the values. However, this time, + * all values should be read as 0x0000. + */ + for (i = 0; i < MAX17055_OCV_TABLE_SIZE; i++) { + reg = 0xff; + if (max17055_read(REG_OCV_TABLE_START + i, ®)) + return EC_ERROR_UNKNOWN; + if (reg) + break; + } + if (i == MAX17055_OCV_TABLE_SIZE) + break; + msleep(20); + } + if (!retries) + return EC_ERROR_TIMEOUT; + + /* + * Delay 180ms is to prepare the environment to load the custom + * battery parameters. Otherwise, the initialization operation + * has a very small probability of failure. + */ + msleep(180); + + return EC_SUCCESS; +} + +static int max17055_exit_hibernate(void) +{ + /* + * Write REG_COMMAND with 0x90 to force the firmware to stop running. + * Write REG_HIBCFG with 0x00 to exit hibernate mode immediately. + * Write REG_COMMAND with 0x00 to run the firmware again. + */ + if (max17055_write(REG_COMMAND, 0x90) || + max17055_write(REG_HIBCFG, 0x00) || + max17055_write(REG_COMMAND, 0x00)) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + +/* Configured MAX17055 with the battery parameters for full model. */ +static int max17055_load_batt_model_full(void) { int reg; int hib_cfg; + + const struct max17055_batt_profile *config; + + config = max17055_get_batt_profile(); + + /* Store the original HibCFG value. */ + if (max17055_read(REG_HIBCFG, &hib_cfg)) + return EC_ERROR_UNKNOWN; + + /* Force exit from hibernate */ + if (max17055_exit_hibernate()) + return EC_ERROR_UNKNOWN; + + /* Write LearnCFG with LS 7 */ + if (max17055_write(REG_LEARNCFG, config->learn_cfg | 0x0070)) + return EC_ERROR_UNKNOWN; + + /* + * Unlock ocv table access, write/compare/verify custom ocv table, + * lock ocv table access. + */ + if (max17055_load_ocv_table(config)) + return EC_ERROR_UNKNOWN; + + /* Write custom parameters */ + if (max17055_write(REG_DESIGN_CAPACITY, config->design_cap) || + max17055_write(REG_DQACC, config->design_cap >> 4) || + max17055_write(REG_DPACC, 0x0c80) || + max17055_write(REG_CHARGE_TERM_CURRENT, config->ichg_term) || + max17055_write(REG_EMPTY_VOLTAGE, config->v_empty_detect)) + return EC_ERROR_UNKNOWN; + + if (max17055_write(REG_RCOMP0, config->rcomp0) || + max17055_write(REG_TEMPCO, config->tempco) || + max17055_write(REG_QR_TABLE00, config->qr_table00) || + max17055_write(REG_QR_TABLE10, config->qr_table10)) + return EC_ERROR_UNKNOWN; + + /* Update required capacity registers */ + if (max17055_write(REG_REMAINING_CAPACITY, 0x0000) || + max17055_read(REG_VFSOC, ®)) + return EC_ERROR_UNKNOWN; + + if (max17055_write(REG_VFSOC0, reg) || + max17055_write(REG_FULL_CHARGE_CAPACITY, config->design_cap) || + max17055_write(REG_FULLCAPNOM, config->design_cap)) + return EC_ERROR_UNKNOWN; + + /* Prepare to Load Model */ + if (max17055_write(REG_REMAINING_CAPACITY, 0x0000) || + max17055_write(REG_MIXCAP, config->design_cap)) + return EC_ERROR_UNKNOWN; + + /* Initiate model loading */ + if (max17055_read(REG_CONFIG2, ®) || + max17055_write(REG_CONFIG2, reg | CONFIG2_LDMDL)) + return EC_ERROR_UNKNOWN; + + if (max17055_poll_flag_clear(REG_CONFIG2, CONFIG2_LDMDL, 500)) + return EC_ERROR_UNKNOWN; + + /* Write LearnCFG with LS 0 */ + if (max17055_write(REG_LEARNCFG, config->learn_cfg & 0xff8f) || + max17055_write(REG_QR_TABLE20, config->qr_table20) || + max17055_write(REG_QR_TABLE30, config->qr_table30)) + return EC_ERROR_UNKNOWN; + + /* Restore the original HibCFG value. */ + if (max17055_write(REG_HIBCFG, hib_cfg)) + return EC_ERROR_UNKNOWN; + + return EC_SUCCESS; +} + +/* + * Configured MAX17055 with the battery parameters for short model or ez model + */ +static int max17055_load_batt_model_short_or_ez(void) +{ + int hib_cfg; int dqacc; int dpacc; - int retries = 50; - const struct max17055_batt_profile *config; config = max17055_get_batt_profile(); @@ -384,10 +559,8 @@ static int max17055_load_batt_model(void) if (max17055_read(REG_HIBCFG, &hib_cfg)) return EC_ERROR_UNKNOWN; - /* Special sequence to exit hibernate mode. */ - if (max17055_write(0x60, 0x90) || - max17055_write(REG_HIBCFG, 0) || - max17055_write(0x60, 0)) + /* Force exit from hibernate */ + if (max17055_exit_hibernate()) return EC_ERROR_UNKNOWN; if (max17055_write(REG_DPACC, dpacc) || @@ -395,15 +568,8 @@ static int max17055_load_batt_model(void) return EC_ERROR_UNKNOWN; /* Delay up to 500 ms until MODELCFG.REFRESH bit == 0. */ - while (--retries) { - if (max17055_read(REG_MODELCFG, ®)) - return EC_ERROR_UNKNOWN; - if (!(MODELCFG_REFRESH & reg)) - break; - msleep(10); - } - if (!retries) - return EC_ERROR_TIMEOUT; + if (max17055_poll_flag_clear(REG_MODELCFG, MODELCFG_REFRESH, 500)) + return EC_ERROR_UNKNOWN; if (!config->is_ez_config) { if (max17055_write(REG_RCOMP0, config->rcomp0) || @@ -421,6 +587,14 @@ static int max17055_load_batt_model(void) return EC_SUCCESS; } +static int max17055_load_batt_model(void) +{ + if (IS_ENABLED(CONFIG_BATTERY_MAX17055_FULL_MODEL)) + return max17055_load_batt_model_full(); + else + return max17055_load_batt_model_short_or_ez(); +} + static void max17055_init(void) { int reg; diff --git a/driver/battery/max17055.h b/driver/battery/max17055.h index ba18af56d5..bdee9ca948 100644 --- a/driver/battery/max17055.h +++ b/driver/battery/max17055.h @@ -10,6 +10,7 @@ #define MAX17055_ADDR 0x6c #define MAX17055_DEVICE_ID 0x4010 +#define MAX17055_OCV_TABLE_SIZE 48 #define REG_STATUS 0x00 #define REG_VALRTTH 0x01 @@ -22,6 +23,7 @@ #define REG_VOLTAGE 0x09 #define REG_CURRENT 0x0a #define REG_AVERAGE_CURRENT 0x0b +#define REG_MIXCAP 0x0f #define REG_FULL_CHARGE_CAPACITY 0x10 #define REG_TIME_TO_EMPTY 0x11 #define REG_QR_TABLE00 0x12 @@ -37,6 +39,7 @@ #define REG_TIME_TO_FULL 0x20 #define REG_DEVICE_NAME 0x21 #define REG_QR_TABLE10 0x22 +#define REG_FULLCAPNOM 0x23 #define REG_LEARNCFG 0x28 #define REG_QR_TABLE20 0x32 #define REG_RCOMP0 0x38 @@ -47,12 +50,18 @@ #define REG_QR_TABLE30 0x42 #define REG_DQACC 0x45 #define REG_DPACC 0x46 +#define REG_VFSOC0 0x48 +#define REG_COMMAND 0x60 +#define REG_LOCK1 0x62 +#define REG_LOCK2 0x63 +#define REG_OCV_TABLE_START 0x80 #define REG_STATUS2 0xb0 #define REG_IALRTTH 0xb4 #define REG_HIBCFG 0xba #define REG_CONFIG2 0xbb #define REG_TIMERH 0xbe #define REG_MODELCFG 0xdb +#define REG_VFSOC 0xff /* Status reg (0x00) flags */ #define STATUS_POR BIT(1) @@ -88,9 +97,12 @@ #define FSTAT_DNR 0x0001 #define FSTAT_FQ 0x0080 +/* Config2 reg (0xbb) flags */ +#define CONFIG2_LDMDL BIT(5) + /* ModelCfg reg (0xdb) flags */ -#define MODELCFG_REFRESH 0x8000 -#define MODELCFG_VCHG 0x0400 +#define MODELCFG_REFRESH BIT(15) +#define MODELCFG_VCHG BIT(10) /* Smart battery status bits (sbs reg 0x16) */ #define BATTERY_DISCHARGING 0x40 @@ -173,6 +185,9 @@ struct max17055_batt_profile { * and v_empty_detect to config max17055 (a.k.a. EZ-config). */ uint8_t is_ez_config; + + /* Used only for full model */ + const uint16_t *ocv_table; }; /* Return the special battery parameters max17055 needs. */ |