diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-05-28 18:10:25 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-06-09 22:20:48 +0000 |
commit | 72357cd1edf885e559dbb715b33cfb861a0a3265 (patch) | |
tree | 48e3181ecd32c2124d80b50b39a965c2f6ac1893 | |
parent | f7ae0fb81b4b43c939ec1be674e940377b8c8d64 (diff) | |
download | chrome-ec-72357cd1edf885e559dbb715b33cfb861a0a3265.tar.gz |
samus: Allow samus to charge w/o battery or with dead batterystabilize-5942.B
Use a EC to PD host command to notify the PD MCU when a battery
is present and charged enough that it is ok to negotiate for a
higher power. The PD MCU will not negotiate until the host command
is received, which allows the system to be powered without a
battery or with a dead battery with 5V.
BUG=chrome-os-partner:28611
BRANCH=none
TEST=Tested on a samus:
1) Tested the normal case of battery charged and plugged in. When
charger is plugged in, the device immediately starts negotiating
for 20V and starts charging.
2) Tested with no battery. Plug in a charger, samus boots and stays
alive. VBUS measured at 5V. When a battery is plugged in, device
negotiates for 20V and starts charging.
3) Tested dead battery by taking a battery with no charge, and
plugging in zinger. Everything boots, but PD does not negotiate
for power. Then when battery reaches 1%, PD negotiates and zinger
switches to 20V without causing a reboot.
Change-Id: Iaa451403674e86cddbd3fe80e9503584910be576
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/201958
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | board/firefly/usb_pd_policy.c | 5 | ||||
-rw-r--r-- | board/fruitpie/usb_pd_policy.c | 5 | ||||
-rw-r--r-- | board/samus/board.c | 14 | ||||
-rw-r--r-- | board/samus/board.h | 1 | ||||
-rw-r--r-- | board/samus/ec.tasklist | 1 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 73 | ||||
-rw-r--r-- | board/zinger/usb_pd_policy.c | 5 | ||||
-rw-r--r-- | common/build.mk | 2 | ||||
-rw-r--r-- | common/charge_state_v2.c | 2 | ||||
-rw-r--r-- | common/host_command_pd.c | 52 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 10 | ||||
-rw-r--r-- | include/charge_state.h | 2 | ||||
-rw-r--r-- | include/config.h | 14 | ||||
-rw-r--r-- | include/ec_commands.h | 19 | ||||
-rw-r--r-- | include/host_command.h | 6 | ||||
-rw-r--r-- | include/usb_pd.h | 7 |
16 files changed, 209 insertions, 9 deletions
diff --git a/board/firefly/usb_pd_policy.c b/board/firefly/usb_pd_policy.c index 0a57d34192..a526702b13 100644 --- a/board/firefly/usb_pd_policy.c +++ b/board/firefly/usb_pd_policy.c @@ -125,3 +125,8 @@ int pd_board_checks(void) return EC_SUCCESS; } + +int pd_power_negotiation_allowed(void) +{ + return 1; +} diff --git a/board/fruitpie/usb_pd_policy.c b/board/fruitpie/usb_pd_policy.c index 9464b242be..6ebc04385b 100644 --- a/board/fruitpie/usb_pd_policy.c +++ b/board/fruitpie/usb_pd_policy.c @@ -123,3 +123,8 @@ int pd_board_checks(void) { return EC_SUCCESS; } + +int pd_power_negotiation_allowed(void) +{ + return 1; +} diff --git a/board/samus/board.c b/board/samus/board.c index 000c1f0db7..d5a9bead21 100644 --- a/board/samus/board.c +++ b/board/samus/board.c @@ -18,6 +18,7 @@ #include "extpower.h" #include "fan.h" #include "gpio.h" +#include "hooks.h" #include "host_command.h" #include "i2c.h" #include "jtag.h" @@ -39,7 +40,8 @@ static void pd_mcu_interrupt(enum gpio_signal signal) { - ccprintf("PD interrupt!\n"); + /* Exchange status with PD MCU. */ + host_command_pd_send_status(); } /* GPIO signal list. Must match order from enum gpio_signal. */ @@ -90,7 +92,8 @@ const struct gpio_info gpio_list[] = { {"CAPSENSE_INT_L", LM4_GPIO_N, (1<<0), GPIO_INPUT, NULL}, #endif {"PD_MCU_INT_L", LM4_GPIO_J, (1<<5), GPIO_PULL_UP| - GPIO_INT_FALLING, + GPIO_INT_FALLING| + GPIO_INT_DSLEEP, pd_mcu_interrupt}, /* Other inputs */ @@ -338,6 +341,13 @@ struct keyboard_scan_config keyscan_config = { }, }; +/* Initialize board. */ +static void board_init(void) +{ + gpio_enable_interrupt(GPIO_PD_MCU_INT_L); +} +DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); + #ifdef CONFIG_BATTERY_PRESENT_CUSTOM /** * Physical check of battery presence. diff --git a/board/samus/board.h b/board/samus/board.h index b914964e78..48b1a94be1 100644 --- a/board/samus/board.h +++ b/board/samus/board.h @@ -44,7 +44,6 @@ #define CONFIG_CHARGER_INPUT_CURRENT 2000 #define CONFIG_CHARGER_DISCHARGE_ON_AC #define CONFIG_FANS 2 -#define CONFIG_HOST_CMD_MASTER #define CONFIG_PECI_TJMAX 100 #define CONFIG_PWM #define CONFIG_PWM_KBLIGHT diff --git a/board/samus/ec.tasklist b/board/samus/ec.tasklist index 2b8da9c77b..ab25faa872 100644 --- a/board/samus/ec.tasklist +++ b/board/samus/ec.tasklist @@ -23,6 +23,7 @@ TASK_ALWAYS(CHARGER, charger_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \ + TASK_NOTEST(PDCMD, pd_command_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ TASK_ALWAYS(POWERBTN, power_button_task, NULL, TASK_STACK_SIZE) \ diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index ea5f2d1703..2e2a42d182 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -8,6 +8,7 @@ #include "console.h" #include "gpio.h" #include "hooks.h" +#include "host_command.h" #include "registers.h" #include "task.h" #include "timer.h" @@ -33,6 +34,9 @@ const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo); /* Cap on the max voltage requested as a sink (in millivolts) */ static unsigned max_mv = -1; /* no cap */ +/* Flag for battery status */ +static int battery_ok; + int pd_choose_voltage(int cnt, uint32_t *src_caps, uint32_t *rdo) { int i; @@ -40,6 +44,10 @@ int pd_choose_voltage(int cnt, uint32_t *src_caps, uint32_t *rdo) int max_uw = 0; int max_i = -1; + /* Don't negotiate power until battery ok signal is given */ + if (!battery_ok) + return -EC_ERROR_UNKNOWN; + /* Get max power */ for (i = 0; i < cnt; i++) { int uw; @@ -119,7 +127,72 @@ void pd_power_supply_reset(void) gpio_set_level(GPIO_USB_C0_5V_EN, 0); } +static void pd_send_ec_int(void) +{ + gpio_set_level(GPIO_EC_INT_L, 0); + + /* + * Delay long enough to guarantee EC see's the change. Slowest + * EC clock speed is 250kHz in deep sleep -> 4us, and add 1us + * for buffer. + */ + usleep(5); + + gpio_set_level(GPIO_EC_INT_L, 1); +} + int pd_board_checks(void) { + static uint64_t last_time; + + /* + * If battery is not yet ok, signal EC to send status. Avoid + * sending requests too frequently. + */ + if (!battery_ok && (get_time().val - last_time >= SECOND)) { + last_time = get_time().val; + pd_send_ec_int(); + } + return EC_SUCCESS; } + +int pd_power_negotiation_allowed(void) +{ + return battery_ok; +} + +static int command_ec_int(int argc, char **argv) +{ + pd_send_ec_int(); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(ecint, command_ec_int, + "", + "Toggle EC interrupt line", + NULL); + +static int ec_status_host_cmd(struct host_cmd_handler_args *args) +{ + const struct ec_params_pd_status *p = args->params; + struct ec_response_pd_status *r = args->response; + + if (p->batt_soc >= CONFIG_USB_PD_MIN_BATT_CHARGE) { + /* + * When battery is above minimum charge, we know + * that we have enough power remaining for us to + * negotiate power over PD. + */ + CPRINTS("Battery is ok, safe to negotiate power"); + battery_ok = 1; + } else { + battery_ok = 0; + } + + args->response_size = sizeof(*r); + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd, + EC_VER_MASK(0)); diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c index 1b52d0876c..04b04fca6b 100644 --- a/board/zinger/usb_pd_policy.c +++ b/board/zinger/usb_pd_policy.c @@ -233,6 +233,11 @@ int pd_board_checks(void) } +int pd_power_negotiation_allowed(void) +{ + return 1; +} + void IRQ_HANDLER(STM32_IRQ_ADC_COMP)(void) { /* cut the power output */ diff --git a/common/build.mk b/common/build.mk index 18c1c47579..09bbfe2564 100644 --- a/common/build.mk +++ b/common/build.mk @@ -43,7 +43,6 @@ common-$(CONFIG_EXTPOWER_SPRING)+=extpower_spring.o common-$(CONFIG_FANS)+=fan.o common-$(CONFIG_FLASH)+=flash.o common-$(CONFIG_FMAP)+=fmap.o -common-$(CONFIG_HOST_CMD_MASTER)+=host_command_master.o common-$(CONFIG_I2C)+=i2c.o common-$(CONFIG_I2C_ARBITRATION)+=i2c_arbitration.o common-$(CONFIG_KEYBOARD_PROTOCOL_8042)+=keyboard_8042.o @@ -72,6 +71,7 @@ common-$(HAS_TASK_CHIPSET)+=chipset.o throttle_ap.o common-$(HAS_TASK_CONSOLE)+=console.o console_output.o uart_buffering.o common-$(HAS_TASK_CONSOLE)+=memory_commands.o common-$(HAS_TASK_HOSTCMD)+=acpi.o host_command.o host_event_commands.o +common-$(HAS_TASK_PDCMD)+=host_command_master.o host_command_pd.o common-$(HAS_TASK_KEYSCAN)+=keyboard_scan.o common-$(HAS_TASK_LIGHTBAR)+=lb_common.o lightbar.o common-$(HAS_TASK_MOTIONSENSE)+=motion_sense.o math_util.o diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 87ad28561b..6a6a93765d 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -744,6 +744,8 @@ uint32_t charge_get_flags(void) flags |= CHARGE_FLAG_FORCE_IDLE; if (curr.ac) flags |= CHARGE_FLAG_EXTERNAL_POWER; + if (curr.batt.flags & BATT_FLAG_RESPONSIVE) + flags |= CHARGE_FLAG_BATT_RESPONSIVE; return flags; } diff --git a/common/host_command_pd.c b/common/host_command_pd.c new file mode 100644 index 0000000000..5d9a3adf6d --- /dev/null +++ b/common/host_command_pd.c @@ -0,0 +1,52 @@ +/* Copyright (c) 2014 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. + */ + +/* Host command module for PD MCU */ + +#include "charge_state.h" +#include "common.h" +#include "host_command.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +#define TASK_EVENT_EXCHANGE_PD_STATUS TASK_EVENT_CUSTOM(1) + +void host_command_pd_send_status(void) +{ + task_set_event(TASK_ID_PDCMD, TASK_EVENT_EXCHANGE_PD_STATUS, 0); +} + +static void pd_exchange_status(void) +{ + struct ec_params_pd_status ec_status; + + /* + * TODO(crosbug.com/p/29499): Change sending state of charge to + * remaining capacity for finer grained control. + */ + /* Send battery state of charge */ + if (charge_get_flags() & CHARGE_FLAG_BATT_RESPONSIVE) + ec_status.batt_soc = charge_get_percent(); + else + ec_status.batt_soc = -1; + + pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, &ec_status, + sizeof(struct ec_params_pd_status), NULL, 0); +} + +void pd_command_task(void) +{ + + while (1) { + /* Wait for the next command event */ + int evt = task_wait_event(-1); + + /* Process event to send status to PD */ + if (evt & TASK_EVENT_EXCHANGE_PD_STATUS) + pd_exchange_status(); + } +} + diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 214d5f15a0..34a6183cd2 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -495,6 +495,10 @@ static void handle_data_request(void *ctxt, uint16_t head, uint32_t *payload) */ pd_task_state = PD_STATE_SNK_REQUESTED; } + /* + * TODO(crosbug.com/p/28332): if pd_choose_voltage + * returns an error, ignore failure for now. + */ } break; #endif /* CONFIG_USB_PD_DUAL_ROLE */ @@ -886,6 +890,12 @@ void pd_task(void) break; } + /* Don't continue if power negotiation is not allowed */ + if (!pd_power_negotiation_allowed()) { + timeout = PD_T_GET_SOURCE_CAP; + break; + } + res = send_control(ctxt, PD_CTRL_GET_SOURCE_CAP); /* packet was acked => PD capable device) */ if (res >= 0) { diff --git a/include/charge_state.h b/include/charge_state.h index 0da544422f..c23e70c260 100644 --- a/include/charge_state.h +++ b/include/charge_state.h @@ -50,6 +50,8 @@ enum charge_state { #define CHARGE_FLAG_FORCE_IDLE (1 << 0) /* External (AC) power is present */ #define CHARGE_FLAG_EXTERNAL_POWER (1 << 1) +/* Battery is responsive */ +#define CHARGE_FLAG_BATT_RESPONSIVE (1 << 2) /* Debugging constants, in the same order as enum charge_state. This string * table was moved here to sync with enum above. diff --git a/include/config.h b/include/config.h index 464ad50953..43f7cfdbca 100644 --- a/include/config.h +++ b/include/config.h @@ -503,9 +503,6 @@ /*****************************************************************************/ -/* Support EC acting as host master for other MCUs. */ -#undef CONFIG_HOST_CMD_MASTER - /* * Support the host asking the EC about the status of the most recent host * command. @@ -866,12 +863,19 @@ #undef CONFIG_UART_TX_DMA /*****************************************************************************/ +/* USB PD config */ + +/* USB PD MCU slave address for host commands */ +#define CONFIG_USB_PD_I2C_SLAVE_ADDR 0x3c + +/* TODO(crosbug.com/p/29499): Determine threshold for power negotiation */ +/* USB PD minimum battery charge to negotiate for more power */ +#define CONFIG_USB_PD_MIN_BATT_CHARGE 1 /* USB PD transmit uses SPI master */ #undef CONFIG_USB_PD_TX_USES_SPI_MASTER -/* USB PD MCU slave address for host commands */ -#define CONFIG_USB_PD_I2C_SLAVE_ADDR 0x3c +/*****************************************************************************/ /* Support simple control of power to the device's USB ports */ #undef CONFIG_USB_PORT_POWER_DUMB diff --git a/include/ec_commands.h b/include/ec_commands.h index 1526084986..5edd754df3 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -2478,6 +2478,25 @@ struct ec_params_reboot_ec { /*****************************************************************************/ /* + * PD commands + * + * These commands are for PD MCU communication. + */ + +/* EC to PD MCU exchange status command */ +#define EC_CMD_PD_EXCHANGE_STATUS 0x100 + +/* Status of EC being sent to PD */ +struct ec_params_pd_status { + int8_t batt_soc; /* battery state of charge */ +} __packed; + +/* Status of PD being sent back to EC */ +struct ec_response_pd_status { +} __packed; + +/*****************************************************************************/ +/* * Deprecated constants. These constants have been renamed for clarity. The * meaning and size has not changed. Programs that use the old names should * switch to the new names soon, as the old names may not be carried forward diff --git a/include/host_command.h b/include/host_command.h index 1fbf0b6554..231ef9a6b8 100644 --- a/include/host_command.h +++ b/include/host_command.h @@ -207,6 +207,12 @@ void host_packet_receive(struct host_packet *pkt); */ void host_throttle_cpu(int throttle); + +/** + * Signal host command task to send status to PD MCU. + */ +void host_command_pd_send_status(void); + /** * Send host command to PD MCU. * diff --git a/include/usb_pd.h b/include/usb_pd.h index 89229079a4..e8f9168aa7 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -185,6 +185,13 @@ void pd_request_source_voltage(int mv); */ int pd_board_checks(void); +/** + * Query if power negotiation is allowed. + * + * @return true if negotation is allowed, false otherwise. + */ +int pd_power_negotiation_allowed(void); + /* * Handle Vendor Defined Message with our vendor ID. * |