summaryrefslogtreecommitdiff
path: root/driver/battery/smart.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/battery/smart.c')
-rw-r--r--driver/battery/smart.c695
1 files changed, 0 insertions, 695 deletions
diff --git a/driver/battery/smart.c b/driver/battery/smart.c
deleted file mode 100644
index 3704618e36..0000000000
--- a/driver/battery/smart.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/* Copyright 2012 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.
- *
- * Smart battery driver.
- */
-
-#include "battery.h"
-#include "battery_smart.h"
-#include "console.h"
-#include "host_command.h"
-#include "i2c.h"
-#include "timer.h"
-#include "util.h"
-
-/* Console output macros */
-#define CPUTS(outstr) cputs(CC_CHARGER, outstr);
-#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
-
-#define BATTERY_NO_RESPONSE_TIMEOUT (1000*MSEC)
-
-static int fake_state_of_charge = -1;
-static int fake_temperature = -1;
-
-static int battery_supports_pec(void)
-{
- static int supports_pec = -1;
-
- if (!IS_ENABLED(CONFIG_SMBUS_PEC))
- return 0;
-
- if (supports_pec < 0) {
- int spec_info;
- int rv = i2c_read16(I2C_PORT_BATTERY, BATTERY_ADDR_FLAGS,
- SB_SPECIFICATION_INFO, &spec_info);
- /* failed, assuming not support and try again later */
- if (rv)
- return 0;
-
- supports_pec = (BATTERY_SPEC_VERSION(spec_info) ==
- BATTERY_SPEC_VER_1_1_WITH_PEC);
- CPRINTS("battery supports pec: %d", supports_pec);
- }
- return supports_pec;
-}
-
-test_mockable int sb_read(int cmd, int *param)
-{
- uint16_t addr_flags = BATTERY_ADDR_FLAGS;
-
-#ifdef CONFIG_BATTERY_CUT_OFF
- /*
- * Some batteries would wake up after cut-off if we talk to it.
- */
- if (battery_is_cut_off())
- return EC_RES_ACCESS_DENIED;
-#endif
- if (battery_supports_pec())
- addr_flags |= I2C_FLAG_PEC;
-
- return i2c_read16(I2C_PORT_BATTERY, addr_flags, cmd, param);
-}
-
-test_mockable int sb_write(int cmd, int param)
-{
- uint16_t addr_flags = BATTERY_ADDR_FLAGS;
-
-#ifdef CONFIG_BATTERY_CUT_OFF
- /*
- * Some batteries would wake up after cut-off if we talk to it.
- */
- if (battery_is_cut_off())
- return EC_RES_ACCESS_DENIED;
-#endif
- if (battery_supports_pec())
- addr_flags |= I2C_FLAG_PEC;
-
- return i2c_write16(I2C_PORT_BATTERY, addr_flags, cmd, param);
-}
-
-int sb_read_string(int offset, uint8_t *data, int len)
-{
- uint16_t addr_flags = BATTERY_ADDR_FLAGS;
-
-#ifdef CONFIG_BATTERY_CUT_OFF
- /*
- * Some batteries would wake up after cut-off if we talk to it.
- */
- if (battery_is_cut_off())
- return EC_RES_ACCESS_DENIED;
-#endif
- if (battery_supports_pec())
- addr_flags |= I2C_FLAG_PEC;
-
- return i2c_read_string(I2C_PORT_BATTERY, addr_flags, offset, data, len);
-}
-
-int sb_read_mfgacc(int cmd, int block, uint8_t *data, int len)
-{
- int rv;
-
- /*
- * First two bytes returned from read are command sent hence read
- * doesn't yield anything if the length is less than 3 bytes.
- */
- if (len < 3)
- return EC_ERROR_INVAL;
-
- /* Send manufacturer access command */
- rv = sb_write(SB_MANUFACTURER_ACCESS, cmd);
- if (rv)
- return rv;
-
- /*
- * Read data on the register block.
- * First two bytes returned are command sent,
- * rest are actual data LSB to MSB.
- */
- rv = sb_read_string(block, data, len);
- if (rv)
- return rv;
- if ((data[0] | data[1] << 8) != cmd)
- return EC_ERROR_UNKNOWN;
-
- return EC_SUCCESS;
-}
-
-int sb_write_block(int reg, const uint8_t *val, int len)
-{
- uint16_t addr_flags = BATTERY_ADDR_FLAGS;
-
-#ifdef CONFIG_BATTERY_CUT_OFF
- /*
- * Some batteries would wake up after cut-off if we talk to it.
- */
- if (battery_is_cut_off())
- return EC_RES_ACCESS_DENIED;
-#endif
-
- if (battery_supports_pec())
- addr_flags |= I2C_FLAG_PEC;
-
- /* TODO: implement smbus_write_block. */
- return i2c_write_block(I2C_PORT_BATTERY, addr_flags, reg, val, len);
-}
-
-int battery_get_mode(int *mode)
-{
- return sb_read(SB_BATTERY_MODE, mode);
-}
-
-/**
- * Force battery to mAh mode (instead of 10mW mode) for reporting capacity.
- *
- * @return non-zero if error.
- */
-
-static int battery_force_mah_mode(void)
-{
- int val, rv;
- rv = battery_get_mode(&val);
- if (rv)
- return rv;
-
- if (val & MODE_CAPACITY)
- rv = sb_write(SB_BATTERY_MODE, val & ~MODE_CAPACITY);
-
- return rv;
-}
-
-int battery_state_of_charge_abs(int *percent)
-{
- return sb_read(SB_ABSOLUTE_STATE_OF_CHARGE, percent);
-}
-
-int battery_remaining_capacity(int *capacity)
-{
- int rv = battery_force_mah_mode();
- if (rv)
- return rv;
-
- return sb_read(SB_REMAINING_CAPACITY, capacity);
-}
-
-int battery_full_charge_capacity(int *capacity)
-{
- int rv = battery_force_mah_mode();
- if (rv)
- return rv;
-
- return sb_read(SB_FULL_CHARGE_CAPACITY, capacity);
-}
-
-int battery_time_to_empty(int *minutes)
-{
- return sb_read(SB_AVERAGE_TIME_TO_EMPTY, minutes);
-}
-
-int battery_run_time_to_empty(int *minutes)
-{
- return sb_read(SB_RUN_TIME_TO_EMPTY, minutes);
-}
-
-int battery_time_to_full(int *minutes)
-{
- return sb_read(SB_AVERAGE_TIME_TO_FULL, minutes);
-}
-
-/* Read battery status */
-int battery_status(int *status)
-{
- return sb_read(SB_BATTERY_STATUS, status);
-}
-
-/* Battery charge cycle count */
-int battery_cycle_count(int *count)
-{
- return sb_read(SB_CYCLE_COUNT, count);
-}
-
-int battery_design_capacity(int *capacity)
-{
- int rv = battery_force_mah_mode();
- if (rv)
- return rv;
-
- return sb_read(SB_DESIGN_CAPACITY, capacity);
-}
-
-/* Designed battery output voltage
- * unit: mV
- */
-int battery_design_voltage(int *voltage)
-{
- return sb_read(SB_DESIGN_VOLTAGE, voltage);
-}
-
-/* Read serial number */
-int battery_serial_number(int *serial)
-{
- return sb_read(SB_SERIAL_NUMBER, serial);
-}
-
-test_mockable int battery_time_at_rate(int rate, int *minutes)
-{
- int rv;
- int ok, time;
- int loop, cmd, output_sign;
-
- if (rate == 0) {
- *minutes = 0;
- return EC_ERROR_INVAL;
- }
-
- rv = sb_write(SB_AT_RATE, rate);
- if (rv)
- return rv;
- loop = 5;
- while (loop--) {
- rv = sb_read(SB_AT_RATE_OK, &ok);
- if (rv)
- return rv;
- if (ok) {
- if (rate > 0) {
- cmd = SB_AT_RATE_TIME_TO_FULL;
- output_sign = -1;
- } else {
- cmd = SB_AT_RATE_TIME_TO_EMPTY;
- output_sign = 1;
- }
- rv = sb_read(cmd, &time);
- if (rv)
- return rv;
-
- *minutes = (time == 0xffff) ? 0 : output_sign * time;
- return EC_SUCCESS;
- } else {
- /* wait 10ms for AT_RATE_OK */
- msleep(10);
- }
- }
- return EC_ERROR_TIMEOUT;
-}
-
-test_mockable int battery_manufacture_date(int *year, int *month, int *day)
-{
- int rv;
- int ymd;
-
- rv = sb_read(SB_MANUFACTURE_DATE, &ymd);
- if (rv)
- return rv;
-
- /* battery date format:
- * ymd = day + month * 32 + (year - 1980) * 512
- */
- *year = ((ymd & MANUFACTURE_DATE_YEAR_MASK) >>
- MANUFACTURE_DATE_YEAR_SHIFT) + MANUFACTURE_DATE_YEAR_OFFSET;
- *month = (ymd & MANUFACTURE_DATE_MONTH_MASK) >>
- MANUFACTURE_DATE_MONTH_SHIFT;
- *day = (ymd & MANUFACTURE_DATE_DAY_MASK) >>
- MANUFACTURE_DATE_DAY_SHIFT;
-
- return EC_SUCCESS;
-}
-
-int get_battery_manufacturer_name(char *dest, int size)
-{
- return sb_read_string(SB_MANUFACTURER_NAME, dest, size);
-}
-
-/* Read device name */
-test_mockable int battery_device_name(char *dest, int size)
-{
- return sb_read_string(SB_DEVICE_NAME, dest, size);
-}
-
-/* Read battery type/chemistry */
-test_mockable int battery_device_chemistry(char *dest, int size)
-{
- return sb_read_string(SB_DEVICE_CHEMISTRY, dest, size);
-}
-
-int battery_get_avg_current(void)
-{
- int current;
-
- /* This is a signed 16-bit value. */
- sb_read(SB_AVERAGE_CURRENT, &current);
- return (int16_t)current;
-}
-
-#ifdef CONFIG_CMD_PWR_AVG
-/*
- * Technically returns only the instantaneous reading, but tests showed that
- * for the majority of charge states above 3% this varies by less than 40mV
- * every minute, so we accept the inaccuracy here.
- */
-int battery_get_avg_voltage(void)
-{
- int voltage = -EC_ERROR_UNKNOWN;
-
- sb_read(SB_VOLTAGE, &voltage);
- return voltage;
-}
-#endif /* CONFIG_CMD_PWR_AVG */
-
-static void apply_fake_state_of_charge(struct batt_params *batt)
-{
- int full;
-
- if (fake_state_of_charge < 0)
- return;
-
- if (batt->flags & BATT_FLAG_BAD_FULL_CAPACITY)
- battery_design_capacity(&full);
- else
- full = batt->full_capacity;
-
- batt->state_of_charge = fake_state_of_charge;
- batt->remaining_capacity = full * fake_state_of_charge / 100;
- battery_compensate_params(batt);
- batt->flags &= ~BATT_FLAG_BAD_STATE_OF_CHARGE;
- batt->flags &= ~BATT_FLAG_BAD_REMAINING_CAPACITY;
-}
-
-void battery_get_params(struct batt_params *batt)
-{
- struct batt_params batt_new = {0};
- int v;
-
- if (sb_read(SB_TEMPERATURE, &batt_new.temperature)
- && fake_temperature < 0)
- batt_new.flags |= BATT_FLAG_BAD_TEMPERATURE;
-
- /* If temperature is faked, override with faked data */
- if (fake_temperature >= 0)
- batt_new.temperature = fake_temperature;
-
- if (sb_read(SB_RELATIVE_STATE_OF_CHARGE, &batt_new.state_of_charge)
- && fake_state_of_charge < 0)
- batt_new.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE;
-
- if (sb_read(SB_VOLTAGE, &batt_new.voltage))
- batt_new.flags |= BATT_FLAG_BAD_VOLTAGE;
-
- /* This is a signed 16-bit value. */
- if (sb_read(SB_CURRENT, &v))
- batt_new.flags |= BATT_FLAG_BAD_CURRENT;
- else
- batt_new.current = (int16_t)v;
-
- if (sb_read(SB_AVERAGE_CURRENT, &v))
- batt_new.flags |= BATT_FLAG_BAD_AVERAGE_CURRENT;
- if (sb_read(SB_CHARGING_VOLTAGE, &batt_new.desired_voltage))
- batt_new.flags |= BATT_FLAG_BAD_DESIRED_VOLTAGE;
-
- if (sb_read(SB_CHARGING_CURRENT, &batt_new.desired_current))
- batt_new.flags |= BATT_FLAG_BAD_DESIRED_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;
-
- if (battery_status(&batt_new.status))
- batt_new.flags |= BATT_FLAG_BAD_STATUS;
-
- /* If any of those reads worked, the battery is responsive */
- if ((batt_new.flags & BATT_FLAG_BAD_ANY) != BATT_FLAG_BAD_ANY)
- batt_new.flags |= BATT_FLAG_RESPONSIVE;
-
-#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE
- if (battery_imbalance_mv() > CONFIG_BATTERY_MAX_IMBALANCE_MV)
- batt_new.flags |= BATT_FLAG_IMBALANCED_CELL;
-#endif
-
-#if defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \
- defined(CONFIG_BATTERY_PRESENT_GPIO)
- /* Hardware can tell us for certain */
- batt_new.is_present = battery_is_present();
-#else
- /* No hardware test, so we only know it's there if it responds */
- if (batt_new.flags & BATT_FLAG_RESPONSIVE)
- batt_new.is_present = BP_YES;
- else
- batt_new.is_present = BP_NOT_SURE;
-#endif
-
- /*
- * 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_DESIRED_VOLTAGE |
- BATT_FLAG_BAD_DESIRED_CURRENT |
- BATT_FLAG_BAD_STATE_OF_CHARGE)) &&
-#ifdef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD
- /*
- * TODO (crosbug.com/p/29467): remove this workaround
- * for dead battery that requests no voltage/current
- */
- ((batt_new.desired_voltage &&
- batt_new.desired_current &&
- batt_new.state_of_charge < BATTERY_LEVEL_FULL) ||
- (batt_new.desired_voltage == 0 &&
- batt_new.desired_current == 0 &&
- batt_new.state_of_charge == 0)))
-#else
- batt_new.desired_voltage &&
- batt_new.desired_current &&
- batt_new.state_of_charge < BATTERY_LEVEL_FULL)
-#endif
- batt_new.flags |= BATT_FLAG_WANT_CHARGE;
- else
- /* Force both to zero */
- batt_new.desired_voltage = batt_new.desired_current = 0;
-
-#ifdef HAS_TASK_HOSTCMD
- /* if there is no host, we don't care about compensation */
- battery_compensate_params(&batt_new);
- board_battery_compensate_params(&batt_new);
-#endif
-
- if (IS_ENABLED(CONFIG_CMD_BATTFAKE))
- apply_fake_state_of_charge(&batt_new);
-
- /* Update visible battery parameters */
- memcpy(batt, &batt_new, sizeof(*batt));
-}
-
-/* Wait until battery is totally stable */
-int battery_wait_for_stable(void)
-{
- int status;
- uint64_t wait_timeout = get_time().val + BATTERY_NO_RESPONSE_TIMEOUT;
-
- CPRINTS("Wait for battery stabilized during %d",
- BATTERY_NO_RESPONSE_TIMEOUT);
- while (get_time().val < wait_timeout) {
- /* Starting pinging battery */
- if (battery_status(&status) == EC_SUCCESS) {
- /* Battery is stable */
- CPRINTS("battery responded with status %x", status);
- return EC_SUCCESS;
- }
- msleep(25); /* clock stretching could hold 25ms */
- }
- CPRINTS("battery not responding");
- return EC_ERROR_NOT_POWERED;
-}
-
-#if defined(CONFIG_CMD_BATTFAKE)
-static int command_battfake(int argc, char **argv)
-{
- char *e;
- int v;
-
- if (argc == 2) {
- v = strtoi(argv[1], &e, 0);
- if (*e || v < -1 || v > 100)
- return EC_ERROR_PARAM1;
-
- fake_state_of_charge = v;
- }
-
- if (fake_state_of_charge >= 0)
- ccprintf("Fake batt %d%%\n", fake_state_of_charge);
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(battfake, command_battfake,
- "percent (-1 = use real level)",
- "Set fake battery level");
-
-static int command_batttempfake(int argc, char **argv)
-{
- char *e;
- int t;
-
- if (argc == 2) {
- t = strtoi(argv[1], &e, 0);
- if (*e || t < -1 || t > 5000)
- return EC_ERROR_PARAM1;
-
- fake_temperature = t;
- }
-
- if (fake_temperature >= 0)
- ccprintf("Fake batt temperature %d.%d K\n",
- fake_temperature / 10, fake_temperature % 10);
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(batttempfake, command_batttempfake,
- "temperature (-1 = use real temperature)",
- "Set fake battery temperature in deciKelvin (2731 = 273.1 K = 0 deg C)");
-#endif
-
-#ifdef CONFIG_CMD_BATT_MFG_ACCESS
-static int command_batt_mfg_access_read(int argc, char **argv)
-{
- char *e;
- uint8_t data[32];
- int cmd, block, len = 6;
- int rv;
-
- if (argc < 3 || argc > 4)
- return EC_ERROR_PARAM_COUNT;
-
- cmd = strtoi(argv[1], &e, 0);
- if (*e || cmd < 0)
- return EC_ERROR_PARAM1;
-
- block = strtoi(argv[2], &e, 0);
- if (*e || block < 0)
- return EC_ERROR_PARAM2;
-
- if (argc > 3) {
- len = strtoi(argv[3], &e, 0);
- len += 2;
- if (*e || len < 3 || len > sizeof(data))
- return EC_ERROR_PARAM3;
- }
-
- rv = sb_read_mfgacc(cmd, block, data, len);
- if (rv)
- return rv;
-
- ccprintf("data[MSB->LSB]=0x");
- do {
- len--;
- ccprintf("%02x ", data[len]);
- } while (len > 2);
- ccprintf("\n");
-
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(battmfgacc, command_batt_mfg_access_read,
- "cmd block | len",
- "Read battery manufacture access data");
-#endif /* CONFIG_CMD_BATT_MFG_ACCESS */
-
-/*****************************************************************************/
-/* Smart battery pass-through
- */
-#ifdef CONFIG_SB_PASSTHROUGH
-static enum ec_status
-host_command_sb_read_word(struct host_cmd_handler_args *args)
-{
- int rv;
- int val;
- const struct ec_params_sb_rd *p = args->params;
- struct ec_response_sb_rd_word *r = args->response;
-
- if (p->reg > 0x1c)
- return EC_RES_INVALID_PARAM;
- rv = sb_read(p->reg, &val);
- if (rv)
- return EC_RES_ERROR;
-
- r->value = val;
- args->response_size = sizeof(struct ec_response_sb_rd_word);
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_SB_READ_WORD,
- host_command_sb_read_word,
- EC_VER_MASK(0));
-
-static enum ec_status
-host_command_sb_write_word(struct host_cmd_handler_args *args)
-{
- int rv;
- const struct ec_params_sb_wr_word *p = args->params;
-
- if (p->reg > 0x1c)
- return EC_RES_INVALID_PARAM;
- rv = sb_write(p->reg, p->value);
- if (rv)
- return EC_RES_ERROR;
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_SB_WRITE_WORD,
- host_command_sb_write_word,
- EC_VER_MASK(0));
-
-static enum ec_status
-host_command_sb_read_block(struct host_cmd_handler_args *args)
-{
- int rv;
- const struct ec_params_sb_rd *p = args->params;
- struct ec_response_sb_rd_block *r = args->response;
-
- if ((p->reg != SB_MANUFACTURER_NAME) &&
- (p->reg != SB_DEVICE_NAME) &&
- (p->reg != SB_DEVICE_CHEMISTRY) &&
- (p->reg != SB_MANUFACTURER_DATA))
- return EC_RES_INVALID_PARAM;
- rv = sb_read_string(p->reg, r->data, 32);
- if (rv)
- return EC_RES_ERROR;
-
- args->response_size = sizeof(struct ec_response_sb_rd_block);
-
- return EC_RES_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_SB_READ_BLOCK,
- host_command_sb_read_block,
- EC_VER_MASK(0));
-
-static enum ec_status
-host_command_sb_write_block(struct host_cmd_handler_args *args)
-{
- /* Not implemented */
- return EC_RES_INVALID_COMMAND;
-}
-DECLARE_HOST_COMMAND(EC_CMD_SB_WRITE_BLOCK,
- host_command_sb_write_block,
- EC_VER_MASK(0));
-#endif
-
-#ifdef CONFIG_CMD_I2C_STRESS_TEST_BATTERY
-test_mockable int sb_i2c_test_read(int cmd, int *param)
-{
- char chemistry[sizeof(CONFIG_BATTERY_DEVICE_CHEMISTRY) + 1];
- int rv;
-
- if (cmd == SB_DEVICE_CHEMISTRY) {
- rv = battery_device_chemistry(chemistry,
- sizeof(CONFIG_BATTERY_DEVICE_CHEMISTRY));
- if (rv)
- return rv;
- if (strcasecmp(chemistry, CONFIG_BATTERY_DEVICE_CHEMISTRY))
- return EC_ERROR_UNKNOWN;
-
- *param = EC_SUCCESS;
- return EC_SUCCESS;
- }
-
-
- return sb_read(cmd, param);
-}
-
-struct i2c_stress_test_dev battery_i2c_stress_test_dev = {
- .reg_info = {
- .read_reg = SB_DEVICE_CHEMISTRY,
- .read_val = EC_SUCCESS,
- .write_reg = SB_AT_RATE,
- },
- .i2c_read_dev = &sb_i2c_test_read,
- .i2c_write_dev = &sb_write,
-};
-#endif /* CONFIG_CMD_I2C_STRESS_TEST_BATTERY */