summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--baseboard/grunt/baseboard.h1
-rw-r--r--baseboard/grunt/baseboard_battery.h44
-rw-r--r--baseboard/grunt/battery.c265
-rw-r--r--board/careena/battery.c65
-rw-r--r--board/careena/board.h5
-rw-r--r--board/careena/build.mk1
-rw-r--r--board/careena/gpio.inc2
-rw-r--r--board/grunt/battery.c65
-rw-r--r--board/grunt/board.h5
-rw-r--r--board/grunt/build.mk1
-rw-r--r--board/grunt/gpio.inc2
11 files changed, 389 insertions, 67 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;
+}
diff --git a/board/careena/battery.c b/board/careena/battery.c
new file mode 100644
index 0000000000..c0af812b9f
--- /dev/null
+++ b/board/careena/battery.c
@@ -0,0 +1,65 @@
+/* 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.
+ *
+ * Battery pack vendor provided charging profile
+ */
+
+#include "common.h"
+#include "baseboard_battery.h"
+#include "util.h"
+
+/*
+ * Battery info for all Careena battery types. Note that the fields
+ * start_charging_min/max and charging_min/max are not used for the charger.
+ * The effective temperature limits are given by discharging_min/max_c.
+ *
+ * Fuel Gauge (FG) parameters which are used for determining if the battery
+ * is connected, the appropriate ship mode (battery cutoff) command, and the
+ * charge/discharge FETs status.
+ *
+ * Ship mode (battery cutoff) requires 2 writes to the appropriate smart battery
+ * register. For some batteries, the charge/discharge FET bits are set when
+ * charging/discharging is active, in other types, these bits set mean that
+ * charging/discharging is disabled. Therefore, in addition to the mask for
+ * these bits, a disconnect value must be specified. Note that for TI fuel
+ * gauge, the charge/discharge FET status is found in Operation Status (0x54),
+ * but a read of Manufacturer Access (0x00) will return the lower 16 bits of
+ * Operation status which contains the FET status bits.
+ *
+ * The assumption for battery types supported is that the charge/discharge FET
+ * status can be read with a sb_read() command and therefore, only the register
+ * address, mask, and disconnect value need to be provided.
+ */
+const struct board_batt_params board_battery_info[] = {
+ /* Panasonic AP15O5L Battery Information */
+ [BATTERY_PANASONIC] = {
+ .fuel_gauge = {
+ .manuf_name = "PANASONIC",
+ .ship_mode = {
+ .reg_addr = 0x3A,
+ .reg_data = { 0xC574, 0xC574 },
+ },
+ .fet = {
+ .reg_addr = 0x0,
+ .reg_mask = 0x4000,
+ .disconnect_val = 0x0,
+ }
+ },
+ .batt_info = {
+ .voltage_max = 13200,
+ .voltage_normal = 11550, /* mV */
+ .voltage_min = 9000, /* mV */
+ .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 = 0,
+ .discharging_max_c = 60,
+ },
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(board_battery_info) == BATTERY_TYPE_COUNT);
+
+const enum battery_type DEFAULT_BATTERY_TYPE = BATTERY_PANASONIC;
diff --git a/board/careena/board.h b/board/careena/board.h
index c76a3c9b72..22d34d3b5e 100644
--- a/board/careena/board.h
+++ b/board/careena/board.h
@@ -30,6 +30,11 @@ enum pwm_channel {
PWM_CH_COUNT
};
+enum battery_type {
+ BATTERY_PANASONIC,
+ BATTERY_TYPE_COUNT,
+};
+
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */
diff --git a/board/careena/build.mk b/board/careena/build.mk
index 9620af3152..c808e65aed 100644
--- a/board/careena/build.mk
+++ b/board/careena/build.mk
@@ -12,3 +12,4 @@ CHIP_VARIANT:=npcx7m6f
BASEBOARD:=grunt
board-y=board.o led.o
+board-$(CONFIG_BATTERY_SMART)+=battery.o
diff --git a/board/careena/gpio.inc b/board/careena/gpio.inc
index ed7dbb2d21..46428ae409 100644
--- a/board/careena/gpio.inc
+++ b/board/careena/gpio.inc
@@ -34,7 +34,7 @@ GPIO(PCH_WAKE_L, PIN(7, 4), GPIO_OUT_HIGH) /* Wake SOC */
GPIO(PCH_RCIN_L, PIN(3, 5), GPIO_ODR_HIGH) /* Cold Reset to SOC */
GPIO(CCD_MODE_ODL, PIN(E, 3), GPIO_INPUT) /* Case Closed Debug Mode */
GPIO(ENTERING_RW, PIN(E, 1), GPIO_OUT_LOW) /* EC Entering RW */
-GPIO(EC_BATT_PRES_ODL, PIN(E, 5), GPIO_INPUT | GPIO_PULL_UP) /* Battery Present */
+GPIO(EC_BATT_PRES_L, PIN(E, 5), GPIO_INPUT | GPIO_PULL_UP) /* Battery Present */
GPIO(PCH_SYS_PWROK, PIN(D, 6), GPIO_OUT_LOW) /* Power OK to SOC */
GPIO(EC_APU_RST, PIN(E, 4), GPIO_INPUT) /* Reset to SOC */
GPIO(CPU_PROCHOT, PIN(3, 4), GPIO_INPUT | GPIO_SEL_1P8V) /* PROCHOT to SOC */
diff --git a/board/grunt/battery.c b/board/grunt/battery.c
new file mode 100644
index 0000000000..3dd9f84832
--- /dev/null
+++ b/board/grunt/battery.c
@@ -0,0 +1,65 @@
+/* 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.
+ *
+ * Battery pack vendor provided charging profile
+ */
+
+#include "common.h"
+#include "baseboard_battery.h"
+#include "util.h"
+
+/*
+ * Battery info for all Grunt battery types. Note that the fields
+ * start_charging_min/max and charging_min/max are not used for the charger.
+ * The effective temperature limits are given by discharging_min/max_c.
+ *
+ * Fuel Gauge (FG) parameters which are used for determining if the battery
+ * is connected, the appropriate ship mode (battery cutoff) command, and the
+ * charge/discharge FETs status.
+ *
+ * Ship mode (battery cutoff) requires 2 writes to the appropriate smart battery
+ * register. For some batteries, the charge/discharge FET bits are set when
+ * charging/discharging is active, in other types, these bits set mean that
+ * charging/discharging is disabled. Therefore, in addition to the mask for
+ * these bits, a disconnect value must be specified. Note that for TI fuel
+ * gauge, the charge/discharge FET status is found in Operation Status (0x54),
+ * but a read of Manufacturer Access (0x00) will return the lower 16 bits of
+ * Operation status which contains the FET status bits.
+ *
+ * The assumption for battery types supported is that the charge/discharge FET
+ * status can be read with a sb_read() command and therefore, only the register
+ * address, mask, and disconnect value need to be provided.
+ */
+const struct board_batt_params board_battery_info[] = {
+ /* Panasonic AP15O5L Battery Information */
+ [BATTERY_PANASONIC] = {
+ .fuel_gauge = {
+ .manuf_name = "PANASONIC",
+ .ship_mode = {
+ .reg_addr = 0x3A,
+ .reg_data = { 0xC574, 0xC574 },
+ },
+ .fet = {
+ .reg_addr = 0x0,
+ .reg_mask = 0x4000,
+ .disconnect_val = 0x0,
+ }
+ },
+ .batt_info = {
+ .voltage_max = 13200,
+ .voltage_normal = 11550, /* mV */
+ .voltage_min = 9000, /* mV */
+ .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 = 0,
+ .discharging_max_c = 60,
+ },
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(board_battery_info) == BATTERY_TYPE_COUNT);
+
+const enum battery_type DEFAULT_BATTERY_TYPE = BATTERY_PANASONIC;
diff --git a/board/grunt/board.h b/board/grunt/board.h
index dbbd036189..a020b6eae0 100644
--- a/board/grunt/board.h
+++ b/board/grunt/board.h
@@ -50,6 +50,11 @@ enum pwm_channel {
PWM_CH_COUNT
};
+enum battery_type {
+ BATTERY_PANASONIC,
+ BATTERY_TYPE_COUNT,
+};
+
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */
diff --git a/board/grunt/build.mk b/board/grunt/build.mk
index 9620af3152..c808e65aed 100644
--- a/board/grunt/build.mk
+++ b/board/grunt/build.mk
@@ -12,3 +12,4 @@ CHIP_VARIANT:=npcx7m6f
BASEBOARD:=grunt
board-y=board.o led.o
+board-$(CONFIG_BATTERY_SMART)+=battery.o
diff --git a/board/grunt/gpio.inc b/board/grunt/gpio.inc
index 4cd840ba02..8f81a05114 100644
--- a/board/grunt/gpio.inc
+++ b/board/grunt/gpio.inc
@@ -35,7 +35,7 @@ GPIO(PCH_WAKE_L, PIN(7, 4), GPIO_OUT_HIGH) /* Wake SOC */
GPIO(PCH_RCIN_L, PIN(0, 2), GPIO_ODR_HIGH) /* Cold Reset to SOC */
GPIO(CCD_MODE_ODL, PIN(E, 3), GPIO_INPUT) /* Case Closed Debug Mode */
GPIO(ENTERING_RW, PIN(E, 1), GPIO_OUT_LOW) /* EC Entering RW */
-GPIO(EC_BATT_PRES_ODL, PIN(E, 5), GPIO_INPUT | GPIO_PULL_UP) /* Battery Present */
+GPIO(EC_BATT_PRES_L, PIN(E, 5), GPIO_INPUT | GPIO_PULL_UP) /* Battery Present */
GPIO(PCH_SYS_PWROK, PIN(D, 6), GPIO_OUT_LOW) /* Power OK to SOC */
GPIO(EC_APU_RST, PIN(E, 4), GPIO_INPUT) /* Reset to SOC */
GPIO(CPU_PROCHOT, PIN(3, 4), GPIO_INPUT | GPIO_SEL_1P8V) /* PROCHOT to SOC */