* [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V
2020-12-02 4:08 [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus Badhri Jagan Sridharan
@ 2020-12-02 4:08 ` Badhri Jagan Sridharan
2020-12-08 9:25 ` Heikki Krogerus
2020-12-08 19:32 ` Guenter Roeck
2020-12-02 4:08 ` [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling Badhri Jagan Sridharan
` (2 subsequent siblings)
3 siblings, 2 replies; 9+ messages in thread
From: Badhri Jagan Sridharan @ 2020-12-02 4:08 UTC (permalink / raw)
To: Guenter Roeck, Heikki Krogerus, Greg Kroah-Hartman
Cc: linux-usb, linux-kernel, Badhri Jagan Sridharan
This change adds vbus_vsafe0v which when set, makes TCPM
query for VSAFE0V by assigning the tcpc.is_vbus_vsafe0v callback.
Also enables ALERT.ExtendedStatus which is triggered when
status of EXTENDED_STATUS.vSafe0V changes.
EXTENDED_STATUS.vSafe0V is set when vbus is at vSafe0V and
cleared otherwise.
Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
---
Changes since v1:
- Removed logic for checking TCPC_POWER_STATUS_MASK reg
read in the irq handler. Sending that as a separate patch.
---
drivers/usb/typec/tcpm/tcpci.c | 39 +++++++++++++++++++++++++++++-----
drivers/usb/typec/tcpm/tcpci.h | 6 ++++++
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index 12d983a75510..f938d9876ce9 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -402,6 +402,19 @@ static int tcpci_get_vbus(struct tcpc_dev *tcpc)
return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
}
+static bool tcpci_is_vbus_vsafe0v(struct tcpc_dev *tcpc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, ®);
+ if (ret < 0)
+ return false;
+
+ return !!(reg & TCPC_EXTENDED_STATUS_VSAFE0V);
+}
+
static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
{
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
@@ -554,12 +567,22 @@ static int tcpci_init(struct tcpc_dev *tcpc)
TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
if (tcpci->controls_vbus)
reg |= TCPC_ALERT_POWER_STATUS;
+ /* Enable VSAFE0V status interrupt when detecting VSAFE0V is supported */
+ if (tcpci->data->vbus_vsafe0v) {
+ reg |= TCPC_ALERT_EXTENDED_STATUS;
+ ret = regmap_write(tcpci->regmap, TCPC_EXTENDED_STATUS_MASK,
+ TCPC_EXTENDED_STATUS_VSAFE0V);
+ if (ret < 0)
+ return ret;
+ }
return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
}
irqreturn_t tcpci_irq(struct tcpci *tcpci)
{
u16 status;
+ int ret;
+ unsigned int raw;
tcpci_read16(tcpci, TCPC_ALERT, &status);
@@ -575,15 +598,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
tcpm_cc_change(tcpci->port);
if (status & TCPC_ALERT_POWER_STATUS) {
- unsigned int reg;
-
- regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, ®);
-
+ regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, &raw);
/*
* If power status mask has been reset, then the TCPC
* has reset.
*/
- if (reg == 0xff)
+ if (raw == 0xff)
tcpm_tcpc_reset(tcpci->port);
else
tcpm_vbus_change(tcpci->port);
@@ -622,6 +642,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
tcpm_pd_receive(tcpci->port, &msg);
}
+ if (status & TCPC_ALERT_EXTENDED_STATUS) {
+ ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, &raw);
+ if (!ret && (raw & TCPC_EXTENDED_STATUS_VSAFE0V))
+ tcpm_vbus_change(tcpci->port);
+ }
+
if (status & TCPC_ALERT_RX_HARD_RST)
tcpm_pd_hard_reset(tcpci->port);
@@ -699,6 +725,9 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
tcpci_set_auto_vbus_discharge_threshold;
}
+ if (tcpci->data->vbus_vsafe0v)
+ tcpci->tcpc.is_vbus_vsafe0v = tcpci_is_vbus_vsafe0v;
+
err = tcpci_parse_config(tcpci);
if (err < 0)
return ERR_PTR(err);
diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h
index 3fe313655f0c..116a69c85e38 100644
--- a/drivers/usb/typec/tcpm/tcpci.h
+++ b/drivers/usb/typec/tcpm/tcpci.h
@@ -49,6 +49,9 @@
#define TCPC_TCPC_CTRL_ORIENTATION BIT(0)
#define TCPC_TCPC_CTRL_BIST_TM BIT(1)
+#define TCPC_EXTENDED_STATUS 0x20
+#define TCPC_EXTENDED_STATUS_VSAFE0V BIT(0)
+
#define TCPC_ROLE_CTRL 0x1a
#define TCPC_ROLE_CTRL_DRP BIT(6)
#define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4
@@ -155,11 +158,14 @@ struct tcpci;
* is sourcing vbus.
* @auto_discharge_disconnect:
* Optional; Enables TCPC to autonously discharge vbus on disconnect.
+ * @vbus_vsafe0v:
+ * optional; Set when TCPC can detect whether vbus is at VSAFE0V.
*/
struct tcpci_data {
struct regmap *regmap;
unsigned char TX_BUF_BYTE_x_hidden:1;
unsigned char auto_discharge_disconnect:1;
+ unsigned char vbus_vsafe0v:1;
int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
--
2.29.2.576.ga3fc446d84-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V
2020-12-02 4:08 ` [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V Badhri Jagan Sridharan
@ 2020-12-08 9:25 ` Heikki Krogerus
2020-12-08 19:32 ` Guenter Roeck
1 sibling, 0 replies; 9+ messages in thread
From: Heikki Krogerus @ 2020-12-08 9:25 UTC (permalink / raw)
To: Badhri Jagan Sridharan
Cc: Guenter Roeck, Greg Kroah-Hartman, linux-usb, linux-kernel
On Tue, Dec 01, 2020 at 08:08:39PM -0800, Badhri Jagan Sridharan wrote:
> This change adds vbus_vsafe0v which when set, makes TCPM
> query for VSAFE0V by assigning the tcpc.is_vbus_vsafe0v callback.
> Also enables ALERT.ExtendedStatus which is triggered when
> status of EXTENDED_STATUS.vSafe0V changes.
> EXTENDED_STATUS.vSafe0V is set when vbus is at vSafe0V and
> cleared otherwise.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> ---
> Changes since v1:
> - Removed logic for checking TCPC_POWER_STATUS_MASK reg
> read in the irq handler. Sending that as a separate patch.
> ---
> drivers/usb/typec/tcpm/tcpci.c | 39 +++++++++++++++++++++++++++++-----
> drivers/usb/typec/tcpm/tcpci.h | 6 ++++++
> 2 files changed, 40 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
> index 12d983a75510..f938d9876ce9 100644
> --- a/drivers/usb/typec/tcpm/tcpci.c
> +++ b/drivers/usb/typec/tcpm/tcpci.c
> @@ -402,6 +402,19 @@ static int tcpci_get_vbus(struct tcpc_dev *tcpc)
> return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
> }
>
> +static bool tcpci_is_vbus_vsafe0v(struct tcpc_dev *tcpc)
> +{
> + struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> + unsigned int reg;
> + int ret;
> +
> + ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, ®);
> + if (ret < 0)
> + return false;
> +
> + return !!(reg & TCPC_EXTENDED_STATUS_VSAFE0V);
> +}
> +
> static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
> {
> struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> @@ -554,12 +567,22 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
> if (tcpci->controls_vbus)
> reg |= TCPC_ALERT_POWER_STATUS;
> + /* Enable VSAFE0V status interrupt when detecting VSAFE0V is supported */
> + if (tcpci->data->vbus_vsafe0v) {
> + reg |= TCPC_ALERT_EXTENDED_STATUS;
> + ret = regmap_write(tcpci->regmap, TCPC_EXTENDED_STATUS_MASK,
> + TCPC_EXTENDED_STATUS_VSAFE0V);
> + if (ret < 0)
> + return ret;
> + }
> return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
> }
>
> irqreturn_t tcpci_irq(struct tcpci *tcpci)
> {
> u16 status;
> + int ret;
> + unsigned int raw;
>
> tcpci_read16(tcpci, TCPC_ALERT, &status);
>
> @@ -575,15 +598,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
> tcpm_cc_change(tcpci->port);
>
> if (status & TCPC_ALERT_POWER_STATUS) {
> - unsigned int reg;
> -
> - regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, ®);
> -
> + regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, &raw);
> /*
> * If power status mask has been reset, then the TCPC
> * has reset.
> */
> - if (reg == 0xff)
> + if (raw == 0xff)
> tcpm_tcpc_reset(tcpci->port);
> else
> tcpm_vbus_change(tcpci->port);
> @@ -622,6 +642,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
> tcpm_pd_receive(tcpci->port, &msg);
> }
>
> + if (status & TCPC_ALERT_EXTENDED_STATUS) {
> + ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, &raw);
> + if (!ret && (raw & TCPC_EXTENDED_STATUS_VSAFE0V))
> + tcpm_vbus_change(tcpci->port);
> + }
> +
> if (status & TCPC_ALERT_RX_HARD_RST)
> tcpm_pd_hard_reset(tcpci->port);
>
> @@ -699,6 +725,9 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
> tcpci_set_auto_vbus_discharge_threshold;
> }
>
> + if (tcpci->data->vbus_vsafe0v)
> + tcpci->tcpc.is_vbus_vsafe0v = tcpci_is_vbus_vsafe0v;
> +
> err = tcpci_parse_config(tcpci);
> if (err < 0)
> return ERR_PTR(err);
> diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h
> index 3fe313655f0c..116a69c85e38 100644
> --- a/drivers/usb/typec/tcpm/tcpci.h
> +++ b/drivers/usb/typec/tcpm/tcpci.h
> @@ -49,6 +49,9 @@
> #define TCPC_TCPC_CTRL_ORIENTATION BIT(0)
> #define TCPC_TCPC_CTRL_BIST_TM BIT(1)
>
> +#define TCPC_EXTENDED_STATUS 0x20
> +#define TCPC_EXTENDED_STATUS_VSAFE0V BIT(0)
> +
> #define TCPC_ROLE_CTRL 0x1a
> #define TCPC_ROLE_CTRL_DRP BIT(6)
> #define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4
> @@ -155,11 +158,14 @@ struct tcpci;
> * is sourcing vbus.
> * @auto_discharge_disconnect:
> * Optional; Enables TCPC to autonously discharge vbus on disconnect.
> + * @vbus_vsafe0v:
> + * optional; Set when TCPC can detect whether vbus is at VSAFE0V.
> */
> struct tcpci_data {
> struct regmap *regmap;
> unsigned char TX_BUF_BYTE_x_hidden:1;
> unsigned char auto_discharge_disconnect:1;
> + unsigned char vbus_vsafe0v:1;
>
> int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> --
> 2.29.2.576.ga3fc446d84-goog
--
heikki
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V
2020-12-02 4:08 ` [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V Badhri Jagan Sridharan
2020-12-08 9:25 ` Heikki Krogerus
@ 2020-12-08 19:32 ` Guenter Roeck
1 sibling, 0 replies; 9+ messages in thread
From: Guenter Roeck @ 2020-12-08 19:32 UTC (permalink / raw)
To: Badhri Jagan Sridharan
Cc: Heikki Krogerus, Greg Kroah-Hartman, linux-usb, linux-kernel
On Tue, Dec 01, 2020 at 08:08:39PM -0800, Badhri Jagan Sridharan wrote:
> This change adds vbus_vsafe0v which when set, makes TCPM
> query for VSAFE0V by assigning the tcpc.is_vbus_vsafe0v callback.
> Also enables ALERT.ExtendedStatus which is triggered when
> status of EXTENDED_STATUS.vSafe0V changes.
> EXTENDED_STATUS.vSafe0V is set when vbus is at vSafe0V and
> cleared otherwise.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> Changes since v1:
> - Removed logic for checking TCPC_POWER_STATUS_MASK reg
> read in the irq handler. Sending that as a separate patch.
> ---
> drivers/usb/typec/tcpm/tcpci.c | 39 +++++++++++++++++++++++++++++-----
> drivers/usb/typec/tcpm/tcpci.h | 6 ++++++
> 2 files changed, 40 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
> index 12d983a75510..f938d9876ce9 100644
> --- a/drivers/usb/typec/tcpm/tcpci.c
> +++ b/drivers/usb/typec/tcpm/tcpci.c
> @@ -402,6 +402,19 @@ static int tcpci_get_vbus(struct tcpc_dev *tcpc)
> return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
> }
>
> +static bool tcpci_is_vbus_vsafe0v(struct tcpc_dev *tcpc)
> +{
> + struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> + unsigned int reg;
> + int ret;
> +
> + ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, ®);
> + if (ret < 0)
> + return false;
> +
> + return !!(reg & TCPC_EXTENDED_STATUS_VSAFE0V);
> +}
> +
> static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
> {
> struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> @@ -554,12 +567,22 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
> if (tcpci->controls_vbus)
> reg |= TCPC_ALERT_POWER_STATUS;
> + /* Enable VSAFE0V status interrupt when detecting VSAFE0V is supported */
> + if (tcpci->data->vbus_vsafe0v) {
> + reg |= TCPC_ALERT_EXTENDED_STATUS;
> + ret = regmap_write(tcpci->regmap, TCPC_EXTENDED_STATUS_MASK,
> + TCPC_EXTENDED_STATUS_VSAFE0V);
> + if (ret < 0)
> + return ret;
> + }
> return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
> }
>
> irqreturn_t tcpci_irq(struct tcpci *tcpci)
> {
> u16 status;
> + int ret;
> + unsigned int raw;
>
> tcpci_read16(tcpci, TCPC_ALERT, &status);
>
> @@ -575,15 +598,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
> tcpm_cc_change(tcpci->port);
>
> if (status & TCPC_ALERT_POWER_STATUS) {
> - unsigned int reg;
> -
> - regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, ®);
> -
> + regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, &raw);
> /*
> * If power status mask has been reset, then the TCPC
> * has reset.
> */
> - if (reg == 0xff)
> + if (raw == 0xff)
> tcpm_tcpc_reset(tcpci->port);
> else
> tcpm_vbus_change(tcpci->port);
> @@ -622,6 +642,12 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
> tcpm_pd_receive(tcpci->port, &msg);
> }
>
> + if (status & TCPC_ALERT_EXTENDED_STATUS) {
> + ret = regmap_read(tcpci->regmap, TCPC_EXTENDED_STATUS, &raw);
> + if (!ret && (raw & TCPC_EXTENDED_STATUS_VSAFE0V))
> + tcpm_vbus_change(tcpci->port);
> + }
> +
> if (status & TCPC_ALERT_RX_HARD_RST)
> tcpm_pd_hard_reset(tcpci->port);
>
> @@ -699,6 +725,9 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
> tcpci_set_auto_vbus_discharge_threshold;
> }
>
> + if (tcpci->data->vbus_vsafe0v)
> + tcpci->tcpc.is_vbus_vsafe0v = tcpci_is_vbus_vsafe0v;
> +
> err = tcpci_parse_config(tcpci);
> if (err < 0)
> return ERR_PTR(err);
> diff --git a/drivers/usb/typec/tcpm/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h
> index 3fe313655f0c..116a69c85e38 100644
> --- a/drivers/usb/typec/tcpm/tcpci.h
> +++ b/drivers/usb/typec/tcpm/tcpci.h
> @@ -49,6 +49,9 @@
> #define TCPC_TCPC_CTRL_ORIENTATION BIT(0)
> #define TCPC_TCPC_CTRL_BIST_TM BIT(1)
>
> +#define TCPC_EXTENDED_STATUS 0x20
> +#define TCPC_EXTENDED_STATUS_VSAFE0V BIT(0)
> +
> #define TCPC_ROLE_CTRL 0x1a
> #define TCPC_ROLE_CTRL_DRP BIT(6)
> #define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4
> @@ -155,11 +158,14 @@ struct tcpci;
> * is sourcing vbus.
> * @auto_discharge_disconnect:
> * Optional; Enables TCPC to autonously discharge vbus on disconnect.
> + * @vbus_vsafe0v:
> + * optional; Set when TCPC can detect whether vbus is at VSAFE0V.
> */
> struct tcpci_data {
> struct regmap *regmap;
> unsigned char TX_BUF_BYTE_x_hidden:1;
> unsigned char auto_discharge_disconnect:1;
> + unsigned char vbus_vsafe0v:1;
>
> int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> --
> 2.29.2.576.ga3fc446d84-goog
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling
2020-12-02 4:08 [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus Badhri Jagan Sridharan
2020-12-02 4:08 ` [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V Badhri Jagan Sridharan
@ 2020-12-02 4:08 ` Badhri Jagan Sridharan
2020-12-08 9:26 ` Heikki Krogerus
2020-12-08 19:33 ` Guenter Roeck
2020-12-08 9:24 ` [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus Heikki Krogerus
2020-12-08 19:31 ` Guenter Roeck
3 siblings, 2 replies; 9+ messages in thread
From: Badhri Jagan Sridharan @ 2020-12-02 4:08 UTC (permalink / raw)
To: Guenter Roeck, Heikki Krogerus, Greg Kroah-Hartman
Cc: linux-usb, linux-kernel, Badhri Jagan Sridharan
Unmask EXTENDED_STATUS_MASK.vSafe0V, ALERT.Extended_Status
and set vbus_vsafe0v to enable VSAFE0V signalling.
Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
---
Changes since v1:
- Setting auto_discharge_disconnect to true instead of 1 as
suggested by Guenter.
---
drivers/usb/typec/tcpm/tcpci_maxim.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c
index c1797239bf08..319266329b42 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim.c
@@ -112,11 +112,18 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
return;
}
+ /* Enable VSAFE0V detection */
+ ret = max_tcpci_write8(chip, TCPC_EXTENDED_STATUS_MASK, TCPC_EXTENDED_STATUS_VSAFE0V);
+ if (ret < 0) {
+ dev_err(chip->dev, "Unable to unmask TCPC_EXTENDED_STATUS_VSAFE0V ret:%d\n", ret);
+ return;
+ }
+
alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
/* Enable Extended alert for detecting Fast Role Swap Signal */
- TCPC_ALERT_EXTND;
+ TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
if (ret < 0) {
@@ -315,6 +322,12 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
}
}
+ if (status & TCPC_ALERT_EXTENDED_STATUS) {
+ ret = max_tcpci_read8(chip, TCPC_EXTENDED_STATUS, (u8 *)®_status);
+ if (ret >= 0 && (reg_status & TCPC_EXTENDED_STATUS_VSAFE0V))
+ tcpm_vbus_change(chip->port);
+ }
+
if (status & TCPC_ALERT_RX_STATUS)
process_rx(chip, status);
@@ -442,6 +455,7 @@ static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id
chip->data.init = tcpci_init;
chip->data.frs_sourcing_vbus = max_tcpci_frs_sourcing_vbus;
chip->data.auto_discharge_disconnect = true;
+ chip->data.vbus_vsafe0v = true;
max_tcpci_init_regs(chip);
chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
--
2.29.2.576.ga3fc446d84-goog
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling
2020-12-02 4:08 ` [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling Badhri Jagan Sridharan
@ 2020-12-08 9:26 ` Heikki Krogerus
2020-12-08 19:33 ` Guenter Roeck
1 sibling, 0 replies; 9+ messages in thread
From: Heikki Krogerus @ 2020-12-08 9:26 UTC (permalink / raw)
To: Badhri Jagan Sridharan
Cc: Guenter Roeck, Greg Kroah-Hartman, linux-usb, linux-kernel
On Tue, Dec 01, 2020 at 08:08:40PM -0800, Badhri Jagan Sridharan wrote:
> Unmask EXTENDED_STATUS_MASK.vSafe0V, ALERT.Extended_Status
> and set vbus_vsafe0v to enable VSAFE0V signalling.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> ---
> Changes since v1:
> - Setting auto_discharge_disconnect to true instead of 1 as
> suggested by Guenter.
> ---
> drivers/usb/typec/tcpm/tcpci_maxim.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c
> index c1797239bf08..319266329b42 100644
> --- a/drivers/usb/typec/tcpm/tcpci_maxim.c
> +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c
> @@ -112,11 +112,18 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
> return;
> }
>
> + /* Enable VSAFE0V detection */
> + ret = max_tcpci_write8(chip, TCPC_EXTENDED_STATUS_MASK, TCPC_EXTENDED_STATUS_VSAFE0V);
> + if (ret < 0) {
> + dev_err(chip->dev, "Unable to unmask TCPC_EXTENDED_STATUS_VSAFE0V ret:%d\n", ret);
> + return;
> + }
> +
> alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
> TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
> TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
> /* Enable Extended alert for detecting Fast Role Swap Signal */
> - TCPC_ALERT_EXTND;
> + TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
>
> ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
> if (ret < 0) {
> @@ -315,6 +322,12 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
> }
> }
>
> + if (status & TCPC_ALERT_EXTENDED_STATUS) {
> + ret = max_tcpci_read8(chip, TCPC_EXTENDED_STATUS, (u8 *)®_status);
> + if (ret >= 0 && (reg_status & TCPC_EXTENDED_STATUS_VSAFE0V))
> + tcpm_vbus_change(chip->port);
> + }
> +
> if (status & TCPC_ALERT_RX_STATUS)
> process_rx(chip, status);
>
> @@ -442,6 +455,7 @@ static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id
> chip->data.init = tcpci_init;
> chip->data.frs_sourcing_vbus = max_tcpci_frs_sourcing_vbus;
> chip->data.auto_discharge_disconnect = true;
> + chip->data.vbus_vsafe0v = true;
>
> max_tcpci_init_regs(chip);
> chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
> --
> 2.29.2.576.ga3fc446d84-goog
--
heikki
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling
2020-12-02 4:08 ` [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling Badhri Jagan Sridharan
2020-12-08 9:26 ` Heikki Krogerus
@ 2020-12-08 19:33 ` Guenter Roeck
1 sibling, 0 replies; 9+ messages in thread
From: Guenter Roeck @ 2020-12-08 19:33 UTC (permalink / raw)
To: Badhri Jagan Sridharan
Cc: Heikki Krogerus, Greg Kroah-Hartman, linux-usb, linux-kernel
On Tue, Dec 01, 2020 at 08:08:40PM -0800, Badhri Jagan Sridharan wrote:
> Unmask EXTENDED_STATUS_MASK.vSafe0V, ALERT.Extended_Status
> and set vbus_vsafe0v to enable VSAFE0V signalling.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> Changes since v1:
> - Setting auto_discharge_disconnect to true instead of 1 as
> suggested by Guenter.
> ---
> drivers/usb/typec/tcpm/tcpci_maxim.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c
> index c1797239bf08..319266329b42 100644
> --- a/drivers/usb/typec/tcpm/tcpci_maxim.c
> +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c
> @@ -112,11 +112,18 @@ static void max_tcpci_init_regs(struct max_tcpci_chip *chip)
> return;
> }
>
> + /* Enable VSAFE0V detection */
> + ret = max_tcpci_write8(chip, TCPC_EXTENDED_STATUS_MASK, TCPC_EXTENDED_STATUS_VSAFE0V);
> + if (ret < 0) {
> + dev_err(chip->dev, "Unable to unmask TCPC_EXTENDED_STATUS_VSAFE0V ret:%d\n", ret);
> + return;
> + }
> +
> alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_FAILED |
> TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_RX_STATUS | TCPC_ALERT_CC_STATUS |
> TCPC_ALERT_VBUS_DISCNCT | TCPC_ALERT_RX_BUF_OVF | TCPC_ALERT_POWER_STATUS |
> /* Enable Extended alert for detecting Fast Role Swap Signal */
> - TCPC_ALERT_EXTND;
> + TCPC_ALERT_EXTND | TCPC_ALERT_EXTENDED_STATUS;
>
> ret = max_tcpci_write16(chip, TCPC_ALERT_MASK, alert_mask);
> if (ret < 0) {
> @@ -315,6 +322,12 @@ static irqreturn_t _max_tcpci_irq(struct max_tcpci_chip *chip, u16 status)
> }
> }
>
> + if (status & TCPC_ALERT_EXTENDED_STATUS) {
> + ret = max_tcpci_read8(chip, TCPC_EXTENDED_STATUS, (u8 *)®_status);
> + if (ret >= 0 && (reg_status & TCPC_EXTENDED_STATUS_VSAFE0V))
> + tcpm_vbus_change(chip->port);
> + }
> +
> if (status & TCPC_ALERT_RX_STATUS)
> process_rx(chip, status);
>
> @@ -442,6 +455,7 @@ static int max_tcpci_probe(struct i2c_client *client, const struct i2c_device_id
> chip->data.init = tcpci_init;
> chip->data.frs_sourcing_vbus = max_tcpci_frs_sourcing_vbus;
> chip->data.auto_discharge_disconnect = true;
> + chip->data.vbus_vsafe0v = true;
>
> max_tcpci_init_regs(chip);
> chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
> --
> 2.29.2.576.ga3fc446d84-goog
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus
2020-12-02 4:08 [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus Badhri Jagan Sridharan
2020-12-02 4:08 ` [PATCH v2 2/3] usb: typec: tcpci: Add support to report vSafe0V Badhri Jagan Sridharan
2020-12-02 4:08 ` [PATCH v2 3/3] usb: typec: tcpci_maxim: Enable VSAFE0V signalling Badhri Jagan Sridharan
@ 2020-12-08 9:24 ` Heikki Krogerus
2020-12-08 19:31 ` Guenter Roeck
3 siblings, 0 replies; 9+ messages in thread
From: Heikki Krogerus @ 2020-12-08 9:24 UTC (permalink / raw)
To: Badhri Jagan Sridharan
Cc: Guenter Roeck, Greg Kroah-Hartman, linux-usb, linux-kernel
On Tue, Dec 01, 2020 at 08:08:38PM -0800, Badhri Jagan Sridharan wrote:
> TCPM at present lacks the notion of VSAFE0V. There
> are three vbus threshold levels that are critical to track:
> a. vSafe5V - VBUS “5 volts” as defined by the USB
> PD specification.
> b. vSinkDisconnect - Threshold used for transition from
> Attached.SNK to Unattached.SNK.
> c. vSafe0V - VBUS “0 volts” as defined by the USB
> PD specification.
>
> Tracking vSafe0V is crucial for entry into Try.SNK and
> Attached.SRC and turning vbus back on by the source in
> response to hard reset.
>
> >From "4.5.2.2.8.2 Exiting from AttachWait.SRC State" section
> in the Type-C spec:
>
> "The port shall transition to Attached.SRC when VBUS is at
> vSafe0V and the SRC.Rd state is detected on exactly one of
> the CC1 or CC2 pins for at least tCCDebounce."
>
> "A DRP that strongly prefers the Sink role may optionally
> transition to Try.SNK instead of Attached.SRC when VBUS
> is at vSafe0V and the SRC.Rd state is detected on exactly
> one of the CC1 or CC2 pins for at least tCCDebounce."
>
> >From "7.1.5 Response to Hard Resets" section in the PD spec:
>
> "After establishing the vSafe0V voltage condition on VBUS,
> the Source Shall wait tSrcRecover before re-applying VCONN
> and restoring VBUS to vSafe5V."
>
> vbus_present in the TCPM code tracks vSafe5V(vbus_present is true)
> and vSinkDisconnect(vbus_present is false).
>
> This change adds is_vbus_vsafe0v callback which when set makes
> TCPM query for vSafe0V voltage level when needed.
>
> Since not all TCPC controllers might have the capability
> to report vSafe0V, TCPM assumes that vSafe0V is same as
> vSinkDisconnect when is_vbus_vsafe0v callback is not set.
> This allows TCPM to continue to support controllers which don't
> have the support for reporting vSafe0V.
>
> Introducing vSafe0V helps fix the failure reported at
> "Step 15. CVS verifies PUT remains in AttachWait.SRC for 500ms"
> of "TD 4.7.2 Try. SNK DRP Connect DRP Test" of
> "Universal Serial Bus Type-C (USB Type-C) Functional Test
> Specification Chapters 4 and 5". Here the compliance tester
> intentionally maintains vbus at greater than vSafe0V and expects
> the Product under test to stay in AttachWait.SRC till vbus drops
> to vSafe0V.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Guenter really should check these, but FWIW:
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> ---
> Changes since v1:
> - Changed return type to bool instead of int for
> is_vbus_vsafe0v as suggested by Guenter and updated
> the documentation.
> ---
> drivers/usb/typec/tcpm/tcpm.c | 63 +++++++++++++++++++++++++++++------
> include/linux/usb/tcpm.h | 7 ++++
> 2 files changed, 59 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index 3bbc1f10af49..4cd6e0196f94 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -258,7 +258,19 @@ struct tcpm_port {
> bool attached;
> bool connected;
> enum typec_port_type port_type;
> +
> + /*
> + * Set to true when vbus is greater than VSAFE5V min.
> + * Set to false when vbus falls below vSinkDisconnect max threshold.
> + */
> bool vbus_present;
> +
> + /*
> + * Set to true when vbus is less than VSAFE0V max.
> + * Set to false when vbus is greater than VSAFE0V max.
> + */
> + bool vbus_vsafe0v;
> +
> bool vbus_never_low;
> bool vbus_source;
> bool vbus_charge;
> @@ -3094,7 +3106,7 @@ static void run_state_machine(struct tcpm_port *port)
> else if (tcpm_port_is_audio(port))
> tcpm_set_state(port, AUDIO_ACC_ATTACHED,
> PD_T_CC_DEBOUNCE);
> - else if (tcpm_port_is_source(port))
> + else if (tcpm_port_is_source(port) && port->vbus_vsafe0v)
> tcpm_set_state(port,
> tcpm_try_snk(port) ? SNK_TRY
> : SRC_ATTACHED,
> @@ -4097,6 +4109,12 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
> {
> tcpm_log_force(port, "VBUS on");
> port->vbus_present = true;
> + /*
> + * When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
> + * states that vbus is not at VSAFE0V, hence clear the vbus_vsafe0v flag here.
> + */
> + port->vbus_vsafe0v = false;
> +
> switch (port->state) {
> case SNK_TRANSITION_SINK_VBUS:
> port->explicit_contract = true;
> @@ -4186,16 +4204,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
> case SNK_HARD_RESET_SINK_OFF:
> tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
> break;
> - case SRC_HARD_RESET_VBUS_OFF:
> - /*
> - * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
> - * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
> - */
> - tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
> - break;
> case HARD_RESET_SEND:
> break;
> -
> case SNK_TRY:
> /* Do nothing, waiting for timeout */
> break;
> @@ -4266,6 +4276,28 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
> }
> }
>
> +static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
> +{
> + tcpm_log_force(port, "VBUS VSAFE0V");
> + port->vbus_vsafe0v = true;
> + switch (port->state) {
> + case SRC_HARD_RESET_VBUS_OFF:
> + /*
> + * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
> + * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
> + */
> + tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
> + break;
> + case SRC_ATTACH_WAIT:
> + if (tcpm_port_is_source(port))
> + tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED,
> + PD_T_CC_DEBOUNCE);
> + break;
> + default:
> + break;
> + }
> +}
> +
> static void _tcpm_pd_hard_reset(struct tcpm_port *port)
> {
> tcpm_log_force(port, "Received hard reset");
> @@ -4301,10 +4333,19 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
> bool vbus;
>
> vbus = port->tcpc->get_vbus(port->tcpc);
> - if (vbus)
> + if (vbus) {
> _tcpm_pd_vbus_on(port);
> - else
> + } else {
> _tcpm_pd_vbus_off(port);
> + /*
> + * When TCPC does not support detecting vsafe0v voltage level,
> + * treat vbus absent as vsafe0v. Else invoke is_vbus_vsafe0v
> + * to see if vbus has discharge to VSAFE0V.
> + */
> + if (!port->tcpc->is_vbus_vsafe0v ||
> + port->tcpc->is_vbus_vsafe0v(port->tcpc))
> + _tcpm_pd_vbus_vsafe0v(port);
> + }
> }
> if (events & TCPM_CC_EVENT) {
> enum typec_cc_status cc1, cc2;
> diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
> index e68aaa12886f..3e39874cfac4 100644
> --- a/include/linux/usb/tcpm.h
> +++ b/include/linux/usb/tcpm.h
> @@ -98,6 +98,12 @@ enum tcpm_transmit_type {
> * will be turned on. requested_vbus_voltage is set to 0 when vbus
> * is going to disappear knowingly i.e. during PR_SWAP and
> * HARD_RESET etc.
> + * @is_vbus_vsafe0v:
> + * Optional; TCPCI spec based TCPC implementations are expected to
> + * detect VSAFE0V voltage level at vbus. When detection of VSAFE0V
> + * is supported by TCPC, set this callback for TCPM to query
> + * whether vbus is at VSAFE0V when needed.
> + * Returns true when vbus is at VSAFE0V, false otherwise.
> */
> struct tcpc_dev {
> struct fwnode_handle *fwnode;
> @@ -128,6 +134,7 @@ struct tcpc_dev {
> int (*enable_auto_vbus_discharge)(struct tcpc_dev *dev, bool enable);
> int (*set_auto_vbus_discharge_threshold)(struct tcpc_dev *dev, enum typec_pwr_opmode mode,
> bool pps_active, u32 requested_vbus_voltage);
> + bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev);
> };
>
> struct tcpm_port;
> --
> 2.29.2.576.ga3fc446d84-goog
--
heikki
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus
2020-12-02 4:08 [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus Badhri Jagan Sridharan
` (2 preceding siblings ...)
2020-12-08 9:24 ` [PATCH v2 1/3] usb: typec: tcpm: Introduce vsafe0v for vbus Heikki Krogerus
@ 2020-12-08 19:31 ` Guenter Roeck
3 siblings, 0 replies; 9+ messages in thread
From: Guenter Roeck @ 2020-12-08 19:31 UTC (permalink / raw)
To: Badhri Jagan Sridharan
Cc: Heikki Krogerus, Greg Kroah-Hartman, linux-usb, linux-kernel
On Tue, Dec 01, 2020 at 08:08:38PM -0800, Badhri Jagan Sridharan wrote:
> TCPM at present lacks the notion of VSAFE0V. There
> are three vbus threshold levels that are critical to track:
> a. vSafe5V - VBUS “5 volts” as defined by the USB
> PD specification.
> b. vSinkDisconnect - Threshold used for transition from
> Attached.SNK to Unattached.SNK.
> c. vSafe0V - VBUS “0 volts” as defined by the USB
> PD specification.
>
> Tracking vSafe0V is crucial for entry into Try.SNK and
> Attached.SRC and turning vbus back on by the source in
> response to hard reset.
>
> From "4.5.2.2.8.2 Exiting from AttachWait.SRC State" section
> in the Type-C spec:
>
> "The port shall transition to Attached.SRC when VBUS is at
> vSafe0V and the SRC.Rd state is detected on exactly one of
> the CC1 or CC2 pins for at least tCCDebounce."
>
> "A DRP that strongly prefers the Sink role may optionally
> transition to Try.SNK instead of Attached.SRC when VBUS
> is at vSafe0V and the SRC.Rd state is detected on exactly
> one of the CC1 or CC2 pins for at least tCCDebounce."
>
> From "7.1.5 Response to Hard Resets" section in the PD spec:
>
> "After establishing the vSafe0V voltage condition on VBUS,
> the Source Shall wait tSrcRecover before re-applying VCONN
> and restoring VBUS to vSafe5V."
>
> vbus_present in the TCPM code tracks vSafe5V(vbus_present is true)
> and vSinkDisconnect(vbus_present is false).
>
> This change adds is_vbus_vsafe0v callback which when set makes
> TCPM query for vSafe0V voltage level when needed.
>
> Since not all TCPC controllers might have the capability
> to report vSafe0V, TCPM assumes that vSafe0V is same as
> vSinkDisconnect when is_vbus_vsafe0v callback is not set.
> This allows TCPM to continue to support controllers which don't
> have the support for reporting vSafe0V.
>
> Introducing vSafe0V helps fix the failure reported at
> "Step 15. CVS verifies PUT remains in AttachWait.SRC for 500ms"
> of "TD 4.7.2 Try. SNK DRP Connect DRP Test" of
> "Universal Serial Bus Type-C (USB Type-C) Functional Test
> Specification Chapters 4 and 5". Here the compliance tester
> intentionally maintains vbus at greater than vSafe0V and expects
> the Product under test to stay in AttachWait.SRC till vbus drops
> to vSafe0V.
>
> Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
> ---
> Changes since v1:
> - Changed return type to bool instead of int for
> is_vbus_vsafe0v as suggested by Guenter and updated
> the documentation.
> ---
> drivers/usb/typec/tcpm/tcpm.c | 63 +++++++++++++++++++++++++++++------
> include/linux/usb/tcpm.h | 7 ++++
> 2 files changed, 59 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index 3bbc1f10af49..4cd6e0196f94 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -258,7 +258,19 @@ struct tcpm_port {
> bool attached;
> bool connected;
> enum typec_port_type port_type;
> +
> + /*
> + * Set to true when vbus is greater than VSAFE5V min.
> + * Set to false when vbus falls below vSinkDisconnect max threshold.
> + */
> bool vbus_present;
> +
> + /*
> + * Set to true when vbus is less than VSAFE0V max.
> + * Set to false when vbus is greater than VSAFE0V max.
> + */
> + bool vbus_vsafe0v;
> +
> bool vbus_never_low;
> bool vbus_source;
> bool vbus_charge;
> @@ -3094,7 +3106,7 @@ static void run_state_machine(struct tcpm_port *port)
> else if (tcpm_port_is_audio(port))
> tcpm_set_state(port, AUDIO_ACC_ATTACHED,
> PD_T_CC_DEBOUNCE);
> - else if (tcpm_port_is_source(port))
> + else if (tcpm_port_is_source(port) && port->vbus_vsafe0v)
> tcpm_set_state(port,
> tcpm_try_snk(port) ? SNK_TRY
> : SRC_ATTACHED,
> @@ -4097,6 +4109,12 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
> {
> tcpm_log_force(port, "VBUS on");
> port->vbus_present = true;
> + /*
> + * When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
> + * states that vbus is not at VSAFE0V, hence clear the vbus_vsafe0v flag here.
> + */
> + port->vbus_vsafe0v = false;
> +
> switch (port->state) {
> case SNK_TRANSITION_SINK_VBUS:
> port->explicit_contract = true;
> @@ -4186,16 +4204,8 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
> case SNK_HARD_RESET_SINK_OFF:
> tcpm_set_state(port, SNK_HARD_RESET_WAIT_VBUS, 0);
> break;
> - case SRC_HARD_RESET_VBUS_OFF:
> - /*
> - * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
> - * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
> - */
> - tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
> - break;
> case HARD_RESET_SEND:
> break;
> -
> case SNK_TRY:
> /* Do nothing, waiting for timeout */
> break;
> @@ -4266,6 +4276,28 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
> }
> }
>
> +static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
> +{
> + tcpm_log_force(port, "VBUS VSAFE0V");
> + port->vbus_vsafe0v = true;
> + switch (port->state) {
> + case SRC_HARD_RESET_VBUS_OFF:
> + /*
> + * After establishing the vSafe0V voltage condition on VBUS, the Source Shall wait
> + * tSrcRecover before re-applying VCONN and restoring VBUS to vSafe5V.
> + */
> + tcpm_set_state(port, SRC_HARD_RESET_VBUS_ON, PD_T_SRC_RECOVER);
> + break;
> + case SRC_ATTACH_WAIT:
> + if (tcpm_port_is_source(port))
> + tcpm_set_state(port, tcpm_try_snk(port) ? SNK_TRY : SRC_ATTACHED,
> + PD_T_CC_DEBOUNCE);
> + break;
> + default:
> + break;
> + }
> +}
> +
> static void _tcpm_pd_hard_reset(struct tcpm_port *port)
> {
> tcpm_log_force(port, "Received hard reset");
> @@ -4301,10 +4333,19 @@ static void tcpm_pd_event_handler(struct kthread_work *work)
> bool vbus;
>
> vbus = port->tcpc->get_vbus(port->tcpc);
> - if (vbus)
> + if (vbus) {
> _tcpm_pd_vbus_on(port);
> - else
> + } else {
> _tcpm_pd_vbus_off(port);
> + /*
> + * When TCPC does not support detecting vsafe0v voltage level,
> + * treat vbus absent as vsafe0v. Else invoke is_vbus_vsafe0v
> + * to see if vbus has discharge to VSAFE0V.
> + */
> + if (!port->tcpc->is_vbus_vsafe0v ||
> + port->tcpc->is_vbus_vsafe0v(port->tcpc))
> + _tcpm_pd_vbus_vsafe0v(port);
> + }
> }
> if (events & TCPM_CC_EVENT) {
> enum typec_cc_status cc1, cc2;
> diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
> index e68aaa12886f..3e39874cfac4 100644
> --- a/include/linux/usb/tcpm.h
> +++ b/include/linux/usb/tcpm.h
> @@ -98,6 +98,12 @@ enum tcpm_transmit_type {
> * will be turned on. requested_vbus_voltage is set to 0 when vbus
> * is going to disappear knowingly i.e. during PR_SWAP and
> * HARD_RESET etc.
> + * @is_vbus_vsafe0v:
> + * Optional; TCPCI spec based TCPC implementations are expected to
> + * detect VSAFE0V voltage level at vbus. When detection of VSAFE0V
> + * is supported by TCPC, set this callback for TCPM to query
> + * whether vbus is at VSAFE0V when needed.
> + * Returns true when vbus is at VSAFE0V, false otherwise.
> */
> struct tcpc_dev {
> struct fwnode_handle *fwnode;
> @@ -128,6 +134,7 @@ struct tcpc_dev {
> int (*enable_auto_vbus_discharge)(struct tcpc_dev *dev, bool enable);
> int (*set_auto_vbus_discharge_threshold)(struct tcpc_dev *dev, enum typec_pwr_opmode mode,
> bool pps_active, u32 requested_vbus_voltage);
> + bool (*is_vbus_vsafe0v)(struct tcpc_dev *dev);
> };
>
> struct tcpm_port;
> --
> 2.29.2.576.ga3fc446d84-goog
>
^ permalink raw reply [flat|nested] 9+ messages in thread