summaryrefslogtreecommitdiff
path: root/driver/ppc
diff options
context:
space:
mode:
authorKeith Short <keithshort@chromium.org>2020-04-20 09:41:39 -0600
committerCommit Bot <commit-bot@chromium.org>2020-04-25 03:56:54 +0000
commitc7cefc07e9fa93984e18b79936bdb418daca9c2d (patch)
tree8dc2d1068aeda03e586a10ae186382dcd0da2ce2 /driver/ppc
parent0392c499b633c5bfb53a61d4504b396e59671c7a (diff)
downloadchrome-ec-c7cefc07e9fa93984e18b79936bdb418daca9c2d.tar.gz
SYV682: Update PPC initialization for no battery condition
Perform a more targeted reset action for the SYV682 PPC during initialization. This prevents a brownout of the EC when operating without a battery and also prevents over voltage trips following an EC reset when there was an existing PD contract. BUG=b:153523568 BRANCH=none TEST=make buildall TEST=On Volteer, connect PD charger to C1 port without battery. Verify board boots after issuing cold reset from servo. Test=On Volteer, verify SNK and SRC operation. Signed-off-by: Keith Short <keithshort@chromium.org> Change-Id: Ibf4e816ce468792e90d5f9337bc4262b07c831a9 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2159083 Reviewed-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-by: Eric Herrmann <eherrmann@chromium.org>
Diffstat (limited to 'driver/ppc')
-rw-r--r--driver/ppc/syv682x.c124
-rw-r--r--driver/ppc/syv682x.h18
2 files changed, 104 insertions, 38 deletions
diff --git a/driver/ppc/syv682x.c b/driver/ppc/syv682x.c
index 9b8c3a4f46..4444d9f5a0 100644
--- a/driver/ppc/syv682x.c
+++ b/driver/ppc/syv682x.c
@@ -17,15 +17,15 @@
#include "usb_pd.h"
#include "util.h"
-#define SYV682X_FLAGS_SOURCE_ENABLED BIT(0)
+#define SYV682X_FLAGS_SOURCE_ENABLED BIT(0)
/* 0 -> CC1, 1 -> CC2 */
-#define SYV682X_FLAGS_CC_POLARITY BIT(1)
-#define SYV682X_FLAGS_VBUS_PRESENT BIT(2)
-#define SYV682X_FLAGS_OCP BIT(3)
-#define SYV682X_FLAGS_OVP BIT(4)
-#define SYV682X_FLAGS_TSD BIT(5)
-#define SYV682X_FLAGS_RVS BIT(6)
-#define SYV682X_FLAGS_VCONN_OCP BIT(7)
+#define SYV682X_FLAGS_CC_POLARITY BIT(1)
+#define SYV682X_FLAGS_VBUS_PRESENT BIT(2)
+#define SYV682X_FLAGS_OCP BIT(3)
+#define SYV682X_FLAGS_OVP BIT(4)
+#define SYV682X_FLAGS_TSD BIT(5)
+#define SYV682X_FLAGS_RVS BIT(6)
+#define SYV682X_FLAGS_VCONN_OCP BIT(7)
static uint32_t irq_pending; /* Bitmask of ports signaling an interrupt. */
static uint8_t flags[CONFIG_USB_PD_PORT_MAX_COUNT];
@@ -94,7 +94,7 @@ static int write_reg(uint8_t port, int reg, int regval)
static int syv682x_is_sourcing_vbus(int port)
{
- return flags[port] & SYV682X_FLAGS_SOURCE_ENABLED;
+ return !!(flags[port] & SYV682X_FLAGS_SOURCE_ENABLED);
}
static int syv682x_discharge_vbus(int port, int enable)
@@ -194,6 +194,7 @@ static int syv682x_vbus_sink_enable(int port, int enable)
/* Select Sink mode and turn on the channel */
regval &= ~(SYV682X_CONTROL_1_HV_DR |
SYV682X_CONTROL_1_PWR_ENB);
+ flags[port] &= ~SYV682X_FLAGS_SOURCE_ENABLED;
} else {
/*
* No need to change the voltage path or channel direction. But,
@@ -455,11 +456,11 @@ void syv682x_interrupt(int port)
syv682x_interrupt_delayed(port, 0);
}
-static int syv682x_init(int port)
+static int syv682x_reset(int port)
{
int rv;
- int regval;
+ CPRINTS("p%d: PPC SW reset", port);
/*
* Reset all I2C registers to default values because the SYV682x does
* not provide a pin reset. The SYV682X_RST_REG bit is self-clearing.
@@ -473,35 +474,56 @@ static int syv682x_init(int port)
if (rv)
return rv;
- rv = read_reg(port, SYV682X_CONTROL_2_REG, &regval);
- if (rv)
- return rv;
+ return EC_SUCCESS;
+}
+
+static bool syv682x_is_sink(uint8_t control_1)
+{
/*
- * Enable smart discharge mode. The SYV682 automatically discharges
- * under the following conditions: UVLO (under voltage lockout), channel
- * shutdown, over current, over voltage, thermal shutdown
+ * The SYV682 integrates power paths: 5V and HV (high voltage).
+ * The SYV682 can source either 5V or HV, but only sinks on the HV path.
+ *
+ * PD analyzer without a device connected confirms the SYV682 acts as
+ * a source under these conditions:
+ * HV_DR && !CH_SEL: source 5V
+ * HV_DR && CH_SEL: source 15V
+ * !HV_DR && !CH_SEL: source 5V
+ *
+ * The SYV682 is only a sink when !HV_DR && CH_SEL
*/
- regval |= SYV682X_CONTROL_2_SDSG;
- rv = write_reg(port, SYV682X_CONTROL_2_REG, regval);
- if (rv)
- return rv;
+ if (!(control_1 & SYV682X_CONTROL_1_PWR_ENB)
+ && !(control_1 & SYV682X_CONTROL_1_HV_DR)
+ && (control_1 & SYV682X_CONTROL_1_CH_SEL))
+ return true;
- /* Select max voltage for OVP */
- rv = read_reg(port, SYV682X_CONTROL_3_REG, &regval);
- if (rv)
- return rv;
- regval &= ~SYV682X_OVP_MASK;
- regval |= (SYV682X_OVP_23_7 << SYV682X_OVP_BIT_SHIFT);
- rv = write_reg(port, SYV682X_CONTROL_3_REG, regval);
+ return false;
+}
+
+static int syv682x_init(int port)
+{
+ int rv;
+ int regval;
+ int status, control_1;
+
+ rv = read_reg(port, SYV682X_STATUS_REG, &status);
if (rv)
return rv;
- /* Check if this if dead battery case */
- rv = read_reg(port, SYV682X_STATUS_REG, &regval);
+ rv = read_reg(port, SYV682X_CONTROL_1_REG, &control_1);
if (rv)
return rv;
- if (regval & SYV682X_STATUS_VSAFE_0V) {
- /* Not dead battery case, so disable channel */
+
+ if (!syv682x_is_sink(control_1)
+ || (status & SYV682X_STATUS_VSAFE_0V)) {
+ /*
+ * PPC is not configured as a sink or there is no VBUS present.
+ * It's safe to perform a full register reset.
+ */
+ rv = syv682x_reset(port);
+ if (rv)
+ return rv;
+
+ /* Disable both power paths */
rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
if (rv)
return rv;
@@ -510,16 +532,42 @@ static int syv682x_init(int port)
if (rv)
return rv;
} else {
- syv682x_vbus_sink_enable(port, 1);
+ /* Dead battery mode, or an existing PD contract is in place */
+ rv = syv682x_vbus_sink_enable(port, 1);
+ if (rv)
+ return rv;
}
- rv = read_reg(port, SYV682X_CONTROL_4_REG, &regval);
+ /*
+ * Set Control Reg 2 to defaults, plus enable smart discharge mode.
+ * The SYV682 automatically discharges under the following conditions:
+ * UVLO (under voltage lockout), channel shutdown, over current, over
+ * voltage, and thermal shutdown
+ */
+ regval = (SYV682X_OC_DELAY_10MS << SYV682X_OC_DELAY_SHIFT)
+ | (SYV682X_DSG_TIME_200MS << SYV682X_DSG_TIME_SHIFT)
+ | (SYV682X_DSG_RON_200_OHM << SYV682X_DSG_RON_SHIFT)
+ | SYV682X_CONTROL_2_SDSG;
+ rv = write_reg(port, SYV682X_CONTROL_2_REG, regval);
if (rv)
return rv;
- /* Remove Rd and connect CC1/CC2 lines to TCPC */
- regval |= SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS;
- /* Disable Fast Role Swap (FRS) */
- regval |= SYV682X_CONTROL_4_CC_FRS;
+
+ /*
+ * Always set the over voltage setting to the maximum to support
+ * sinking from a 20V PD charger. The common PPC code doesn't provide
+ * any hooks for indicating what the currently negotiated voltage is.
+ */
+ regval = (SYV682X_OVP_23_7 << SYV682X_OVP_BIT_SHIFT);
+ rv = write_reg(port, SYV682X_CONTROL_3_REG, regval);
+ if (rv)
+ return rv;
+
+ /*
+ * Remove Rd, connect CC1/CC2 lines to TCPC, and disable fast role
+ * swap.
+ */
+ regval = SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS
+ | SYV682X_CONTROL_4_CC_FRS;
rv = write_reg(port, SYV682X_CONTROL_4_REG, regval);
if (rv)
return rv;
diff --git a/driver/ppc/syv682x.h b/driver/ppc/syv682x.h
index 3b13df10bc..af418bd2f4 100644
--- a/driver/ppc/syv682x.h
+++ b/driver/ppc/syv682x.h
@@ -45,6 +45,24 @@
#define SYV682X_ILIM_3_30 3
/* Control Register 2 */
+#define SYV682X_OC_DELAY_MASK GENMASK(7, 6)
+#define SYV682X_OC_DELAY_SHIFT 6
+#define SYV682X_OC_DELAY_1MS 0
+#define SYV682X_OC_DELAY_10MS 1
+#define SYV682X_OC_DELAY_50MS 2
+#define SYV682X_OC_DELAY_100MS 3
+#define SYV682X_DSG_TIME_MASK GENMASK(5, 4)
+#define SYV682X_DSG_TIME_SHIFT 4
+#define SYV682X_DSG_TIME_50MS 0
+#define SYV682X_DSG_TIME_100MS 1
+#define SYV682X_DSG_TIME_200MS 2
+#define SYV682X_DSG_TIME_400MS 3
+#define SYV682X_DSG_RON_MASK GENMASK(3, 2)
+#define SYV682X_DSG_RON_SHIFT 2
+#define SYV682X_DSG_RON_200_OHM 0
+#define SYV682X_DSG_RON_400_OHM 1
+#define SYV682X_DSG_RON_800_OHM 2
+#define SYV682X_DSG_RON_1600_OHM 3
#define SYV682X_CONTROL_2_SDSG BIT(1)
#define SYV682X_CONTROL_2_FDSG BIT(0)