diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/charge_manager.c | 13 | ||||
-rw-r--r-- | common/charge_ramp.c | 4 | ||||
-rw-r--r-- | common/usb_charger.c | 138 | ||||
-rw-r--r-- | common/usb_pd_policy.c | 6 |
5 files changed, 158 insertions, 4 deletions
diff --git a/common/build.mk b/common/build.mk index be87443078..3941a40c5f 100644 --- a/common/build.mk +++ b/common/build.mk @@ -76,6 +76,7 @@ common-$(CONFIG_STREAM)+=in_stream.o out_stream.o stream_adaptor.o common-$(CONFIG_SWITCH)+=switch.o common-$(CONFIG_SW_CRC)+=crc.o common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o thermal.o throttle_ap.o +common-$(CONFIG_USB_CHARGER)+=usb_charger.o common-$(CONFIG_USB_PORT_POWER_DUMB)+=usb_port_power_dumb.o common-$(CONFIG_USB_PORT_POWER_SMART)+=usb_port_power_smart.o common-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_protocol.o usb_pd_policy.o diff --git a/common/charge_manager.c b/common/charge_manager.c index b52f297c45..24fbae2d38 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -23,6 +23,19 @@ #define POWER_SWAP_TIMEOUT (PD_T_SRC_RECOVER_MAX + PD_T_SRC_TURN_ON + \ PD_T_SAFE_0V + 500 * MSEC) +/* Charge supplier priority: lower number indicates higher priority. */ +test_mockable const int supplier_priority[] = { + [CHARGE_SUPPLIER_PD] = 0, + [CHARGE_SUPPLIER_TYPEC] = 1, + [CHARGE_SUPPLIER_PROPRIETARY] = 1, + [CHARGE_SUPPLIER_BC12_DCP] = 1, + [CHARGE_SUPPLIER_BC12_CDP] = 2, + [CHARGE_SUPPLIER_BC12_SDP] = 3, + [CHARGE_SUPPLIER_OTHER] = 3, + [CHARGE_SUPPLIER_VBUS] = 4 +}; +BUILD_ASSERT(ARRAY_SIZE(supplier_priority) == CHARGE_SUPPLIER_COUNT); + /* Keep track of available charge for each charge port. */ static struct charge_port_info available_charge[CHARGE_SUPPLIER_COUNT] [CONFIG_USB_PD_PORT_COUNT]; diff --git a/common/charge_ramp.c b/common/charge_ramp.c index cc71f987b6..e5f6d99e26 100644 --- a/common/charge_ramp.c +++ b/common/charge_ramp.c @@ -197,10 +197,8 @@ void chg_ramp_task(void) /* Detect delay is over, fall through to next state */ ramp_st_new = CHG_RAMP_OVERCURRENT_DETECT; -#ifdef CONFIG_USB_PD_HOST_EVENT_ON_POWER_CHANGE /* notify host of power info change */ pd_send_host_event(PD_EVENT_POWER_CHANGE); -#endif case CHG_RAMP_OVERCURRENT_DETECT: /* Check if we should ramp or go straight to stable */ task_wait_time = SECOND; @@ -297,10 +295,8 @@ void chg_ramp_task(void) #ifdef CONFIG_USB_PD_LOGGING charge_manager_save_log(active_port); #endif -#ifdef CONFIG_USB_PD_HOST_EVENT_ON_POWER_CHANGE /* notify host of power info change */ pd_send_host_event(PD_EVENT_POWER_CHANGE); -#endif } /* Keep an eye on VBUS and restart ramping if it dips */ diff --git a/common/usb_charger.c b/common/usb_charger.c new file mode 100644 index 0000000000..bb85fc3c7f --- /dev/null +++ b/common/usb_charger.c @@ -0,0 +1,138 @@ +/* Copyright 2015 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. + */ + +/* + * USB charger / BC1.2 task. This code assumes that CONFIG_CHARGE_MANAGER + * is defined and implemented. PI3USB9281 is the only charger detector + * currently supported. + */ + +#include "charge_manager.h" +#include "common.h" +#include "ec_commands.h" +#include "gpio.h" +#include "pi3usb9281.h" +#include "task.h" +#include "timer.h" +#include "usb_pd.h" + +/* Wait after a charger is detected to debounce pin contact order */ +#define USB_CHG_DEBOUNCE_DELAY_MS 1000 +/* + * Wait after reset, before re-enabling attach interrupt, so that the + * spurious attach interrupt from certain ports is ignored. + */ +#define USB_CHG_RESET_DELAY_MS 100 + +void usb_charger_task(void) +{ + int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1); +#if (CONFIG_USB_PD_PORT_COUNT == 1) + int vbus_source = GPIO_USB_C0_5V_EN; +#else + int vbus_source = (port == 0 ? GPIO_USB_C0_5V_EN : GPIO_USB_C1_5V_EN); +#endif + int device_type, charger_status; + struct charge_port_info charge; + int type; + charge.voltage = USB_BC12_CHARGE_VOLTAGE; + + while (1) { + /* Read interrupt register to clear on chip */ + pi3usb9281_get_interrupts(port); + + if (gpio_get_level(vbus_source)) { + /* If we're sourcing VBUS then we're not charging */ + device_type = charger_status = 0; + } else { + /* Set device type */ + device_type = pi3usb9281_get_device_type(port); + charger_status = pi3usb9281_get_charger_status(port); + } + + /* Debounce pin plug order if we detect a charger */ + if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) { + msleep(USB_CHG_DEBOUNCE_DELAY_MS); + + /* + * Trigger chip reset to refresh detection registers. + * WARNING: This reset is acceptable for samus_pd, + * but may not be acceptable for devices that have + * an OTG / device mode, as we may be interrupting + * the connection. + */ + pi3usb9281_reset(port); + /* + * Restore data switch settings - switches return to + * closed on reset until restored. + */ + board_set_usb_switches(port, USB_SWITCH_RESTORE); + /* Clear possible disconnect interrupt */ + pi3usb9281_get_interrupts(port); + /* Mask attach interrupt */ + pi3usb9281_set_interrupt_mask(port, + 0xff & + ~PI3USB9281_INT_ATTACH); + /* Re-enable interrupts */ + pi3usb9281_enable_interrupts(port); + msleep(USB_CHG_RESET_DELAY_MS); + + /* Clear possible attach interrupt */ + pi3usb9281_get_interrupts(port); + /* Re-enable attach interrupt */ + pi3usb9281_set_interrupt_mask(port, 0xff); + + /* Re-read ID registers */ + device_type = pi3usb9281_get_device_type(port); + charger_status = pi3usb9281_get_charger_status(port); + } + + /* Attachment: decode + update available charge */ + if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) { + if (PI3USB9281_CHG_STATUS_ANY(charger_status)) + type = CHARGE_SUPPLIER_PROPRIETARY; + else if (device_type & PI3USB9281_TYPE_CDP) + type = CHARGE_SUPPLIER_BC12_CDP; + else if (device_type & PI3USB9281_TYPE_DCP) + type = CHARGE_SUPPLIER_BC12_DCP; + else if (device_type & PI3USB9281_TYPE_SDP) + type = CHARGE_SUPPLIER_BC12_SDP; + else + type = CHARGE_SUPPLIER_OTHER; + + charge.current = pi3usb9281_get_ilim(device_type, + charger_status); + charge_manager_update_charge(type, port, &charge); + } else { /* Detachment: update available charge to 0 */ + charge.current = 0; + charge_manager_update_charge( + CHARGE_SUPPLIER_PROPRIETARY, + port, + &charge); + charge_manager_update_charge( + CHARGE_SUPPLIER_BC12_CDP, + port, + &charge); + charge_manager_update_charge( + CHARGE_SUPPLIER_BC12_DCP, + port, + &charge); + charge_manager_update_charge( + CHARGE_SUPPLIER_BC12_SDP, + port, + &charge); + charge_manager_update_charge( + CHARGE_SUPPLIER_OTHER, + port, + &charge); + } + + /* notify host of power info change */ + pd_send_host_event(PD_EVENT_POWER_CHANGE); + + /* Wait for interrupt */ + task_wait_event(-1); + } +} diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index 19c69a7369..3972e2289c 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -914,3 +914,9 @@ int pd_custom_flash_vdm(int port, int cnt, uint32_t *payload) } return rsize; } + +static void stub_pd_send_host_event(int mask) +{ +} +void pd_send_host_event(int mask) + __attribute__((weak, alias("stub_pd_send_host_event"))); |