From 0ab7ffefc75159861c7e35d9e6eb673997358c14 Mon Sep 17 00:00:00 2001 From: Ting Shen Date: Wed, 13 Feb 2019 12:21:21 +0800 Subject: battery: add support for mm8013 battery gauge Implements basic functions that makes mm8013 looks like a battery on ec side. BUG=b:123267889 TEST=Build a kukui ec with CONFIG_BATTERY_MM8013 defined, verify the battery readings are sane. BRANCH=None Change-Id: Ica5237b5425681447f3cac0f0889a0ebdc35bf8f Signed-off-by: Ting Shen Reviewed-on: https://chromium-review.googlesource.com/1469192 Commit-Ready: Ting Shen Tested-by: Ting Shen Reviewed-by: Yilun Lin --- driver/battery/mm8013.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++++ driver/battery/mm8013.h | 40 ++++++++ driver/build.mk | 1 + include/config.h | 2 + 4 files changed, 293 insertions(+) create mode 100644 driver/battery/mm8013.c create mode 100644 driver/battery/mm8013.h diff --git a/driver/battery/mm8013.c b/driver/battery/mm8013.c new file mode 100644 index 0000000000..b3034464e7 --- /dev/null +++ b/driver/battery/mm8013.c @@ -0,0 +1,250 @@ +/* Copyright 2019 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 MM8013. + */ + +#include "battery.h" +#include "battery_smart.h" +#include "console.h" +#include "i2c.h" +#include "mm8013.h" +#include "timer.h" +#include "util.h" + +#define BATTERY_PACK_INFO_LENGTH 8 + +/* MM8013 requires a 100us wait time after a read operation. */ +#define I2C_WAIT_TIME 100 + +static int mm8013_read16(int offset, int *data) +{ + int rv; + + *data = 0; + rv = i2c_read16(I2C_PORT_BATTERY, MM8013_ADDR, offset, data); + usleep(I2C_WAIT_TIME); + if (rv) + return rv; + return EC_SUCCESS; +} + +static int mm8013_read_block(int offset, uint8_t *data, int len) +{ + int rv; + + rv = i2c_read_block(I2C_PORT_BATTERY, MM8013_ADDR, offset, data, len); + usleep(I2C_WAIT_TIME); + if (rv) + return rv; + return EC_SUCCESS; +} + +static int battery_flag(int *flag) +{ + return mm8013_read16(REG_FLAGS, flag); +} + +static int battery_current(int *current) +{ + int16_t tmp; + int rv; + + rv = mm8013_read_block(REG_AVERAGE_CURRENT, + (uint8_t *)&tmp, sizeof(int16_t)); + if (rv) + return rv; + *current = tmp; + + return EC_SUCCESS; +} + +int battery_device_name(char *device_name, int buf_size) +{ + int rv; + char out_buf[BATTERY_PACK_INFO_LENGTH + 1]; + + rv = mm8013_read_block(REG_PRODUCT_INFORMATION, + (uint8_t *)out_buf, BATTERY_PACK_INFO_LENGTH); + if (rv) + return rv; + + out_buf[BATTERY_PACK_INFO_LENGTH] = '\0'; + strzcpy(device_name, out_buf, buf_size); + + return EC_SUCCESS; +} + +int battery_state_of_charge_abs(int *percent) +{ + return mm8013_read16(REG_STATE_OF_CHARGE, percent); +} + +int battery_remaining_capacity(int *capacity) +{ + return mm8013_read16(REG_REMAINING_CAPACITY, capacity); +} + +int battery_full_charge_capacity(int *capacity) +{ + return mm8013_read16(REG_FULL_CHARGE_CAPACITY, capacity); +} + +int battery_time_to_empty(int *minutes) +{ + return mm8013_read16(REG_AVERAGE_TIME_TO_EMPTY, minutes); +} + +int battery_time_to_full(int *minutes) +{ + return mm8013_read16(REG_AVERAGE_TIME_TO_FULL, minutes); +} + +int battery_cycle_count(int *count) +{ + return mm8013_read16(REG_CYCLE_COUNT, count); +} + +int battery_design_capacity(int *capacity) +{ + return mm8013_read16(REG_DESIGN_CAPACITY, capacity); +} + +int battery_time_at_rate(int rate, int *minutes) +{ + return EC_ERROR_UNIMPLEMENTED; +} + +int battery_manufacturer_name(char *dest, int size) +{ + strzcpy(dest, "", size); + + return EC_SUCCESS; +} + +int battery_device_chemistry(char *dest, int size) +{ + strzcpy(dest, "", size); + + return EC_SUCCESS; +} + +int battery_serial_number(int *serial) +{ + 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 flag = 0; + + *status = 0; + + rv = battery_flag(&flag); + if (rv) + return rv; + + if (flag & (MM8013_FLAG_OTC | MM8013_FLAG_OTD)) + *status |= STATUS_OVERTEMP_ALARM; + if (flag & MM8013_FLAG_FC) + *status |= STATUS_FULLY_CHARGED; + if (flag & MM8013_FLAG_DSG) + *status |= STATUS_DISCHARGING; + if (flag & MM8013_FLAG_BATHI) + *status |= STATUS_OVERCHARGED_ALARM; + + return EC_SUCCESS; +} + +enum battery_present battery_is_present(void) +{ + int temp; + + if (mm8013_read16(REG_TEMPERATURE, &temp)) + return BP_NOT_SURE; + return BP_YES; +} + +void battery_get_params(struct batt_params *batt) +{ + struct batt_params batt_new = {0}; + int flag = 0; + + /* + * Assuming the battery is responsive as long as + * mm8013 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 (mm8013_read16(REG_TEMPERATURE, &batt_new.temperature)) + batt_new.flags |= BATT_FLAG_BAD_TEMPERATURE; + + if (mm8013_read16(REG_STATE_OF_CHARGE, &batt_new.state_of_charge)) + batt_new.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; + + if (mm8013_read16(REG_VOLTAGE, &batt_new.voltage)) + batt_new.flags |= BATT_FLAG_BAD_VOLTAGE; + + if (battery_current(&batt_new.current)) + batt_new.flags |= BATT_FLAG_BAD_CURRENT; + + 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; + + if (battery_flag(&flag) && (flag & MM8013_FLAG_CHG)) + 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(phoenixshen): Implement this function. */ + return EC_SUCCESS; +} diff --git a/driver/battery/mm8013.h b/driver/battery/mm8013.h new file mode 100644 index 0000000000..1915c81832 --- /dev/null +++ b/driver/battery/mm8013.h @@ -0,0 +1,40 @@ +/* Copyright 2019 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 MM8013. + */ + +#ifndef __CROS_EC_MM8013_H +#define __CROS_EC_MM8013_H + +#define MM8013_ADDR 0xaa + +#define REG_TEMPERATURE 0x06 +#define REG_VOLTAGE 0x08 +#define REG_FLAGS 0x0a +#define REG_FULL_CHARGE_CAPACITY 0x0e +#define REG_REMAINING_CAPACITY 0x10 +#define REG_AVERAGE_CURRENT 0x14 +#define REG_AVERAGE_TIME_TO_EMPTY 0x16 +#define REG_AVERAGE_TIME_TO_FULL 0x18 +#define REG_STATE_OF_CHARGE 0x2c +#define REG_CYCLE_COUNT 0x2a +#define REG_DESIGN_CAPACITY 0x3c +#define REG_PRODUCT_INFORMATION 0x64 + +/* Over Temperature in charge */ +#define MM8013_FLAG_OTC (1 << 15) +/* Over Temperature in discharge */ +#define MM8013_FLAG_OTD (1 << 14) +/* Over-charge */ +#define MM8013_FLAG_BATHI (1 << 13) +/* Full Charge */ +#define MM8013_FLAG_FC (1 << 9) +/* Charge allowed */ +#define MM8013_FLAG_CHG (1 << 8) +/* Discharge */ +#define MM8013_FLAG_DSG (1 << 0) + + +#endif /* __CROS_EC_MM8013_H */ diff --git a/driver/build.mk b/driver/build.mk index 0a81e0b41b..313a4fe6dd 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -44,6 +44,7 @@ driver-$(CONFIG_BATTERY_BQ27621)+=battery/bq27621_g1.o driver-$(CONFIG_BATTERY_MAX17055)+=battery/max17055.o driver-$(CONFIG_BATTERY_SMART)+=battery/smart.o driver-$(CONFIG_BATTERY_BQ4050)+=battery/bq4050.o +driver-$(CONFIG_BATTERY_MM8013)+=battery/mm8013.o # Battery charger ICs driver-$(CONFIG_CHARGER_BD9995X)+=charger/bd9995x.o diff --git a/include/config.h b/include/config.h index ee7ba39095..8baea11ff9 100644 --- a/include/config.h +++ b/include/config.h @@ -305,6 +305,7 @@ #undef CONFIG_BATTERY_BQ27621 #undef CONFIG_BATTERY_BQ4050 #undef CONFIG_BATTERY_MAX17055 +#undef CONFIG_BATTERY_MM8013 /* * MAX17055 support alert on voltage, current, temperature, and state-of-charge. @@ -3981,6 +3982,7 @@ defined(CONFIG_BATTERY_BQ27621) || \ defined(CONFIG_BATTERY_BQ4050) || \ defined(CONFIG_BATTERY_MAX17055) || \ + defined(CONFIG_BATTERY_MM8013) || \ defined(CONFIG_BATTERY_SMART) #define CONFIG_BATTERY #endif -- cgit v1.2.1