diff options
-rw-r--r-- | common/usb_charger.c | 9 | ||||
-rw-r--r-- | driver/charger/bd99955.c | 122 | ||||
-rw-r--r-- | include/usb_charge.h | 8 |
3 files changed, 56 insertions, 83 deletions
diff --git a/common/usb_charger.c b/common/usb_charger.c index 33754120a1..2cd9cfbcd3 100644 --- a/common/usb_charger.c +++ b/common/usb_charger.c @@ -59,14 +59,13 @@ int usb_charger_port_is_sourcing_vbus(int port) void usb_charger_vbus_change(int port, int vbus_level) { /* If VBUS has transitioned low, notify PD module directly */ - pd_vbus_low(port); + if (!vbus_level) + pd_vbus_low(port); + /* Update VBUS supplier and signal VBUS change to USB_CHG task */ update_vbus_supplier(port, vbus_level); -#ifdef HAS_TASK_USB_CHG - /* USB Charger task */ - task_set_event(TASK_ID_USB_CHG, (1 << port), 0); -#else +#ifdef HAS_TASK_USB_CHG_P0 /* USB Charger task(s) */ task_set_event(USB_CHG_PORT_TO_TASK_ID(port), USB_CHG_EVENT_VBUS, 0); #endif diff --git a/driver/charger/bd99955.c b/driver/charger/bd99955.c index 4e74823ebc..cf3ad64d95 100644 --- a/driver/charger/bd99955.c +++ b/driver/charger/bd99955.c @@ -177,6 +177,8 @@ static int bd99955_get_charger_op_status(int *status) } #ifdef HAS_TASK_USB_CHG +static int bc12_detected_type[CONFIG_USB_PD_PORT_COUNT]; + static int bd99955_get_bc12_device_type(enum bd99955_charge_port port) { int rv; @@ -307,7 +309,6 @@ static void bd99955_bc12_detach(int port, int type) pd_send_host_event(PD_EVENT_POWER_CHANGE); } -#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER static int bd99955_enable_vbus_detect_interrupts(int port, int enable) { int reg; @@ -350,7 +351,8 @@ static int bd99955_enable_vbus_detect_interrupts(int port, int enable) return ch_raw_write16(port_reg, reg, BD99955_EXTENDED_COMMAND); } -static int bd99955_get_vbus_detect_interrupts(int port, int get) +/* Read + clear active interrupt bits for a given port */ +static int bd99955_get_vbus_detect_interrupts(int port) { int rv; int reg; @@ -358,44 +360,35 @@ static int bd99955_get_vbus_detect_interrupts(int port, int get) port_reg = (port == BD99955_CHARGE_PORT_VBUS) ? BD99955_CMD_INT1_STATUS : BD99955_CMD_INT2_STATUS; - if (get) { - rv = ch_raw_read16(port_reg, ®, BD99955_EXTENDED_COMMAND); - return rv ? 0 : reg & - (BD99955_CMD_INT_SET_RES | BD99955_CMD_INT_SET_DET); - } else - return ch_raw_write16(port_reg, - (BD99955_CMD_INT_SET_RES | BD99955_CMD_INT_SET_DET), - BD99955_EXTENDED_COMMAND); -} -#endif /* CONFIG_USB_PD_VBUS_DETECT_CHARGER */ + rv = ch_raw_read16(port_reg, ®, BD99955_EXTENDED_COMMAND); -static void usb_charger_task_init(int *bc12_type) -{ - int port; + if (rv) + return 0; - for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; port++) { - bc12_type[port] = CHARGE_SUPPLIER_NONE; + /* Clear the interrupt status bits we just read */ + ch_raw_write16(port_reg, reg, BD99955_EXTENDED_COMMAND); -#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER - /* Clear any pending VBUS interrupts */ - bd99955_get_vbus_detect_interrupts(port, 0); -#endif - } + return reg; } -static void usb_charger_process(enum bd99955_charge_port port, int *bc12_type) +static void usb_charger_process(enum bd99955_charge_port port) { - int vbus_provided = pd_snk_is_vbus_provided(port); + int vbus_provided = bd99955_is_vbus_provided(port); + /* Inform other modules about VBUS level */ + /* TODO: map charger port num to board port num, they may differ. */ + usb_charger_vbus_change(port, vbus_provided); + + /* Do BC1.2 detection */ if (vbus_provided) { /* Charger/sync attached */ - bc12_type[port] = bd99955_bc12_detect(port); - } else if (bc12_type[port] != CHARGE_SUPPLIER_NONE && + bc12_detected_type[port] = bd99955_bc12_detect(port); + } else if (bc12_detected_type[port] != CHARGE_SUPPLIER_NONE && !vbus_provided) { /* Charger/sync detached */ - bd99955_bc12_detach(port, bc12_type[port]); - bc12_type[port] = CHARGE_SUPPLIER_NONE; + bd99955_bc12_detach(port, bc12_detected_type[port]); + bc12_detected_type[port] = CHARGE_SUPPLIER_NONE; } } #endif /* HAS_TASK_USB_CHG */ @@ -661,11 +654,6 @@ static void bd99995_init(void) reg &= ~BD99955_CMD_VM_CTRL_SET_EXTIADPEN; ch_raw_write16(BD99955_CMD_VM_CTRL_SET, reg, BD99955_EXTENDED_COMMAND); - -#if defined(HAS_TASK_USB_CHG) && defined(CONFIG_USB_PD_VBUS_DETECT_CHARGER) - bd99955_enable_vbus_detect_interrupts(BD99955_CHARGE_PORT_VBUS, 1); - bd99955_enable_vbus_detect_interrupts(BD99955_CHARGE_PORT_VCC, 1); -#endif } DECLARE_HOOK(HOOK_INIT, bd99995_init, HOOK_PRIO_INIT_EXTPOWER); @@ -792,54 +780,46 @@ void usb_charger_set_switches(int port, enum usb_switch setting) bd99955_enable_usb_switch(port, usb_switch_state[port]); } -#ifdef CONFIG_USB_PD_VBUS_DETECT_CHARGER -void bd99955_vbus_interrupt_deferred(void) -{ - int port; - int intr; - - for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; port++) { - /* Get the VBUS interrupt */ - intr = bd99955_get_vbus_detect_interrupts(port, 1); - if (!intr) - continue; - - if (intr & BD99955_CMD_INT_SET_RES) - usb_charger_vbus_change(port, 0); - - if (intr & BD99955_CMD_INT_SET_DET) - usb_charger_vbus_change(port, 1); - - /* Clear the VBUS interrupt */ - bd99955_get_vbus_detect_interrupts(port, 0); - } -} -DECLARE_DEFERRED(bd99955_vbus_interrupt_deferred); - void bd99955_vbus_interrupt(enum gpio_signal signal) { - hook_call_deferred(&bd99955_vbus_interrupt_deferred_data, 0); + task_wake(TASK_ID_USB_CHG); } -#endif /* CONFIG_USB_PD_VBUS_DETECT_CHARGER */ void usb_charger_task(void) { - int evt = USB_CHG_EVENT_VBUS_P0 | USB_CHG_EVENT_VBUS_P1; - int bc12_type[CONFIG_USB_PD_PORT_COUNT]; + static int initialized; + int changed, port; - usb_charger_task_init(bc12_type); + for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; port++) + bc12_detected_type[port] = CHARGE_SUPPLIER_NONE; - while (1) { - if (evt & USB_CHG_EVENT_VBUS_P0) - usb_charger_process(BD99955_CHARGE_PORT_VBUS, - &bc12_type[BD99955_CHARGE_PORT_VBUS]); + bd99955_enable_vbus_detect_interrupts(BD99955_CHARGE_PORT_VBUS, 1); + bd99955_enable_vbus_detect_interrupts(BD99955_CHARGE_PORT_VCC, 1); - if (evt & USB_CHG_EVENT_VBUS_P1) - usb_charger_process(BD99955_CHARGE_PORT_VCC, - &bc12_type[BD99955_CHARGE_PORT_VCC]); + while (1) { + changed = 0; + for (port = 0; port < CONFIG_USB_PD_PORT_COUNT; port++) { + /* Get the VBUS interrupt */ + if (bd99955_get_vbus_detect_interrupts(port) || + !initialized) { + /* Detect based on current state of VBUS */ + usb_charger_process(port); + changed = 1; + } + } + + initialized = 1; - /* Wait for interrupt */ - evt = task_wait_event(-1); + /* + * Re-read interrupt registers immediately if we got an + * interrupt. We're dealing with multiple independent + * interrupt sources and the interrupt pin may have + * never deasserted if both sources were not in clear + * state simultaneously. + */ + if (!changed) + /* Wait for task wake */ + task_wait_event(-1); } } #endif /* HAS_TASK_USB_CHG */ diff --git a/include/usb_charge.h b/include/usb_charge.h index 382f373f8a..34893eabf7 100644 --- a/include/usb_charge.h +++ b/include/usb_charge.h @@ -47,13 +47,7 @@ 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 */ -#ifdef HAS_TASK_USB_CHG -/* One task for all the ports */ -#define USB_CHG_EVENT_VBUS_P0 TASK_EVENT_CUSTOM(1) -#define USB_CHG_EVENT_VBUS_P1 TASK_EVENT_CUSTOM(2) -#elif defined(HAS_TASK_USB_CHG_P0) -/* One task per port */ +#ifdef HAS_TASK_USB_CHG_P0 #define USB_CHG_EVENT_BC12 TASK_EVENT_CUSTOM(1) #define USB_CHG_EVENT_VBUS TASK_EVENT_CUSTOM(2) #define USB_CHG_EVENT_INTR TASK_EVENT_CUSTOM(4) |