summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTing Shen <phoenixshen@google.com>2019-02-13 12:21:21 +0800
committerchrome-bot <chrome-bot@chromium.org>2019-02-20 08:20:10 -0800
commit0ab7ffefc75159861c7e35d9e6eb673997358c14 (patch)
treee6384e4461a681a24461bc2c7ab803e57e90cf76
parentf37c7fb0871c8c1f9c80a743a53e852f65bbbb5b (diff)
downloadchrome-ec-0ab7ffefc75159861c7e35d9e6eb673997358c14.tar.gz
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 <phoenixshen@google.com> Reviewed-on: https://chromium-review.googlesource.com/1469192 Commit-Ready: Ting Shen <phoenixshen@chromium.org> Tested-by: Ting Shen <phoenixshen@chromium.org> Reviewed-by: Yilun Lin <yllin@chromium.org>
-rw-r--r--driver/battery/mm8013.c250
-rw-r--r--driver/battery/mm8013.h40
-rw-r--r--driver/build.mk1
-rw-r--r--include/config.h2
4 files changed, 293 insertions, 0 deletions
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, "<unkn>", size);
+
+ return EC_SUCCESS;
+}
+
+int battery_device_chemistry(char *dest, int size)
+{
+ strzcpy(dest, "<unkn>", 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