summaryrefslogtreecommitdiff
path: root/board/samus/extpower.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/samus/extpower.c')
-rw-r--r--board/samus/extpower.c441
1 files changed, 0 insertions, 441 deletions
diff --git a/board/samus/extpower.c b/board/samus/extpower.c
deleted file mode 100644
index 22cd13b44d..0000000000
--- a/board/samus/extpower.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/* Copyright 2013 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.
- */
-
-/*
- * Pure GPIO-based external power detection, buffered to PCH.
- * Drive high in S5-S0 when AC_PRESENT is high, otherwise drive low.
- */
-
-#include "bq24773.h"
-#include "charge_state.h"
-#include "charger.h"
-#include "chipset.h"
-#include "common.h"
-#include "console.h"
-#include "extpower.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "i2c.h"
-#include "system.h"
-#include "task.h"
-#include "util.h"
-
-/* Console output macros */
-#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
-
-/* Max number of attempts to enable/disable NVDC charger */
-#define CHARGER_MODE_ATTEMPTS 3
-
-/* Backboost has been detected */
-static int bkboost_detected;
-
-/* Charging is disabled */
-static int charge_is_disabled;
-
-/* Extpower task has been initialized */
-static int extpower_task_initialized;
-
-/*
- * Charge circuit occasionally gets wedged and doesn't charge.
- * This variable keeps track of the state of the circuit.
- */
-static enum {
- CHARGE_CIRCUIT_OK,
- CHARGE_CIRCUIT_WEDGED,
-} charge_circuit_state = CHARGE_CIRCUIT_OK;
-
-int extpower_is_present(void)
-{
- return gpio_get_level(GPIO_AC_PRESENT);
-}
-
-static void extpower_buffer_to_pch(void)
-{
- if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) {
- /* Drive low in G3 state */
- gpio_set_level(GPIO_PCH_ACOK, 0);
- } else {
- /* Buffer from extpower in S5+ (where 3.3DSW enabled) */
- gpio_set_level(GPIO_PCH_ACOK, extpower_is_present());
- }
-}
-DECLARE_HOOK(HOOK_CHIPSET_PRE_INIT, extpower_buffer_to_pch, HOOK_PRIO_DEFAULT);
-
-static void extpower_shutdown(void)
-{
- /* Drive ACOK buffer to PCH low when shutting down */
- gpio_set_level(GPIO_PCH_ACOK, 0);
-}
-DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, extpower_shutdown, HOOK_PRIO_DEFAULT);
-
-void extpower_interrupt(enum gpio_signal signal)
-{
- /* Trigger notification of external power change */
- extpower_buffer_to_pch();
-
- /* Wake extpower task only if task has been initialized */
- if (extpower_task_initialized)
- task_wake(TASK_ID_EXTPOWER);
-}
-
-static void extpower_init(void)
-{
- extpower_buffer_to_pch();
-
- /* Enable interrupts, now that we've initialized */
- gpio_enable_interrupt(GPIO_AC_PRESENT);
-}
-DECLARE_HOOK(HOOK_INIT, extpower_init, HOOK_PRIO_DEFAULT);
-
-/*
- * Save power in S3/S5/G3 by disabling charging when the battery is
- * full. Restore charging when battery is not full anymore. This saves
- * power because our input AC path is inefficient.
- */
-
-static void check_charging_cutoff(void)
-{
- /* If battery is full disable charging */
- if (charge_get_percent() == 100) {
- charge_is_disabled = 1;
- host_command_pd_send_status(PD_CHARGE_NONE);
- }
-}
-DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, check_charging_cutoff, HOOK_PRIO_DEFAULT);
-
-static void cancel_charging_cutoff(void)
-{
- /* If charging is disabled, enable it */
- if (charge_is_disabled) {
- charge_is_disabled = 0;
- host_command_pd_send_status(PD_CHARGE_5V);
- }
-}
-DECLARE_HOOK(HOOK_CHIPSET_RESUME, cancel_charging_cutoff, HOOK_PRIO_DEFAULT);
-
-static void batt_soc_change(void)
-{
- /* If in S0, leave charging alone */
- if (chipset_in_state(CHIPSET_STATE_ON)) {
- host_command_pd_send_status(PD_CHARGE_NO_CHANGE);
- return;
- }
-
- /* Check to disable or enable charging based on batt state of charge */
- if (!charge_is_disabled && charge_get_percent() == 100) {
- host_command_pd_send_status(PD_CHARGE_NONE);
- charge_is_disabled = 1;
- } else if (charge_is_disabled && charge_get_percent() < 100) {
- charge_is_disabled = 0;
- host_command_pd_send_status(PD_CHARGE_5V);
- } else {
- /* Leave charging alone, but update battery SOC */
- host_command_pd_send_status(PD_CHARGE_NO_CHANGE);
- }
-}
-DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, batt_soc_change, HOOK_PRIO_DEFAULT);
-
-/**
- * Enable/disable NVDC charger to control AC to system and battery.
- */
-static void charger_disable(int disable)
-{
- int i, rv;
-
- for (i = 0; i < CHARGER_MODE_ATTEMPTS; i++) {
- rv = charger_discharge_on_ac(disable);
- if (rv == EC_SUCCESS)
- return;
- }
-
- CPRINTS("Setting learn mode %d failed!", disable);
-}
-
-static void allow_max_request(void)
-{
- int prochot_status;
- if (charge_circuit_state == CHARGE_CIRCUIT_WEDGED) {
- /* Read PROCHOT status register to clear it */
- i2c_read8(I2C_PORT_CHARGER, BQ24773_ADDR_FLAGS,
- BQ24773_PROCHOT_STATUS, &prochot_status);
- charge_circuit_state = CHARGE_CIRCUIT_OK;
- }
- host_command_pd_send_status(PD_CHARGE_MAX);
-}
-DECLARE_DEFERRED(allow_max_request);
-
-static void allow_min_charging(void)
-{
- if (!charge_is_disabled && charge_circuit_state == CHARGE_CIRCUIT_OK)
- host_command_pd_send_status(PD_CHARGE_5V);
-}
-DECLARE_DEFERRED(allow_min_charging);
-
-static void extpower_board_hacks(int extpower, int extpower_prev)
-{
- /* Cancel deferred attempt to enable max charge request */
- hook_call_deferred(&allow_max_request_data, -1);
-
- /*
- * When AC is detected, delay briefly before allowing PD
- * to negotiate up to the max voltage to give charge circuit
- * time to settle down. When AC goes away, disable charging
- * for a brief time, allowing charge state machine time to
- * see AC has gone away, and then set PD to only allow
- * 5V charging for the next time AC is connected.
- *
- * Use NVDC charger learn mode (charger_disable()) when AC
- * is not present to avoid backboosting when AC is plugged in.
- *
- * When in G3, PP5000 needs to be enabled to accurately sense
- * CC voltage when AC is attached. When AC is disconnceted
- * it needs to be off to save power.
- */
- if (extpower && !extpower_prev) {
- /* AC connected */
- charger_disable(0);
- hook_call_deferred(&allow_max_request_data, 500*MSEC);
- set_pp5000_in_g3(PP5000_IN_G3_AC, 1);
- } else if (extpower && extpower_prev) {
- /*
- * Glitch on AC_PRESENT, attempt to recover from
- * backboost
- */
- host_command_pd_send_status(PD_CHARGE_NONE);
- } else {
- /* AC disconnected */
- if (!charge_is_disabled &&
- charge_circuit_state == CHARGE_CIRCUIT_OK)
- host_command_pd_send_status(PD_CHARGE_NONE);
-
- charger_disable(1);
-
- hook_call_deferred(&allow_min_charging_data, 100*MSEC);
- set_pp5000_in_g3(PP5000_IN_G3_AC, 0);
- }
- extpower_prev = extpower;
-}
-
-/* Return boostin_voltage or negative if error */
-static int get_boostin_voltage(void)
-{
- /* Static structs to save stack space */
- static struct ec_response_usb_pd_power_info pd_power_ret;
- static struct ec_params_usb_pd_power_info pd_power_args;
- int ret;
- int err;
-
- /* Boost-in voltage is maximum of voltage now on each port */
- pd_power_args.port = 0;
- err = pd_host_command(EC_CMD_USB_PD_POWER_INFO, 0,
- &pd_power_args,
- sizeof(struct ec_params_usb_pd_power_info),
- &pd_power_ret,
- sizeof(struct ec_response_usb_pd_power_info));
- if (err < 0)
- return err;
- ret = pd_power_ret.meas.voltage_now;
-
- pd_power_args.port = 1;
- err = pd_host_command(EC_CMD_USB_PD_POWER_INFO, 0,
- &pd_power_args,
- sizeof(struct ec_params_usb_pd_power_info),
- &pd_power_ret,
- sizeof(struct ec_response_usb_pd_power_info));
- if (err < 0)
- return err;
-
- /* Get max of two measuremente */
- if (pd_power_ret.meas.voltage_now > ret)
- ret = pd_power_ret.meas.voltage_now;
-
- return ret;
-}
-
-/*
- * Send command to PD to write a custom persistent log entry indicating that
- * charging was wedged. Returns pd_host_command success status.
- */
-static int log_charge_wedged(void)
-{
- static struct ec_params_pd_write_log_entry log_args;
-
- log_args.type = PD_EVENT_MCU_BOARD_CUSTOM;
- log_args.port = 0;
-
- return pd_host_command(EC_CMD_PD_WRITE_LOG_ENTRY, 0,
- &log_args,
- sizeof(struct ec_params_pd_write_log_entry),
- NULL, 0);
-}
-
-/* Time interval between checking if charge circuit is wedged */
-#define CHARGE_WEDGE_CHECK_INTERVAL (2*SECOND)
-
-/*
- * Number of iterations through check_charge_wedged() with charging stalled
- * before attempting unwedge.
- */
-#define CHARGE_STALLED_COUNT 5
-/*
- * Number of iterations through check_charge_wedged() with charging stalled
- * after we already just tried unwedging the circuit, before we try again.
- */
-#define CHARGE_STALLED_REPEATEDLY_COUNT 60
-
-/*
- * Minimum number of iterations through check_charge_wedged() between
- * unwedge attempts.
- */
-#define MIN_COUNTS_BETWEEN_UNWEDGES 3
-
-static void check_charge_wedged(void)
-{
- int rv, prochot_status, batt_discharging_on_ac, boostin_voltage = 0;
- static int counts_since_wedged;
- static int charge_stalled_count = CHARGE_STALLED_COUNT;
- uint8_t *batt_flags = host_get_memmap(EC_MEMMAP_BATT_FLAG);
-
- if (charge_circuit_state == CHARGE_CIRCUIT_OK) {
- /* Check PROCHOT warning */
- rv = i2c_read8(I2C_PORT_CHARGER, BQ24773_ADDR_FLAGS,
- BQ24773_PROCHOT_STATUS, &prochot_status);
- if (rv)
- prochot_status = 0;
-
- batt_discharging_on_ac =
- (*batt_flags & EC_BATT_FLAG_AC_PRESENT) &&
- (*batt_flags & EC_BATT_FLAG_DISCHARGING);
-
- /*
- * If PROCHOT is set or we are discharging on AC, then we
- * need to know boostin_voltage.
- */
- if (prochot_status || batt_discharging_on_ac)
- boostin_voltage = get_boostin_voltage();
-
- /*
- * If AC is present, and battery is discharging, and
- * boostin voltage is above 5V, then we might be wedged.
- */
- if (batt_discharging_on_ac) {
- if (boostin_voltage > 6000)
- charge_stalled_count--;
- else if (boostin_voltage >= 0)
- charge_stalled_count = CHARGE_STALLED_COUNT;
- /* If boostin_voltage < 0, don't change stalled count */
- } else {
- charge_stalled_count = CHARGE_STALLED_COUNT;
- }
-
- /*
- * If we were recently wedged, then give ourselves a free pass
- * here. This gives an opportunity for reading the PROCHOT
- * status to clear it if the error has gone away.
- */
- if (counts_since_wedged < MIN_COUNTS_BETWEEN_UNWEDGES)
- counts_since_wedged++;
-
- /*
- * If PROCHOT is asserted AND boost_in voltage is above 5V,
- * then charge circuit is wedged. If charging has been stalled
- * long enough, then also consider the circuit wedged.
- *
- * To unwedge the charge circuit turn on learn mode and notify
- * PD to disable charging on all ports.
- * Note: learn mode is critical here because when in this state
- * backboosting causes >20V on boostin even after PD disables
- * CHARGE_EN lines.
- */
- if ((prochot_status && boostin_voltage > 6000 &&
- counts_since_wedged >= MIN_COUNTS_BETWEEN_UNWEDGES) ||
- charge_stalled_count <= 0) {
- counts_since_wedged = 0;
- host_command_pd_send_status(PD_CHARGE_NONE);
- charger_disable(1);
- charge_circuit_state = CHARGE_CIRCUIT_WEDGED;
- log_charge_wedged();
- CPRINTS("Charge wedged! PROCHOT %02x, Stalled: %d",
- prochot_status, charge_stalled_count);
-
- /*
- * If this doesn't clear the problem, then start
- * the stall counter higher so that we don't retry
- * unwedging for a while. Note, if we do start charging
- * properly, then stall counter will be set to
- * default, so that we will trigger faster the first
- * time it stalls out.
- */
- charge_stalled_count = CHARGE_STALLED_REPEATEDLY_COUNT;
- }
- } else {
- /*
- * Charge circuit is wedged and we already disabled charging,
- * Now start to recover from wedged state by allowing 5V.
- */
- host_command_pd_send_status(PD_CHARGE_5V);
- }
-}
-
-/**
- * Task to handle external power change
- */
-void extpower_task(void)
-{
- int extpower = extpower_is_present();
- int extpower_prev = 0;
-
- extpower_board_hacks(extpower, extpower_prev);
- extpower_prev = extpower;
- extpower_task_initialized = 1;
-
- /* Enable backboost detection interrupt */
- gpio_enable_interrupt(GPIO_BKBOOST_DET);
-
- while (1) {
- if (task_wait_event(CHARGE_WEDGE_CHECK_INTERVAL) ==
- TASK_EVENT_TIMER) {
- /*
- * If we are NOT purposely discharging on AC, then
- * periodically check if charge circuit is wedged.
- */
- if (!board_is_discharging_on_ac())
- check_charge_wedged();
- } else {
- /* Must have received power change interrupt */
- extpower = extpower_is_present();
-
- /* Various board hacks to run on extpower change */
- extpower_board_hacks(extpower, extpower_prev);
- extpower_prev = extpower;
-
- hook_notify(HOOK_AC_CHANGE);
-
- /* Forward notification to host */
- if (extpower)
- host_set_single_event(
- EC_HOST_EVENT_AC_CONNECTED);
- else
- host_set_single_event(
- EC_HOST_EVENT_AC_DISCONNECTED);
- }
- }
-}
-
-void bkboost_det_interrupt(enum gpio_signal signal)
-{
- /* Backboost has been detected, save it, and disable interrupt */
- bkboost_detected = 1;
- gpio_disable_interrupt(GPIO_BKBOOST_DET);
-}
-
-static int command_backboost_det(int argc, char **argv)
-{
- ccprintf("Backboost detected: %d\n", bkboost_detected);
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(bkboost, command_backboost_det, NULL,
- "Read backboost detection");