diff options
Diffstat (limited to 'driver')
-rw-r--r-- | driver/tcpm/nct38xx.c | 21 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 45 | ||||
-rw-r--r-- | driver/tcpm/tcpci.h | 55 |
3 files changed, 99 insertions, 22 deletions
diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c index 8061f7190c..1196621e71 100644 --- a/driver/tcpm/nct38xx.c +++ b/driver/tcpm/nct38xx.c @@ -64,15 +64,29 @@ static int nct38xx_tcpm_init(int port) if (rv) return rv; - /* Enable VBus monitor */ + /* Enable VBus monitor and Disable FRS */ rv = tcpc_read(port, TCPC_REG_POWER_CTRL, ®); if (rv) return rv; - reg = reg & ~TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS; + reg = reg & ~(TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS | + TCPC_REG_POWER_CTRL_FRS_ENABLE); rv = tcpc_write(port, TCPC_REG_POWER_CTRL, reg); if (rv) return rv; + /* Set FRS direction for SNK detect, if FRS is enabled */ + if (IS_ENABLED(CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP)) { + reg = TCPC_REG_DEV_CAP_2_SNK_FR_SWAP; + rv = tcpc_write(port, TCPC_REG_DEV_CAP_2, reg); + if (rv) + return rv; + + reg = TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR; + rv = tcpc_write(port, TCPC_REG_CONFIG_EXT_1, reg); + if (rv) + return rv; + } + /* Start VBus monitor */ rv = tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); @@ -364,4 +378,7 @@ const struct tcpm_drv nct38xx_tcpm_drv = { #ifdef CONFIG_USB_PD_TCPC_LOW_POWER .enter_low_power_mode = &tcpci_enter_low_power_mode, #endif +#ifdef CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP + .set_frs_enable = &tcpci_tcpc_fast_role_swap_enable, +#endif }; diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 5d5bf4499a..257649fc66 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -146,6 +146,7 @@ int tcpc_xfer_unlocked(int port, const uint8_t *out, int out_size, static int init_alert_mask(int port) { + int rv; uint16_t mask; /* @@ -160,7 +161,17 @@ static int init_alert_mask(int port) #endif ; /* Set the alert mask in TCPC */ - return tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); + rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); + + if (IS_ENABLED(CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP)) { + if (rv) + return rv; + + /* Sink FRS allowed */ + mask = TCPC_REG_ALERT_EXT_SNK_FRS; + rv = tcpc_write(port, TCPC_REG_ALERT_EXT, mask); + } + return rv; } static int clear_alert_mask(int port) @@ -345,6 +356,12 @@ static int tcpm_alert_status(int port, int *alert) return tcpc_read16(port, TCPC_REG_ALERT, alert); } +static int tcpm_alert_ext_status(int port, int *alert_ext) +{ + /* Read TCPC Extended Alert register */ + return tcpc_read(port, TCPC_REG_ALERT_EXT, alert_ext); +} + int tcpci_tcpm_set_rx_enable(int port, int enable) { int detect_sop_en = 0; @@ -371,6 +388,23 @@ int tcpci_tcpm_set_rx_enable(int port, int enable) return tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en); } +#ifdef CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP +void tcpci_tcpc_fast_role_swap_enable(int port, int enable) +{ + int reg; + + if (tcpc_read(port, TCPC_REG_POWER_CTRL, ®)) + return; + + if (enable) + reg |= TCPC_REG_POWER_CTRL_FRS_ENABLE; + else + reg &= ~TCPC_REG_POWER_CTRL_FRS_ENABLE; + + tcpc_write(port, TCPC_REG_POWER_CTRL, reg); +} +#endif + #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC int tcpci_tcpm_get_vbus_level(int port) { @@ -579,12 +613,17 @@ static int register_mask_reset(int port) void tcpci_tcpc_alert(int port) { int status = 0; + int alert_ext = 0; int failed_attempts; uint32_t pd_event = 0; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); + /* Get Extended Alert register if needed */ + if (status & TCPC_REG_ALERT_ALERT_EXT) + tcpm_alert_ext_status(port, &alert_ext); + /* * Check for TX complete first b/c PD state machine waits on TX * completion events. This will send an event to the PD tasks @@ -645,6 +684,10 @@ void tcpci_tcpc_alert(int port) pd_event |= TASK_EVENT_WAKE; } + if (IS_ENABLED(CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP) + && (alert_ext & TCPC_REG_ALERT_EXT_SNK_FRS)) + pd_got_frs_signal(port); + #ifndef CONFIG_USB_PD_TCPC_LOW_POWER /* * Check registers to see if we can tell that the TCPC has reset. If diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h index 491fe195ed..930bfd6d70 100644 --- a/driver/tcpm/tcpci.h +++ b/driver/tcpm/tcpci.h @@ -18,22 +18,23 @@ #define TCPC_REG_TC_REV 0x6 #define TCPC_REG_PD_REV 0x8 #define TCPC_REG_PD_INT_REV 0xa -#define TCPC_REG_ALERT 0x10 +#define TCPC_REG_ALERT 0x10 #define TCPC_REG_ALERT_MASK_ALL 0xffff -#define TCPC_REG_ALERT_VENDOR_DEF (1<<15) -#define TCPC_REG_ALERT_VBUS_DISCNCT (1<<11) -#define TCPC_REG_ALERT_RX_BUF_OVF (1<<10) -#define TCPC_REG_ALERT_FAULT (1<<9) -#define TCPC_REG_ALERT_V_ALARM_LO (1<<8) -#define TCPC_REG_ALERT_V_ALARM_HI (1<<7) -#define TCPC_REG_ALERT_TX_SUCCESS (1<<6) -#define TCPC_REG_ALERT_TX_DISCARDED (1<<5) -#define TCPC_REG_ALERT_TX_FAILED (1<<4) -#define TCPC_REG_ALERT_RX_HARD_RST (1<<3) -#define TCPC_REG_ALERT_RX_STATUS (1<<2) -#define TCPC_REG_ALERT_POWER_STATUS (1<<1) -#define TCPC_REG_ALERT_CC_STATUS (1<<0) +#define TCPC_REG_ALERT_VENDOR_DEF BIT(15) +#define TCPC_REG_ALERT_ALERT_EXT BIT(14) +#define TCPC_REG_ALERT_VBUS_DISCNCT BIT(11) +#define TCPC_REG_ALERT_RX_BUF_OVF BIT(10) +#define TCPC_REG_ALERT_FAULT BIT(9) +#define TCPC_REG_ALERT_V_ALARM_LO BIT(8) +#define TCPC_REG_ALERT_V_ALARM_HI BIT(7) +#define TCPC_REG_ALERT_TX_SUCCESS BIT(6) +#define TCPC_REG_ALERT_TX_DISCARDED BIT(5) +#define TCPC_REG_ALERT_TX_FAILED BIT(4) +#define TCPC_REG_ALERT_RX_HARD_RST BIT(3) +#define TCPC_REG_ALERT_RX_STATUS BIT(2) +#define TCPC_REG_ALERT_POWER_STATUS BIT(1) +#define TCPC_REG_ALERT_CC_STATUS BIT(0) #define TCPC_REG_ALERT_TX_COMPLETE (TCPC_REG_ALERT_TX_SUCCESS | \ TCPC_REG_ALERT_TX_DISCARDED | \ TCPC_REG_ALERT_TX_FAILED) @@ -41,6 +42,7 @@ #define TCPC_REG_ALERT_MASK 0x12 #define TCPC_REG_POWER_STATUS_MASK 0x14 #define TCPC_REG_FAULT_STATUS_MASK 0x15 + #define TCPC_REG_CONFIG_STD_OUTPUT 0x18 #define TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK (3 << 2) #define TCPC_REG_CONFIG_STD_OUTPUT_MUX_NONE (0 << 2) @@ -65,9 +67,10 @@ #define TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS BIT(1) #define TCPC_REG_POWER_CTRL 0x1c -#define TCPC_REG_POWER_CTRL_FORCE_DISCHARGE BIT(2) -#define TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT BIT(4) +#define TCPC_REG_POWER_CTRL_FRS_ENABLE BIT(7) #define TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS BIT(6) +#define TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT BIT(4) +#define TCPC_REG_POWER_CTRL_FORCE_DISCHARGE BIT(2) #define TCPC_REG_POWER_CTRL_SET(vconn) (vconn) #define TCPC_REG_POWER_CTRL_VCONN(reg) ((reg) & 0x1) @@ -81,11 +84,17 @@ #define TCPC_REG_POWER_STATUS 0x1e #define TCPC_REG_POWER_STATUS_MASK_ALL 0xff -#define TCPC_REG_POWER_STATUS_VBUS_PRES (1<<2) -#define TCPC_REG_POWER_STATUS_VBUS_DET (1<<3) -#define TCPC_REG_POWER_STATUS_UNINIT (1<<6) +#define TCPC_REG_POWER_STATUS_UNINIT BIT(6) +#define TCPC_REG_POWER_STATUS_VBUS_DET BIT(3) +#define TCPC_REG_POWER_STATUS_VBUS_PRES BIT(2) + #define TCPC_REG_FAULT_STATUS 0x1f +#define TCPC_REG_ALERT_EXT 0x21 +#define TCPC_REG_ALERT_EXT_TIMER_EXPIRED BIT(2) +#define TCPC_REG_ALERT_EXT_SRC_FRS BIT(1) +#define TCPC_REG_ALERT_EXT_SNK_FRS BIT(0) + #define TCPC_REG_COMMAND 0x23 #define TCPC_REG_COMMAND_ENABLE_VBUS_DETECT 0x33 #define TCPC_REG_COMMAND_SNK_CTRL_LOW 0x44 @@ -96,10 +105,16 @@ #define TCPC_REG_COMMAND_I2CIDLE 0xFF #define TCPC_REG_DEV_CAP_1 0x24 + #define TCPC_REG_DEV_CAP_2 0x26 +#define TCPC_REG_DEV_CAP_2_SNK_FR_SWAP BIT(9) + #define TCPC_REG_STD_INPUT_CAP 0x28 #define TCPC_REG_STD_OUTPUT_CAP 0x29 +#define TCPC_REG_CONFIG_EXT_1 0x2A +#define TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR BIT(1) + #define TCPC_REG_MSG_HDR_INFO 0x2e #define TCPC_REG_MSG_HDR_INFO_SET(drole, prole) \ ((drole) << 3 | (PD_REV20 << 1) | (prole)) @@ -171,4 +186,6 @@ int tcpci_tcpm_set_snk_ctrl(int port, int enable); int tcpci_tcpm_set_src_ctrl(int port, int enable); #endif +void tcpci_tcpc_fast_role_swap_enable(int port, int enable); + #endif /* __CROS_EC_USB_PD_TCPM_TCPCI_H */ |