summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorScott <scollyer@chromium.org>2015-07-30 15:10:11 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-08-21 08:10:03 +0000
commitd862dd05982198a2f5d450820a02172e0ba6396b (patch)
treec9c96e5ea91537a3aae99370952eb2a13156a1af /driver
parent646760bb20fde94683d3be2fa4b046d47933d85f (diff)
downloadchrome-ec-d862dd05982198a2f5d450820a02172e0ba6396b.tar.gz
pd: Enable detection of VBUS via the TCPM/TCPCI interface
Modified TCPC layer to utilize the Power_Status and Power_Status_Mask registers. VBUS status is stored in Power_Status and when a change is detected, it's communicated to the TCPM via the ALERT# line. BUG=chrome-os-partner:43440 BRANCH=none TEST=Tested the feature on Glados and Oak connecting to both Ziger and Samus. Verfied that VBUS status is communicated via the TCPCI and that PD contracts are established without using the VBUS_WAKE GPIO lines on Glados and Oak. Change-Id: Ie5aa32eecc887f3cb00880a285f1e710b7064384 Signed-off-by: Scott Collyer <scollyer@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/289931 Reviewed-by: Rong Chang <rongchang@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org> Commit-Queue: Rong Chang <rongchang@chromium.org> Tested-by: Rong Chang <rongchang@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/tcpm/stub.c6
-rw-r--r--driver/tcpm/tcpci.c73
-rw-r--r--driver/tcpm/tcpci.h1
3 files changed, 67 insertions, 13 deletions
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