summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_protocol.c20
-rw-r--r--common/usb_pd_tcpc.c51
-rw-r--r--driver/tcpm/stub.c6
-rw-r--r--driver/tcpm/tcpci.c73
-rw-r--r--driver/tcpm/tcpci.h1
-rw-r--r--include/config.h7
-rw-r--r--include/usb_pd_tcpc.h8
-rw-r--r--include/usb_pd_tcpm.h19
8 files changed, 167 insertions, 18 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 3b5cd5b445..b124ad0245 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -20,6 +20,7 @@
#include "task.h"
#include "timer.h"
#include "util.h"
+#include "usb_charge.h"
#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpm.h"
@@ -211,6 +212,15 @@ int pd_is_connected(int port)
}
#ifdef CONFIG_USB_PD_DUAL_ROLE
+static inline int pd_is_vbus_present(int port)
+{
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+ return tcpm_get_vbus_level(port);
+#else
+ return pd_snk_is_vbus_provided(port);
+#endif
+}
+
static int pd_snk_debug_acc_toggle(int port)
{
#ifdef CONFIG_CASE_CLOSED_DEBUG
@@ -219,7 +229,7 @@ static int pd_snk_debug_acc_toggle(int port)
* (without having seen Rp before), that might be a powered debug
* accessory, let's toggle to source to try to detect it.
*/
- return pd_snk_is_vbus_provided(port);
+ return pd_is_vbus_present(port);
#else
/* Debug accessories not supported, never toggle */
return 0;
@@ -1966,7 +1976,7 @@ void pd_task(void)
/* Wait for CC debounce and VBUS present */
if (get_time().val < pd[port].cc_debounce ||
- !pd_snk_is_vbus_provided(port))
+ !pd_is_vbus_present(port))
break;
if (pd_try_src_enable &&
@@ -2044,7 +2054,7 @@ void pd_task(void)
PD_STATE_SNK_DISCOVERY);
}
- if (!pd_snk_is_vbus_provided(port) &&
+ if (!pd_is_vbus_present(port) &&
!snk_hard_reset_vbus_off) {
/* VBUS has gone low, reset timeout */
snk_hard_reset_vbus_off = 1;
@@ -2054,7 +2064,7 @@ void pd_task(void)
PD_T_SRC_TURN_ON,
PD_STATE_SNK_DISCONNECTED);
}
- if (pd_snk_is_vbus_provided(port) &&
+ if (pd_is_vbus_present(port) &&
snk_hard_reset_vbus_off) {
/* VBUS went high again */
set_state(port, PD_STATE_SNK_DISCOVERY);
@@ -2503,7 +2513,7 @@ void pd_task(void)
* a hard reset.
*/
if (pd[port].power_role == PD_ROLE_SINK &&
- !pd_snk_is_vbus_provided(port) &&
+ !pd_is_vbus_present(port) &&
pd[port].task_state != PD_STATE_SNK_HARD_RESET_RECOVER &&
pd[port].task_state != PD_STATE_HARD_RESET_EXECUTE) {
/* Sink: detect disconnect by monitoring VBUS */
diff --git a/common/usb_pd_tcpc.c b/common/usb_pd_tcpc.c
index d7314b1a53..5c42640d5b 100644
--- a/common/usb_pd_tcpc.c
+++ b/common/usb_pd_tcpc.c
@@ -227,6 +227,9 @@ static struct pd_port_controller {
uint8_t rx_enabled;
/* TCPC flags */
uint8_t flags;
+ /* Power status */
+ uint8_t power_status;
+ uint8_t power_status_mask;
/* Last received */
int rx_head[RX_BUFFER_SIZE+1];
@@ -958,6 +961,29 @@ int tcpc_set_polarity(int port, int polarity)
return EC_SUCCESS;
}
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+static int tcpc_set_power_status(int port, int vbus_present)
+{
+ /* Update VBUS present bit */
+ if (vbus_present)
+ pd[port].power_status |= TCPC_REG_POWER_VBUS_PRES;
+ else
+ pd[port].power_status &= ~TCPC_REG_POWER_VBUS_PRES;
+
+ /* Set bit Port Power Status bit in Alert register */
+ if (pd[port].power_status_mask & TCPC_REG_POWER_VBUS_PRES)
+ alert(port, TCPC_REG_ALERT_POWER_STATUS);
+
+ return EC_SUCCESS;
+}
+#endif /* CONFIG_USB_PD_TCPM_VBUS */
+
+int tcpc_set_power_status_mask(int port, uint8_t mask)
+{
+ pd[port].power_status_mask = mask;
+ return EC_SUCCESS;
+}
+
int tcpc_set_vconn(int port, int enable)
{
#ifdef CONFIG_USBC_VCONN
@@ -1011,6 +1037,25 @@ int tcpc_get_message(int port, uint32_t *payload, int *head)
return EC_SUCCESS;
}
+
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+void pd_vbus_evt_p0(enum gpio_signal signal)
+{
+ tcpc_set_power_status(TASK_ID_TO_PD_PORT(TASK_ID_PD_C0),
+ !gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L));
+ task_wake(TASK_ID_PD_C0);
+}
+
+#if CONFIG_USB_PD_PORT_COUNT >= 2
+void pd_vbus_evt_p1(enum gpio_signal signal)
+{
+ tcpc_set_power_status(TASK_ID_TO_PD_PORT(TASK_ID_PD_C1),
+ !gpio_get_level(GPIO_USB_C1_VBUS_WAKE_L));
+ task_wake(TASK_ID_PD_C1);
+}
+#endif /* PD_PORT_COUNT >= 2 */
+#endif /* CONFIG_USB_PD_TCPM_VBUS */
+
#ifndef CONFIG_USB_POWER_DELIVERY
static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload)
{
@@ -1044,6 +1089,9 @@ static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload)
tcpc_set_rx_enable(port, payload[1] &
TCPC_REG_RX_DETECT_SOP_HRST_MASK);
break;
+ case TCPC_REG_POWER_STATUS_MASK:
+ tcpc_set_power_status_mask(port, payload[1]);
+ break;
case TCPC_REG_TX_HDR:
pd[port].tx_head = (payload[2] << 8) | payload[1];
break;
@@ -1114,6 +1162,9 @@ static int tcpc_i2c_read(int port, int reg, uint8_t *payload)
memcpy(payload, pd[port].rx_payload[pd[port].rx_buf_tail],
sizeof(pd[port].rx_payload[pd[port].rx_buf_tail]));
return sizeof(pd[port].rx_payload[pd[port].rx_buf_tail]);
+ case TCPC_REG_POWER_STATUS:
+ payload[0] = pd[port].power_status;
+ return 1;
case TCPC_REG_TX_BYTE_CNT:
payload[0] = PD_HEADER_CNT(pd[port].tx_head);
return 1;
diff --git a/driver/tcpm/stub.c b/driver/tcpm/stub.c
index 444730fc18..35f0329484 100644
--- a/driver/tcpm/stub.c
+++ b/driver/tcpm/stub.c
@@ -16,6 +16,7 @@ extern int tcpc_alert_mask_set(int port, uint16_t mask);
extern int tcpc_get_cc(int port, int *cc1, int *cc2);
extern int tcpc_set_cc(int port, int pull);
extern int tcpc_set_polarity(int port, int polarity);
+extern int tcpc_set_power_status_mask(int port, uint8_t mask);
extern int tcpc_set_vconn(int port, int enable);
extern int tcpc_set_msg_header(int port, int power_role, int data_role);
extern int tcpc_set_rx_enable(int port, int enable);
@@ -63,6 +64,11 @@ int tcpm_set_polarity(int port, int polarity)
return tcpc_set_polarity(port, polarity);
}
+int tcpm_set_power_status_mask(int port, uint8_t mask)
+{
+ return tcpc_set_power_status_mask(port, mask);
+}
+
int tcpm_set_vconn(int port, int enable)
{
return tcpc_set_vconn(port, enable);
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index 606b84e31c..939ab9ccf2 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -9,6 +9,7 @@
#include "task.h"
#include "tcpci.h"
#include "timer.h"
+#include "usb_charge.h"
#include "usb_pd.h"
#include "usb_pd_tcpc.h"
#include "usb_pd_tcpm.h"
@@ -17,7 +18,7 @@
/* Convert port number to tcpc i2c address */
#define I2C_ADDR_TCPC(p) (CONFIG_TCPC_I2C_BASE_ADDR + 2*(p))
-static int tcpc_polarity, tcpc_vconn;
+static int tcpc_polarity, tcpc_vconn, tcpc_vbus[CONFIG_USB_PD_PORT_COUNT];
static int init_alert_mask(int port)
{
@@ -30,13 +31,30 @@ static int init_alert_mask(int port)
*/
mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED |
TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS |
- TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS;
+ TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+ | TCPC_REG_ALERT_POWER_STATUS
+#endif
+ ;
/* Set the alert mask in TCPC */
rv = tcpm_alert_mask_set(port, mask);
return rv;
}
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+static int init_power_status_mask(int port)
+{
+ uint8_t mask;
+ int rv;
+
+ mask = TCPC_REG_POWER_VBUS_PRES;
+ rv = tcpm_set_power_status_mask(port, mask);
+
+ return rv;
+}
+#endif
+
int tcpm_init(int port)
{
int rv, err = 0;
@@ -52,6 +70,10 @@ int tcpm_init(int port)
if (rv == EC_SUCCESS && !(err & TCPC_REG_ERROR_STATUS_UNINIT)) {
i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
TCPC_REG_ALERT, 0xff);
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+ /* Initialize power_status_mask */
+ init_power_status_mask(port);
+#endif
return init_alert_mask(port);
}
msleep(10);
@@ -85,6 +107,12 @@ int tcpm_get_cc(int port, int *cc1, int *cc2)
return rv;
}
+int tcpm_get_power_status(int port, int *status)
+{
+ return i2c_read8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
+ TCPC_REG_POWER_STATUS, status);
+}
+
int tcpm_set_cc(int port, int pull)
{
/*
@@ -124,11 +152,9 @@ int tcpm_set_msg_header(int port, int power_role, int data_role)
int tcpm_alert_status(int port, int *alert)
{
- int rv;
/* Read TCPC Alert register */
- rv = i2c_read16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
- TCPC_REG_ALERT, alert);
- return rv;
+ return i2c_read16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
+ TCPC_REG_ALERT, alert);
}
int tcpm_set_rx_enable(int port, int enable)
@@ -139,18 +165,26 @@ int tcpm_set_rx_enable(int port, int enable)
enable ? TCPC_REG_RX_DETECT_SOP_HRST_MASK : 0);
}
-int tcpm_alert_mask_set(int port, uint16_t mask)
+int tcpm_set_power_status_mask(int port, uint8_t mask)
{
- int rv;
/* write to the Alert Mask register */
- rv = i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
- TCPC_REG_ALERT_MASK, mask);
+ return i2c_write8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
+ TCPC_REG_POWER_STATUS_MASK , mask);
+}
- if (rv)
- return rv;
+int tcpm_alert_mask_set(int port, uint16_t mask)
+{
+ /* write to the Alert Mask register */
+ return i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
+ TCPC_REG_ALERT_MASK, mask);
+}
- return rv;
+#ifdef CONFIG_USB_PD_TCPM_VBUS
+int tcpm_get_vbus_level(int port)
+{
+ return tcpc_vbus[port];
}
+#endif
int tcpm_get_message(int port, uint32_t *payload, int *head)
{
@@ -215,6 +249,7 @@ int tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header,
void tcpc_alert(int port)
{
int status;
+ int power_status;
/* Read the Alert register from the TCPC */
tcpm_alert_status(port, &status);
@@ -231,6 +266,18 @@ void tcpc_alert(int port)
/* CC status changed, wake task */
task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
}
+ if (status & TCPC_REG_ALERT_POWER_STATUS) {
+ /* Read Power Status register */
+ tcpm_get_power_status(port, &power_status);
+ /* Update VBUS status */
+ tcpc_vbus[port] = power_status &
+ TCPC_REG_POWER_VBUS_PRES ? 1 : 0;
+#if defined(CONFIG_USB_PD_TCPM_VBUS) && defined(CONFIG_USB_CHARGER)
+ /* Update charge manager with new VBUS state */
+ usb_charger_vbus_change(port, tcpc_vbus[port]);
+#endif /* CONFIG_USB_PD_TCPM_VBUS && CONFIG_USB_CHARGER */
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ }
if (status & TCPC_REG_ALERT_RX_STATUS) {
/* message received */
task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index 18f9a75e95..cbfac0380c 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -45,6 +45,7 @@
#define TCPC_REG_CC_STATUS_CC1(reg) ((reg) & 0x3)
#define TCPC_REG_POWER_STATUS 0x19
+#define TCPC_REG_POWER_VBUS_PRES (1<<5)
#define TCPC_REG_ERROR_STATUS 0x1a
#define TCPC_REG_ERROR_STATUS_UNINIT (1<<7)
#define TCPC_REG_ROLE_CTRL 0x1b
diff --git a/include/config.h b/include/config.h
index 7172f54697..a7555c4acc 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1628,6 +1628,13 @@
#undef CONFIG_USB_PD_TCPM_STUB
#undef CONFIG_USB_PD_TCPM_TCPCI
+/*
+ * Use this option if the TCPC port controller is on a seperate chip from
+ * the TCPM layer and if VUBS detect GPIO is not available on the TCPM
+ * mcu.
+ */
+#undef CONFIG_USB_PD_TCPM_VBUS
+
/* Define the type-c port controller I2C base address. */
#undef CONFIG_TCPC_I2C_BASE_ADDR
diff --git a/include/usb_pd_tcpc.h b/include/usb_pd_tcpc.h
index 64d68f1f3a..a640714c4f 100644
--- a/include/usb_pd_tcpc.h
+++ b/include/usb_pd_tcpc.h
@@ -35,4 +35,12 @@
void tcpc_i2c_process(int read, int port, int len, uint8_t *payload,
void (*send_response)(int));
+/**
+ * Handle VBUS wake interrupts
+ *
+ * @param signal The VBUS wake interrupt signal
+ */
+void pd_vbus_evt_p0(enum gpio_signal signal);
+void pd_vbus_evt_p1(enum gpio_signal signal);
+
#endif /* __CROS_EC_USB_PD_TCPC_H */
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index bd4803bf03..8d446bcae8 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -113,6 +113,15 @@ int tcpm_alert_mask_set(int port, uint16_t mask);
int tcpm_get_cc(int port, int *cc1, int *cc2);
/**
+ * Read VBUS
+ *
+ * @param port Type-C port number
+ *
+ * @return 0 => VBUS not detected, 1 => VBUS detected
+ */
+int tcpm_get_vbus_level(int port);
+
+/**
* Set the CC pull resistor. This sets our role as either source or sink.
*
* @param port Type-C port number
@@ -133,6 +142,16 @@ int tcpm_set_cc(int port, int pull);
int tcpm_set_polarity(int port, int polarity);
/**
+ * Set TCPC Power Status Mask
+ *
+ * @param port Type-C port number
+ * @param mask => new mask value
+ *
+ * @return EC_SUCCESS or error
+ */
+int tcpm_set_power_status_mask(int port, uint8_t mask);
+
+/**
* Set Vconn.
*
* @param port Type-C port number