summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--baseboard/octopus/baseboard.h1
-rw-r--r--baseboard/octopus/variant_usbc_ec_tcpcs.c2
-rw-r--r--board/ampton/board.c4
-rw-r--r--driver/tcpm/ps8xxx.c107
-rw-r--r--driver/tcpm/tcpci.c2
-rw-r--r--include/config.h11
-rw-r--r--include/driver/tcpm/ps8xxx_public.h8
-rw-r--r--include/driver/tcpm/tcpci.h1
8 files changed, 132 insertions, 4 deletions
diff --git a/baseboard/octopus/baseboard.h b/baseboard/octopus/baseboard.h
index c342e48687..420f6f6715 100644
--- a/baseboard/octopus/baseboard.h
+++ b/baseboard/octopus/baseboard.h
@@ -184,6 +184,7 @@
#define CONFIG_USB_PD_TCPM_ITE_ON_CHIP /* C0 & C1 TCPC: ITE EC */
#define CONFIG_USB_MUX_IT5205 /* C0 MUX: IT5205 */
#define CONFIG_USB_PD_TCPM_PS8751 /* C1 Mux: PS8751 */
+ #define CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER
#define CONFIG_USBC_PPC_SN5S330 /* C0 & C1 PPC: each SN5S330 */
#define CONFIG_USBC_PPC_VCONN
#define CONFIG_USBC_PPC_DEDICATED_INT
diff --git a/baseboard/octopus/variant_usbc_ec_tcpcs.c b/baseboard/octopus/variant_usbc_ec_tcpcs.c
index c9d191438a..fa34ffaf18 100644
--- a/baseboard/octopus/variant_usbc_ec_tcpcs.c
+++ b/baseboard/octopus/variant_usbc_ec_tcpcs.c
@@ -80,7 +80,7 @@ struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_MAX_COUNT] = {
.i2c_port = I2C_PORT_USBC1,
.i2c_addr_flags = PS8751_I2C_ADDR1_FLAGS,
.flags = USB_MUX_FLAG_NOT_TCPC,
- .driver = &tcpci_tcpm_usb_mux_driver,
+ .driver = &ps8xxx_usb_mux_driver,
.hpd_update = &ps8xxx_tcpc_update_hpd_status,
}
};
diff --git a/board/ampton/board.c b/board/ampton/board.c
index 42c5a2351d..b2984036cd 100644
--- a/board/ampton/board.c
+++ b/board/ampton/board.c
@@ -76,7 +76,7 @@ const struct usb_mux ampton_usb_muxes[CONFIG_USB_PD_PORT_MAX_COUNT] = {
.i2c_port = I2C_PORT_USBC0,
.i2c_addr_flags = PS8751_I2C_ADDR1_FLAGS,
.flags = USB_MUX_FLAG_NOT_TCPC,
- .driver = &tcpci_tcpm_usb_mux_driver,
+ .driver = &ps8xxx_usb_mux_driver,
.hpd_update = &ps8xxx_tcpc_update_hpd_status,
.board_init = &tune_mux,
},
@@ -86,7 +86,7 @@ const struct usb_mux ampton_usb_muxes[CONFIG_USB_PD_PORT_MAX_COUNT] = {
.i2c_port = I2C_PORT_USBC1,
.i2c_addr_flags = PS8751_I2C_ADDR1_FLAGS,
.flags = USB_MUX_FLAG_NOT_TCPC,
- .driver = &tcpci_tcpm_usb_mux_driver,
+ .driver = &ps8xxx_usb_mux_driver,
.hpd_update = &ps8xxx_tcpc_update_hpd_status,
.board_init = &tune_mux,
}
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c
index ba79cb5c3b..8390815c76 100644
--- a/driver/tcpm/ps8xxx.c
+++ b/driver/tcpm/ps8xxx.c
@@ -48,6 +48,13 @@
#endif /* CONFIG_USB_PD_TCPM_PS8751 */
+#ifdef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER
+#if !defined(CONFIG_USB_PD_TCPM_PS8751)
+#error "Custom MUX driver is available only for PS8751"
+#endif
+
+#endif /* CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER */
+
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
@@ -76,6 +83,8 @@ static bool ps8815_role_control_delay[CONFIG_USB_PD_PORT_MAX_COUNT];
*/
static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT];
+void ps8xxx_wake_from_standby(const struct usb_mux *me);
+
#if defined(CONFIG_USB_PD_TCPM_PS8705) || \
defined(CONFIG_USB_PD_TCPM_PS8751) || \
defined(CONFIG_USB_PD_TCPM_PS8755) || \
@@ -300,6 +309,11 @@ void ps8xxx_tcpc_update_hpd_status(const struct usb_mux *me,
{
int port = me->usb_port;
+ if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER) &&
+ product_id[me->usb_port] == PS8751_PRODUCT_ID &&
+ me->flags & USB_MUX_FLAG_NOT_TCPC)
+ ps8xxx_wake_from_standby(me);
+
dp_set_hpd(me, hpd_lvl);
if (hpd_irq) {
@@ -640,3 +654,96 @@ struct i2c_stress_test_dev ps8xxx_i2c_stress_test_dev = {
.i2c_write = &tcpc_i2c_write,
};
#endif /* CONFIG_CMD_I2C_STRESS_TEST_TCPC */
+
+#ifdef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER
+
+static int ps8xxx_mux_init(const struct usb_mux *me)
+{
+ RETURN_ERROR(tcpci_tcpm_mux_init(me));
+
+ /* If this MUX is also the TCPC, then skip init */
+ if (!(me->flags & USB_MUX_FLAG_NOT_TCPC))
+ return EC_SUCCESS;
+
+ product_id[me->usb_port] = board_get_ps8xxx_product_id(me->usb_port);
+
+ return EC_SUCCESS;
+}
+
+/*
+ * PS8751 goes to standby mode automatically when both CC lines are set to RP.
+ * In standby mode it doesn't respond to first I2C access, but next
+ * transactions are working fine (until it goes to sleep again).
+ *
+ * To wake device documentation recommends read content of 0xA0 register.
+ */
+void ps8xxx_wake_from_standby(const struct usb_mux *me)
+{
+ int reg;
+
+ /* Since we are waking up device, this call will most likely fail */
+ mux_read(me, PS8XXX_REG_I2C_DEBUGGING_ENABLE, &reg);
+ msleep(10);
+}
+
+static int ps8xxx_mux_set(const struct usb_mux *me, mux_state_t mux_state)
+{
+
+ if (product_id[me->usb_port] == PS8751_PRODUCT_ID &&
+ me->flags & USB_MUX_FLAG_NOT_TCPC) {
+ ps8xxx_wake_from_standby(me);
+
+ /*
+ * To operate properly, when working as mux only, PS8751 CC
+ * lines needs to be RD all the time. Changing to RP after
+ * setting mux breaks SuperSpeed connection.
+ */
+ if (mux_state != USB_PD_MUX_NONE)
+ RETURN_ERROR(mux_write(me, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP,
+ TYPEC_RP_USB,
+ TYPEC_CC_RD,
+ TYPEC_CC_RD)));
+ }
+
+ return tcpci_tcpm_mux_set(me, mux_state);
+}
+
+static int ps8xxx_mux_get(const struct usb_mux *me, mux_state_t *mux_state)
+{
+ if (product_id[me->usb_port] == PS8751_PRODUCT_ID &&
+ me->flags & USB_MUX_FLAG_NOT_TCPC)
+ ps8xxx_wake_from_standby(me);
+
+ return tcpci_tcpm_mux_get(me, mux_state);
+}
+
+static int ps8xxx_mux_enter_low_power(const struct usb_mux *me)
+{
+ /*
+ * Set PS8751 lines to RP. This allows device to standby
+ * automatically after ~2 seconds
+ */
+ if (product_id[me->usb_port] == PS8751_PRODUCT_ID &&
+ me->flags & USB_MUX_FLAG_NOT_TCPC) {
+ /*
+ * It may happen that this write will fail, but
+ * RP seems to be set correctly
+ */
+ mux_write(me, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, TYPEC_RP_USB,
+ TYPEC_CC_RP, TYPEC_CC_RP));
+ return EC_SUCCESS;
+ }
+
+ return tcpci_tcpm_mux_enter_low_power(me);
+}
+
+const struct usb_mux_driver ps8xxx_usb_mux_driver = {
+ .init = &ps8xxx_mux_init,
+ .set = &ps8xxx_mux_set,
+ .get = &ps8xxx_mux_get,
+ .enter_low_power_mode = &ps8xxx_mux_enter_low_power,
+};
+
+#endif /* CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER */
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index 0f03f06a35..36f4cf4085 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -1498,7 +1498,7 @@ int tcpci_tcpm_mux_init(const struct usb_mux *me)
return error ? EC_ERROR_UNKNOWN : EC_SUCCESS;
}
-static int tcpci_tcpm_mux_enter_low_power(const struct usb_mux *me)
+int tcpci_tcpm_mux_enter_low_power(const struct usb_mux *me)
{
/* If this MUX is also the TCPC, then skip low power */
if (!(me->flags & USB_MUX_FLAG_NOT_TCPC))
diff --git a/include/config.h b/include/config.h
index 0775614ddf..d5245403e3 100644
--- a/include/config.h
+++ b/include/config.h
@@ -4292,6 +4292,17 @@
#undef CONFIG_USB_PD_TCPM_PS8815
/*
+ * Enable PS8751 custom mux driver. It was designed to make use of Low Power
+ * Mode on PS8751 TCPC/MUX chip when running as MUX only (CC lines are not
+ * connected, eg. Ampton).
+ *
+ * If your PS8751 is working in the ordinary way (as TCPC and MUX) or you don't
+ * need to take advantage of Low Power Mode when working as MUX only, standard
+ * TCPC MUX driver (CONFIG_USB_PD_TCPM_MUX) will work fine.
+ */
+#undef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER
+
+/*
* Defined automatically by chip and depends on chip. This guards the onboard
* TCPM driver, but CONFIG_USB_PD_TCPM_ITE_ON_CHIP needs to be defined in
* board.h for either of these driver to actually be included in the final
diff --git a/include/driver/tcpm/ps8xxx_public.h b/include/driver/tcpm/ps8xxx_public.h
index 84ca9511cb..e2393fa5d1 100644
--- a/include/driver/tcpm/ps8xxx_public.h
+++ b/include/driver/tcpm/ps8xxx_public.h
@@ -63,4 +63,12 @@ void ps8xxx_tcpc_update_hpd_status(const struct usb_mux *me,
extern struct i2c_stress_test_dev ps8xxx_i2c_stress_test_dev;
#endif /* defined(CONFIG_CMD_I2C_STRESS_TEST_TCPC) */
+/*
+ * This driver was designed to use Low Power Mode on PS8751 TCPC/MUX chip
+ * when running as MUX only (CC lines are not connected, eg. Ampton).
+ * To achieve this RP on CC lines is set when device should enter LPM and
+ * RD when mux should work.
+ */
+extern const struct usb_mux_driver ps8xxx_usb_mux_driver;
+
#endif /* __CROS_EC_DRIVER_TCPM_PS8XXX_PUBLIC_H */
diff --git a/include/driver/tcpm/tcpci.h b/include/driver/tcpm/tcpci.h
index 8e2d288fa0..0dc5dadc6a 100644
--- a/include/driver/tcpm/tcpci.h
+++ b/include/driver/tcpm/tcpci.h
@@ -278,6 +278,7 @@ int tcpci_tcpc_debug_accessory(int port, bool enable);
int tcpci_tcpm_mux_init(const struct usb_mux *me);
int tcpci_tcpm_mux_set(const struct usb_mux *me, mux_state_t mux_state);
int tcpci_tcpm_mux_get(const struct usb_mux *me, mux_state_t *mux_state);
+int tcpci_tcpm_mux_enter_low_power(const struct usb_mux *me);
int tcpci_get_chip_info(int port, int live,
struct ec_response_pd_chip_info_v1 *chip_info);
#ifdef CONFIG_USBC_PPC