summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2022-03-09 18:16:08 +0000
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-06-15 23:29:29 +0000
commitce5856c7694b1984784f9e1cc0c7ce3d08cb0439 (patch)
tree471609774b55ebb389c6e26e29cbe25b17689e3c
parentdbd7e8249d3cf0a834629127ee378fdf4b700681 (diff)
downloadchrome-ec-ce5856c7694b1984784f9e1cc0c7ce3d08cb0439.tar.gz
Agah: Enable bypass mode
This patch enables bypass mode for ISL9241 on Agah. Tested cases: 1. Boot on BJ. 2. Unplug BJ. 3. Boot on Type-C. 4. Unplug Type-C. 5. Switch from Type-C to BJ. 6. Not switching from BJ to Type-C. BUG=b:214057333, b:216206104 BRANCH=None TEST=On Agah. See above. Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Change-Id: I8d015d401291391b8b8e7f25e9db8697d211cd4d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3583044 Reviewed-by: Kenny Pan <kennypan@google.com>
-rw-r--r--baseboard/brya/usb_pd_policy.c3
-rw-r--r--board/agah/board.c1
-rw-r--r--board/agah/board.h16
-rw-r--r--board/agah/charger_isl9241.c242
-rw-r--r--board/agah/ec.tasklist1
-rw-r--r--board/agah/gpio.inc4
6 files changed, 226 insertions, 41 deletions
diff --git a/baseboard/brya/usb_pd_policy.c b/baseboard/brya/usb_pd_policy.c
index 4d5ece38ca..e3e85539bf 100644
--- a/baseboard/brya/usb_pd_policy.c
+++ b/baseboard/brya/usb_pd_policy.c
@@ -75,6 +75,9 @@ int pd_set_power_supply_ready(int port)
int board_vbus_source_enabled(int port)
{
+ /* BJ port is always sink. */
+ if (port >= CONFIG_USB_PD_PORT_MAX_COUNT)
+ return 0;
return ppc_is_sourcing_vbus(port);
}
diff --git a/board/agah/board.c b/board/agah/board.c
index e3a9e1b93e..d1cc519402 100644
--- a/board/agah/board.c
+++ b/board/agah/board.c
@@ -52,6 +52,7 @@ DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, board_chipset_suspend, HOOK_PRIO_DEFAULT);
static void board_init(void)
{
gpio_enable_interrupt(GPIO_PG_PP3300_S5_OD);
+ gpio_enable_interrupt(GPIO_BJ_ADP_PRESENT_ODL);
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
diff --git a/board/agah/board.h b/board/agah/board.h
index 9b9998d6a8..ed8b43ffd9 100644
--- a/board/agah/board.h
+++ b/board/agah/board.h
@@ -138,10 +138,15 @@
/* Charger defines */
#define CONFIG_CHARGER_ISL9241
-#define CONFIG_CHARGE_RAMP_SW
#define CONFIG_CHARGER_SENSE_RESISTOR 10
#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10
+/* Barrel jack adapter settings */
+#undef CONFIG_DEDICATED_CHARGE_PORT_COUNT
+#define CONFIG_DEDICATED_CHARGE_PORT_COUNT 1
+/* This is the next available port # after USB-C ports. */
+#define DEDICATED_CHARGE_PORT 2
+
/*
* Older boards have a different ADC assignment.
*/
@@ -197,6 +202,12 @@ enum mft_channel {
MFT_CH_COUNT
};
+enum charge_port {
+ CHARGE_PORT_TYPEC0,
+ CHARGE_PORT_TYPEC1,
+ CHARGE_PORT_BARRELJACK,
+};
+
/**
* Interrupt handler for PG_PP3300_S5_OD changes.
*
@@ -204,6 +215,9 @@ enum mft_channel {
*/
void board_power_interrupt(enum gpio_signal signal);
+/* IRQ for BJ plug/unplug. */
+void bj_present_interrupt(enum gpio_signal signal);
+
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */
diff --git a/board/agah/charger_isl9241.c b/board/agah/charger_isl9241.c
index 85e0de90fe..2276a72e29 100644
--- a/board/agah/charger_isl9241.c
+++ b/board/agah/charger_isl9241.c
@@ -6,18 +6,21 @@
#include "common.h"
#include "charge_manager.h"
+#include "charge_state.h"
#include "charge_state_v2.h"
#include "charger.h"
#include "compile_time_macros.h"
#include "console.h"
#include "driver/charger/isl9241.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "stdbool.h"
#include "usbc_ppc.h"
#include "usb_pd.h"
#include "util.h"
-
-#define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ## args)
-#define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
/* Charger Chip Configuration */
const struct charger_config_t chg_chips[] = {
@@ -29,62 +32,227 @@ const struct charger_config_t chg_chips[] = {
};
BUILD_ASSERT(ARRAY_SIZE(chg_chips) == CHARGER_NUM);
+static int board_disable_bj_port(void)
+{
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP, 0);
+ /* If the current port is BJ, disable bypass mode. */
+ if (charge_manager_get_supplier() == CHARGE_SUPPLIER_DEDICATED)
+ return charger_enable_bypass_mode(0, 0);
+
+ CPRINTS("BJ power is disabled");
+
+ return EC_SUCCESS;
+}
+
+static int board_enable_bj_port(void)
+{
+ if (gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL))
+ return EC_ERROR_INVAL;
+ gpio_set_level(GPIO_EN_PPVAR_BJ_ADP, 1);
+
+ CPRINTS("BJ power is enabled");
+
+ return charger_enable_bypass_mode(0, 1);
+}
+
+/*
+ * TODO:
+ *
+ * When AC is being plugged in (including switching source port),
+ * 1. Deassert NVIDIA_GPU_ACOFF_ODL.
+ * 2. Call evaluate_d_notify.
+ *
+ * When AC is being lost,
+ * 1. Assert NVIDIA_GPU_ACOFF_ODL.
+ * 2. Set D-Notify to D5.
+ * 3. Differ-call
+ * a. Deassert NVIDIA_GPU_ACOFF_ODL.
+ * b. evaluate_d_notify
+ */
+static int board_throttle_ap_gpu(bool enable)
+{
+ int rv = EC_SUCCESS;
+
+ if (!chipset_in_state(CHIPSET_STATE_ON))
+ return EC_SUCCESS;
+
+ CPRINTS("TODO: %s to %s AP & GPU (%d)", rv ? "Failed" : "Succeeded",
+ enable ? "throttle" : "unthrottle", rv);
+
+ return rv;
+}
+
+/* Disable all VBUS sink ports except <port>. <port> = -1 disables all ports. */
+static int board_disable_vbus_sink(int port)
+{
+ int i, r, rv = EC_SUCCESS;
+
+ for (i = 0; i < ppc_cnt; i++) {
+ if (i == port)
+ continue;
+ /*
+ * Do not return early if one fails otherwise we can get into a
+ * boot loop assertion failure.
+ */
+ r = ppc_vbus_sink_enable(i, 0);
+ CPRINTS("%s to disable sink path C%d (%d).",
+ r ? "Failed" : "Succeeded", i, r);
+ rv |= r;
+ }
+
+ return rv;
+}
+
+/* Minimum battery SoC required for switching source port. */
+#define MIN_BATT_FOR_SWITCHING_SOURCE_PORT 1
+
+/*
+ * It should also work on POR with/without a battery:
+ *
+ * 1. EC gathers power info of all ports.
+ * 2. Identify the highest power port.
+ * 3. If
+ * 1. battery soc = 0% --> Exit
+ * 2. BJ_ADP_PRESENT_ODL = 1 --> Exit
+ * 3. highest power port == active port --> Exit
+ * 4. If
+ * 1. in S0, throttle AP & GPU to the DC rating.
+ * 5. Turn off the current active port.
+ * 6. Turn on the highest power port.
+ * 7. If
+ * 1. in S0, throttle AP & GPU back.
+ *
+ * TODO: Are the following cases covered?
+ * 1. Two AC adapters are plugged. Then, the active adapter is removed.
+ *
+ * TODO: Recover from incomplete execution:
+ * 1. Failed to turn on/off PPC.
+ */
int board_set_active_charge_port(int port)
{
- int is_valid_port = board_is_usb_pd_port_present(port);
- int i;
+ enum charge_supplier supplier = charge_manager_get_supplier();
+ int active_port = charge_manager_get_active_charge_port();
+
+ CPRINTS("Changing charge port to %d (current port=%d supplier=%d)",
+ port, active_port, supplier);
if (port == CHARGE_PORT_NONE) {
- CPRINTSUSB("Disabling all charger ports");
-
- /* Disable all ports. */
- for (i = 0; i < ppc_cnt; i++) {
- /*
- * Do not return early if one fails otherwise we can
- * get into a boot loop assertion failure.
- */
- if (ppc_vbus_sink_enable(i, 0))
- CPRINTSUSB("Disabling C%d as sink failed.", i);
- }
+ CPRINTS("Disabling all charger ports");
+
+ board_throttle_ap_gpu(1);
+
+ board_disable_bj_port();
+ board_disable_vbus_sink(-1);
return EC_SUCCESS;
- } else if (!is_valid_port) {
- return EC_ERROR_INVAL;
}
- /* Check if the port is sourcing VBUS. */
- if (ppc_is_sourcing_vbus(port)) {
- CPRINTFUSB("Skip enable C%d", port);
+ if (port < 0 || CHARGE_PORT_COUNT <= port) {
+ return EC_ERROR_INVAL;
+ } else if (port == active_port) {
+ return EC_SUCCESS;
+ } else if (board_vbus_source_enabled(port)) {
+ /* Don't charge from a USBC source port */
+ CPRINTS("Don't enable C%d. It's sourcing.", port);
return EC_ERROR_INVAL;
}
- CPRINTSUSB("New charge port: C%d", port);
-
/*
- * Turn off the other ports' sink path FETs, before enabling the
- * requested charge port.
+ * We need to check the battery if we're switching a source port. If
+ * we're just starting up or no AC was previously plugged, we shouldn't
+ * check the battery. Both cases can be caught by supplier == NONE.
*/
- for (i = 0; i < ppc_cnt; i++) {
- if (i == port)
- continue;
-
- if (ppc_vbus_sink_enable(i, 0))
- CPRINTSUSB("C%d: sink path disable failed.", i);
+ if (supplier != CHARGE_SUPPLIER_NONE) {
+ if (charge_get_percent() < MIN_BATT_FOR_SWITCHING_SOURCE_PORT)
+ return EC_ERROR_NOT_POWERED;
}
- /* Enable requested charge port. */
- if (ppc_vbus_sink_enable(port, 1)) {
- CPRINTSUSB("C%d: sink path enable failed.", port);
- return EC_ERROR_UNKNOWN;
+ /* Turn off other ports' sink paths before enabling requested port. */
+ if (port == CHARGE_PORT_TYPEC0 || port == CHARGE_PORT_TYPEC1) {
+ /*
+ * BJ port is on POR. So, we need to turn it off even if we're
+ * not previously on BJ.
+ */
+ board_disable_bj_port();
+ if (board_disable_vbus_sink(port))
+ return EC_ERROR_UNCHANGED;
+
+ /* Enable requested USBC charge port. */
+ if (ppc_vbus_sink_enable(port, 1)) {
+ CPRINTS("Failed to enable sink path for C%d", port);
+ return EC_ERROR_UNKNOWN;
+ }
+ } else if (port == CHARGE_PORT_BARRELJACK) {
+ /*
+ * We can't proceed unless both ports are successfully
+ * disconnected as sources.
+ */
+ if (board_disable_vbus_sink(-1))
+ return EC_ERROR_UNKNOWN;
+ board_enable_bj_port();
}
+ /* Switching port is complete. Turn off throttling. */
+ if (supplier != CHARGE_SUPPLIER_NONE)
+ board_throttle_ap_gpu(0);
+
+ CPRINTS("New charger p%d", port);
+
return EC_SUCCESS;
}
-__overridable void board_set_charge_limit(int port, int supplier, int charge_ma,
- int max_ma, int charge_mv)
+void board_set_charge_limit(int port, int supplier, int charge_ma,
+ int max_ma, int charge_mv)
{
charge_set_input_current_limit(MAX(charge_ma,
CONFIG_CHARGER_INPUT_CURRENT),
charge_mv);
}
+
+static const struct charge_port_info bj_power = {
+ /* 150W (also default) */
+ .voltage = 19500,
+ .current = 7700,
+};
+
+/* Debounce time for BJ plug/unplug */
+#define BJ_DEBOUNCE_MS 1000
+
+static void bj_connect_deferred(void)
+{
+ static int8_t bj_connected = -1;
+ const struct charge_port_info *pi = NULL;
+ int connected = !gpio_get_level(GPIO_BJ_ADP_PRESENT_ODL);
+
+ if (connected == bj_connected)
+ return;
+
+ if (connected)
+ pi = &bj_power;
+
+ charge_manager_update_charge(CHARGE_SUPPLIER_DEDICATED,
+ DEDICATED_CHARGE_PORT, pi);
+ bj_connected = connected;
+ CPRINTS("BJ %s", connected ? "connected" : "disconnected");
+}
+DECLARE_DEFERRED(bj_connect_deferred);
+
+void bj_present_interrupt(enum gpio_signal signal)
+{
+ hook_call_deferred(&bj_connect_deferred_data, BJ_DEBOUNCE_MS * MSEC);
+}
+
+static void bj_state_init(void)
+{
+ /*
+ * Initialize all charge suppliers to 0. The charge manager waits until
+ * all ports have reported in before doing anything.
+ */
+ for (int i = 0; i < CHARGE_PORT_COUNT; i++) {
+ for (int j = 0; j < CHARGE_SUPPLIER_COUNT; j++)
+ charge_manager_update_charge(j, i, NULL);
+ }
+
+ bj_connect_deferred();
+}
+DECLARE_HOOK(HOOK_INIT, bj_state_init, HOOK_PRIO_INIT_CHARGE_MANAGER + 1);
diff --git a/board/agah/ec.tasklist b/board/agah/ec.tasklist
index ea1f6e7e09..7286caf6c6 100644
--- a/board/agah/ec.tasklist
+++ b/board/agah/ec.tasklist
@@ -12,7 +12,6 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, HOOKS_TASK_STACK_SIZE) \
- TASK_ALWAYS(CHG_RAMP, chg_ramp_task, NULL, BASEBOARD_CHG_RAMP_TASK_STACK_SIZE) \
TASK_ALWAYS(USB_CHG_P0, usb_charger_task, 0, TASK_STACK_SIZE) \
TASK_ALWAYS(USB_CHG_P1, usb_charger_task, 0, TASK_STACK_SIZE) \
TASK_ALWAYS(CHARGER, charger_task, NULL, BASEBOARD_CHARGER_TASK_STACK_SIZE) \
diff --git a/board/agah/gpio.inc b/board/agah/gpio.inc
index a1573f6290..3c4f2a2bef 100644
--- a/board/agah/gpio.inc
+++ b/board/agah/gpio.inc
@@ -26,6 +26,7 @@ GPIO_INT(PG_PP3300_S5_OD, PIN(B, 4), GPIO_INT_BOTH | GPIO_PULL_UP
GPIO_INT(USB_C2_BC12_INT_ODL, PIN(8, 3), GPIO_INT_FALLING, bc12_interrupt)
GPIO_INT(USB_C2_TCPC_INT_ODL, PIN(A, 7), GPIO_INT_FALLING, tcpc_alert_event)
GPIO_INT(USB_C2_PPC_INT_ODL, PIN(7, 0), GPIO_INT_FALLING, ppc_interrupt)
+GPIO_INT(BJ_ADP_PRESENT_ODL, PIN(5, 6), GPIO_INT_BOTH | GPIO_PULL_UP, bj_present_interrupt)
/* USED GPIOs: */
GPIO(CCD_MODE_ODL, PIN(E, 5), GPIO_INPUT)
@@ -69,7 +70,6 @@ GPIO(USB_C2_FRS_EN, PIN(D, 4), GPIO_OUT_LOW)
/* Barreljack */
GPIO(EN_PPVAR_BJ_ADP, PIN(A, 2), GPIO_OUT_LOW)
-GPIO(BJ_ADP_PRESENT_L, PIN(5, 6), GPIO_INPUT)
/*
* The NPCX keyboard driver does not use named GPIOs to access
@@ -128,4 +128,4 @@ UNUSED(PIN(7, 3)) /* GPIO73 */
UNUSED(PIN(4, 1)) /* GPIO41 */
UNUSED(PIN(5, 0)) /* GPIO50 */
UNUSED(PIN(6, 0)) /* GPIO60 */
-UNUSED(PIN(C, 2)) /* GPIOC2 */ \ No newline at end of file
+UNUSED(PIN(C, 2)) /* GPIOC2 */