diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2019-01-03 18:54:39 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-01-24 00:51:50 -0800 |
commit | c7db1b252418b36a6a0ec619b45ad0aa443af3c8 (patch) | |
tree | 75bd5f744b0dcddc5f03c05ba64de174595c8ed5 /driver | |
parent | b76cddd8525347057f88ea6f357206355f152cbf (diff) | |
download | chrome-ec-c7db1b252418b36a6a0ec619b45ad0aa443af3c8.tar.gz |
PI3USB9238: Read device type and charge registers after INTB assertionstabilize-11647.70.Bstabilize-11647.104.Brelease-R73-11647.B
PI3USB9238 can fail to detect BC 1.2 charger because the initialization
timing after reset differs chip to chip.
This patch checks the interrupt register in a loop to wait until device
type and charger status registers are ready.
Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org>
BUG=b/119166282
BRANCH=nami
TEST=Verify BC 1.2 chargers are reliably detected as
DCP (wall-charger), CDP (type-A port on chromebook),
and SDP (type-c port on chromebook) by type-c port of Vayne
(via A-to-C cable).
Change-Id: I970007723fcff5e2818765705d534d1a581b33e7
Reviewed-on: https://chromium-review.googlesource.com/1399202
Commit-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/bc12/pi3usb9281.c | 125 | ||||
-rw-r--r-- | driver/pi3usb9281.h | 2 |
2 files changed, 85 insertions, 42 deletions
diff --git a/driver/bc12/pi3usb9281.c b/driver/bc12/pi3usb9281.c index 06a1efba61..b45b3c49a5 100644 --- a/driver/bc12/pi3usb9281.c +++ b/driver/bc12/pi3usb9281.c @@ -30,12 +30,10 @@ #define PI3USB9281_SW_RESET_DELAY 20 /* Wait after a charger is detected to debounce pin contact order */ -#define PI3USB9281_DETECT_DEBOUNCE_DELAY_MS 1000 -/* - * Wait after reset, before re-enabling attach interrupt, so that the - * spurious attach interrupt from certain ports is ignored. - */ -#define PI3USB9281_RESET_DEBOUNCE_DELAY_MS 100 +#define PI3USB9281_DETECT_DEBOUNCE_MS 1000 +#define PI3USB9281_RESET_DEBOUNCE_MS 100 +#define PI3USB9281_RESET_STARTUP_DELAY (200 * MSEC) +#define PI3USB9281_RESET_STARTUP_DELAY_INTERVAL_MS 40 /* Store the state of our USB data switches so that they can be restored. */ static int usb_switch_state[CONFIG_USB_PD_PORT_COUNT]; @@ -135,6 +133,10 @@ static int pi3usb9281_write_ctrl_u(int port, uint8_t ctrl) return pi3usb9281_do_write_ctrl(port, ctrl, 0); } +/* + * Mask particular interrupts (e.g. attach, detach, ovp, ocp). + * 1: UnMask (enable). 0: Mask (disable) + */ static int pi3usb9281_set_interrupt_mask(int port, uint8_t mask) { return pi3usb9281_write(port, PI3USB9281_REG_INT_MASK, ~mask); @@ -286,22 +288,44 @@ void usb_charger_set_switches(int port, enum usb_switch setting) mutex_unlock(&usb_switch_lock[port]); } -static void bc12_detect(int port) +static int pc3usb9281_read_interrupt(int port) +{ + timestamp_t timeout; + timeout.val = get_time().val + PI3USB9281_RESET_STARTUP_DELAY; + do { + /* Read (& clear) possible attach & detach interrupt */ + if (pi3usb9281_get_interrupts(port) & + PI3USB9281_INT_ATTACH_DETACH) + return EC_SUCCESS; + msleep(PI3USB9281_RESET_STARTUP_DELAY_INTERVAL_MS); + } while (get_time().val < timeout.val); + return EC_ERROR_TIMEOUT; +} + +/* + * Handle BC 1.2 attach & detach event + * + * On attach, it resets pi3usb9281 for debounce. This reset should immediately + * trigger another attach or detach interrupt. If other (unexpected) event is + * observed, it forwards the event so that the caller can handle it. + */ +static uint32_t bc12_detect(int port) { - int device_type, charger_status; - int type; + int device_type, chg_status; + uint32_t evt = 0; if (usb_charger_port_is_sourcing_vbus(port)) { /* If we're sourcing VBUS then we're not charging */ - device_type = charger_status = 0; + device_type = PI3USB9281_TYPE_NONE; + chg_status = PI3USB9281_CHG_NONE; } else { /* Set device type */ device_type = pi3usb9281_get_device_type(port); - charger_status = pi3usb9281_get_charger_status(port); + chg_status = pi3usb9281_get_charger_status(port); } /* Debounce pin plug order if we detect a charger */ - if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) { + if (device_type || PI3USB9281_CHG_STATUS_ANY(chg_status)) { /* next operation might trigger a detach interrupt */ pi3usb9281_disable_interrupts(port); /* @@ -313,45 +337,62 @@ static void bc12_detect(int port) pi3usb9281_set_pins(port, 0); /* Delay to debounce pin attach order */ - msleep(PI3USB9281_DETECT_DEBOUNCE_DELAY_MS); + msleep(PI3USB9281_DETECT_DEBOUNCE_MS); /* - * Trigger chip reset to refresh detection registers. + * Reset PI3USB9281 to refresh detection registers. After reset, + * - Interrupt is globally disabled + * - All interrupts are unmasked (=enabled) + * * 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); + + /* + * Wait after reset, before re-enabling interrupt, so that + * spurious interrupts from this port are ignored. + */ + msleep(PI3USB9281_RESET_DEBOUNCE_MS); + /* Re-enable interrupts */ pi3usb9281_enable_interrupts(port); - msleep(PI3USB9281_RESET_DEBOUNCE_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); + /* + * Consume interrupt (expectedly) triggered by the reset. + * If it's other event (e.g. VBUS), return immediately. + */ + evt = task_wait_event(PI3USB9281_RESET_DEBOUNCE_MS * MSEC); + if (evt & USB_CHG_EVENT_BC12) + evt &= ~USB_CHG_EVENT_BC12; + else if (evt & USB_CHG_EVENT_INTR) + evt &= ~USB_CHG_EVENT_INTR; + else + return evt; + + /* Debounce is done. Registers should have trustworthy values */ + device_type = PI3USB9281_TYPE_NONE; + chg_status = PI3USB9281_CHG_NONE; + if (pc3usb9281_read_interrupt(port) == EC_SUCCESS) { + device_type = pi3usb9281_get_device_type(port); + chg_status = pi3usb9281_get_charger_status(port); + } } /* Attachment: decode + update available charge */ - if (device_type || PI3USB9281_CHG_STATUS_ANY(charger_status)) { + if (device_type || PI3USB9281_CHG_STATUS_ANY(chg_status)) { struct charge_port_info chg; - if (PI3USB9281_CHG_STATUS_ANY(charger_status)) + int type; + + if (PI3USB9281_CHG_STATUS_ANY(chg_status)) type = CHARGE_SUPPLIER_PROPRIETARY; else if (device_type & PI3USB9281_TYPE_CDP) type = CHARGE_SUPPLIER_BC12_CDP; @@ -363,7 +404,7 @@ static void bc12_detect(int port) type = CHARGE_SUPPLIER_OTHER; chg.voltage = USB_CHARGER_VOLTAGE_MV; - chg.current = pi3usb9281_get_ilim(device_type, charger_status); + chg.current = pi3usb9281_get_ilim(device_type, chg_status); charge_manager_update_charge(type, port, &chg); } else { /* Detachment */ @@ -378,34 +419,32 @@ static void bc12_detect(int port) charge_manager_update_charge(CHARGE_SUPPLIER_OTHER, port, NULL); } + + return evt; } void usb_charger_task(void *u) { - const int attach_mask = PI3USB9281_INT_ATTACH | PI3USB9281_INT_DETACH; int port = (task_get_current() == TASK_ID_USB_CHG_P0 ? 0 : 1); - int interrupt; uint32_t evt; /* Initialize chip and enable interrupts */ pi3usb9281_init(port); - bc12_detect(port); + evt = bc12_detect(port); while (1) { - /* Wait for interrupt */ - evt = task_wait_event(-1); - /* Interrupt from the Pericom chip, determine charger type */ if (evt & USB_CHG_EVENT_BC12) { /* Read interrupt register to clear on chip */ pi3usb9281_get_interrupts(port); - bc12_detect(port); + evt = bc12_detect(port); } else if (evt & USB_CHG_EVENT_INTR) { + /* USB_CHG_EVENT_INTR & _BC12 are mutually exclusive */ /* Check the interrupt register, and clear on chip */ - interrupt = pi3usb9281_get_interrupts(port); - if (interrupt & attach_mask) - bc12_detect(port); + if (pi3usb9281_get_interrupts(port) & + PI3USB9281_INT_ATTACH_DETACH) + evt = bc12_detect(port); } /* @@ -421,6 +460,8 @@ void usb_charger_task(void *u) pd_snk_is_vbus_provided(port)); #endif } + + evt = task_wait_event(-1); } } diff --git a/driver/pi3usb9281.h b/driver/pi3usb9281.h index fd4375b9b1..8ed4c77c57 100644 --- a/driver/pi3usb9281.h +++ b/driver/pi3usb9281.h @@ -38,6 +38,8 @@ #define PI3USB9281_INT_OVP (1 << 5) #define PI3USB9281_INT_OCP (1 << 6) #define PI3USB9281_INT_OVP_OC (1 << 7) +#define PI3USB9281_INT_ATTACH_DETACH (PI3USB9281_INT_ATTACH | \ + PI3USB9281_INT_DETACH) #define PI3USB9281_TYPE_NONE 0 #define PI3USB9281_TYPE_MHL (1 << 0) |