summaryrefslogtreecommitdiff
path: root/driver/ppc
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2018-11-08 11:02:22 -0700
committerMartin Roth <martinroth@chromium.org>2018-11-14 18:16:40 +0000
commite8672c61878772c5541406b8cf3f3d3c90647d59 (patch)
tree82721c0c96db93c80bce691f2b3fc83354e24e1e /driver/ppc
parenta8f0850daf0ec4c2320faff13d8bddb3e692299d (diff)
downloadchrome-ec-e8672c61878772c5541406b8cf3f3d3c90647d59.tar.gz
SN5S330: treat interrupts as level-sensitive
The SN5S330 PPC will pull its /INT pin low until all interrupts are cleared. Since the interrupt pin is treated as edge-sensitive, its handler needs to provide level-checking before exiting. Otherwise, if not all interrupts are cleared before the handler exits, the EC won't see another edge to call the handler again. Boards which share the PPC interrupt pin with other sources may choose to implement their own callback, if they are able to determine which chip was the source of the interrupt. BUG=b:118846062 BRANCH=None TEST=performed several power swaps and unplugs on a pair of Careenas, verifying that in instances where the handler had to loop around we correctly cleared the interrupts and the "ectool usbpdpower" output was normal Change-Id: Iccbe40976a746d109d67b9a91f8fbd81898f9b3f Signed-off-by: Diana Z <dzigterman@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1327123 Reviewed-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Edward Hill <ecgh@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/1335679 Reviewed-by: Martin Roth <martinroth@chromium.org> Tested-by: Martin Roth <martinroth@chromium.org>
Diffstat (limited to 'driver/ppc')
-rw-r--r--driver/ppc/sn5s330.c63
1 files changed, 41 insertions, 22 deletions
diff --git a/driver/ppc/sn5s330.c b/driver/ppc/sn5s330.c
index 66ffa2678b..b90605a3e1 100644
--- a/driver/ppc/sn5s330.c
+++ b/driver/ppc/sn5s330.c
@@ -614,37 +614,56 @@ static int sn5s330_vbus_source_enable(int port, int enable)
static void sn5s330_handle_interrupt(int port)
{
- int rise = 0;
- int fall = 0;
+ int attempt = 0;
/*
- * The only interrupts that should be enabled are the PP1 overcurrent
- * condition, and for VBUS_GOOD if PPC is being used to detect VBUS.
+ * SN5S330's /INT pin is level, so process interrupts until it
+ * deasserts if the chip has a dedicated interrupt pin.
*/
- read_reg(port, SN5S330_INT_TRIP_RISE_REG1, &rise);
- read_reg(port, SN5S330_INT_TRIP_FALL_REG1, &fall);
+#ifdef CONFIG_USBC_PPC_DEDICATED_INT
+ while (ppc_get_alert_status(port))
+#endif
+ {
+ int rise = 0;
+ int fall = 0;
- /* Let the board know about the overcurrent event. */
- if (rise & SN5S330_ILIM_PP1_MASK)
- board_overcurrent_event(port);
+ attempt++;
- /* Clear the interrupt sources. */
- write_reg(port, SN5S330_INT_TRIP_RISE_REG1, rise);
- write_reg(port, SN5S330_INT_TRIP_FALL_REG1, fall);
+ if (attempt > 1)
+ CPRINTS("ppc p%d: Could not clear interrupts on first "
+ "try, retrying", port);
-#if defined(CONFIG_USB_PD_VBUS_DETECT_PPC) && defined(CONFIG_USB_CHARGER)
- read_reg(port, SN5S330_INT_TRIP_RISE_REG3, &rise);
- read_reg(port, SN5S330_INT_TRIP_FALL_REG3, &fall);
+ /*
+ * The only interrupts that should be enabled are the PP1
+ * overcurrent condition, and for VBUS_GOOD if PPC is being
+ * used to detect VBUS.
+ */
+ read_reg(port, SN5S330_INT_TRIP_RISE_REG1, &rise);
+ read_reg(port, SN5S330_INT_TRIP_FALL_REG1, &fall);
- /* Inform other modules about VBUS level */
- if (rise & SN5S330_VBUS_GOOD_MASK
- || fall & SN5S330_VBUS_GOOD_MASK)
- usb_charger_vbus_change(port, sn5s330_is_vbus_present(port));
+ /* Let the board know about the overcurrent event. */
+ if (rise & SN5S330_ILIM_PP1_MASK)
+ board_overcurrent_event(port);
- /* Clear the interrupt sources. */
- write_reg(port, SN5S330_INT_TRIP_RISE_REG3, rise);
- write_reg(port, SN5S330_INT_TRIP_FALL_REG3, fall);
+ /* Clear the interrupt sources. */
+ write_reg(port, SN5S330_INT_TRIP_RISE_REG1, rise);
+ write_reg(port, SN5S330_INT_TRIP_FALL_REG1, fall);
+
+#if defined(CONFIG_USB_PD_VBUS_DETECT_PPC) && defined(CONFIG_USB_CHARGER)
+ read_reg(port, SN5S330_INT_TRIP_RISE_REG3, &rise);
+ read_reg(port, SN5S330_INT_TRIP_FALL_REG3, &fall);
+
+ /* Inform other modules about VBUS level */
+ if (rise & SN5S330_VBUS_GOOD_MASK
+ || fall & SN5S330_VBUS_GOOD_MASK)
+ usb_charger_vbus_change(port,
+ sn5s330_is_vbus_present(port));
+
+ /* Clear the interrupt sources. */
+ write_reg(port, SN5S330_INT_TRIP_RISE_REG3, rise);
+ write_reg(port, SN5S330_INT_TRIP_FALL_REG3, fall);
#endif /* CONFIG_USB_PD_VBUS_DETECT_PPC && CONFIG_USB_CHARGER */
+ }
}
static void sn5s330_irq_deferred(void)