summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2018-08-01 16:55:20 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-09-04 21:03:58 -0700
commit50c762e0425570fab9b5a4eef13c3c76131bb1ff (patch)
tree464793ed291f2f0505a7cc37031cc1c641800581
parent4c1841b9f30a733c3bcb5fc5ed9b9bf3d7d61c19 (diff)
downloadchrome-ec-50c762e0425570fab9b5a4eef13c3c76131bb1ff.tar.gz
ppc: Add driver for Silergy SYV682x PPC
Initial version of driver for Silergy SYV682x PPC. This version of the driver does not support the Alert line from the SYV682x. Alert will need to be support for FRS and to detect OVP or OC cases that cause the power path to be disabled. BUG=b:111281797 BRANCH=none TEST=Tested on DragonEgg and verified that can attach as both sink or source port. Change-Id: Ia0450db666b50f90d6e074024bd9b89ea7d50ed6 Signed-off-by: Scott Collyer <scollyer@google.com> Reviewed-on: https://chromium-review.googlesource.com/1159828 Commit-Ready: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Furquan Shaikh <furquan@chromium.org>
-rw-r--r--driver/build.mk1
-rw-r--r--driver/ppc/syv682x.c326
-rw-r--r--driver/ppc/syv682x.h68
-rw-r--r--include/config.h1
4 files changed, 396 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk
index ad3283ce3c..f95d80748d 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -126,6 +126,7 @@ driver-$(CONFIG_USB_MUX_VIRTUAL)+=usb_mux_virtual.o
# Type-C Power Path Controllers (PPC)
driver-$(CONFIG_USBC_PPC_SN5S330)+=ppc/sn5s330.o
+driver-$(CONFIG_USBC_PPC_SYV682X)+=ppc/syv682x.o
driver-$(CONFIG_USBC_PPC_NX20P3483)+=ppc/nx20p348x.o
# video converters
diff --git a/driver/ppc/syv682x.c b/driver/ppc/syv682x.c
new file mode 100644
index 0000000000..c15bb3d19b
--- /dev/null
+++ b/driver/ppc/syv682x.c
@@ -0,0 +1,326 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Silergy SYV682x USB-C Power Path Controller */
+#include "common.h"
+#include "console.h"
+#include "driver/ppc/syv682x.h"
+#include "i2c.h"
+#include "usb_pd_tcpm.h"
+#include "usbc_ppc.h"
+#include "util.h"
+
+#define SYV682X_FLAGS_SOURCE_ENABLED (1 << 0)
+/* 0 -> CC1, 1 -> CC2 */
+#define SYV682X_FLAGS_CC_POLARITY (1 << 1)
+static uint8_t flags[CONFIG_USB_PD_PORT_COUNT];
+
+#define SYV682X_VBUS_DET_THRESH_MV 4000
+
+static int read_reg(uint8_t port, int reg, int *regval)
+{
+ return i2c_read8(ppc_chips[port].i2c_port,
+ ppc_chips[port].i2c_addr,
+ reg,
+ regval);
+}
+
+static int write_reg(uint8_t port, int reg, int regval)
+{
+ return i2c_write8(ppc_chips[port].i2c_port,
+ ppc_chips[port].i2c_addr,
+ reg,
+ regval);
+}
+
+static int syv682x_is_sourcing_vbus(int port)
+{
+ return flags[port] & SYV682X_FLAGS_SOURCE_ENABLED;
+}
+
+static int syv682x_vbus_sink_enable(int port, int enable)
+{
+ int regval;
+ int rv;
+
+ /*
+ * For sink mode need to make sure high voltage power path is connected
+ * and sink mode is selected.
+ */
+ rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
+ if (rv)
+ return rv;
+
+ if (enable) {
+ /* Select high voltage path */
+ regval |= SYV682X_CONTROL_1_CH_SEL;
+ /* Select Sink mode and turn on the channel */
+ regval &= ~(SYV682X_CONTROL_1_HV_DR |
+ SYV682X_CONTROL_1_PWR_ENB);
+ } else {
+ /*
+ * No need to change the voltage path or channel direction. But,
+ * turn both paths off.
+ */
+ regval |= SYV682X_CONTROL_1_PWR_ENB;
+ }
+
+ return write_reg(port, SYV682X_CONTROL_1_REG, regval);
+}
+
+#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC
+static int syv682x_is_vbus_present(int port)
+{
+ int val;
+ int vbus = 0;
+
+ /*
+ * TODO (b/112661747): This PPC doesn't fully support VBUS detection.
+ * It can detect both VSafe5V and VSafe0V. This function is intended
+ * here until detecting VBUS differently per channel is supported.
+ */
+ if (read_reg(port, SYV682X_STATUS_REG, &val))
+ return vbus;
+
+ /*
+ * VBUS is considered present if VSafe5V is detected or neither VSafe5V
+ * or VSafe0V is detected, which implies VBUS > 5V.
+ */
+ if ((val & SYV682X_STATUS_VSAFE_5V) ||
+ !(val & (SYV682X_STATUS_VSAFE_5V | SYV682X_STATUS_VSAFE_0V)))
+ vbus = 1;
+
+ return vbus;
+}
+#endif
+
+static int syv682x_vbus_source_enable(int port, int enable)
+{
+ int regval;
+ int rv;
+
+ /*
+ * For source mode need to make sure 5V power path is connected
+ * and source mode is selected.
+ */
+ rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
+ if (rv)
+ return rv;
+
+ if (enable) {
+ /* Select 5V path and turn on channel */
+ regval &= ~(SYV682X_CONTROL_1_CH_SEL |
+ SYV682X_CONTROL_1_PWR_ENB);
+ /* Disable HV Sink path */
+ regval |= SYV682X_CONTROL_1_HV_DR;
+ } else {
+ /*
+ * No need to change the voltage path or channel direction. But,
+ * turn both paths off.
+ */
+ regval |= SYV682X_CONTROL_1_PWR_ENB;
+ }
+
+ rv = write_reg(port, SYV682X_CONTROL_1_REG, regval);
+ if (rv)
+ return rv;
+
+ if (enable)
+ flags[port] |= SYV682X_FLAGS_SOURCE_ENABLED;
+ else
+ flags[port] &= ~SYV682X_FLAGS_SOURCE_ENABLED;
+
+ return EC_SUCCESS;
+}
+
+static int syv682x_set_vbus_source_current_limit(int port,
+ enum tcpc_rp_value rp)
+{
+ int rv;
+ int limit;
+ int regval;
+
+ rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
+ if (rv)
+ return rv;
+
+ /* We need buffer room for all current values. */
+ switch (rp) {
+ case TYPEC_RP_3A0:
+ limit = SYV682X_ILIM_3_30;
+ break;
+
+ case TYPEC_RP_1A5:
+ limit = SYV682X_ILIM_1_75;
+ break;
+
+ case TYPEC_RP_USB:
+ default:
+ /* 1.25 A is lowest current limit setting for SVY682 */
+ limit = SYV682X_ILIM_1_25;
+ break;
+ };
+
+ regval &= ~SYV682X_ILIM_MASK;
+ regval |= (limit << SYV682X_ILIM_BIT_SHIFT);
+ return write_reg(port, SYV682X_CONTROL_1_REG, regval);
+}
+
+static int syv682x_discharge_vbus(int port, int enable)
+{
+ int regval;
+ int rv;
+
+ rv = read_reg(port, SYV682X_CONTROL_2_REG, &regval);
+ if (rv)
+ return rv;
+
+ if (enable)
+ regval |= SYV682X_CONTROL_2_FDSG;
+ else
+ regval &= ~SYV682X_CONTROL_2_FDSG;
+
+ return write_reg(port, SYV682X_CONTROL_2_REG, regval);
+}
+
+#ifdef CONFIG_USBC_PPC_POLARITY
+static int syv682x_set_polarity(int port, int polarity)
+{
+ /*
+ * The SYV682x does not explicitly set CC polarity. However, if VCONN is
+ * being used then the polarity is required to connect 5V to the correct
+ * CC line. So this function saves the CC polarity as a bit in the flags
+ * variable so VCONN is connected the correct CC line. The flag bit
+ * being set means polarity = CC2, the flag bit clear means
+ * polarity = CC1.
+ */
+ if (polarity)
+ flags[port] |= SYV682X_FLAGS_CC_POLARITY;
+ else
+ flags[port] &= ~SYV682X_FLAGS_CC_POLARITY;
+
+ return EC_SUCCESS;
+}
+#endif
+
+#ifdef CONFIG_USBC_PPC_VCONN
+static int syv682x_set_vconn(int port, int enable)
+{
+ int regval;
+ int rv;
+
+ rv = read_reg(port, SYV682X_CONTROL_4_REG, &regval);
+ if (rv)
+ return rv;
+
+ if (enable)
+ regval |= flags[port] & SYV682X_FLAGS_CC_POLARITY ?
+ SYV682X_CONTROL_4_VCONN1 : SYV682X_CONTROL_4_VCONN2;
+ else
+ regval &= ~(SYV682X_CONTROL_4_VCONN2 |
+ SYV682X_CONTROL_4_VCONN1);
+
+ return write_reg(port, SYV682X_CONTROL_4_REG, regval);
+}
+#endif
+
+#ifdef CONFIG_CMD_PPC_DUMP
+static int syv682x_dump(int port)
+{
+ int reg_addr;
+ int data;
+ int rv;
+ const int i2c_port = ppc_chips[port].i2c_port;
+ const int i2c_addr = ppc_chips[port].i2c_addr;
+
+ for (reg_addr = SYV682X_STATUS_REG; reg_addr <= SYV682X_CONTROL_4_REG;
+ reg_addr++) {
+ rv = i2c_read8(i2c_port, i2c_addr, reg_addr, &data);
+ if (rv)
+ ccprintf("ppc_syv682[p%d]: Failed to read reg 0x%02x\n",
+ port, reg_addr);
+ else
+ ccprintf("ppc_syv682[p%d]: reg 0x%02x = 0x%02x\n",
+ port, reg_addr, data);
+ }
+
+ cflush();
+
+ return EC_SUCCESS;
+}
+#endif /* defined(CONFIG_CMD_PPC_DUMP) */
+
+static int syv682x_init(int port)
+{
+ int rv;
+ int regval;
+
+ /* Set VBUS discharge to manual mode */
+ rv = read_reg(port, SYV682X_CONTROL_2_REG, &regval);
+ if (rv)
+ return rv;
+ regval &= ~SYV682X_CONTROL_2_SDSG;
+ rv = write_reg(port, SYV682X_CONTROL_2_REG, regval);
+ if (rv)
+ return rv;
+
+ /* 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);
+ if (rv)
+ return rv;
+
+ /* Check if this if dead battery case */
+ rv = read_reg(port, SYV682X_CONTROL_1_REG, &regval);
+ if (rv)
+ return rv;
+ if (regval & SYV682X_STATUS_VSAFE_0V) {
+ /* Not dead battery case, so disable channel */
+ regval |= SYV682X_CONTROL_1_PWR_ENB;
+ rv = write_reg(port, SYV682X_CONTROL_1_REG, regval);
+ if (rv)
+ return rv;
+ } else {
+ syv682x_vbus_sink_enable(port, 1);
+ }
+
+ rv = read_reg(port, SYV682X_CONTROL_4_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;
+ rv = write_reg(port, SYV682X_CONTROL_4_REG, regval);
+ if (rv)
+ return rv;
+
+ return EC_SUCCESS;
+}
+
+const struct ppc_drv syv682x_drv = {
+ .init = &syv682x_init,
+ .is_sourcing_vbus = &syv682x_is_sourcing_vbus,
+ .vbus_sink_enable = &syv682x_vbus_sink_enable,
+ .vbus_source_enable = &syv682x_vbus_source_enable,
+#ifdef CONFIG_CMD_PPC_DUMP
+ .reg_dump = &syv682x_dump,
+#endif /* defined(CONFIG_CMD_PPC_DUMP) */
+#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC
+ .is_vbus_present = &syv682x_is_vbus_present,
+#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */
+ .set_vbus_source_current_limit = &syv682x_set_vbus_source_current_limit,
+ .discharge_vbus = &syv682x_discharge_vbus,
+#ifdef CONFIG_USBC_PPC_POLARITY
+ .set_polarity = &syv682x_set_polarity,
+#endif
+#ifdef CONFIG_USBC_PPC_VCONN
+ .set_vconn = &syv682x_set_vconn,
+#endif
+};
diff --git a/driver/ppc/syv682x.h b/driver/ppc/syv682x.h
new file mode 100644
index 0000000000..5188a75b79
--- /dev/null
+++ b/driver/ppc/syv682x.h
@@ -0,0 +1,68 @@
+/* Copyright 2018 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Silergy SYV682x Type-C Power Path Controller */
+
+#ifndef __CROS_EC_SYV682X_H
+#define __CROS_EC_SYV682X_H
+
+/* 8 bit I2C addresses */
+#define SYV682X_ADDR0 0x80
+#define SYV682X_ADDR1 0x82
+#define SYV682X_ADDR2 0x84
+#define SYV682x_ADDR3 0x86
+
+/* SYV682x register addresses */
+#define SYV682X_STATUS_REG 0x00
+#define SYV682X_CONTROL_1_REG 0x01
+#define SYV682X_CONTROL_2_REG 0x02
+#define SYV682X_CONTROL_3_REG 0x03
+#define SYV682X_CONTROL_4_REG 0x04
+
+/* Status Register */
+#define SYV682X_STATUS_VSAFE_5V (1 << 1)
+#define SYV682X_STATUS_VSAFE_0V (1 << 0)
+
+/* Control Register 1 */
+#define SYV682X_CONTROL_1_CH_SEL (1 << 1)
+#define SYV682X_CONTROL_1_HV_DR (1 << 2)
+#define SYV682X_CONTROL_1_PWR_ENB (1 << 7)
+
+#define SYV682X_ILIM_MASK 0x18
+#define SYV682X_ILIM_BIT_SHIFT 3
+#define SYV682X_ILIM_1_25 0
+#define SYV682X_ILIM_1_75 1
+#define SYV682X_ILIM_2_25 2
+#define SYV682X_ILIM_3_30 3
+
+/* Control Register 2 */
+#define SYV682X_CONTROL_2_SDSG (1 << 1)
+#define SYV682X_CONTROL_2_FDSG (1 << 0)
+
+/* Control Register 3 */
+#define SYV682X_OVP_MASK 0x70
+#define SYV682X_OVP_BIT_SHIFT 4
+#define SYV682X_OVP_06_0 0
+#define SYV682X_OVP_08_0 1
+#define SYV682X_OVP_11_1 2
+#define SYV682X_OVP_12_1 3
+#define SYV682X_OVP_14_2 4
+#define SYV682X_OVP_17_9 5
+#define SYV682X_OVP_21_6 6
+#define SYV682X_OVP_23_7 7
+
+/* Control Register 4 */
+#define SYV682X_CONTROL_4_CC1_BPS (1 << 7)
+#define SYV682X_CONTROL_4_CC2_BPS (1 << 6)
+#define SYV682X_CONTROL_4_VCONN1 (1 << 5)
+#define SYV682X_CONTROL_4_VCONN2 (1 << 4)
+#define SYV682X_CONTROL_4_VBAT_OVP (1 << 3)
+#define SYV682X_CONTROL_4_VCONN_OCP (1 << 2)
+#define SYV682X_CONTROL_4_CC_FRS (1 << 1)
+
+struct ppc_drv;
+extern const struct ppc_drv syv682x_drv;
+
+#endif /* defined(__CROS_EC_SYV682X_H) */
diff --git a/include/config.h b/include/config.h
index 261628c996..0aedd97799 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3252,6 +3252,7 @@
/* USB Type-C Power Path Controllers (PPC) */
#undef CONFIG_USBC_PPC_NX20P3483
#undef CONFIG_USBC_PPC_SN5S330
+#undef CONFIG_USBC_PPC_SYV682X
/* PPC is capable of providing VCONN */
#undef CONFIG_USBC_PPC_VCONN