summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2019-01-03 18:54:39 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-01-24 00:51:50 -0800
commitc7db1b252418b36a6a0ec619b45ad0aa443af3c8 (patch)
tree75bd5f744b0dcddc5f03c05ba64de174595c8ed5
parentb76cddd8525347057f88ea6f357206355f152cbf (diff)
downloadchrome-ec-stabilize-11647.70.B.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>
-rw-r--r--driver/bc12/pi3usb9281.c125
-rw-r--r--driver/pi3usb9281.h2
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)