summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2017-01-25 18:39:39 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-02-09 22:50:50 -0800
commit4ff544a573302336b1e2d8b55bfa8a32f847de4e (patch)
tree1951ca71b4247a18d3f306dcd37879f6bd8a2c4b /driver
parentb889e47410698986822712078ec232c1715b4845 (diff)
downloadchrome-ec-4ff544a573302336b1e2d8b55bfa8a32f847de4e.tar.gz
Add host command to get PD chip information
This patch adds a host command to get PD chip info. For PS8751, tcpci_get_chip_info will fail if the chip is in low power mode. It can be woken up by reading a random register first then wait for 10ms. This code doesn't have the wake-up read to avoid 10ms delay. Instead, we call this function immediately after the chip is initialized because it'll gurantee the chip is awake. Once it's called, the chip info will be stored in cache, which can be accessed by tcpc_get_chip_info without worrying about chip states. localhost ~ # ectool pdchipinfo 0 vendor_id: 0xaaaa product_id: 0x3429 device_id: 0xad fw_version: 0x15 localhost ~ # ectool pdchipinfo 1 vendor_id: 0x1da0 product_id: 0x8751 device_id: 0x1 fw_version: 0x37 BUG=chrome-os-partner:62383 BRANCH=none TEST=ectool pdchipinfo 0/1. make buildall Change-Id: I3f1667d00ce1826936d90882ada1df6ed6b0ea37 Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/433166
Diffstat (limited to 'driver')
-rw-r--r--driver/tcpm/anx74xx.c13
-rw-r--r--driver/tcpm/ps8751.c2
-rw-r--r--driver/tcpm/tcpci.c113
-rw-r--r--driver/tcpm/tcpci.h1
-rw-r--r--driver/tcpm/tcpm.h9
5 files changed, 110 insertions, 28 deletions
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index 0501788080..5854c62c8f 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -9,6 +9,7 @@
#include "anx74xx.h"
#include "task.h"
+#include "tcpci.h"
#include "tcpm.h"
#include "timer.h"
#include "usb_charge.h"
@@ -17,6 +18,11 @@
#include "usb_pd_tcpc.h"
#include "util.h"
+#if !defined(CONFIG_USB_PD_TCPM_TCPCI)
+#error "ANX74xx is using part of standard TCPCI control"
+#error "Please upgrade your board configuration"
+#endif
+
struct anx_state {
int polarity;
int vconn_en;
@@ -571,12 +577,10 @@ static int anx74xx_tcpm_set_polarity(int port, int polarity)
return rv;
}
-#ifdef CONFIG_USB_PD_TCPC_FW_VERSION
int anx74xx_tcpc_get_fw_version(int port, int *version)
{
return tcpc_read(port, ANX74XX_REG_FW_VERSION, version);
}
-#endif
static int anx74xx_tcpm_set_vconn(int port, int enable)
{
@@ -884,9 +888,7 @@ int anx74xx_tcpm_init(int port)
if (rv)
return EC_ERROR_UNKNOWN;
-#ifdef CONFIG_USB_PD_TCPC_FW_VERSION
- board_print_tcpc_fw_version(port);
-#endif
+ tcpm_get_chip_info(port, NULL);
return EC_SUCCESS;
}
@@ -909,6 +911,7 @@ const struct tcpm_drv anx74xx_tcpm_drv = {
#ifdef CONFIG_USB_PD_DISCHARGE_TCPC
.tcpc_discharge_vbus = &anx74xx_tcpc_discharge_vbus,
#endif
+ .get_chip_info = &tcpci_get_chip_info,
};
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
diff --git a/driver/tcpm/ps8751.c b/driver/tcpm/ps8751.c
index f889f17134..66b895696e 100644
--- a/driver/tcpm/ps8751.c
+++ b/driver/tcpm/ps8751.c
@@ -61,12 +61,10 @@ void ps8751_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq)
}
}
-#ifdef CONFIG_USB_PD_TCPC_FW_VERSION
int ps8751_tcpc_get_fw_version(int port, int *version)
{
return tcpc_read(port, PS8751_REG_VERSION, version);
}
-#endif
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
struct i2c_stress_test_dev ps8751_i2c_stress_test_dev = {
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index a2e196351f..ad50cdbb8d 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -5,6 +5,9 @@
/* Type-C port manager */
+#include "anx74xx.h"
+#include "ec_commands.h"
+#include "ps8751.h"
#include "task.h"
#include "tcpci.h"
#include "tcpm.h"
@@ -23,7 +26,6 @@ static int selected_rp[CONFIG_USB_PD_PORT_COUNT];
static int init_alert_mask(int port)
{
uint16_t mask;
- int rv;
/*
* Create mask of alert events that will cause the TCPC to
@@ -37,13 +39,7 @@ static int init_alert_mask(int port)
#endif
;
/* Set the alert mask in TCPC */
- rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask);
-
-#ifdef CONFIG_USB_PD_TCPC_FW_VERSION
- board_print_tcpc_fw_version(port);
-#endif
-
- return rv;
+ return tcpc_write16(port, TCPC_REG_ALERT_MASK, mask);
}
static int init_power_status_mask(int port)
@@ -318,6 +314,72 @@ void tcpci_tcpc_alert(int port)
}
/*
+ * For PS8751, this function will fail if the chip is in low power mode.
+ * PS8751 has to be woken up by reading a random register first then wait for
+ * 10ms.
+ *
+ * This code doesn't have the wake-up read to avoid 10ms delay. Instead, we
+ * call this function immediately after the chip is reset or initialized
+ * because it'll gurantee the chip is awake. Once it's called, the chip info
+ * will be stored in cache, which can be accessed by tcpm_get_chip_info without
+ * worrying about chip states.
+ */
+int tcpci_get_chip_info(int port, struct ec_response_pd_chip_info **chip_info)
+{
+ static struct ec_response_pd_chip_info info[CONFIG_USB_PD_PORT_COUNT];
+ int error;
+ int val;
+
+ if (port >= CONFIG_USB_PD_PORT_COUNT)
+ return EC_ERROR_INVAL;
+
+ /* If chip_info is NULL, chip info will be stored in cache and can be
+ * read later by another call. */
+ if (chip_info)
+ *chip_info = &info[port];
+
+ if (info[port].vendor_id)
+ return EC_SUCCESS;
+
+ error = tcpc_read16(port, TCPC_REG_VENDOR_ID, &val);
+ if (error)
+ return error;
+ info[port].vendor_id = val;
+
+ error = tcpc_read16(port, TCPC_REG_PRODUCT_ID, &val);
+ if (error)
+ return error;
+ info[port].product_id = val;
+
+ error = tcpc_read16(port, TCPC_REG_BCD_DEV, &val);
+ if (error)
+ return error;
+ info[port].device_id = val;
+
+ switch(info[port].vendor_id) {
+#ifdef CONFIG_USB_PD_TCPM_ANX74XX
+ case ANX74XX_VENDOR_ID:
+ error = anx74xx_tcpc_get_fw_version(port, &val);
+ break;
+#endif
+#ifdef CONFIG_USB_PD_TCPM_PS8751
+ case PS8751_VENDOR_ID:
+ error = ps8751_tcpc_get_fw_version(port, &val);
+ break;
+#endif
+ default:
+ /* Even if the chip doesn't implement get_fw_version, we
+ * return success. The version will be 0xffff. */
+ return EC_SUCCESS;
+ }
+ if (error)
+ return error;
+ info[port].fw_version = val;
+
+ return EC_SUCCESS;
+}
+
+/*
* On TCPC i2c failure, make 30 tries (at least 300ms) before giving up
* in order to allow the TCPC time to boot / reset.
*/
@@ -325,30 +387,38 @@ void tcpci_tcpc_alert(int port)
int tcpci_tcpm_init(int port)
{
- int rv;
+ int error;
int power_status;
int tries = TCPM_INIT_TRIES;
while (1) {
- rv = tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status);
+ error = tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status);
/*
* If read succeeds and the uninitialized bit is clear, then
* initalization is complete, clear all alert bits and write
* the initial alert mask.
*/
- if (rv == EC_SUCCESS &&
- !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) {
- tcpc_write16(port, TCPC_REG_ALERT, 0xffff);
- /* Initialize power_status_mask */
- init_power_status_mask(port);
- /* Update VBUS status */
- tcpc_vbus[port] = power_status &
- TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
- return init_alert_mask(port);
- } else if (rv != EC_SUCCESS && --tries == 0)
- return rv;
+ if (!error && !(power_status & TCPC_REG_POWER_STATUS_UNINIT))
+ break;
+ else if (error && --tries == 0)
+ return error;
msleep(10);
}
+
+ tcpc_write16(port, TCPC_REG_ALERT, 0xffff);
+ /* Initialize power_status_mask */
+ init_power_status_mask(port);
+ /* Update VBUS status */
+ tcpc_vbus[port] = power_status &
+ TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
+ error = init_alert_mask(port);
+ if (error)
+ return error;
+
+ /* Read chip info here when we know the chip is awake. */
+ tcpm_get_chip_info(port, NULL);
+
+ return EC_SUCCESS;
}
#ifdef CONFIG_USB_PD_TCPM_MUX
@@ -432,4 +502,5 @@ const struct tcpm_drv tcpci_tcpm_drv = {
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
.drp_toggle = &tcpci_tcpc_drp_toggle,
#endif
+ .get_chip_info = &tcpci_get_chip_info,
};
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index 42f851cfe2..a11050eaf0 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -137,5 +137,6 @@ int tcpci_tcpm_transmit(int port, enum tcpm_transmit_type type,
int tcpci_tcpm_mux_init(int i2c_addr);
int tcpci_tcpm_mux_set(int i2c_addr, mux_state_t mux_state);
int tcpci_tcpm_mux_get(int i2c_addr, mux_state_t *mux_state);
+int tcpci_get_chip_info(int port, struct ec_response_pd_chip_info **chip_info);
#endif /* __CROS_EC_USB_PD_TCPM_TCPCI_H */
diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h
index 1c7c6edff3..9f8e38cbfc 100644
--- a/driver/tcpm/tcpm.h
+++ b/driver/tcpm/tcpm.h
@@ -9,6 +9,7 @@
#define __CROS_EC_USB_PD_TCPM_TCPM_H
#include "common.h"
+#include "ec_commands.h"
#include "gpio.h"
#include "i2c.h"
#include "usb_pd_tcpm.h"
@@ -162,6 +163,14 @@ static inline int tcpc_i2c_write(const int port, const int addr,
}
#endif
+static inline int tcpm_get_chip_info(int port,
+ struct ec_response_pd_chip_info **info)
+{
+ if (tcpc_config[port].drv->get_chip_info)
+ return tcpc_config[port].drv->get_chip_info(port, info);
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
#else
/**