summaryrefslogtreecommitdiff
path: root/driver/battery
diff options
context:
space:
mode:
Diffstat (limited to 'driver/battery')
-rw-r--r--driver/battery/max17055.c208
-rw-r--r--driver/battery/max17055.h19
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, &reg))
+ 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) ||
+ 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, &reg))
+ 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, &reg))
+ 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, &reg) ||
+ 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, &reg))
- 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. */