summaryrefslogtreecommitdiff
path: root/driver/battery/max17055.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/battery/max17055.c')
-rw-r--r--driver/battery/max17055.c692
1 files changed, 0 insertions, 692 deletions
diff --git a/driver/battery/max17055.c b/driver/battery/max17055.c
deleted file mode 100644
index bb0b941937..0000000000
--- a/driver/battery/max17055.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/* Copyright 2017 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Battery driver for MAX17055.
- */
-
-#include "battery.h"
-#include "console.h"
-#include "extpower.h"
-#include "hooks.h"
-#include "i2c.h"
-#include "max17055.h"
-#include "printf.h"
-#include "timer.h"
-#include "util.h"
-
-/* Console output macros */
-#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
-
-/*
- * For max17055 to finish battery presence detection, this is the minimal time
- * we have to wait since the last POR. LSB = 175ms.
- */
-#define RELIABLE_BATT_DETECT_TIME 0x10
-
-/*
- * Convert the register values to the units that match
- * smart battery protocol.
- */
-
-/* Voltage reg value to mV */
-#define VOLTAGE_CONV(REG) ((REG * 5) >> 6)
-/* Current reg value to mA */
-#define CURRENT_CONV(REG) (((REG * 25) >> 4) / BATTERY_MAX17055_RSENSE)
-/* Capacity reg value to mAh */
-#define CAPACITY_CONV(REG) (REG * 5 / BATTERY_MAX17055_RSENSE)
-/* Time reg value to minute */
-#define TIME_CONV(REG) ((REG * 3) >> 5)
-/* Temperature reg value to 0.1K */
-#define TEMPERATURE_CONV(REG) (((REG * 10) >> 8) + 2731)
-/* Percentage reg value to 1% */
-#define PERCENTAGE_CONV(REG) (REG >> 8)
-/* Cycle count reg value (LSB = 1%) to absolute count (100%) */
-#define CYCLE_COUNT_CONV(REG) ((REG * 5) >> 9)
-
-/* Useful macros */
-#define MAX17055_READ_DEBUG(offset, ptr_reg) \
- do { \
- if (max17055_read(offset, ptr_reg)) { \
- CPRINTS("%s: failed to read reg %02x", \
- __func__, offset); \
- return; \
- } \
- } while (0)
-#define MAX17055_WRITE_DEBUG(offset, reg) \
- do { \
- if (max17055_write(offset, reg)) { \
- CPRINTS("%s: failed to read reg %02x", \
- __func__, offset); \
- return; \
- } \
- } while (0)
-
-static int fake_state_of_charge = -1;
-
-static int max17055_read(int offset, int *data)
-{
- return i2c_read16(I2C_PORT_BATTERY, MAX17055_ADDR_FLAGS,
- offset, data);
-}
-
-static int max17055_write(int offset, int data)
-{
- return i2c_write16(I2C_PORT_BATTERY, MAX17055_ADDR_FLAGS,
- offset, data);
-}
-
-/* Return 1 if the device id is correct. */
-static int max17055_probe(void)
-{
- int dev_id;
-
- if (max17055_read(REG_DEVICE_NAME, &dev_id))
- return 0;
- if (dev_id == MAX17055_DEVICE_ID)
- return 1;
- return 0;
-}
-
-int battery_device_name(char *device_name, int buf_size)
-{
- int dev_id;
- int rv;
-
- rv = max17055_read(REG_DEVICE_NAME, &dev_id);
- if (!rv)
- snprintf(device_name, buf_size, "0x%04x", dev_id);
-
- return rv;
-}
-
-int battery_state_of_charge_abs(int *percent)
-{
- return EC_ERROR_UNIMPLEMENTED;
-}
-
-int battery_remaining_capacity(int *capacity)
-{
- int rv;
- int reg;
-
- rv = max17055_read(REG_REMAINING_CAPACITY, &reg);
- if (!rv)
- *capacity = CAPACITY_CONV(reg);
- return rv;
-}
-
-int battery_full_charge_capacity(int *capacity)
-{
- int rv;
- int reg;
-
- rv = max17055_read(REG_FULL_CHARGE_CAPACITY, &reg);
- if (!rv)
- *capacity = CAPACITY_CONV(reg);
- return rv;
-}
-
-int battery_time_to_empty(int *minutes)
-{
- int rv;
- int reg;
-
- rv = max17055_read(REG_TIME_TO_EMPTY, &reg);
- if (!rv)
- *minutes = TIME_CONV(reg);
- return rv;
-}
-
-int battery_time_to_full(int *minutes)
-{
- int rv;
- int reg;
-
- rv = max17055_read(REG_TIME_TO_FULL, &reg);
- if (!rv)
- *minutes = TIME_CONV(reg);
- return rv;
-}
-
-int battery_cycle_count(int *count)
-{
- int rv;
- int reg;
-
- rv = max17055_read(REG_CYCLE_COUNT, &reg);
- if (!rv)
- *count = CYCLE_COUNT_CONV(reg);
- return rv;
-}
-
-int battery_design_capacity(int *capacity)
-{
- int rv;
- int reg;
-
- rv = max17055_read(REG_DESIGN_CAPACITY, &reg);
- if (!rv)
- *capacity = CAPACITY_CONV(reg);
- return rv;
-}
-
-int battery_time_at_rate(int rate, int *minutes)
-{
- return EC_ERROR_UNIMPLEMENTED;
-}
-
-int battery_device_chemistry(char *dest, int size)
-{
- strzcpy(dest, "<unkn>", size);
-
- return EC_SUCCESS;
-}
-
-int battery_serial_number(int *serial)
-{
- /* TODO(philipchen): Implement this function. */
- *serial = 0xFFFFFFFF;
- return EC_SUCCESS;
-}
-
-int battery_manufacture_date(int *year, int *month, int *day)
-{
- return EC_ERROR_UNIMPLEMENTED;
-}
-
-int battery_design_voltage(int *voltage)
-{
- *voltage = battery_get_info()->voltage_normal;
-
- return EC_SUCCESS;
-}
-
-int battery_get_mode(int *mode)
-{
- return EC_ERROR_UNIMPLEMENTED;
-}
-
-int battery_status(int *status)
-{
- int rv;
- int reg;
-
- *status = 0;
-
- rv = max17055_read(REG_FSTAT, &reg);
- if (rv)
- return rv;
- if (reg & FSTAT_FQ)
- *status |= BATTERY_FULLY_CHARGED;
-
- rv = max17055_read(REG_AVERAGE_CURRENT, &reg);
- if (rv)
- return rv;
- if (reg >> 15)
- *status |= BATTERY_DISCHARGING;
-
- return EC_SUCCESS;
-}
-
-enum battery_present battery_is_present(void)
-{
- int reg = 0;
- static uint8_t batt_pres_sure;
-
- if (max17055_read(REG_STATUS, &reg))
- return BP_NOT_SURE;
-
- if (reg & STATUS_BST)
- return BP_NO;
-
- if (!batt_pres_sure) {
- /*
- * The battery detection result is not reliable within
- * ~2.8 secs since POR.
- */
- if (!max17055_read(REG_TIMERH, &reg)) {
- /*
- * The LSB of TIMERH reg is 3.2 hrs. If the reg has a
- * nonzero value, battery detection must have been
- * settled.
- */
- if (reg) {
- batt_pres_sure = 1;
- return BP_YES;
- }
- if (!max17055_read(REG_TIMER, &reg) &&
- ((uint32_t)reg > RELIABLE_BATT_DETECT_TIME)) {
- batt_pres_sure = 1;
- return BP_YES;
- }
- }
- return BP_NOT_SURE;
- }
- return BP_YES;
-}
-
-void battery_get_params(struct batt_params *batt)
-{
- int reg = 0;
- struct batt_params batt_new = {0};
-
- /*
- * Assuming the battery is responsive as long as
- * max17055 finds battery is present.
- */
- batt_new.is_present = battery_is_present();
-
- if (batt_new.is_present == BP_YES)
- batt_new.flags |= BATT_FLAG_RESPONSIVE;
- else if (batt_new.is_present == BP_NO)
- /* Battery is not present, gauge won't report useful info. */
- goto batt_out;
-
- if (max17055_read(REG_TEMPERATURE, &reg))
- batt_new.flags |= BATT_FLAG_BAD_TEMPERATURE;
-
- batt_new.temperature = TEMPERATURE_CONV((int16_t)reg);
-
- if (max17055_read(REG_STATE_OF_CHARGE, &reg) &&
- fake_state_of_charge < 0)
- batt_new.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE;
-
- batt_new.state_of_charge = fake_state_of_charge >= 0 ?
- fake_state_of_charge : PERCENTAGE_CONV(reg);
-
- if (max17055_read(REG_VOLTAGE, &reg))
- batt_new.flags |= BATT_FLAG_BAD_VOLTAGE;
-
- batt_new.voltage = VOLTAGE_CONV(reg);
-
- if (max17055_read(REG_AVERAGE_CURRENT, &reg))
- batt_new.flags |= BATT_FLAG_BAD_CURRENT;
-
- batt_new.current = CURRENT_CONV((int16_t)reg);
-
- batt_new.desired_voltage = battery_get_info()->voltage_max;
- batt_new.desired_current = BATTERY_DESIRED_CHARGING_CURRENT;
-
- if (battery_remaining_capacity(&batt_new.remaining_capacity))
- batt_new.flags |= BATT_FLAG_BAD_REMAINING_CAPACITY;
-
- if (battery_full_charge_capacity(&batt_new.full_capacity))
- batt_new.flags |= BATT_FLAG_BAD_FULL_CAPACITY;
-
- /*
- * Charging allowed if both desired voltage and current are nonzero
- * and battery isn't full (and we read them all correctly).
- */
- if (!(batt_new.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) &&
- batt_new.desired_voltage &&
- batt_new.desired_current &&
- batt_new.state_of_charge < BATTERY_LEVEL_FULL)
- batt_new.flags |= BATT_FLAG_WANT_CHARGE;
-
- if (battery_status(&batt_new.status))
- batt_new.flags |= BATT_FLAG_BAD_STATUS;
-
-batt_out:
- /* Update visible battery parameters */
- memcpy(batt, &batt_new, sizeof(*batt));
-}
-
-#ifdef CONFIG_CMD_PWR_AVG
-int battery_get_avg_current(void)
-{
- /* TODO(crbug.com/752320) implement this */
- return EC_ERROR_UNIMPLEMENTED;
-}
-
-int battery_get_avg_voltage(void)
-{
- /* TODO(crbug.com/752320) implement this */
- return -EC_ERROR_UNIMPLEMENTED;
-}
-#endif /* CONFIG_CMD_PWR_AVG */
-
-/* Wait until battery is totally stable. */
-int battery_wait_for_stable(void)
-{
- /* TODO(philipchen): Implement this function. */
- return EC_SUCCESS;
-}
-
-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;
-
- const struct max17055_batt_profile *config;
-
- config = max17055_get_batt_profile();
-
- if (config->is_ez_config) {
- dqacc = config->design_cap / 32;
- /* Choose the model for charge voltage > 4.275V. */
- dpacc = dqacc * 51200 / config->design_cap;
- } else {
- dqacc = config->design_cap / 16;
- dpacc = config->dpacc;
- }
-
- if (max17055_write(REG_DESIGN_CAPACITY, config->design_cap) ||
- max17055_write(REG_DQACC, dqacc) ||
- max17055_write(REG_CHARGE_TERM_CURRENT, config->ichg_term) ||
- max17055_write(REG_EMPTY_VOLTAGE, config->v_empty_detect))
- return EC_ERROR_UNKNOWN;
-
- if (!config->is_ez_config) {
- if (max17055_write(REG_LEARNCFG, config->learn_cfg))
- return EC_ERROR_UNKNOWN;
- }
-
- /* 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;
-
- if (max17055_write(REG_DPACC, dpacc) ||
- max17055_write(REG_MODELCFG, (MODELCFG_REFRESH | MODELCFG_VCHG)))
- return EC_ERROR_UNKNOWN;
-
- /* Delay up to 500 ms until MODELCFG.REFRESH bit == 0. */
- 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) ||
- max17055_write(REG_TEMPCO, config->tempco) ||
- max17055_write(REG_QR_TABLE00, config->qr_table00) ||
- max17055_write(REG_QR_TABLE10, config->qr_table10) ||
- 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;
-}
-
-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;
- int retries = 80;
-#ifdef CONFIG_BATTERY_MAX17055_ALERT
- const struct max17055_alert_profile *alert_profile =
- max17055_get_alert_profile();
-#endif
-
- if (!max17055_probe()) {
- CPRINTS("Wrong max17055 id!");
- return;
- }
-
- /*
- * Set CONFIG.TSEL to measure temperature using external thermistor.
- * Set it as early as possible because max17055 takes up to 1000ms to
- * have the first reliable external temperature reading.
- */
- MAX17055_READ_DEBUG(REG_CONFIG, &reg);
- MAX17055_WRITE_DEBUG(REG_CONFIG, (reg | CONF_TSEL));
-
- MAX17055_READ_DEBUG(REG_STATUS, &reg);
-
- /* Check for POR */
- if (STATUS_POR & reg) {
- /* Delay up to 800 ms until FSTAT.DNR bit == 0. */
- while (--retries) {
- MAX17055_READ_DEBUG(REG_FSTAT, &reg);
- if (!(FSTAT_DNR & reg))
- break;
- msleep(10);
- }
- if (!retries) {
- CPRINTS("%s: timeout waiting for FSTAT.DNR cleared",
- __func__);
- return;
- }
-
- if (max17055_load_batt_model()) {
- CPRINTS("max17055 configuration failed!");
- return;
- }
-
- /* Clear POR bit */
- MAX17055_READ_DEBUG(REG_STATUS, &reg);
- MAX17055_WRITE_DEBUG(REG_STATUS, (reg & ~STATUS_POR));
- } else {
- const struct max17055_batt_profile *config;
-
- config = max17055_get_batt_profile();
- MAX17055_READ_DEBUG(REG_DESIGN_CAPACITY, &reg);
-
- /*
- * Reload the battery model if the current running one
- * is wrong.
- */
- if (config->design_cap != reg) {
- CPRINTS("max17055 reconfig...");
- if (max17055_load_batt_model()) {
- CPRINTS("max17055 configuration failed!");
- return;
- }
- }
- }
-
-#ifdef CONFIG_BATTERY_MAX17055_ALERT
- /* Set voltage alert range */
- MAX17055_WRITE_DEBUG(REG_VALRTTH, alert_profile->v_alert_mxmn);
- /* Set temperature alert range */
- MAX17055_WRITE_DEBUG(REG_TALRTTH, alert_profile->t_alert_mxmn);
- /* Set state-of-charge alert range */
- MAX17055_WRITE_DEBUG(REG_SALRTTH, alert_profile->s_alert_mxmn);
- /* Set current alert range */
- MAX17055_WRITE_DEBUG(REG_IALRTTH, alert_profile->i_alert_mxmn);
-
- /* Disable all sticky bits; enable alert AEN */
- MAX17055_READ_DEBUG(REG_CONFIG, &reg);
- MAX17055_WRITE_DEBUG(REG_CONFIG, (reg & ~CONF_ALL_STICKY) | CONF_AEN);
-
- /* Clear alerts */
- MAX17055_READ_DEBUG(REG_STATUS, &reg);
- MAX17055_WRITE_DEBUG(REG_STATUS, reg & ~STATUS_ALL_ALRT);
-#endif
-
- CPRINTS("max17055 configuration succeeded!");
-}
-DECLARE_HOOK(HOOK_INIT, max17055_init, HOOK_PRIO_DEFAULT);