summaryrefslogtreecommitdiff
path: root/baseboard
diff options
context:
space:
mode:
authorEdward Hill <ecgh@chromium.org>2018-05-24 11:29:19 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-06-01 17:44:19 -0700
commitf30bb2839f0cd22efe0468680daf66e45a3ce862 (patch)
tree65913ed7628af5291f1f43d74aaf114476f46de8 /baseboard
parent31fbb6889e75eb1ebe823a74a9bc95da78b991ad (diff)
downloadchrome-ec-f30bb2839f0cd22efe0468680daf66e45a3ce862.tar.gz
grunt: Board specific battery info
Split battery info between baseboard and board, following the Octopus example. This will allow Grunt and Careena to define their own lists of supported battery types. This also adds CONFIG_BATTERY_REVIVE_DISCONNECT support, and checks the charge/discharge FET status. BUG=b:79704826,b:74018100 BRANCH=none TEST=Grunt still boots ok. Change-Id: I6e82ac5e48f9aabf59b63add253108513f0a6b60 Signed-off-by: Edward Hill <ecgh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1072039 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'baseboard')
-rw-r--r--baseboard/grunt/baseboard.h1
-rw-r--r--baseboard/grunt/baseboard_battery.h44
-rw-r--r--baseboard/grunt/battery.c265
3 files changed, 245 insertions, 65 deletions
diff --git a/baseboard/grunt/baseboard.h b/baseboard/grunt/baseboard.h
index 511b39cf31..ac5fbf113e 100644
--- a/baseboard/grunt/baseboard.h
+++ b/baseboard/grunt/baseboard.h
@@ -45,6 +45,7 @@
#define CONFIG_BATTERY_CUT_OFF
#define CONFIG_BATTERY_HW_PRESENT_CUSTOM
#define CONFIG_BATTERY_PRESENT_CUSTOM
+#define CONFIG_BATTERY_REVIVE_DISCONNECT
#define CONFIG_BATTERY_SMART
#define CONFIG_BC12_DETECT_BQ24392
diff --git a/baseboard/grunt/baseboard_battery.h b/baseboard/grunt/baseboard_battery.h
new file mode 100644
index 0000000000..513c45a512
--- /dev/null
+++ b/baseboard/grunt/baseboard_battery.h
@@ -0,0 +1,44 @@
+/* Copyright 2018 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.
+ */
+
+/* Grunt baseboard battery configuration */
+
+#ifndef __CROS_EC_BASEBOARD_BATTERY_H
+#define __CROS_EC_BASEBOARD_BATTERY_H
+
+#include "battery.h"
+
+/* Number of writes needed to invoke battery cutoff command */
+#define SHIP_MODE_WRITES 2
+
+struct ship_mode_info {
+ const uint8_t reg_addr;
+ const uint16_t reg_data[SHIP_MODE_WRITES];
+};
+
+struct fet_info {
+ const int mfgacc_support;
+ const uint8_t reg_addr;
+ const uint16_t reg_mask;
+ const uint16_t disconnect_val;
+};
+
+struct fuel_gauge_info {
+ const char *manuf_name;
+ const char *device_name;
+ const uint8_t override_nil;
+ const struct ship_mode_info ship_mode;
+ const struct fet_info fet;
+};
+struct board_batt_params {
+ const struct fuel_gauge_info fuel_gauge;
+ const struct battery_info batt_info;
+};
+
+/* Forward declare board specific data used by baseboard code */
+extern const struct board_batt_params board_battery_info[];
+extern const enum battery_type DEFAULT_BATTERY_TYPE;
+
+#endif /* __CROS_EC_BASEBOARD_BATTERY_H */
diff --git a/baseboard/grunt/battery.c b/baseboard/grunt/battery.c
index 8c9755daac..0f76f5d9cd 100644
--- a/baseboard/grunt/battery.c
+++ b/baseboard/grunt/battery.c
@@ -6,55 +6,157 @@
*/
#include "battery.h"
+#include "baseboard_battery.h"
#include "battery_smart.h"
+#include "charge_state.h"
+#include "common.h"
#include "console.h"
-#include "extpower.h"
#include "gpio.h"
#include "hooks.h"
-#include "timer.h"
+#include "util.h"
#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
-/* Shutdown mode parameter to write to manufacturer access register */
-#define SB_SHUTDOWN_DATA 0x0010
static enum battery_present batt_pres_prev = BP_NOT_SURE;
-/* Battery may delay reporting battery present */
-static int battery_report_present = 1;
-
-static const struct battery_info info = {
- .voltage_max = 13200, /* mV */
- .voltage_normal = 11550,
- .voltage_min = 9000,
- .precharge_current = 256, /* mA */
- .start_charging_min_c = 0,
- .start_charging_max_c = 50,
- .charging_min_c = 0,
- .charging_max_c = 60,
- .discharging_min_c = -20,
- .discharging_max_c = 75,
-};
+/* Get type of the battery connected on the board */
+static int board_get_battery_type(void)
+{
+ char manu_name[32], device_name[32];
+ int i;
+ static enum battery_type board_battery_type = BATTERY_TYPE_COUNT;
+
+ /*
+ * If board_battery_type is not the default value, then can return here
+ * as there is no need to query the fuel gauge.
+ */
+ if (board_battery_type != BATTERY_TYPE_COUNT)
+ return board_battery_type;
+
+ /* Get the manufacture name. If can't read then just exit */
+ if (battery_manufacturer_name(manu_name, sizeof(manu_name)))
+ return board_battery_type;
+
+ /*
+ * Compare the manufacturer name read from the fuel gauge to the
+ * manufacture names defined in the board_battery_info table above. If
+ * a device name has been specified in the board_battery_info table,
+ * then both the manufacture and device name must match.
+ */
+ for (i = 0; i < BATTERY_TYPE_COUNT; i++) {
+ const struct fuel_gauge_info * const fuel_gauge =
+ &board_battery_info[i].fuel_gauge;
+
+ if (strcasecmp(manu_name, fuel_gauge->manuf_name))
+ continue;
+
+ if (fuel_gauge->device_name == NULL) {
+ board_battery_type = i;
+ break;
+ }
+
+ if (battery_device_name(device_name, sizeof(device_name)))
+ continue;
+
+ if (strcasecmp(device_name, fuel_gauge->device_name))
+ continue;
+
+ CPRINTS("found batt:%s", fuel_gauge->manuf_name);
+ board_battery_type = i;
+
+ break;
+ }
+
+ return board_battery_type;
+}
+
+/*
+ * Initialize the battery type for the board.
+ *
+ * Very first battery board_battery_info is called by the charger driver to
+ * initialize the charger parameters hence initialize the battery type for the
+ * board as soon as the I2C is initialized.
+ */
+static void board_init_battery_type(void)
+{
+ if (board_get_battery_type() == BATTERY_TYPE_COUNT)
+ CPRINTS("battery not found");
+}
+DECLARE_HOOK(HOOK_INIT, board_init_battery_type, HOOK_PRIO_INIT_I2C + 1);
+
+static inline const struct board_batt_params *board_get_batt_params(void)
+{
+ int type = board_get_battery_type();
+
+ return &board_battery_info[type == BATTERY_TYPE_COUNT ?
+ DEFAULT_BATTERY_TYPE : type];
+}
const struct battery_info *battery_get_info(void)
{
- return &info;
+ return &board_get_batt_params()->batt_info;
}
int board_cut_off_battery(void)
{
int rv;
+ int cmd;
+ int data;
+ int type = board_get_battery_type();
+
+ /* If battery type is unknown can't send ship mode command */
+ if (type == BATTERY_TYPE_COUNT)
+ return EC_RES_ERROR;
+
/* Ship mode command must be sent twice to take effect */
- rv = sb_write(SB_MANUFACTURER_ACCESS, SB_SHUTDOWN_DATA);
+ cmd = board_battery_info[type].fuel_gauge.ship_mode.reg_addr;
+ data = board_battery_info[type].fuel_gauge.ship_mode.reg_data[0];
+ rv = sb_write(cmd, data);
if (rv != EC_SUCCESS)
- return rv;
- return sb_write(SB_MANUFACTURER_ACCESS, SB_SHUTDOWN_DATA);
+ return EC_RES_ERROR;
+
+ data = board_battery_info[type].fuel_gauge.ship_mode.reg_data[1];
+ rv = sb_write(cmd, data);
+
+ return rv ? EC_RES_ERROR : EC_RES_SUCCESS;
+}
+
+int charger_profile_override(struct charge_state_data *curr)
+{
+ int type = board_get_battery_type();
+
+ /*
+ * Some batteries, when fully discharged, may request 0 voltage/current
+ * which can then inadvertently disable the charger leading to the
+ * battery not waking up. For this type of battery, marked by
+ * override_nil being set, if SOC is 0 and requested voltage/current is
+ * 0, then use precharge current and max voltage instead.
+ */
+ if (type != BATTERY_TYPE_COUNT &&
+ board_battery_info[type].fuel_gauge.override_nil) {
+ int v = board_battery_info[type].batt_info.voltage_max;
+ int i = board_battery_info[type].batt_info.precharge_current;
+
+ if (curr->requested_voltage == 0 &&
+ curr->requested_current == 0 &&
+ curr->batt.state_of_charge == 0) {
+ /*
+ * Battery is dead, override with precharge current and
+ * max voltage setting for the battery.
+ */
+ curr->requested_voltage = v;
+ curr->requested_current = i;
+ }
+ }
+
+ return 0;
}
enum battery_present battery_hw_present(void)
{
/* The GPIO is low when the battery is physically present */
- return gpio_get_level(GPIO_EC_BATT_PRES_ODL) ? BP_NO : BP_YES;
+ return gpio_get_level(GPIO_EC_BATT_PRES_L) ? BP_NO : BP_YES;
}
static int battery_init(void)
@@ -65,62 +167,95 @@ static int battery_init(void)
!!(batt_status & STATUS_INITIALIZED);
}
-/* Allow booting now that the battery has woke up */
-static void battery_now_present(void)
+/*
+ * This function checks the charge/discharge FET status bits. Each battery type
+ * supported provides the register address, mask, and disconnect value for these
+ * 2 FET status bits. If the FET status matches the disconnected value, then
+ * BATTERY_DISCONNECTED is returned. This function is required to handle the
+ * cases when the fuel gauge is awake and will return a non-zero state of
+ * charge, but is not able yet to provide power (i.e. discharge FET is not
+ * active). By returning BATTERY_DISCONNECTED the AP will not be powered up
+ * until either the external charger is able to provided enough power, or
+ * the battery is able to provide power and thus prevent a brownout when the
+ * AP is powered on by the EC.
+ */
+enum battery_disconnect_state battery_get_disconnect_state(void)
{
- CPRINTS("battery will now report present");
- battery_report_present = 1;
-}
-DECLARE_DEFERRED(battery_now_present);
+ int rv;
+ int reg;
+ uint8_t data[6];
+ int type = board_get_battery_type();
+
+ /* If battery type is not known, can't check CHG/DCHG FETs */
+ if (type == BATTERY_TYPE_COUNT) {
+ /* Still don't know, so return here */
+ return BATTERY_DISCONNECT_ERROR;
+ }
+
+ /* Read the status of charge/discharge FETs */
+ if (board_battery_info[type].fuel_gauge.fet.mfgacc_support == 1) {
+ rv = sb_read_mfgacc(PARAM_OPERATION_STATUS,
+ SB_ALT_MANUFACTURER_ACCESS, data, sizeof(data));
+ /* Get the lowest 16bits of the OperationStatus() data */
+ reg = data[2] | data[3] << 8;
+ } else
+ rv = sb_read(board_battery_info[type].fuel_gauge.fet.reg_addr,
+ &reg);
+
+ if (rv)
+ return BATTERY_DISCONNECT_ERROR;
+
+ if ((reg & board_battery_info[type].fuel_gauge.fet.reg_mask) ==
+ board_battery_info[type].fuel_gauge.fet.disconnect_val) {
+ CPRINTS("Batt disconnected: reg 0x%04x mask 0x%04x disc 0x%04x",
+ reg,
+ board_battery_info[type].fuel_gauge.fet.reg_mask,
+ board_battery_info[type].fuel_gauge.fet.disconnect_val);
+ return BATTERY_DISCONNECTED;
+ }
-static int battery_check_disconnect(void)
-{
- /* TODO(ecgh): Read the status of charge/discharge FETs */
return BATTERY_NOT_DISCONNECTED;
}
-enum battery_present battery_is_present(void)
+/*
+ * Physical detection of battery.
+ */
+static enum battery_present battery_check_present_status(void)
{
enum battery_present batt_pres;
- static int battery_report_present_timer_started;
/* Get the physical hardware status */
batt_pres = battery_hw_present();
/*
- * Make sure battery status is implemented, I2C transactions are
- * success & the battery status is Initialized to find out if it
- * is a working battery and it is not in the cut-off mode.
+ * If the battery is not physically connected, then no need to perform
+ * any more checks.
*/
- if (batt_pres == BP_YES && batt_pres_prev != batt_pres &&
- (battery_is_cut_off() != BATTERY_CUTOFF_STATE_NORMAL ||
- battery_check_disconnect() != BATTERY_NOT_DISCONNECTED ||
- battery_init() == 0)) {
- battery_report_present = 0;
- /*
- * When this path is taken, the _timer_started flag must be
- * reset so the 'else if' path will be entered and the
- * battery_report_present flag can be set by the deferred
- * call. This handles the case of the battery being disconected
- * and reconnected while running or if battery_init() returns an
- * error due to a failed sb_read.
- */
- battery_report_present_timer_started = 0;
- } else if (batt_pres == BP_YES && batt_pres_prev == BP_NO &&
- !battery_report_present_timer_started) {
- /*
- * Wait 1/2 second before reporting present if it was
- * previously reported as not present
- */
- battery_report_present_timer_started = 1;
- battery_report_present = 0;
- hook_call_deferred(&battery_now_present_data, 500 * MSEC);
- }
+ if (batt_pres != BP_YES)
+ return batt_pres;
- if (!battery_report_present)
- batt_pres = BP_NO;
+ /*
+ * If the battery is present now and was present last time we checked,
+ * return early.
+ */
+ if (batt_pres == batt_pres_prev)
+ return batt_pres;
- batt_pres_prev = batt_pres;
+ /*
+ * Ensure that battery is:
+ * 1. Not in cutoff
+ * 2. Initialized
+ */
+ if (battery_is_cut_off() != BATTERY_CUTOFF_STATE_NORMAL ||
+ battery_init() == 0) {
+ batt_pres = BP_NO;
+ }
return batt_pres;
}
+
+enum battery_present battery_is_present(void)
+{
+ batt_pres_prev = battery_check_present_status();
+ return batt_pres_prev;
+}