summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2018-08-16 10:06:19 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-09-13 18:58:35 -0700
commita68497b87a0fcdfa1e4130600687fdb40430df84 (patch)
tree944ff0753b669173ea153f212e5299ee0ac21652
parentab54765cf1c71d1f1a91ab08d68521b29d8fec76 (diff)
downloadchrome-ec-a68497b87a0fcdfa1e4130600687fdb40430df84.tar.gz
ppc: Add support for nx20p3481
This CL is an incremental change to the nx20p348x driver to add support for the nx20p3481 ppc. Sink/source modes are controlled via the switch control register instead of gpio signals. Another difference is that the values of mode in register 0x1 are slightly different between the 3481 and 3483. The 3481 needs to use the switch status register to verify whether it's in sink or source mode. This register is now checked for both the 3483 and 3481. A delay is required for the switch status register to reflect the control setting just applied. In addition, the nx20p3481 supports Fast Role Swap (FRS). For FRS, only the detection is supported, and it's assumed that it's caused by the removal of an external charger, not an actual FRS event. BUG=b:111281797 BRANCH=none TEST=Verified on DragonEgg that port acts correctly as a sink. Have not been able to verify source operation. Change-Id: I2fb4200a5d9c3ce460e9b913a5b09441e458bb7e Signed-off-by: Scott Collyer <scollyer@google.com> Reviewed-on: https://chromium-review.googlesource.com/1178995 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--driver/build.mk3
-rw-r--r--driver/ppc/nx20p348x.c105
-rw-r--r--driver/ppc/nx20p348x.h26
-rw-r--r--include/config.h1
4 files changed, 121 insertions, 14 deletions
diff --git a/driver/build.mk b/driver/build.mk
index 74bf4c573a..50b478ef0d 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -127,6 +127,9 @@ driver-$(CONFIG_USB_MUX_VIRTUAL)+=usb_mux_virtual.o
# Type-C Power Path Controllers (PPC)
driver-$(CONFIG_USBC_PPC_SN5S330)+=ppc/sn5s330.o
+ifeq ($(CONFIG_USBC_PPC_NX20P3481)$(CONFIG_USBC_PPC_NX20P3483),y)
+driver-y += ppc/nx20p348x.o
+endif
driver-$(CONFIG_USBC_PPC_SYV682X)+=ppc/syv682x.o
driver-$(CONFIG_USBC_PPC_NX20P3483)+=ppc/nx20p348x.o
diff --git a/driver/ppc/nx20p348x.c b/driver/ppc/nx20p348x.c
index a5ee9d5e31..48ee5ca9b2 100644
--- a/driver/ppc/nx20p348x.c
+++ b/driver/ppc/nx20p348x.c
@@ -130,25 +130,36 @@ static int nx20p348x_vbus_sink_enable(int port, int enable)
{
int status;
int rv;
- int desired_mode = enable ? NX20P348X_MODE_HV_SNK :
- NX20P348X_MODE_STANDBY;
+ int control = enable ? NX20P348X_SWITCH_CONTROL_HVSNK : 0;
enable = !!enable;
+#if defined(CONFIG_USBC_PPC_NX20P3481)
+ rv = write_reg(port, NX20P348X_SWITCH_CONTROL_REG, control);
+#elif defined(CONFIG_USBC_PPC_NX20P3483)
/*
* We cannot use an EC GPIO for EN_SNK since an EC reset will float the
* GPIO thus browning out the board (without a battery).
*/
rv = tcpm_set_snk_ctrl(port, enable);
+#else
+#error "Either the NX20P3481 or NX20P3483 must be selected"
+#endif
if (rv)
return rv;
- /* Read device status register to get mode */
- rv = read_reg(port, NX20P348X_DEVICE_STATUS_REG, &status);
+ /*
+ * Read switch status register. The bit definitions for switch control
+ * and switch status resister are identical, so the control value can be
+ * compared against the status value. The control switch has a debounce
+ * (15 msec) before the status will reflect the control command.
+ */
+ msleep(NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC);
+ rv = read_reg(port, NX20P348X_SWITCH_STATUS_REG, &status);
if (rv)
return rv;
- return ((status & NX20P348X_DEVICE_MODE_MASK) == desired_mode) ?
+ return (status & NX20P348X_SWITCH_STATUS_MASK) == control ?
EC_SUCCESS : EC_ERROR_UNKNOWN;
}
@@ -156,25 +167,36 @@ static int nx20p348x_vbus_source_enable(int port, int enable)
{
int status;
int rv;
- int desired_mode = enable ? NX20P348X_MODE_5V_SRC :
- NX20P348X_MODE_STANDBY;
+ int control = enable ? NX20P348X_SWITCH_CONTROL_5VSRC : 0;
enable = !!enable;
+#if defined(CONFIG_USBC_PPC_NX20P3481)
+ rv = write_reg(port, NX20P348X_SWITCH_CONTROL_REG, control);
+#elif defined(CONFIG_USBC_PPC_NX20P3483)
/*
* For parity's sake, we should not use an EC GPIO for EN_SRC since we
* cannot use it for EN_SNK (for brown out reason listed above).
*/
rv = tcpm_set_src_ctrl(port, enable);
+#else
+#error "Either the NX20P3481 or NX20P3483 must be selected"
+#endif
if (rv)
return rv;
- /* Read device status register to get mode */
- rv = read_reg(port, NX20P348X_DEVICE_STATUS_REG, &status);
+ /*
+ * Read switch status register. The bit definitions for switch control
+ * and switch status resister are identical, so the control value can be
+ * compared against the status value. The control switch has a debounce
+ * (15 msec) before the status will reflect the control command.
+ */
+ msleep(NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC);
+ rv = read_reg(port, NX20P348X_SWITCH_STATUS_REG, &status);
if (rv)
return rv;
- if ((status & NX20P348X_DEVICE_MODE_MASK) != desired_mode)
+ if ((status & NX20P348X_SWITCH_STATUS_MASK) != control)
return EC_ERROR_UNKNOWN;
/* Cache the Vbus state */
@@ -201,6 +223,10 @@ static int nx20p348x_init(int port)
/* Mask interrupts for interrupt 1 register */
mask = ~(NX20P348X_INT1_OC_5VSRC | NX20P348X_INT1_DBEXIT_ERR);
+#ifdef CONFIG_USBC_PPC_NX20P3481
+ /* Unmask Fast Role Swap detect interrupt */
+ mask &= ~NX20P348X_INT1_FRS_DET;
+#endif
rv = write_reg(port, NX20P348X_INTERRUPT1_MASK_REG, mask);
if (rv)
return rv;
@@ -297,6 +323,28 @@ static void nx20p348x_handle_interrupt(int port)
*/
}
+#ifdef CONFIG_USBC_PPC_NX20P3481
+ /* Check for FRS detection */
+ if (reg & NX20P348X_INT1_FRS_DET) {
+ /*
+ * TODO(b/113069469): Need to check for CC status and verifiy
+ * that a sink is attached to continue with FRS. If a sink is
+ * not attached, then this FRS detect is a false detect which is
+ * triggered when removing an external charger. If FRS was
+ * detected by the PPC, then it has automatically enabled the
+ * 5V SRC mode and this must be undone for a proper detach.
+ */
+ /* Check CC status */
+
+ /*
+ * False detect, disable SRC mode which was enabled by
+ * NX20P3481.
+ */
+ CPRINTS("C%d: PPC FRS false detect, disabling SRC mode!", port);
+ nx20p348x_vbus_source_enable(port, 0);
+ }
+#endif
+
/*
* Read interrupt 2 status register. Note, interrupt register is
* automatically cleared by reading.
@@ -354,6 +402,34 @@ static int nx20p348x_dump(int port)
}
#endif /* defined(CONFIG_CMD_PPC_DUMP) */
+/*
+ * TODO (b/112697473): The NX20P348x PPCs do not support vbus detection or vconn
+ * generation. However, if a different PPC does support these features and needs
+ * these config options, then these functions do need to exist. The
+ * configuration for what each PPC supports should be converted to bits within
+ * a flags variable that is part of the ppc_config_t struct.
+ */
+#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC
+static int nx20p348x_is_vbus_present(int port)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */
+
+#ifdef CONFIG_USBC_PPC_POLARITY
+static int nx20p348x_set_polarity(int port, int polarity)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+#endif
+
+#ifdef CONFIG_USBC_PPC_VCONN
+static int nx20p348x_set_vconn(int port, int enable)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+#endif
+
const struct ppc_drv nx20p348x_drv = {
.init = &nx20p348x_init,
.is_sourcing_vbus = &nx20p348x_is_sourcing_vbus,
@@ -365,4 +441,13 @@ const struct ppc_drv nx20p348x_drv = {
.set_vbus_source_current_limit =
&nx20p348x_set_vbus_source_current_limit,
.discharge_vbus = &nx20p348x_discharge_vbus,
+#ifdef CONFIG_USB_PD_VBUS_DETECT_PPC
+ .is_vbus_present = &nx20p348x_is_vbus_present,
+#endif /* defined(CONFIG_USB_PD_VBUS_DETECT_PPC) */
+#ifdef CONFIG_USBC_PPC_POLARITY
+ .set_polarity = &nx20p348x_set_polarity,
+#endif /* defined(CONFIG_USBC_PPC_POLARITY) */
+#ifdef CONFIG_USBC_PPC_VCONN
+ .set_vconn = &nx20p348x_set_vconn,
+#endif /* defined(CONFIG_USBC_PPC_VCONN) */
};
diff --git a/driver/ppc/nx20p348x.h b/driver/ppc/nx20p348x.h
index 52224b6a8e..68048be6ea 100644
--- a/driver/ppc/nx20p348x.h
+++ b/driver/ppc/nx20p348x.h
@@ -13,6 +13,11 @@
#define NX20P3483_ADDR2 0xE4
#define NX20P3483_ADDR3 0xE6
+#define NX20P3481_ADDR0 0xE8
+#define NX20P3481_ADDR1 0xEA
+#define NX20P3481_ADDR2 0xEC
+#define NX20P3481_ADDR3 0xEE
+
/*
* This PPC hard-codes the over voltage protect of Vbus at 6.8V in dead-battery
* mode. If we ever are every going to drop the PD rail, we need to first ensure
@@ -43,15 +48,27 @@
/* Device Status Modes */
#define NX20P348X_DEVICE_MODE_MASK 0x7
#define NX20P348X_MODE_DEAD_BATTERY 0
-#define NX20P348X_MODE_HV_SNK 1
-#define NX20P348X_MODE_5V_SRC 2
-#define NX20P348X_MODE_HV_SRC 3
-#define NX20P348X_MODE_STANDBY 4
+/* After dead battery, mode values are different between 3481 and 3483 */
+#define NX20P3481_MODE_NORMAL 1
+#define NX20P3481_MODE_FRS 2
+#define NX20P3481_MODE_STANDBY 3
+
+#define NX20P3483_MODE_HV_SNK 1
+#define NX20P3483_MODE_5V_SRC 2
+#define NX20P3483_MODE_HV_SRC 3
+#define NX20P3483_MODE_STANDBY 4
+
+/* Switch Control Register */
+#define NX20P348X_SWITCH_CONTROL_HVSNK (1 << 0)
+#define NX20P348X_SWITCH_CONTROL_HVSRC (1 << 1)
+#define NX20P348X_SWITCH_CONTROL_5VSRC (1 << 2)
/* Switch Status Register */
#define NX20P348X_HVSNK_STS (1 << 0)
#define NX20P348X_HVSRC_STS (1 << 1)
#define NX20P348X_5VSRC_STS (1 << 2)
+#define NX20P348X_SWITCH_STATUS_DEBOUNCE_MSEC 25
+#define NX20P348X_SWITCH_STATUS_MASK 0x7
/* Internal 5V VBUS Switch Current Limit Settings (min) */
#define NX20P348X_ILIM_MASK 0xF
@@ -84,6 +101,7 @@
/* Interrupt 1 Register Bits */
#define NX20P348X_INT1_DBEXIT_ERR (1 << 7)
+#define NX20P348X_INT1_FRS_DET (1 << 6)
#define NX20P348X_INT1_OV_5VSRC (1 << 4)
#define NX20P348X_INT1_RCP_5VSRC (1 << 3)
#define NX20P348X_INT1_SC_5VSRC (1 << 2)
diff --git a/include/config.h b/include/config.h
index b4e2935bd8..179f7cfb51 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3249,6 +3249,7 @@
#undef CONFIG_USBC_PPC_POLARITY
/* USB Type-C Power Path Controllers (PPC) */
+#undef CONFIG_USBC_PPC_NX20P3481
#undef CONFIG_USBC_PPC_NX20P3483
#undef CONFIG_USBC_PPC_SN5S330
#undef CONFIG_USBC_PPC_SYV682X