summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2020-12-03 01:06:01 -0800
committerCommit Bot <commit-bot@chromium.org>2020-12-10 00:47:35 +0000
commit868c16a6257bac63079304b4e83d75083dabd5f6 (patch)
treec206f9609b7efa2a3b608bbcfe06f1aa52076ffc
parent3625c3c9ff9e94583f80b199668ec34f6124c720 (diff)
downloadchrome-ec-868c16a6257bac63079304b4e83d75083dabd5f6.tar.gz
OCPC: Add explicit precharge phase
This commit adds an explicit precharge phase to the OCPC algorithm. This allows the OCPC module to take advantage of the linear charging feature available on the supported charger ICs. With linear charging, the charger IC can control the BFET in the linear region to provide low precharge currents while maintaining a high VSYS in order to prevent brownounts in the system. The precharge phase is active when the battery voltage is less than the minimum battery voltage, or the voltage is less than the nominal voltage and the desired charge current is less than or equal to the defined precharge current. BUG=b:174683659 BRANCH=dedede TEST=Build and flash drawcia. Drain battery until DFET is disabled. Plug in a charger on the sub board, verify that battery is able to be revived, battery is able to charge at precharge current limits without exceeding, and battery is able to transition to the fast charge portion of the charge curve without excessively exceeding the target current limit. TEST=Cutoff battyey, plug in charger, verify that battery is able to be revived from the sub board. Signed-off-by: Aseda Aboagye <aaboagye@google.com> Change-Id: I59b119bac8ed9266889aace63d58d5da63e382f3 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2570939 Commit-Queue: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r--common/ocpc.c82
1 files changed, 76 insertions, 6 deletions
diff --git a/common/ocpc.c b/common/ocpc.c
index 417983bfba..b6ec4e4ab6 100644
--- a/common/ocpc.c
+++ b/common/ocpc.c
@@ -66,6 +66,7 @@ static int lb;
enum phase {
PHASE_UNKNOWN = -1,
+ PHASE_PRECHARGE,
PHASE_CC,
PHASE_CV_TRIP,
PHASE_CV_COMPLETE,
@@ -75,6 +76,8 @@ __overridable void board_ocpc_init(struct ocpc_data *ocpc)
{
}
+static enum ec_error_list ocpc_precharge_enable(bool enable);
+
static void calc_resistance_stats(void)
{
int i;
@@ -187,6 +190,7 @@ int ocpc_config_secondary_charger(int *desired_input_current,
static timestamp_t delay;
int i, step, loc;
bool icl_reached = false;
+ static timestamp_t precharge_exit;
/*
* There's nothing to do if we're not using this charger. Should
@@ -252,6 +256,7 @@ int ocpc_config_secondary_charger(int *desired_input_current,
if (ocpc->last_vsys == OCPC_UNINIT) {
ph = PHASE_UNKNOWN;
+ precharge_exit.val = 0;
iterations = 0;
}
@@ -290,11 +295,56 @@ int ocpc_config_secondary_charger(int *desired_input_current,
/* Set our current target accordingly. */
if (batt.desired_voltage) {
- if (batt.voltage < batt.desired_voltage) {
- if (ph < PHASE_CV_TRIP)
+ if (((batt.voltage < batt_info->voltage_min) ||
+ ((batt.voltage < batt_info->voltage_normal) &&
+ (batt.desired_current <= batt_info->precharge_current))) &&
+ (ph != PHASE_PRECHARGE)) {
+ /*
+ * If the charger IC doesn't support the linear charge
+ * feature, proceed to the CC phase.
+ */
+ result = ocpc_precharge_enable(true);
+ if (result == EC_ERROR_UNIMPLEMENTED) {
+ ph = PHASE_CC;
+ } else if (result == EC_SUCCESS) {
+ CPRINTS("OCPC: Enabling linear precharge");
+ ph = PHASE_PRECHARGE;
+ i_ma = batt.desired_current;
+ }
+ } else if (batt.voltage < batt.desired_voltage) {
+ if ((ph == PHASE_PRECHARGE) &&
+ (batt.desired_current >
+ batt_info->precharge_current)) {
+ /*
+ * Precharge phase is complete. Now set the
+ * target VSYS to the battery voltage to prevent
+ * a large current spike during the transition.
+ */
+ /*
+ * If we'd like to exit precharge, let's wait a
+ * short delay.
+ */
+ if (!precharge_exit.val) {
+ CPRINTS("OCPC: Preparing to exit "
+ "precharge");
+ precharge_exit = get_time();
+ precharge_exit.val += 3 * SECOND;
+ }
+ if (timestamp_expired(precharge_exit, NULL)) {
+ CPRINTS("OCPC: Precharge complete");
+ charger_set_voltage(CHARGER_SECONDARY,
+ batt.voltage);
+ ocpc->last_vsys = batt.voltage;
+ ocpc_precharge_enable(false);
+ ph = PHASE_CC;
+ precharge_exit.val = 0;
+ }
+ }
+
+ if ((ph != PHASE_PRECHARGE) && (ph < PHASE_CV_TRIP))
ph = PHASE_CC;
i_ma = batt.desired_current;
- } else{
+ } else {
/*
* Once the battery voltage reaches the desired voltage,
* we should note that we've reached the CV step and set
@@ -334,7 +384,7 @@ int ocpc_config_secondary_charger(int *desired_input_current,
derivative = error - ocpc->last_error;
ocpc->last_error = error;
- ocpc->integral += error;
+ ocpc->integral += error;
if (ocpc->integral > 500)
ocpc->integral = 500;
}
@@ -353,7 +403,8 @@ int ocpc_config_secondary_charger(int *desired_input_current,
CPRINTS_DBG("min_vsys_target = %d", min_vsys_target);
/* Obtain the drive from our PID controller. */
- if (ocpc->last_vsys != OCPC_UNINIT) {
+ if ((ocpc->last_vsys != OCPC_UNINIT) &&
+ (ph > PHASE_PRECHARGE)) {
drive = (k_p * error / k_p_div) +
(k_i * ocpc->integral / k_i_div) +
(k_d * derivative / k_d_div);
@@ -368,11 +419,18 @@ int ocpc_config_secondary_charger(int *desired_input_current,
}
/*
+ * For the pre-charge phase, simply keep the VSYS target at the desired
+ * voltage.
+ */
+ if (ph == PHASE_PRECHARGE)
+ vsys_target = batt.desired_voltage;
+
+ /*
* Adjust our VSYS target by applying the calculated drive. Note that
* we won't apply our drive the first time through this function such
* that we can determine our initial error.
*/
- if (ocpc->last_vsys != OCPC_UNINIT)
+ if ((ocpc->last_vsys != OCPC_UNINIT) && (ph > PHASE_PRECHARGE))
vsys_target = ocpc->last_vsys + drive;
/*
@@ -500,6 +558,18 @@ __overridable void ocpc_get_pid_constants(int *kp, int *kp_div,
{
}
+static enum ec_error_list ocpc_precharge_enable(bool enable)
+{
+ /* Enable linear charging on the primary charger IC. */
+ int rv = charger_enable_linear_charge(CHARGER_PRIMARY, enable);
+
+ if (rv)
+ CPRINTS("OCPC: Failed to %sble linear charge!", enable ? "ena"
+ : "dis");
+
+ return rv;
+}
+
static void ocpc_set_pid_constants(void)
{
ocpc_get_pid_constants(&k_p, &k_p_div, &k_i, &k_i_div, &k_d, &k_d_div);