diff options
-rw-r--r-- | board/glados/board.c | 59 | ||||
-rw-r--r-- | board/kunimitsu/board.c | 59 | ||||
-rw-r--r-- | board/ryu/board.c | 45 | ||||
-rw-r--r-- | board/samus_pd/board.c | 92 | ||||
-rw-r--r-- | board/strago/board.c | 47 | ||||
-rw-r--r-- | common/usb_charger.c | 280 | ||||
-rw-r--r-- | include/usb_charge.h | 11 |
7 files changed, 211 insertions, 382 deletions
diff --git a/board/glados/board.c b/board/glados/board.c index fe7773d085..5e026b71b6 100644 --- a/board/glados/board.c +++ b/board/glados/board.c @@ -47,51 +47,28 @@ static void pd_mcu_interrupt(enum gpio_signal signal) host_command_pd_send_status(0); } -static void update_vbus_supplier(int port, int vbus_level) -{ - struct charge_port_info charge; - - /* - * If VBUS is low, or VBUS is high and we are not outputting VBUS - * ourselves, then update the VBUS supplier. - */ - if (!vbus_level || !usb_charger_port_is_sourcing_vbus(port)) { - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, - port, - &charge); - } -} - void vbus0_evt(enum gpio_signal signal) { /* VBUS present GPIO is inverted */ - int vbus_level = !gpio_get_level(signal); - - CPRINTF("VBUS C0, %d\n", vbus_level); - update_vbus_supplier(0, vbus_level); + usb_charger_vbus_change(0, !gpio_get_level(signal)); task_wake(TASK_ID_PD_C0); } void vbus1_evt(enum gpio_signal signal) { /* VBUS present GPIO is inverted */ - int vbus_level = !gpio_get_level(signal); - - CPRINTF("VBUS C1, %d\n", vbus_level); - update_vbus_supplier(0, vbus_level); + usb_charger_vbus_change(1, !gpio_get_level(signal)); task_wake(TASK_ID_PD_C1); } void usb0_evt(enum gpio_signal signal) { - task_wake(TASK_ID_USB_CHG_P0); + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0); } void usb1_evt(enum gpio_signal signal) { - task_wake(TASK_ID_USB_CHG_P1); + task_set_event(TASK_ID_USB_CHG_P1, USB_CHG_EVENT_BC12, 0); } #include "gpio_list.h" @@ -234,40 +211,12 @@ DECLARE_HOOK(HOOK_CHIPSET_PRE_INIT, pmic_init, HOOK_PRIO_DEFAULT); /* Initialize board. */ static void board_init(void) { - int i; - struct charge_port_info charge_none; - /* Enable PD MCU interrupt */ gpio_enable_interrupt(GPIO_PD_MCU_INT); /* Enable VBUS interrupt */ gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE_L); gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE_L); - /* Initialize all pericom charge suppliers to 0 */ - charge_none.voltage = USB_CHARGER_VOLTAGE_MV; - charge_none.current = 0; - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { - charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, - i, - &charge_none); - } - - /* Initialize VBUS supplier based on whether or not VBUS is present */ - update_vbus_supplier(0, !gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L)); - update_vbus_supplier(1, !gpio_get_level(GPIO_USB_C1_VBUS_WAKE_L)); - /* Enable pericom BC1.2 interrupts */ gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L); gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L); diff --git a/board/kunimitsu/board.c b/board/kunimitsu/board.c index e9cade936f..16b75e9b8a 100644 --- a/board/kunimitsu/board.c +++ b/board/kunimitsu/board.c @@ -53,51 +53,28 @@ static void pd_mcu_interrupt(enum gpio_signal signal) host_command_pd_send_status(0); } -static void update_vbus_supplier(int port, int vbus_level) -{ - struct charge_port_info charge; - - /* - * If VBUS is low, or VBUS is high and we are not outputting VBUS - * ourselves, then update the VBUS supplier. - */ - if (!vbus_level || !usb_charger_port_is_sourcing_vbus(port)) { - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, - port, - &charge); - } -} - void vbus0_evt(enum gpio_signal signal) { /* VBUS present GPIO is inverted */ - int vbus_level = !gpio_get_level(signal); - - CPRINTF("VBUS C0, %d\n", vbus_level); - update_vbus_supplier(0, vbus_level); + usb_charger_vbus_change(0, !gpio_get_level(signal)); task_wake(TASK_ID_PD_C0); } void vbus1_evt(enum gpio_signal signal) { /* VBUS present GPIO is inverted */ - int vbus_level = !gpio_get_level(signal); - - CPRINTF("VBUS C1, %d\n", vbus_level); - update_vbus_supplier(0, vbus_level); + usb_charger_vbus_change(1, !gpio_get_level(signal)); task_wake(TASK_ID_PD_C1); } void usb0_evt(enum gpio_signal signal) { - task_wake(TASK_ID_USB_CHG_P0); + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0); } void usb1_evt(enum gpio_signal signal) { - task_wake(TASK_ID_USB_CHG_P1); + task_set_event(TASK_ID_USB_CHG_P1, USB_CHG_EVENT_BC12, 0); } #include "gpio_list.h" @@ -320,40 +297,12 @@ BUILD_ASSERT(ARRAY_SIZE(buttons) == CONFIG_BUTTON_COUNT); /* Initialize board. */ static void board_init(void) { - int i; - struct charge_port_info charge_none; - /* Enable PD MCU interrupt */ gpio_enable_interrupt(GPIO_PD_MCU_INT); /* Enable VBUS interrupt */ gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE_L); gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE_L); - /* Initialize all pericom charge suppliers to 0 */ - charge_none.voltage = USB_CHARGER_VOLTAGE_MV; - charge_none.current = 0; - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { - charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, - i, - &charge_none); - } - - /* Initialize VBUS supplier based on whether or not VBUS is present */ - update_vbus_supplier(0, !gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L)); - update_vbus_supplier(1, !gpio_get_level(GPIO_USB_C1_VBUS_WAKE_L)); - /* Enable pericom BC1.2 interrupts */ gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L); gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L); diff --git a/board/ryu/board.c b/board/ryu/board.c index ad1f5788b6..045fbe3dd4 100644 --- a/board/ryu/board.c +++ b/board/ryu/board.c @@ -58,34 +58,15 @@ static int charge_current_limit; */ static struct ec_response_host_event_status host_event_status __aligned(4); -static void vbus_log(void) -{ - CPRINTS("VBUS %d", gpio_get_level(GPIO_CHGR_ACOK)); -} -DECLARE_DEFERRED(vbus_log); - void vbus_evt(enum gpio_signal signal) { - struct charge_port_info charge; - int vbus_level = gpio_get_level(signal); - - /* - * If VBUS is low, or VBUS is high and we are not outputting VBUS - * ourselves, then update the VBUS supplier. - */ - if (!vbus_level || !gpio_get_level(GPIO_CHGR_OTG)) { - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, &charge); - } - - hook_call_deferred(vbus_log, 0); + usb_charger_vbus_change(0, gpio_get_level(signal)); task_wake(TASK_ID_PD); } void usb_evt(enum gpio_signal signal) { - task_wake(TASK_ID_USB_CHG_P0); + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0); } #include "gpio_list.h" @@ -152,28 +133,6 @@ BUILD_ASSERT(ARRAY_SIZE(pi3usb9281_chips) == static void board_init(void) { int i; - struct charge_port_info charge_none, charge_vbus; - - /* Initialize all pericom charge suppliers to 0 */ - charge_none.voltage = USB_CHARGER_VOLTAGE_MV; - charge_none.current = 0; - charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY, - 0, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, 0, &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, 0, &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, 0, &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, 0, &charge_none); - - /* Initialize VBUS supplier based on whether or not VBUS is present */ - charge_vbus.voltage = USB_CHARGER_VOLTAGE_MV; - charge_vbus.current = USB_CHARGER_MIN_CURR_MA; - if (gpio_get_level(GPIO_CHGR_ACOK)) - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, - &charge_vbus); - else - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, - &charge_none); /* Enable pericom BC1.2 interrupts. */ gpio_enable_interrupt(GPIO_USBC_BC12_INT_L); diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c index eb2273121b..e59646058c 100644 --- a/board/samus_pd/board.c +++ b/board/samus_pd/board.c @@ -102,67 +102,24 @@ DECLARE_DEFERRED(pericom_port1_reenable_interrupts); void vbus0_evt(enum gpio_signal signal) { - struct charge_port_info charge; - int vbus_level = gpio_get_level(signal); - - /* - * If VBUS is low, or VBUS is high and we are not outputting VBUS - * ourselves, then update the VBUS supplier. - */ - if (!vbus_level || !gpio_get_level(GPIO_USB_C0_5V_EN)) { - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, &charge); - } - - /* - * Re-enable interrupts on pericom charger detector since the - * chip may periodically reset itself, and come back up with - * registers in default state. TODO(crosbug.com/p/33823): Fix - * these unwanted resets. - */ - hook_call_deferred(pericom_port0_reenable_interrupts, 0); + usb_charger_vbus_change(0, gpio_get_level(signal)); task_wake(TASK_ID_PD_C0); } void vbus1_evt(enum gpio_signal signal) { - struct charge_port_info charge; - int vbus_level = gpio_get_level(signal); - - /* - * If VBUS is low, or VBUS is high and we are not outputting VBUS - * ourselves, then update the VBUS supplier. - */ - if (!vbus_level || !gpio_get_level(GPIO_USB_C1_5V_EN)) { - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 1, &charge); - } - - /* - * Re-enable interrupts on pericom charger detector since the - * chip may periodically reset itself, and come back up with - * registers in default state. TODO(crosbug.com/p/33823): Fix - * these unwanted resets. - */ - hook_call_deferred(pericom_port1_reenable_interrupts, 0); + usb_charger_vbus_change(1, gpio_get_level(signal)); task_wake(TASK_ID_PD_C1); } -static void wake_usb_charger_task(int port) -{ - task_wake(port ? TASK_ID_USB_CHG_P1 : TASK_ID_USB_CHG_P0); -} - void usb0_evt(enum gpio_signal signal) { - wake_usb_charger_task(0); + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0); } void usb1_evt(enum gpio_signal signal) { - wake_usb_charger_task(1); + task_set_event(TASK_ID_USB_CHG_P1, USB_CHG_EVENT_BC12, 0); } static void chipset_s5_to_s3(void) @@ -252,10 +209,9 @@ void board_config_pre_init(void) /* Initialize board. */ static void board_init(void) { - int pd_enable, i; + int pd_enable; int slp_s5 = gpio_get_level(GPIO_PCH_SLP_S5_L); int slp_s3 = gpio_get_level(GPIO_PCH_SLP_S3_L); - struct charge_port_info charge_none, charge_vbus; /* * Enable CC lines after all GPIO have been initialized. Note, it is @@ -268,44 +224,6 @@ static void board_init(void) gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE); gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE); - /* Initialize all pericom charge suppliers to 0 */ - charge_none.voltage = USB_CHARGER_VOLTAGE_MV; - charge_none.current = 0; - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { - charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, - i, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, - i, - &charge_none); - } - - /* Initialize VBUS supplier based on whether or not VBUS is present */ - charge_vbus.voltage = USB_CHARGER_VOLTAGE_MV; - charge_vbus.current = USB_CHARGER_MIN_CURR_MA; - if (gpio_get_level(GPIO_USB_C0_VBUS_WAKE)) - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, - &charge_vbus); - else - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 0, - &charge_none); - - if (gpio_get_level(GPIO_USB_C1_VBUS_WAKE)) - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 1, - &charge_vbus); - else - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, 1, - &charge_none); - /* Enable pericom BC1.2 interrupts. */ gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L); gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L); diff --git a/board/strago/board.c b/board/strago/board.c index a2c5b75992..6b6b3a7089 100644 --- a/board/strago/board.c +++ b/board/strago/board.c @@ -56,35 +56,16 @@ static void pd_mcu_interrupt(enum gpio_signal signal) #endif } -static void update_vbus_supplier(int port, int vbus_level) -{ - struct charge_port_info charge; - - /* - * If VBUS is low, or VBUS is high and we are not outputting VBUS - * ourselves, then update the VBUS supplier. - */ - if (!vbus_level || !usb_charger_port_is_sourcing_vbus(port)) { - charge.voltage = USB_CHARGER_VOLTAGE_MV; - charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, - port, - &charge); - } -} - void vbus0_evt(enum gpio_signal signal) { /* VBUS present GPIO is inverted */ - int vbus_level = !gpio_get_level(signal); - - update_vbus_supplier(0, vbus_level); + usb_charger_vbus_change(0, !gpio_get_level(signal)); task_wake(TASK_ID_PD); } void usb0_evt(enum gpio_signal signal) { - task_wake(TASK_ID_USB_CHG_P0); + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0); } #include "gpio_list.h" @@ -311,35 +292,11 @@ DECLARE_HOOK(HOOK_INIT, adc_pre_init, HOOK_PRIO_INIT_ADC - 1); /* Initialize board. */ static void board_init(void) { - struct charge_port_info charge_none; - /* Enable PD MCU interrupt */ gpio_enable_interrupt(GPIO_PD_MCU_INT); /* Enable VBUS interrupt */ gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE_L); - /* Initialize all pericom charge suppliers to 0 */ - charge_none.voltage = USB_CHARGER_VOLTAGE_MV; - charge_none.current = 0; - charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY, - 0, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, - 0, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, - 0, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, - 0, - &charge_none); - charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, - 0, - &charge_none); - - /* Initialize VBUS supplier based on whether or not VBUS is present */ - update_vbus_supplier(0, !gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L)); - /* Enable pericom BC1.2 interrupts */ gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L); } diff --git a/common/usb_charger.c b/common/usb_charger.c index de81ad0497..f686ffaff1 100644 --- a/common/usb_charger.c +++ b/common/usb_charger.c @@ -11,14 +11,18 @@ #include "charge_manager.h" #include "common.h" +#include "console.h" #include "ec_commands.h" #include "gpio.h" +#include "hooks.h" #include "pi3usb9281.h" #include "task.h" #include "timer.h" #include "usb_charge.h" #include "usb_pd.h" +#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) + /* Wait after a charger is detected to debounce pin contact order */ #define USB_CHG_DEBOUNCE_DELAY_MS 1000 /* @@ -34,6 +38,23 @@ static int usb_switch_state[CONFIG_USB_PD_PORT_COUNT]; static struct mutex usb_switch_lock[CONFIG_USB_PD_PORT_COUNT]; +static void update_vbus_supplier(int port, int vbus_level) +{ + struct charge_port_info charge; + + /* + * If VBUS is low, or VBUS is high and we are not outputting VBUS + * ourselves, then update the VBUS supplier. + */ + if (!vbus_level || !usb_charger_port_is_sourcing_vbus(port)) { + charge.voltage = USB_CHARGER_VOLTAGE_MV; + charge.current = vbus_level ? USB_CHARGER_MIN_CURR_MA : 0; + charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, + port, + &charge); + } +} + int usb_charger_port_is_sourcing_vbus(int port) { if (port == 0) @@ -59,121 +80,186 @@ void usb_charger_set_switches(int port, enum usb_switch setting) mutex_unlock(&usb_switch_lock[port]); } -void usb_charger_task(void) +void usb_charger_vbus_change(int port, int vbus_level) { - int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1); + /* Update VBUS supplier and signal VBUS change to USB_CHG task */ + update_vbus_supplier(port, vbus_level); +#if CONFIG_USB_PD_PORT_COUNT == 2 + task_set_event(port ? TASK_ID_USB_CHG_P1 : TASK_ID_USB_CHG_P0, + USB_CHG_EVENT_VBUS, 0); +#else + task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_VBUS, 0); +#endif +} +static void usb_charger_bc12_detect(int port) +{ int device_type, charger_status; struct charge_port_info charge; int type; charge.voltage = USB_CHARGER_VOLTAGE_MV; + /* Read interrupt register to clear on chip */ + pi3usb9281_get_interrupts(port); + + if (usb_charger_port_is_sourcing_vbus(port)) { + /* 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); + + /* next operation might trigger a detach interrupt */ + pi3usb9281_disable_interrupts(port); + /* Ensure D+/D- are open before resetting */ + pi3usb9281_set_switch_manual(port, 1); + pi3usb9281_set_pins(port, 0); + /* Let D+/D- relax to their idle state */ + msleep(40); + + /* + * 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. + */ + usb_charger_set_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); +} + +void usb_charger_task(void) +{ + int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1); + uint32_t evt; + /* Initialize chip and enable interrupts */ pi3usb9281_init(port); + usb_charger_bc12_detect(port); + while (1) { - /* Read interrupt register to clear on chip */ - pi3usb9281_get_interrupts(port); + /* Wait for interrupt */ + evt = task_wait_event(-1); - if (usb_charger_port_is_sourcing_vbus(port)) { - /* 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); - } + /* Interrupt from the Pericom chip, determine charger type */ + if (evt & USB_CHG_EVENT_BC12) + usb_charger_bc12_detect(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); - - /* next operation might trigger a detach interrupt */ - pi3usb9281_disable_interrupts(port); - /* Ensure D+/D- are open before resetting */ - pi3usb9281_set_switch_manual(port, 1); - pi3usb9281_set_pins(port, 0); - /* Let D+/D- relax to their idle state */ - msleep(40); - - /* - * 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. - */ - usb_charger_set_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 */ + /* + * Re-enable interrupts on pericom charger detector since the + * chip may periodically reset itself, and come back up with + * registers in default state. TODO(crosbug.com/p/33823): Fix + * these unwanted resets. + */ + if (evt & USB_CHG_EVENT_VBUS) { 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); + CPRINTS("VBUS p%d %d", port, + pd_snk_is_vbus_provided(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); - } +static void usb_charger_init(void) +{ + int i; + struct charge_port_info charge_none; - /* notify host of power info change */ - pd_send_host_event(PD_EVENT_POWER_CHANGE); + /* Initialize all pericom charge suppliers to 0 */ + charge_none.voltage = USB_CHARGER_VOLTAGE_MV; + charge_none.current = 0; + for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { + charge_manager_update_charge(CHARGE_SUPPLIER_PROPRIETARY, + i, + &charge_none); + charge_manager_update_charge(CHARGE_SUPPLIER_BC12_CDP, + i, + &charge_none); + charge_manager_update_charge(CHARGE_SUPPLIER_BC12_DCP, + i, + &charge_none); + charge_manager_update_charge(CHARGE_SUPPLIER_BC12_SDP, + i, + &charge_none); + charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, + i, + &charge_none); - /* Wait for interrupt */ - task_wait_event(-1); + /* Initialize VBUS supplier based on whether VBUS is present */ + update_vbus_supplier(i, pd_snk_is_vbus_provided(i)); } } +DECLARE_HOOK(HOOK_INIT, usb_charger_init, HOOK_PRIO_DEFAULT); diff --git a/include/usb_charge.h b/include/usb_charge.h index 60f2c9742c..e7d620bd81 100644 --- a/include/usb_charge.h +++ b/include/usb_charge.h @@ -47,6 +47,10 @@ int usb_charge_set_mode(int usb_port_id, enum usb_charge_mode mode); */ int usb_charge_ports_enabled(void); +/* Events handled by the USB_CHG task */ +#define USB_CHG_EVENT_BC12 TASK_EVENT_CUSTOM(1) +#define USB_CHG_EVENT_VBUS TASK_EVENT_CUSTOM(2) + /** * Returns true if the passed port is a power source. * @@ -69,5 +73,12 @@ enum usb_switch { */ void usb_charger_set_switches(int port, enum usb_switch setting); +/** + * Notify USB_CHG task that VBUS level has changed. + * + * @param port port number. + * @param vbus_level new VBUS level + */ +void usb_charger_vbus_change(int port, int vbus_level); #endif /* __CROS_EC_USB_CHARGE_H */ |