diff options
-rw-r--r-- | baseboard/octopus/baseboard.h | 1 | ||||
-rw-r--r-- | baseboard/octopus/variant_usbc_ec_tcpcs.c | 2 | ||||
-rw-r--r-- | board/ampton/board.c | 4 | ||||
-rw-r--r-- | driver/tcpm/ps8xxx.c | 107 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 2 | ||||
-rw-r--r-- | include/config.h | 11 | ||||
-rw-r--r-- | include/driver/tcpm/ps8xxx_public.h | 8 | ||||
-rw-r--r-- | include/driver/tcpm/tcpci.h | 1 |
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, ®); + 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 |