summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Herrmann <eherrmann@chromium.org>2020-12-03 09:53:20 -0800
committerCommit Bot <commit-bot@chromium.org>2020-12-08 01:32:22 +0000
commita0f2c4640c879521d2e9893317fe50ee1a4c76ee (patch)
treeb360d3a3ba168d3cdbcb0ef02396b71556986425
parentde6407f867863eb2976194b3d55d0fe4d4e33a6f (diff)
downloadchrome-ec-a0f2c4640c879521d2e9893317fe50ee1a4c76ee.tar.gz
SYV682: Disable VCONN on VCONN OCP
The SYV682 has a 'soft' overcurrent protection on VCONN which current limits to ~600mA. If the cause is a short it will eventually hit thermal shutdown. Instead, we should disable VCONN when we get an OCP event. We must allow current spikes for at least 1ms, so disable with a deglitch. BUG=b:170441866,b:172710638 TEST=make buildall TEST=On Voxel, short VCONN to ground for at least 100ms, then observe that VCONN is disabled and 'VCONN OC!' is printed in the EC console. BRANCH=None Signed-off-by: Eric Herrmann <eherrmann@chromium.org> Change-Id: I6712543b73072c959597c73cd493f248267a42ae Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2572237 Reviewed-by: Keith Short <keithshort@chromium.org> Tested-by: Keith Short <keithshort@chromium.org>
-rw-r--r--driver/ppc/syv682x.c30
1 files changed, 26 insertions, 4 deletions
diff --git a/driver/ppc/syv682x.c b/driver/ppc/syv682x.c
index b4c48f1365..43561b4bfb 100644
--- a/driver/ppc/syv682x.c
+++ b/driver/ppc/syv682x.c
@@ -30,7 +30,8 @@
static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */
static uint8_t flags[CONFIG_USB_PD_PORT_MAX_COUNT];
-static timestamp_t oc_timer[CONFIG_USB_PD_PORT_MAX_COUNT];
+static timestamp_t vbus_oc_timer[CONFIG_USB_PD_PORT_MAX_COUNT];
+static timestamp_t vconn_oc_timer[CONFIG_USB_PD_PORT_MAX_COUNT];
#define SYV682X_VBUS_DET_THRESH_MV 4000
/* Longest time that can be programmed in DSG_TIME field */
@@ -39,6 +40,7 @@ static timestamp_t oc_timer[CONFIG_USB_PD_PORT_MAX_COUNT];
#define INTERRUPT_DELAY_MS 10
/* Deglitch in ms of sourcing overcurrent detection */
#define SOURCE_OC_DEGLITCH_MS 100
+#define VCONN_OC_DEGLITCH_MS 100
#if SOURCE_OC_DEGLITCH_MS < INTERRUPT_DELAY_MS
#error "SOURCE_OC_DEGLITCH_MS should be at least INTERRUPT_DELAY_MS"
@@ -245,11 +247,11 @@ static void syv682x_handle_status_interrupt(int port, int regval)
*/
if (syv682x_interrupt_filter(port, regval, SYV682X_STATUS_OC_5V,
SYV682X_FLAGS_5V_OC)) {
- oc_timer[port].val =
+ vbus_oc_timer[port].val =
get_time().val + SOURCE_OC_DEGLITCH_MS * MSEC;
} else if ((regval & SYV682X_STATUS_OC_5V) &&
- (get_time().val > oc_timer[port].val)) {
- oc_timer[port].val = UINT64_MAX;
+ (get_time().val > vbus_oc_timer[port].val)) {
+ vbus_oc_timer[port].val = UINT64_MAX;
flags[port] &= ~SYV682X_FLAGS_5V_OC;
syv682x_vbus_source_enable(port, 0);
pd_handle_overcurrent(port);
@@ -274,8 +276,28 @@ static void syv682x_handle_status_interrupt(int port, int regval)
static void syv682x_handle_control_4_interrupt(int port, int regval)
{
+ /*
+ * VCONN OC is actually notifying that it is current limiting
+ * to 600mA. If this happens for a long time, we will trip TSD
+ * which will disable the channel. We should disable the sourcing path
+ * before that happens for safety reasons.
+ *
+ * On first check, set the flag and set the timer. This also clears the
+ * flag if the OC is gone.
+ */
if (syv682x_interrupt_filter(port, regval, SYV682X_CONTROL_4_VCONN_OCP,
SYV682X_FLAGS_VCONN_OCP)) {
+ vconn_oc_timer[port].val =
+ get_time().val + VCONN_OC_DEGLITCH_MS * MSEC;
+ } else if ((regval & SYV682X_CONTROL_4_VCONN_OCP) &&
+ (get_time().val > vconn_oc_timer[port].val)) {
+ vconn_oc_timer[port].val = UINT64_MAX;
+ flags[port] &= ~SYV682X_FLAGS_VCONN_OCP;
+ /* Disable VCONN */
+ regval &=
+ ~(SYV682X_CONTROL_4_VCONN2 | SYV682X_CONTROL_4_VCONN1);
+ write_reg(port, SYV682X_CONTROL_4_REG, regval);
+
ppc_prints("VCONN OC!", port);
}