summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYH Lin <yueherngl@google.com>2019-05-02 15:20:54 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2019-05-09 16:30:27 +0000
commit8dd9bf0e772d544ffa820bfc94edc60357dd1a2d (patch)
tree4159a8d598b4e9f72a85fdf4e6a68ea320b0db9f
parent9f5a0195e351dddf6d025af47037ac7b9aca3064 (diff)
downloadchrome-ec-8dd9bf0e772d544ffa820bfc94edc60357dd1a2d.tar.gz
MAX17055: Add the full model driver
This patch adds the full model driver for MAX17055. The full model of MAX17055 provides more accurate soc estimation than the short model or ez model. BUG=b:130979269 BRANCH=none TEST=Do a full charge test Change-Id: I4cf249cf0c47fd30f75f4e38b74c7995285603e6 Signed-off-by: YH Lin <yueherngl@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1592726
-rw-r--r--driver/battery/max17055.c208
-rw-r--r--driver/battery/max17055.h19
-rw-r--r--include/config.h6
3 files changed, 214 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. */
diff --git a/include/config.h b/include/config.h
index 8f160543e8..dc2ec752b2 100644
--- a/include/config.h
+++ b/include/config.h
@@ -345,6 +345,12 @@
*/
#undef CONFIG_BATTERY_MAX17055_ALERT
+/*
+ * Enable full model driver of MAX17055.
+ *
+ * It provides a better soc estimation. ocv_table needs to be supplied.
+ */
+#undef CONFIG_BATTERY_MAX17055_FULL_MODEL
/* Compile mock battery support; used by tests. */
#undef CONFIG_BATTERY_MOCK