summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwen zhang <zhangwen6@huaqin.corp-partner.google.com>2020-11-11 22:32:27 +0800
committerCommit Bot <commit-bot@chromium.org>2020-11-13 01:37:26 +0000
commitf5fa2ebb38046f8c123e124c44f293296aa503af (patch)
tree0c5f98ad717f018c4248bd744d921591ab977790
parent2f1da8fe2f1ef9a2daf8e02dcf9650c2e37a37b2 (diff)
downloadchrome-ec-f5fa2ebb38046f8c123e124c44f293296aa503af.tar.gz
Kakadu: Add new battery support for gauge bq27542
Configure battery parameter and driver for gauge bq27542 on kakadu. BUG=b:172197008, b:171456201 BRANCH=firmware-kukui-12573.B TEST=1.make -j BOARD=kakadu 2.verified the battery parameter and the result is OK. Change-Id: I4c2cc11df1e13cb7313280afca717a7f1e2461ff Signed-off-by: wen zhang <zhangwen6@huaqin.corp-partner.google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2531765 Reviewed-by: Ting Shen <phoenixshen@chromium.org> (cherry picked from commit 0b8148c1f2b20cb3883ec7ed2058a53b2f063ff6) Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2534436 Reviewed-by: Chen-Tsung Hsieh <chentsung@chromium.org> Commit-Queue: Chen-Tsung Hsieh <chentsung@chromium.org>
-rw-r--r--baseboard/kukui/baseboard.h3
-rw-r--r--baseboard/kukui/battery_bq27541.c225
-rw-r--r--baseboard/kukui/build.mk1
-rw-r--r--board/kakadu/board.h3
-rw-r--r--driver/battery/bq27541.c79
5 files changed, 306 insertions, 5 deletions
diff --git a/baseboard/kukui/baseboard.h b/baseboard/kukui/baseboard.h
index daffcfe807..7cbcf90d65 100644
--- a/baseboard/kukui/baseboard.h
+++ b/baseboard/kukui/baseboard.h
@@ -12,6 +12,7 @@
* Variant battery defines, pick one:
* VARIANT_KUKUI_BATTERY_MAX17055
* VARIANT_KUKUI_BATTERY_MM8013
+ * VARIANT_KUKUI_BATTERY_BQ27541
* VARIANT_KUKUI_BATTERY_SMART
*/
#if defined(VARIANT_KUKUI_BATTERY_MAX17055)
@@ -20,6 +21,8 @@
#define BATTERY_MAX17055_RSENSE 5 /* m-ohm */
#elif defined(VARIANT_KUKUI_BATTERY_MM8013)
#define CONFIG_BATTERY_MM8013
+#elif defined(VARIANT_KUKUI_BATTERY_BQ27541)
+#define CONFIG_BATTERY_BQ27541
#elif defined(VARIANT_KUKUI_BATTERY_SMART)
#define CONFIG_BATTERY_SMART
#define CONFIG_BATTERY_FUEL_GAUGE
diff --git a/baseboard/kukui/battery_bq27541.c b/baseboard/kukui/battery_bq27541.c
new file mode 100644
index 0000000000..94f46b3326
--- /dev/null
+++ b/baseboard/kukui/battery_bq27541.c
@@ -0,0 +1,225 @@
+/* Copyright 2020 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 pack vendor provided charging profile
+ */
+
+#include "battery.h"
+#include "charge_state.h"
+#include "charger_mt6370.h"
+#include "console.h"
+#include "driver/tcpm/mt6370.h"
+#include "ec_commands.h"
+#include "util.h"
+
+#define TEMP_OUT_OF_RANGE TEMP_ZONE_COUNT
+
+#define BATT_ID 0
+
+#define BATTERY_CPT_CHARGE_MIN_TEMP 0
+#define BATTERY_CPT_CHARGE_MAX_TEMP 50
+
+#define CHARGER_LIMIT_TIMEOUT_HOURS 48
+#define CHARGER_LIMIT_TIMEOUT_HOURS_TEMP 2
+
+#define BAT_LEVEL_PD_LIMIT 85
+
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
+
+enum battery_type {
+ BATTERY_CPT = 0,
+ BATTERY_COUNT
+};
+
+static const struct battery_info info[] = {
+ [BATTERY_CPT] = {
+ .voltage_max = 4400,
+ .voltage_normal = 3850,
+ .voltage_min = 3000,
+ .precharge_voltage = 3400,
+ .precharge_current = 256,
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 45,
+ .charging_min_c = 0,
+ .charging_max_c = 50,
+ .discharging_min_c = -20,
+ .discharging_max_c = 60,
+ },
+};
+
+const struct battery_info *battery_get_info(void)
+{
+ return &info[BATT_ID];
+}
+
+int charger_profile_override(struct charge_state_data *curr)
+{
+ static timestamp_t deadline_48;
+ static timestamp_t deadline_2;
+ int cycle_count = 0, rv, val;
+ unsigned char rcv = 0, rcv_cycle = 0, rcv_soh = 0;
+ /* (FullCharge Capacity / Design Capacity) * 100 = SOH */
+ int full_cap = 0, design_cap = 0, soh = 0;
+ /* battery temp in 0.1 deg C */
+ int bat_temp_c = curr->batt.temperature - 2731;
+ /*
+ * Keep track of battery temperature range:
+ *
+ * ZONE_0 ZONE_1 ZONE_2
+ * -----+--------+--------+------------+----- Temperature (C)
+ * t0 t1 t2 t3
+ */
+ enum {
+ TEMP_ZONE_0, /* t0 < bat_temp_c <= t1 */
+ TEMP_ZONE_1, /* t1 < bat_temp_c <= t2 */
+ TEMP_ZONE_2, /* t2 < bat_temp_c <= t3 */
+ TEMP_ZONE_3, /* t3 < bat_temp_c <= t4 */
+ TEMP_ZONE_COUNT
+ } temp_zone;
+
+ static struct {
+ int temp_min; /* 0.1 deg C */
+ int temp_max; /* 0.1 deg C */
+ int desired_current; /* mA */
+ int desired_voltage; /* mV */
+ } temp_zones[BATTERY_COUNT][TEMP_ZONE_COUNT] = {
+ [BATTERY_CPT] = {
+ /* TEMP_ZONE_0 */
+ {BATTERY_CPT_CHARGE_MIN_TEMP * 10, 150, 1408, 4370},
+ /* TEMP_ZONE_1 */
+ {150, 430, 3520, 4370},
+ /* TEMP_ZONE_2 */
+ {430, 450, 2112, 4320},
+ /* TEMP_ZONE_3 */
+ {450, BATTERY_CPT_CHARGE_MAX_TEMP * 10, 1760, 4170},
+ },
+ };
+ BUILD_ASSERT(ARRAY_SIZE(temp_zones[0]) == TEMP_ZONE_COUNT);
+ BUILD_ASSERT(ARRAY_SIZE(temp_zones) == BATTERY_COUNT);
+
+ if ((curr->batt.flags & BATT_FLAG_BAD_TEMPERATURE) ||
+ (bat_temp_c < temp_zones[BATT_ID][0].temp_min) ||
+ (bat_temp_c >= temp_zones[BATT_ID][TEMP_ZONE_COUNT - 1].temp_max))
+ temp_zone = TEMP_OUT_OF_RANGE;
+ else {
+ for (temp_zone = 0; temp_zone < TEMP_ZONE_COUNT; temp_zone++) {
+ if (bat_temp_c <
+ temp_zones[BATT_ID][temp_zone].temp_max)
+ break;
+ }
+ }
+
+ switch (temp_zone) {
+ case TEMP_ZONE_0:
+ case TEMP_ZONE_1:
+ case TEMP_ZONE_2:
+ case TEMP_ZONE_3:
+ curr->requested_current =
+ temp_zones[BATT_ID][temp_zone].desired_current;
+ curr->requested_voltage =
+ temp_zones[BATT_ID][temp_zone].desired_voltage;
+ break;
+ case TEMP_OUT_OF_RANGE:
+ curr->requested_current = curr->requested_voltage = 0;
+ curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE;
+ curr->state = ST_IDLE;
+ break;
+ }
+
+ /* Check cycle count to decrease charging voltage. */
+ rv = battery_cycle_count(&val);
+ if (!rv)
+ cycle_count = val;
+ if (cycle_count > 20 && cycle_count <= 50)
+ rcv_cycle = 50;
+ else if (cycle_count > 50 && cycle_count <= 300)
+ rcv_cycle = 65;
+ else if (cycle_count > 300 && cycle_count <= 600)
+ rcv_cycle = 80;
+ else if (cycle_count > 600 && cycle_count <= 1000)
+ rcv_cycle = 100;
+ else if (cycle_count > 1000)
+ rcv_cycle = 150;
+ /* Check SOH to decrease charging voltage. */
+ if (!battery_full_charge_capacity(&full_cap) &&
+ !battery_design_capacity(&design_cap))
+ soh = ((full_cap * 100) / design_cap);
+ if (soh > 70 && soh <= 75)
+ rcv_soh = 50;
+ else if (soh > 60 && soh <= 70)
+ rcv_soh = 65;
+ else if (soh > 55 && soh <= 60)
+ rcv_soh = 80;
+ else if (soh > 50 && soh <= 55)
+ rcv_soh = 100;
+ else if (soh <= 50)
+ rcv_soh = 150;
+ rcv = MAX(rcv_cycle, rcv_soh);
+ curr->requested_voltage -= rcv;
+
+ /* Should not keep charging voltage > 4250mV for 48hrs. */
+ if ((curr->state == ST_DISCHARGE) ||
+ curr->chg.voltage < 4250) {
+ deadline_48.val = 0;
+ /* Starting count 48hours */
+ } else if (curr->state == ST_CHARGE ||
+ curr->state == ST_PRECHARGE) {
+ if (deadline_48.val == 0)
+ deadline_48.val = get_time().val +
+ CHARGER_LIMIT_TIMEOUT_HOURS * HOUR;
+ /* If charging voltage keep > 4250 for 48hrs,
+ * set charging voltage = 4250
+ */
+ else if (timestamp_expired(deadline_48, NULL))
+ curr->requested_voltage = 4250;
+ }
+ /* Should not keeep battery voltage > 4100mV and
+ * battery temperature > 45C for two hour
+ */
+ if (curr->state == ST_DISCHARGE ||
+ curr->batt.voltage < 4100 ||
+ bat_temp_c < 450) {
+ deadline_2.val = 0;
+ } else if (curr->state == ST_CHARGE ||
+ curr->state == ST_PRECHARGE) {
+ if (deadline_2.val == 0)
+ deadline_2.val = get_time().val +
+ CHARGER_LIMIT_TIMEOUT_HOURS_TEMP * HOUR;
+ else if (timestamp_expired(deadline_2, NULL)) {
+ /* Set discharge and charging voltage = 4100mV */
+ if (curr->batt.voltage >= 4100) {
+ curr->requested_current = 0;
+ curr->requested_voltage = 4100;
+ }
+ }
+ }
+
+#ifdef VARIANT_KUKUI_CHARGER_MT6370
+ mt6370_charger_profile_override(curr);
+#endif /* CONFIG_CHARGER_MT6370 */
+
+ return 0;
+}
+
+enum ec_status charger_profile_override_get_param(uint32_t param,
+ uint32_t *value)
+{
+ return EC_RES_INVALID_PARAM;
+}
+
+enum ec_status charger_profile_override_set_param(uint32_t param,
+ uint32_t value)
+{
+ return EC_RES_INVALID_PARAM;
+}
+
+int get_battery_manufacturer_name(char *dest, int size)
+{
+ static const char * const name[] = {
+ [BATTERY_CPT] = "AS1XXXD3Ka",
+ };
+ ASSERT(dest);
+ strzcpy(dest, name[BATT_ID], size);
+ return EC_SUCCESS;
+}
diff --git a/baseboard/kukui/build.mk b/baseboard/kukui/build.mk
index cd0b5a7353..2d05a718ba 100644
--- a/baseboard/kukui/build.mk
+++ b/baseboard/kukui/build.mk
@@ -12,6 +12,7 @@ baseboard-$(CONFIG_BOOTBLOCK)+=emmc.o
baseboard-$(VARIANT_KUKUI_BATTERY_MAX17055)+=battery_max17055.o
baseboard-$(VARIANT_KUKUI_BATTERY_MM8013)+=battery_mm8013.o
+baseboard-$(VARIANT_KUKUI_BATTERY_BQ27541)+=battery_bq27541.o
baseboard-$(VARIANT_KUKUI_BATTERY_SMART)+=battery_smart.o
baseboard-$(VARIANT_KUKUI_CHARGER_MT6370)+=charger_mt6370.o
diff --git a/board/kakadu/board.h b/board/kakadu/board.h
index dd94b07e98..88578fed06 100644
--- a/board/kakadu/board.h
+++ b/board/kakadu/board.h
@@ -8,7 +8,8 @@
#ifndef __CROS_EC_BOARD_H
#define __CROS_EC_BOARD_H
-#define VARIANT_KUKUI_BATTERY_MM8013
+#define BQ27541_ADDR 0x55
+#define VARIANT_KUKUI_BATTERY_BQ27541
#define VARIANT_KUKUI_POGO_KEYBOARD
#define VARIANT_KUKUI_CHARGER_MT6370
diff --git a/driver/battery/bq27541.c b/driver/battery/bq27541.c
index b9c80c3b24..31d0292907 100644
--- a/driver/battery/bq27541.c
+++ b/driver/battery/bq27541.c
@@ -2,10 +2,11 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
- * Battery driver for BQ27541/BQ27741/BQ27742.
+ * Battery driver for BQ27541/BQ27542/BQ27741/BQ27742.
*/
#include "battery.h"
+#include "battery_smart.h"
#include "console.h"
#include "extpower.h"
#include "hooks.h"
@@ -14,6 +15,7 @@
#define BQ27541_ADDR_FLAGS 0x55
#define BQ27541_TYPE_ID 0x0541
+#define BQ27542_TYPE_ID 0x0542
#define BQ27741_TYPE_ID 0x0741
#define BQ27742_TYPE_ID 0x0742
@@ -39,12 +41,25 @@
#define REG_TT_EAT_CONSTANT_POWER 0x26
#define REG_CYCLE_COUNT 0x2a
#define REG_STATE_OF_CHARGE 0x2c
+#define REG_DATA_FLASH_BLOCK 0x3f
#define REG_DESIGN_CAPACITY 0x3c
+#define REG_MANUFACTURER_INFO 0x52
#define REG_DEVICE_NAME_LENGTH 0x62
#define MAX_DEVICE_NAME_LENGTH 7
#define REG_DEVICE_NAME 0x63
#define REG_PROTECTOR 0x6d
+/* Over-charge */
+#define BQ27542_FLAG_BATHI BIT(13)
+/* Over Temperature in discharge */
+#define BQ27542_FLAG_OTD BIT(11)
+/* Over Temperature in charge */
+#define BQ27542_FLAG_OTC BIT(7)
+/* Charge allowed */
+#define BQ27542_FLAG_CHG BIT(3)
+/* Discharge */
+#define BQ27542_FLAG_DSG BIT(0)
+
static int battery_type_id;
static int fake_state_of_charge = -1;
@@ -69,10 +84,12 @@ int bq27541_probe(void)
rv = bq27541_write(REG_CTRL, 0x1);
rv |= bq27541_read(REG_CTRL, &battery_type_id);
-
+ /* Read twice to get the right value */
+ rv |= bq27541_read(REG_CTRL, &battery_type_id);
if (rv)
return rv;
if (battery_type_id == BQ27541_TYPE_ID ||
+ battery_type_id == BQ27542_TYPE_ID ||
battery_type_id == BQ27741_TYPE_ID ||
battery_type_id == BQ27742_TYPE_ID)
return EC_SUCCESS;
@@ -95,6 +112,16 @@ int battery_device_name(char *device_name, int buf_size)
strzcpy(device_name, "<BATT>", len);
return 0;
}
+ /* Battery pack vendor specific */
+ if (battery_type_id == BQ27542_TYPE_ID) {
+ rv = bq27541_write(REG_DATA_FLASH_BLOCK, 0x1);
+ for (i = 0; i < len; ++i) {
+ rv |= bq27541_read8(REG_MANUFACTURER_INFO + i, &val);
+ device_name[i] = val;
+ }
+ device_name[i] = '\0';
+ return rv;
+ }
rv = bq27541_read8(REG_DEVICE_NAME_LENGTH, &val);
if (rv)
@@ -112,7 +139,7 @@ int battery_device_name(char *device_name, int buf_size)
int battery_state_of_charge_abs(int *percent)
{
- return EC_ERROR_UNIMPLEMENTED;
+ return bq27541_read(REG_STATE_OF_CHARGE, percent);
}
int battery_remaining_capacity(int *capacity)
@@ -149,6 +176,9 @@ int battery_time_at_rate(int rate, int *minutes)
{
int rv;
+ if (battery_type_id == BQ27542_TYPE_ID)
+ return EC_ERROR_UNIMPLEMENTED;
+
rv = bq27541_write(REG_AT_RATE, rate);
if (rv)
return rv;
@@ -192,7 +222,7 @@ static int battery_charging_allowed(int *allowed)
if (battery_type_id == BQ27541_TYPE_ID ||
battery_type_id == BQ27741_TYPE_ID)
*allowed = (val & 0x100);
- else /* BQ27742_TYPE_ID */
+ else /* BQ27742_TYPE_ID, BQ27542_TYPE_ID */
*allowed = (val & 0x8);
return EC_SUCCESS;
@@ -205,6 +235,25 @@ int battery_get_mode(int *mode)
int battery_status(int *status)
{
+ int rv;
+ int flag = 0;
+
+ *status = 0;
+ if (battery_type_id == BQ27542_TYPE_ID) {
+ rv = bq27541_read(REG_FLAGS, &flag);
+ if (rv)
+ return rv;
+
+ if (flag & (BQ27542_FLAG_OTC | BQ27542_FLAG_OTD))
+ *status |= STATUS_OVERTEMP_ALARM;
+ if (flag & BQ27542_FLAG_DSG)
+ *status |= STATUS_DISCHARGING;
+ if (flag & BQ27542_FLAG_BATHI)
+ *status |= STATUS_OVERCHARGED_ALARM;
+
+ return EC_SUCCESS;
+ }
+
return EC_ERROR_UNIMPLEMENTED;
}
@@ -244,6 +293,12 @@ void battery_get_params(struct batt_params *batt)
batt->flags |= BATT_FLAG_BAD_CURRENT;
batt->current = (int16_t)v;
+ if (battery_remaining_capacity(&batt->remaining_capacity))
+ batt->flags |= BATT_FLAG_BAD_REMAINING_CAPACITY;
+
+ if (battery_full_charge_capacity(&batt->full_capacity))
+ batt->flags |= BATT_FLAG_BAD_FULL_CAPACITY;
+
/* Default to not desiring voltage and current */
batt->desired_voltage = batt->desired_current = 0;
@@ -348,3 +403,19 @@ DECLARE_CONSOLE_COMMAND(battfake, command_battfake,
"percent (-1 = use real level)",
"Set fake battery level");
+#ifdef CONFIG_CMD_PWR_AVG
+int battery_get_avg_current(void)
+{
+ int current = -EC_ERROR_UNKNOWN;
+
+ bq27541_read(REG_AVERAGE_CURRENT, &current);
+ return current;
+}
+
+int battery_get_avg_voltage(void)
+{
+ /* BQ27541 does not have this parameter */
+ return -EC_ERROR_UNIMPLEMENTED;
+}
+#endif /* CONFIG_CMD_PWR_AVG */
+