From c8ed615adfb7ca4847b05fab39ffc5e457490341 Mon Sep 17 00:00:00 2001 From: Caveh Jalali Date: Tue, 20 Jun 2017 18:20:00 -0700 Subject: tcpm: add .release driver operation. similar to the USB_PD_TCPC case, add release/init operations when the pd_task enters/leaves the PD_STATE_SUSPENDED state. one use case for PD_SUSPEND is to get exlusive access to the TCPC for things like firmware update, so the release/init operation is needed to get the TCPC and driver into a good state. updated all tcpm_drv style drivers. for backward compatibility, "old" drivers that may not handle init/release properly simply return EC_ERROR_UNIMPLEMENTED for tcpm_release(). pd_task() uses this as a signal that it should not try to re-init() the driver. TEST=tested in combination with follow-on CLs to do TCPC firmware update on electro. also built for kevin, eve, sand which are some of the other boards using these drivers. "make buildall -j" passes. BRANCH=none BUG=b:35586896 Change-Id: I8cc98b488c5ee96cf4f0b07518aa58d3e224ff5c Signed-off-by: Duncan Laurie Original-Commit-Id: c74c0785927ab7770143d5ff503b4c0ca9df9ff1 Original-Change-Id: I3d2964a79e710428f7a6e7004d68ab424af85be8 Original-Signed-off-by: Caveh Jalali Original-Reviewed-on: https://chromium-review.googlesource.com/544660 Original-Reviewed-by: Shawn N Reviewed-on: https://chromium-review.googlesource.com/914654 --- common/usb_pd_protocol.c | 21 +++++++++++++++++++-- driver/tcpm/anx74xx.c | 6 ++++++ driver/tcpm/anx7688.c | 7 ++++++- driver/tcpm/fusb302.c | 6 ++++++ driver/tcpm/fusb302.h | 1 - driver/tcpm/it83xx.c | 6 ++++++ driver/tcpm/tcpci.c | 33 +++++++++++++++++++++++++++++++++ driver/tcpm/tcpm.h | 5 +++++ include/usb_pd_tcpm.h | 10 ++++++++++ 9 files changed, 91 insertions(+), 4 deletions(-) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 9f6bf2a1ea..2505fdb7ad 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -2234,21 +2234,38 @@ void pd_task(void *u) PD_STATE_SNK_DISCONNECTED); } break; - case PD_STATE_SUSPENDED: + case PD_STATE_SUSPENDED: { +#ifndef CONFIG_USB_PD_TCPC + int rstatus; +#endif CPRINTS("TCPC p%d suspended!", port); #ifdef CONFIG_USB_PD_TCPC pd_rx_disable_monitoring(port); pd_hw_release(port); pd_power_supply_reset(port); +#else + rstatus = tcpm_release(port); + if (rstatus != 0 && rstatus != EC_ERROR_UNIMPLEMENTED) + CPRINTS("TCPC p%d release failed!", port); #endif /* Wait for resume */ while (pd[port].task_state == PD_STATE_SUSPENDED) task_wait_event(-1); #ifdef CONFIG_USB_PD_TCPC pd_hw_init(port, PD_ROLE_DEFAULT(port)); -#endif CPRINTS("TCPC p%d resumed!", port); +#else + if (rstatus != EC_ERROR_UNIMPLEMENTED && + tcpm_init(port) != 0) { + /* stay in PD_STATE_SUSPENDED */ + CPRINTS("TCPC p%d init failed!", port); + break; + } + set_state(port, PD_DEFAULT_STATE(port)); + CPRINTS("TCPC p%d resumed!", port); +#endif break; + } case PD_STATE_SNK_DISCONNECTED: #ifdef CONFIG_USB_PD_LOW_POWER timeout = drp_state != PD_DRP_TOGGLE_ON ? SECOND diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c index 4c3fd41410..461242d79f 100644 --- a/driver/tcpm/anx74xx.c +++ b/driver/tcpm/anx74xx.c @@ -1060,8 +1060,14 @@ static int anx74xx_tcpm_init(int port) return EC_SUCCESS; } +static int anx74xx_tcpm_release(int port) +{ + return EC_ERROR_UNIMPLEMENTED; +} + const struct tcpm_drv anx74xx_tcpm_drv = { .init = &anx74xx_tcpm_init, + .release = &anx74xx_tcpm_release, .get_cc = &anx74xx_tcpm_get_cc, #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .get_vbus_level = &anx74xx_tcpm_get_vbus_level, diff --git a/driver/tcpm/anx7688.c b/driver/tcpm/anx7688.c index 7dda345302..6b73108739 100644 --- a/driver/tcpm/anx7688.c +++ b/driver/tcpm/anx7688.c @@ -61,6 +61,11 @@ static int anx7688_init(int port) return rv; } +static int anx7688_release(int port) +{ + return EC_ERROR_UNIMPLEMENTED; +} + static void anx7688_update_hpd_enable(int port) { int status, reg, rv; @@ -178,6 +183,7 @@ static int anx7688_tcpm_get_vbus_level(int port) /* ANX7688 is a TCPCI compatible port controller */ const struct tcpm_drv anx7688_tcpm_drv = { .init = &anx7688_init, + .release = &anx7688_release, .get_cc = &tcpci_tcpm_get_cc, #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .get_vbus_level = &anx7688_tcpm_get_vbus_level, @@ -200,4 +206,3 @@ const struct usb_mux_driver anx7688_usb_mux_driver = { .get = tcpci_tcpm_mux_get, }; #endif /* CONFIG_USB_PD_TCPM_MUX */ - diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c index 9bdde5e591..3be0288bf1 100644 --- a/driver/tcpm/fusb302.c +++ b/driver/tcpm/fusb302.c @@ -428,6 +428,11 @@ static int fusb302_tcpm_init(int port) return 0; } +static int fusb302_tcpm_release(int port) +{ + return EC_ERROR_UNIMPLEMENTED; +} + static int fusb302_tcpm_get_cc(int port, int *cc1, int *cc2) { if (state[port].pulling_up) { @@ -926,6 +931,7 @@ void tcpm_set_bist_test_data(int port) const struct tcpm_drv fusb302_tcpm_drv = { .init = &fusb302_tcpm_init, + .release = &fusb302_tcpm_release, .get_cc = &fusb302_tcpm_get_cc, #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .get_vbus_level = &fusb302_tcpm_get_vbus_level, diff --git a/driver/tcpm/fusb302.h b/driver/tcpm/fusb302.h index dc191bee5a..1773645e91 100644 --- a/driver/tcpm/fusb302.h +++ b/driver/tcpm/fusb302.h @@ -206,4 +206,3 @@ enum fusb302_txfifo_tokens { extern const struct tcpm_drv fusb302_tcpm_drv; #endif /* __CROS_EC_DRIVER_TCPM_FUSB302_H */ - diff --git a/driver/tcpm/it83xx.c b/driver/tcpm/it83xx.c index e30c73bac8..f5e78bbbb9 100644 --- a/driver/tcpm/it83xx.c +++ b/driver/tcpm/it83xx.c @@ -351,6 +351,11 @@ static int it83xx_tcpm_init(int port) return EC_SUCCESS; } +static int it83xx_tcpm_release(int port) +{ + return EC_ERROR_UNIMPLEMENTED; +} + static int it83xx_tcpm_get_cc(int port, int *cc1, int *cc2) { *cc2 = it83xx_get_cc(port, USBPD_CC_PIN_2); @@ -504,6 +509,7 @@ static int it83xx_tcpm_get_chip_info(int port, int renew, const struct tcpm_drv it83xx_tcpm_drv = { .init = &it83xx_tcpm_init, + .release = &it83xx_tcpm_release, .get_cc = &it83xx_tcpm_get_cc, #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .get_vbus_level = NULL, diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 8da8bdd532..c7cdad4390 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -42,6 +42,11 @@ static int init_alert_mask(int port) return tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); } +static int clear_alert_mask(int port) +{ + return tcpc_write16(port, TCPC_REG_ALERT_MASK, 0); +} + static int init_power_status_mask(int port) { uint8_t mask; @@ -57,6 +62,11 @@ static int init_power_status_mask(int port) return rv; } +static int clear_power_status_mask(int port) +{ + return tcpc_write(port, TCPC_REG_POWER_STATUS_MASK, 0); +} + int tcpci_tcpm_get_cc(int port, int *cc1, int *cc2) { int status; @@ -436,6 +446,28 @@ int tcpci_tcpm_init(int port) return EC_SUCCESS; } +/* + * Dissociate from the TCPC. + */ + +int tcpci_tcpm_release(int port) +{ + int error; + + error = clear_alert_mask(port); + if (error) + return error; + error = clear_power_status_mask(port); + if (error) + return error; + /* Clear pending interrupts */ + error = tcpc_write16(port, TCPC_REG_ALERT, 0xffff); + if (error) + return error; + + return EC_SUCCESS; +} + #ifdef CONFIG_USB_PD_TCPM_MUX int tcpci_tcpm_mux_init(int i2c_addr) @@ -498,6 +530,7 @@ const struct usb_mux_driver tcpci_tcpm_usb_mux_driver = { const struct tcpm_drv tcpci_tcpm_drv = { .init = &tcpci_tcpm_init, + .release = &tcpci_tcpm_release, .get_cc = &tcpci_tcpm_get_cc, #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .get_vbus_level = &tcpci_tcpm_get_vbus_level, diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h index 71af9361f9..b2d8aef2ea 100644 --- a/driver/tcpm/tcpm.h +++ b/driver/tcpm/tcpm.h @@ -75,6 +75,11 @@ static inline int tcpm_init(int port) return tcpc_config[port].drv->init(port); } +static inline int tcpm_release(int port) +{ + return tcpc_config[port].drv->release(port); +} + static inline int tcpm_get_cc(int port, int *cc1, int *cc2) { return tcpc_config[port].drv->get_cc(port, cc1, cc2); diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index fe5d6232e6..3f231fb3f7 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -66,6 +66,16 @@ struct tcpm_drv { */ int (*init)(int port); + /** + * Release the TCPM hardware and disconnect the driver. + * Only .init() can be called after .release(). + * + * @param port Type-C port number + * + * @return EC_SUCCESS or error + */ + int (*release)(int port); + /** * Read the CC line status. * -- cgit v1.2.1