All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-21 15:02 ` ShuFanLee
  0 siblings, 0 replies; 22+ messages in thread
From: ShuFanLee @ 2018-02-21 15:02 UTC (permalink / raw)
  To: heikki.krogerus, linux, greg
  Cc: shufan_lee, cy_huang, linux-kernel, linux-usb

From: ShuFanLee <shufan_lee@richtek.com>

Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq.
More operations can be extended in tcpci_data if needed.
According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
TCPC shall not start DRP toggling until subsequently the TCPM
writes to the COMMAND register to start DRP toggling.
DRP toggling flow is chagned as following:
  - Write DRP = 0 & Rd/Rd
  - Write DRP = 1
  - Set LOOK4CONNECTION command

Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
---
 drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++---------
 drivers/staging/typec/tcpci.h |  13 +++++
 2 files changed, 115 insertions(+), 26 deletions(-)

 patch changelogs between v1 & v2
 - Remove unnecessary i2c_client in the structure of tcpci
 - Rename structure of tcpci_vendor_data to tcpci_data
 - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver
 - Add set_vconn ops in tcpci_data
   (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn)
 - Export tcpci_irq so that vendor can call it in their own IRQ handler

 patch changelogs between v2 & v3
 - Change the return type of tcpci_irq from int to irqreturn_t

diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
index 9bd4412..4959c69 100644
--- a/drivers/staging/typec/tcpci.c
+++ b/drivers/staging/typec/tcpci.c
@@ -21,7 +21,6 @@
 
 struct tcpci {
 	struct device *dev;
-	struct i2c_client *client;
 
 	struct tcpm_port *port;
 
@@ -30,6 +29,12 @@ struct tcpci {
 	bool controls_vbus;
 
 	struct tcpc_dev tcpc;
+	struct tcpci_data *data;
+};
+
+struct tcpci_chip {
+	struct tcpci *tcpci;
+	struct tcpci_data data;
 };
 
 static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
@@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
 	return container_of(tcpc, struct tcpci, tcpc);
 }
 
-static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
-			u16 *val)
+static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
 {
 	return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
 }
@@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
 static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
 				    enum typec_cc_status cc)
 {
+	int ret;
 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
-	unsigned int reg = TCPC_ROLE_CTRL_DRP;
+	unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
+			   (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
 
 	switch (cc) {
 	default:
@@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
 		break;
 	}
 
-	return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+	if (ret < 0)
+		return ret;
+	usleep_range(500, 1000);
+	reg |= TCPC_ROLE_CTRL_DRP;
+	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+			   TCPC_CMD_LOOK4CONNECTION);
+	if (ret < 0)
+		return ret;
+	return 0;
 }
 
 static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
@@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
 	int ret;
 
+	/* Handle vendor set vconn */
+	if (tcpci->data) {
+		if (tcpci->data->set_vconn) {
+			ret = tcpci->data->set_vconn(tcpci, tcpci->data,
+						     enable);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
 			   enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
 	if (ret < 0)
@@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
 	if (time_after(jiffies, timeout))
 		return -ETIMEDOUT;
 
+	/* Handle vendor init */
+	if (tcpci->data) {
+		if (tcpci->data->init) {
+			ret = tcpci->data->init(tcpci, tcpci->data);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	/* Clear all events */
 	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
 	if (ret < 0)
@@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
 	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
 }
 
-static irqreturn_t tcpci_irq(int irq, void *dev_id)
+static irqreturn_t _tcpci_irq(int irq, void *dev_id)
 {
 	struct tcpci *tcpci = dev_id;
+
+	return tcpci_irq(tcpci);
+}
+
+irqreturn_t tcpci_irq(struct tcpci *tcpci)
+{
 	u16 status;
 
 	tcpci_read16(tcpci, TCPC_ALERT, &status);
@@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
 
 	return IRQ_HANDLED;
 }
+EXPORT_SYMBOL_GPL(tcpci_irq);
 
 static const struct regmap_config tcpci_regmap_config = {
 	.reg_bits = 8,
@@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
 	return 0;
 }
 
-static int tcpci_probe(struct i2c_client *client,
-		       const struct i2c_device_id *i2c_id)
+struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
 {
 	struct tcpci *tcpci;
 	int err;
 
-	tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
+	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
 	if (!tcpci)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	tcpci->client = client;
-	tcpci->dev = &client->dev;
-	i2c_set_clientdata(client, tcpci);
-	tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
-	if (IS_ERR(tcpci->regmap))
-		return PTR_ERR(tcpci->regmap);
+	tcpci->dev = dev;
+	tcpci->data = data;
+	tcpci->regmap = data->regmap;
 
 	tcpci->tcpc.init = tcpci_init;
 	tcpci->tcpc.get_vbus = tcpci_get_vbus;
@@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
 
 	err = tcpci_parse_config(tcpci);
 	if (err < 0)
-		return err;
+		return ERR_PTR(err);
+
+	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
+	if (PTR_ERR_OR_ZERO(tcpci->port))
+		return ERR_CAST(tcpci->port);
 
-	/* Disable chip interrupts */
-	tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
+	return tcpci;
+}
+EXPORT_SYMBOL_GPL(tcpci_register_port);
+
+void tcpci_unregister_port(struct tcpci *tcpci)
+{
+	tcpm_unregister_port(tcpci->port);
+}
+EXPORT_SYMBOL_GPL(tcpci_unregister_port);
 
-	err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
-					tcpci_irq,
+static int tcpci_probe(struct i2c_client *client,
+		       const struct i2c_device_id *i2c_id)
+{
+	struct tcpci_chip *chip;
+	int err;
+	u16 val = 0;
+
+	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
+	if (IS_ERR(chip->data.regmap))
+		return PTR_ERR(chip->data.regmap);
+
+	/* Disable chip interrupts before requesting irq */
+	err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
+			       sizeof(u16));
+	if (err < 0)
+		return err;
+
+	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+					_tcpci_irq,
 					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
-					dev_name(tcpci->dev), tcpci);
+					dev_name(&client->dev), chip);
 	if (err < 0)
 		return err;
 
-	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
-	return PTR_ERR_OR_ZERO(tcpci->port);
+	chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
+	if (PTR_ERR_OR_ZERO(chip->tcpci))
+		return PTR_ERR(chip->tcpci);
+
+	i2c_set_clientdata(client, chip);
+	return 0;
 }
 
 static int tcpci_remove(struct i2c_client *client)
 {
-	struct tcpci *tcpci = i2c_get_clientdata(client);
+	struct tcpci_chip *chip = i2c_get_clientdata(client);
 
-	tcpm_unregister_port(tcpci->port);
+	tcpci_unregister_port(chip->tcpci);
 
 	return 0;
 }
diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
index fdfb06c..40025b2 100644
--- a/drivers/staging/typec/tcpci.h
+++ b/drivers/staging/typec/tcpci.h
@@ -59,6 +59,7 @@
 #define TCPC_POWER_CTRL_VCONN_ENABLE	BIT(0)
 
 #define TCPC_CC_STATUS			0x1d
+#define TCPC_CC_STATUS_DRPRST		BIT(5)
 #define TCPC_CC_STATUS_TERM		BIT(4)
 #define TCPC_CC_STATUS_CC2_SHIFT	2
 #define TCPC_CC_STATUS_CC2_MASK		0x3
@@ -121,4 +122,16 @@
 #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG		0x76
 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG		0x78
 
+struct tcpci;
+struct tcpci_data {
+	struct regmap *regmap;
+	int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
+	int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
+			 bool enable);
+};
+
+struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
+void tcpci_unregister_port(struct tcpci *tcpci);
+irqreturn_t tcpci_irq(struct tcpci *tcpci);
+
 #endif /* __LINUX_USB_TCPCI_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-21 15:02 ` ShuFanLee
  0 siblings, 0 replies; 22+ messages in thread
From: ShuFanLee @ 2018-02-21 15:02 UTC (permalink / raw)
  To: heikki.krogerus, linux, greg
  Cc: shufan_lee, cy_huang, linux-kernel, linux-usb

From: ShuFanLee <shufan_lee@richtek.com>

Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq.
More operations can be extended in tcpci_data if needed.
According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
TCPC shall not start DRP toggling until subsequently the TCPM
writes to the COMMAND register to start DRP toggling.
DRP toggling flow is chagned as following:
  - Write DRP = 0 & Rd/Rd
  - Write DRP = 1
  - Set LOOK4CONNECTION command

Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
---
 drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++---------
 drivers/staging/typec/tcpci.h |  13 +++++
 2 files changed, 115 insertions(+), 26 deletions(-)

 patch changelogs between v1 & v2
 - Remove unnecessary i2c_client in the structure of tcpci
 - Rename structure of tcpci_vendor_data to tcpci_data
 - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver
 - Add set_vconn ops in tcpci_data
   (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn)
 - Export tcpci_irq so that vendor can call it in their own IRQ handler

 patch changelogs between v2 & v3
 - Change the return type of tcpci_irq from int to irqreturn_t

diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
index 9bd4412..4959c69 100644
--- a/drivers/staging/typec/tcpci.c
+++ b/drivers/staging/typec/tcpci.c
@@ -21,7 +21,6 @@
 
 struct tcpci {
 	struct device *dev;
-	struct i2c_client *client;
 
 	struct tcpm_port *port;
 
@@ -30,6 +29,12 @@ struct tcpci {
 	bool controls_vbus;
 
 	struct tcpc_dev tcpc;
+	struct tcpci_data *data;
+};
+
+struct tcpci_chip {
+	struct tcpci *tcpci;
+	struct tcpci_data data;
 };
 
 static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
@@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
 	return container_of(tcpc, struct tcpci, tcpc);
 }
 
-static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
-			u16 *val)
+static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
 {
 	return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
 }
@@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
 static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
 				    enum typec_cc_status cc)
 {
+	int ret;
 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
-	unsigned int reg = TCPC_ROLE_CTRL_DRP;
+	unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
+			   (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
 
 	switch (cc) {
 	default:
@@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
 		break;
 	}
 
-	return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+	if (ret < 0)
+		return ret;
+	usleep_range(500, 1000);
+	reg |= TCPC_ROLE_CTRL_DRP;
+	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+			   TCPC_CMD_LOOK4CONNECTION);
+	if (ret < 0)
+		return ret;
+	return 0;
 }
 
 static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
@@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
 	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
 	int ret;
 
+	/* Handle vendor set vconn */
+	if (tcpci->data) {
+		if (tcpci->data->set_vconn) {
+			ret = tcpci->data->set_vconn(tcpci, tcpci->data,
+						     enable);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
 			   enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
 	if (ret < 0)
@@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
 	if (time_after(jiffies, timeout))
 		return -ETIMEDOUT;
 
+	/* Handle vendor init */
+	if (tcpci->data) {
+		if (tcpci->data->init) {
+			ret = tcpci->data->init(tcpci, tcpci->data);
+			if (ret < 0)
+				return ret;
+		}
+	}
+
 	/* Clear all events */
 	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
 	if (ret < 0)
@@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
 	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
 }
 
-static irqreturn_t tcpci_irq(int irq, void *dev_id)
+static irqreturn_t _tcpci_irq(int irq, void *dev_id)
 {
 	struct tcpci *tcpci = dev_id;
+
+	return tcpci_irq(tcpci);
+}
+
+irqreturn_t tcpci_irq(struct tcpci *tcpci)
+{
 	u16 status;
 
 	tcpci_read16(tcpci, TCPC_ALERT, &status);
@@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
 
 	return IRQ_HANDLED;
 }
+EXPORT_SYMBOL_GPL(tcpci_irq);
 
 static const struct regmap_config tcpci_regmap_config = {
 	.reg_bits = 8,
@@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
 	return 0;
 }
 
-static int tcpci_probe(struct i2c_client *client,
-		       const struct i2c_device_id *i2c_id)
+struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
 {
 	struct tcpci *tcpci;
 	int err;
 
-	tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
+	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
 	if (!tcpci)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	tcpci->client = client;
-	tcpci->dev = &client->dev;
-	i2c_set_clientdata(client, tcpci);
-	tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
-	if (IS_ERR(tcpci->regmap))
-		return PTR_ERR(tcpci->regmap);
+	tcpci->dev = dev;
+	tcpci->data = data;
+	tcpci->regmap = data->regmap;
 
 	tcpci->tcpc.init = tcpci_init;
 	tcpci->tcpc.get_vbus = tcpci_get_vbus;
@@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
 
 	err = tcpci_parse_config(tcpci);
 	if (err < 0)
-		return err;
+		return ERR_PTR(err);
+
+	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
+	if (PTR_ERR_OR_ZERO(tcpci->port))
+		return ERR_CAST(tcpci->port);
 
-	/* Disable chip interrupts */
-	tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
+	return tcpci;
+}
+EXPORT_SYMBOL_GPL(tcpci_register_port);
+
+void tcpci_unregister_port(struct tcpci *tcpci)
+{
+	tcpm_unregister_port(tcpci->port);
+}
+EXPORT_SYMBOL_GPL(tcpci_unregister_port);
 
-	err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
-					tcpci_irq,
+static int tcpci_probe(struct i2c_client *client,
+		       const struct i2c_device_id *i2c_id)
+{
+	struct tcpci_chip *chip;
+	int err;
+	u16 val = 0;
+
+	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
+	if (IS_ERR(chip->data.regmap))
+		return PTR_ERR(chip->data.regmap);
+
+	/* Disable chip interrupts before requesting irq */
+	err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
+			       sizeof(u16));
+	if (err < 0)
+		return err;
+
+	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+					_tcpci_irq,
 					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
-					dev_name(tcpci->dev), tcpci);
+					dev_name(&client->dev), chip);
 	if (err < 0)
 		return err;
 
-	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
-	return PTR_ERR_OR_ZERO(tcpci->port);
+	chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
+	if (PTR_ERR_OR_ZERO(chip->tcpci))
+		return PTR_ERR(chip->tcpci);
+
+	i2c_set_clientdata(client, chip);
+	return 0;
 }
 
 static int tcpci_remove(struct i2c_client *client)
 {
-	struct tcpci *tcpci = i2c_get_clientdata(client);
+	struct tcpci_chip *chip = i2c_get_clientdata(client);
 
-	tcpm_unregister_port(tcpci->port);
+	tcpci_unregister_port(chip->tcpci);
 
 	return 0;
 }
diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
index fdfb06c..40025b2 100644
--- a/drivers/staging/typec/tcpci.h
+++ b/drivers/staging/typec/tcpci.h
@@ -59,6 +59,7 @@
 #define TCPC_POWER_CTRL_VCONN_ENABLE	BIT(0)
 
 #define TCPC_CC_STATUS			0x1d
+#define TCPC_CC_STATUS_DRPRST		BIT(5)
 #define TCPC_CC_STATUS_TERM		BIT(4)
 #define TCPC_CC_STATUS_CC2_SHIFT	2
 #define TCPC_CC_STATUS_CC2_MASK		0x3
@@ -121,4 +122,16 @@
 #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG		0x76
 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG		0x78
 
+struct tcpci;
+struct tcpci_data {
+	struct regmap *regmap;
+	int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
+	int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
+			 bool enable);
+};
+
+struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
+void tcpci_unregister_port(struct tcpci *tcpci);
+irqreturn_t tcpci_irq(struct tcpci *tcpci);
+
 #endif /* __LINUX_USB_TCPCI_H */

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-21 22:15   ` Guenter Roeck
  0 siblings, 0 replies; 22+ messages in thread
From: Guenter Roeck @ 2018-02-21 22:15 UTC (permalink / raw)
  To: ShuFanLee
  Cc: heikki.krogerus, greg, shufan_lee, cy_huang, linux-kernel, linux-usb

On Wed, Feb 21, 2018 at 11:02:23PM +0800, ShuFanLee wrote:
> From: ShuFanLee <shufan_lee@richtek.com>
> 
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
> TCPC shall not start DRP toggling until subsequently the TCPM
> writes to the COMMAND register to start DRP toggling.
> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd
>   - Write DRP = 1
>   - Set LOOK4CONNECTION command
> 
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>

Mostly loooks good to me. Couple of nitpicks below.

Guenter

> ---
>  drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
> 
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
> 
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
> 
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
>  
>  struct tcpci {
>  	struct device *dev;
> -	struct i2c_client *client;
>  
>  	struct tcpm_port *port;
>  
> @@ -30,6 +29,12 @@ struct tcpci {
>  	bool controls_vbus;
>  
>  	struct tcpc_dev tcpc;
> +	struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +	struct tcpci *tcpci;
> +	struct tcpci_data data;
>  };
>  
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
> @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>  	return container_of(tcpc, struct tcpci, tcpc);
>  }
>  
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -			u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
>  {
>  	return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
>  }
> @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
>  static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>  				    enum typec_cc_status cc)
>  {
> +	int ret;
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -	unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +	unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
> +			   (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
>  
>  	switch (cc) {
>  	default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>  		break;
>  	}
>  
> -	return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	usleep_range(500, 1000);
> +	reg |= TCPC_ROLE_CTRL_DRP;
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +			   TCPC_CMD_LOOK4CONNECTION);
> +	if (ret < 0)
> +		return ret;
> +	return 0;

regmap_write returns a negative return code or 0, thus this can be
simplified to
	return regmap_write(...);

>  }
>  
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>  	int ret;
>  
> +	/* Handle vendor set vconn */
> +	if (tcpci->data) {
> +		if (tcpci->data->set_vconn) {
> +			ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +						     enable);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>  			   enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>  	if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	if (time_after(jiffies, timeout))
>  		return -ETIMEDOUT;
>  
> +	/* Handle vendor init */
> +	if (tcpci->data) {
> +		if (tcpci->data->init) {
> +			ret = tcpci->data->init(tcpci, tcpci->data);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	/* Clear all events */
>  	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>  	if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
>  }
>  
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>  	struct tcpci *tcpci = dev_id;
> +
> +	return tcpci_irq(tcpci);
> +}

Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci)
> +{
>  	u16 status;
>  
>  	tcpci_read16(tcpci, TCPC_ALERT, &status);
> @@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
>  
>  	return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);
>  
>  static const struct regmap_config tcpci_regmap_config = {
>  	.reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>  	return 0;
>  }
>  
> -static int tcpci_probe(struct i2c_client *client,
> -		       const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
>  {
>  	struct tcpci *tcpci;
>  	int err;
>  
> -	tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>  	if (!tcpci)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
> -	tcpci->client = client;
> -	tcpci->dev = &client->dev;
> -	i2c_set_clientdata(client, tcpci);
> -	tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -	if (IS_ERR(tcpci->regmap))
> -		return PTR_ERR(tcpci->regmap);
> +	tcpci->dev = dev;
> +	tcpci->data = data;
> +	tcpci->regmap = data->regmap;
>  
>  	tcpci->tcpc.init = tcpci_init;
>  	tcpci->tcpc.get_vbus = tcpci_get_vbus;
> @@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
>  
>  	err = tcpci_parse_config(tcpci);
>  	if (err < 0)
> -		return err;
> +		return ERR_PTR(err);
> +
> +	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +	if (PTR_ERR_OR_ZERO(tcpci->port))
> +		return ERR_CAST(tcpci->port);
>  
> -	/* Disable chip interrupts */
> -	tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +	return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci)
> +{
> +	tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
>  
> -	err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -					tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +		       const struct i2c_device_id *i2c_id)
> +{
> +	struct tcpci_chip *chip;
> +	int err;
> +	u16 val = 0;
> +
> +	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> +	if (IS_ERR(chip->data.regmap))
> +		return PTR_ERR(chip->data.regmap);
> +
> +	/* Disable chip interrupts before requesting irq */
> +	err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +			       sizeof(u16));
> +	if (err < 0)
> +		return err;
> +
> +	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +					_tcpci_irq,
>  					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -					dev_name(tcpci->dev), tcpci);
> +					dev_name(&client->dev), chip);
>  	if (err < 0)
>  		return err;
>  
> -	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -	return PTR_ERR_OR_ZERO(tcpci->port);
> +	chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +	if (PTR_ERR_OR_ZERO(chip->tcpci))
> +		return PTR_ERR(chip->tcpci);
> +
> +	i2c_set_clientdata(client, chip);
> +	return 0;
>  }
>  
>  static int tcpci_remove(struct i2c_client *client)
>  {
> -	struct tcpci *tcpci = i2c_get_clientdata(client);
> +	struct tcpci_chip *chip = i2c_get_clientdata(client);
>  
> -	tcpm_unregister_port(tcpci->port);
> +	tcpci_unregister_port(chip->tcpci);
>  
>  	return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE	BIT(0)
>  
>  #define TCPC_CC_STATUS			0x1d
> +#define TCPC_CC_STATUS_DRPRST		BIT(5)
>  #define TCPC_CC_STATUS_TERM		BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT	2
>  #define TCPC_CC_STATUS_CC2_MASK		0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG		0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG		0x78
>  
> +struct tcpci;
> +struct tcpci_data {
> +	struct regmap *regmap;
> +	int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +	int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +			 bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
> +void tcpci_unregister_port(struct tcpci *tcpci);
> +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> -- 
> 1.9.1
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-21 22:15   ` Guenter Roeck
  0 siblings, 0 replies; 22+ messages in thread
From: Guenter Roeck @ 2018-02-21 22:15 UTC (permalink / raw)
  To: ShuFanLee
  Cc: heikki.krogerus, greg, shufan_lee, cy_huang, linux-kernel, linux-usb

On Wed, Feb 21, 2018 at 11:02:23PM +0800, ShuFanLee wrote:
> From: ShuFanLee <shufan_lee@richtek.com>
> 
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
> TCPC shall not start DRP toggling until subsequently the TCPM
> writes to the COMMAND register to start DRP toggling.
> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd
>   - Write DRP = 1
>   - Set LOOK4CONNECTION command
> 
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>

Mostly loooks good to me. Couple of nitpicks below.

Guenter

> ---
>  drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
> 
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
> 
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
> 
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
>  
>  struct tcpci {
>  	struct device *dev;
> -	struct i2c_client *client;
>  
>  	struct tcpm_port *port;
>  
> @@ -30,6 +29,12 @@ struct tcpci {
>  	bool controls_vbus;
>  
>  	struct tcpc_dev tcpc;
> +	struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +	struct tcpci *tcpci;
> +	struct tcpci_data data;
>  };
>  
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
> @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>  	return container_of(tcpc, struct tcpci, tcpc);
>  }
>  
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -			u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
>  {
>  	return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
>  }
> @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
>  static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>  				    enum typec_cc_status cc)
>  {
> +	int ret;
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -	unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +	unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
> +			   (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
>  
>  	switch (cc) {
>  	default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>  		break;
>  	}
>  
> -	return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	usleep_range(500, 1000);
> +	reg |= TCPC_ROLE_CTRL_DRP;
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +			   TCPC_CMD_LOOK4CONNECTION);
> +	if (ret < 0)
> +		return ret;
> +	return 0;

regmap_write returns a negative return code or 0, thus this can be
simplified to
	return regmap_write(...);

>  }
>  
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>  	int ret;
>  
> +	/* Handle vendor set vconn */
> +	if (tcpci->data) {
> +		if (tcpci->data->set_vconn) {
> +			ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +						     enable);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>  			   enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>  	if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	if (time_after(jiffies, timeout))
>  		return -ETIMEDOUT;
>  
> +	/* Handle vendor init */
> +	if (tcpci->data) {
> +		if (tcpci->data->init) {
> +			ret = tcpci->data->init(tcpci, tcpci->data);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	/* Clear all events */
>  	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>  	if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
>  }
>  
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>  	struct tcpci *tcpci = dev_id;
> +
> +	return tcpci_irq(tcpci);
> +}

Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci)
> +{
>  	u16 status;
>  
>  	tcpci_read16(tcpci, TCPC_ALERT, &status);
> @@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
>  
>  	return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);
>  
>  static const struct regmap_config tcpci_regmap_config = {
>  	.reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>  	return 0;
>  }
>  
> -static int tcpci_probe(struct i2c_client *client,
> -		       const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
>  {
>  	struct tcpci *tcpci;
>  	int err;
>  
> -	tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>  	if (!tcpci)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
>  
> -	tcpci->client = client;
> -	tcpci->dev = &client->dev;
> -	i2c_set_clientdata(client, tcpci);
> -	tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -	if (IS_ERR(tcpci->regmap))
> -		return PTR_ERR(tcpci->regmap);
> +	tcpci->dev = dev;
> +	tcpci->data = data;
> +	tcpci->regmap = data->regmap;
>  
>  	tcpci->tcpc.init = tcpci_init;
>  	tcpci->tcpc.get_vbus = tcpci_get_vbus;
> @@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
>  
>  	err = tcpci_parse_config(tcpci);
>  	if (err < 0)
> -		return err;
> +		return ERR_PTR(err);
> +
> +	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +	if (PTR_ERR_OR_ZERO(tcpci->port))
> +		return ERR_CAST(tcpci->port);
>  
> -	/* Disable chip interrupts */
> -	tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +	return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci)
> +{
> +	tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
>  
> -	err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -					tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +		       const struct i2c_device_id *i2c_id)
> +{
> +	struct tcpci_chip *chip;
> +	int err;
> +	u16 val = 0;
> +
> +	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> +	if (IS_ERR(chip->data.regmap))
> +		return PTR_ERR(chip->data.regmap);
> +
> +	/* Disable chip interrupts before requesting irq */
> +	err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +			       sizeof(u16));
> +	if (err < 0)
> +		return err;
> +
> +	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +					_tcpci_irq,
>  					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -					dev_name(tcpci->dev), tcpci);
> +					dev_name(&client->dev), chip);
>  	if (err < 0)
>  		return err;
>  
> -	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -	return PTR_ERR_OR_ZERO(tcpci->port);
> +	chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +	if (PTR_ERR_OR_ZERO(chip->tcpci))
> +		return PTR_ERR(chip->tcpci);
> +
> +	i2c_set_clientdata(client, chip);
> +	return 0;
>  }
>  
>  static int tcpci_remove(struct i2c_client *client)
>  {
> -	struct tcpci *tcpci = i2c_get_clientdata(client);
> +	struct tcpci_chip *chip = i2c_get_clientdata(client);
>  
> -	tcpm_unregister_port(tcpci->port);
> +	tcpci_unregister_port(chip->tcpci);
>  
>  	return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE	BIT(0)
>  
>  #define TCPC_CC_STATUS			0x1d
> +#define TCPC_CC_STATUS_DRPRST		BIT(5)
>  #define TCPC_CC_STATUS_TERM		BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT	2
>  #define TCPC_CC_STATUS_CC2_MASK		0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG		0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG		0x78
>  
> +struct tcpci;
> +struct tcpci_data {
> +	struct regmap *regmap;
> +	int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +	int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +			 bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
> +void tcpci_unregister_port(struct tcpci *tcpci);
> +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> -- 
> 1.9.1
>
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-22 10:16   ` Jun Li
  0 siblings, 0 replies; 22+ messages in thread
From: Jun Li @ 2018-02-22 10:16 UTC (permalink / raw)
  To: ShuFanLee, heikki.krogerus, linux, greg
  Cc: shufan_lee, cy_huang, linux-kernel, linux-usb, dl-linux-imx

Hi,

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org
> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of ShuFanLee
> Sent: 2018年2月21日 23:02
> To: heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: shufan_lee@richtek.com; cy_huang@richtek.com;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
> Subject: [PATCH] staging: typec: handle vendor defined part and modify drp
> toggling flow
> 
> From: ShuFanLee <shufan_lee@richtek.com>
> 
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export
> tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not
> start DRP toggling until subsequently the TCPM writes to the COMMAND
> register to start DRP toggling.

My understanding of above statement is TCPM(this Linux driver) can enable
DRP and CC1/CC2 in one shot, but TCPC(your typec chip internal firmware)
needs wait until TCPM writes to COMMAND register to start drp toggling.

> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd

Why fixed to be Rd/Rd? in this case, it means the starting value:

Tcpci 4.4.5.2:
"When initiating autonomous DRP toggling, the TCPM shall write B6 (DRP) =1b
and the starting value of Rp/Rd to B3..0 (CC1/CC2) to indicate DRP autonomous
toggling mode to the TCPC."

>   - Write DRP = 1

What's your problem if combine above 2 in one shot?

>   - Set LOOK4CONNECTION command
> 
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
> ---
>  drivers/staging/typec/tcpci.c | 128
> +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
> 
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue
> driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before
> disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
> 
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
> 
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
> 
>  struct tcpci {
>  	struct device *dev;
> -	struct i2c_client *client;
> 
>  	struct tcpm_port *port;
> 
> @@ -30,6 +29,12 @@ struct tcpci {
>  	bool controls_vbus;
> 
>  	struct tcpc_dev tcpc;
> +	struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +	struct tcpci *tcpci;
> +	struct tcpci_data data;
>  };
> 
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,8
> +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>  	return container_of(tcpc, struct tcpci, tcpc);  }
> 
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -			u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16
> +*val)
>  {
>  	return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));  } @@
> -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> typec_cc_status cc)  static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>  				    enum typec_cc_status cc)
>  {
> +	int ret;
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -	unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +	unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC1_SHIFT) |
> +			   (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC2_SHIFT);
> 
>  	switch (cc) {
>  	default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>  		break;
>  	}
> 
> -	return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	usleep_range(500, 1000);

Why need a wait here? It seems you actually don't want to do autonomously toggling
from the very beginning, instead, you begin with a directly control on CC, keep it(Rd)
for some time, then switch to use autonomously toggling, why you need such kind of
sequence? I think it's special and not following tcpci spec.
 
> +	reg |= TCPC_ROLE_CTRL_DRP;
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +			   TCPC_CMD_LOOK4CONNECTION);
> +	if (ret < 0)
> +		return ret;
> +	return 0;
>  }
> 
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc,
> bool enable)
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>  	int ret;
> 
> +	/* Handle vendor set vconn */
> +	if (tcpci->data) {
> +		if (tcpci->data->set_vconn) {
> +			ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +						     enable);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>  			   enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>  	if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	if (time_after(jiffies, timeout))
>  		return -ETIMEDOUT;
> 
> +	/* Handle vendor init */
> +	if (tcpci->data) {
> +		if (tcpci->data->init) {
> +			ret = tcpci->data->init(tcpci, tcpci->data);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	/* Clear all events */
>  	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>  	if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);  }
> 
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>  	struct tcpci *tcpci = dev_id;
> +
> +	return tcpci_irq(tcpci);
> +}
> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci) {
>  	u16 status;
> 
>  	tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,7 @@
> static irqreturn_t tcpci_irq(int irq, void *dev_id)
> 
>  	return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);

I don't catch the point of how you handle private events by above change,
maybe post your RT1711H part as a user in one series can make it clear,
I assume this can be done in existing tcpci_irq like above vender specific
handling as well:
      tcpci->data->priv_events(tcpci, tcpci->data);

Li Jun
> 
>  static const struct regmap_config tcpci_regmap_config = {
>  	.reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>  	return 0;
>  }
> 
> -static int tcpci_probe(struct i2c_client *client,
> -		       const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data)
>  {
>  	struct tcpci *tcpci;
>  	int err;
> 
> -	tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>  	if (!tcpci)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
> 
> -	tcpci->client = client;
> -	tcpci->dev = &client->dev;
> -	i2c_set_clientdata(client, tcpci);
> -	tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -	if (IS_ERR(tcpci->regmap))
> -		return PTR_ERR(tcpci->regmap);
> +	tcpci->dev = dev;
> +	tcpci->data = data;
> +	tcpci->regmap = data->regmap;
> 
>  	tcpci->tcpc.init = tcpci_init;
>  	tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +507,63 @@ static
> int tcpci_probe(struct i2c_client *client,
> 
>  	err = tcpci_parse_config(tcpci);
>  	if (err < 0)
> -		return err;
> +		return ERR_PTR(err);
> +
> +	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +	if (PTR_ERR_OR_ZERO(tcpci->port))
> +		return ERR_CAST(tcpci->port);
> 
> -	/* Disable chip interrupts */
> -	tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +	return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci) {
> +	tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
> 
> -	err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -					tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +		       const struct i2c_device_id *i2c_id) {
> +	struct tcpci_chip *chip;
> +	int err;
> +	u16 val = 0;
> +
> +	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	chip->data.regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> +	if (IS_ERR(chip->data.regmap))
> +		return PTR_ERR(chip->data.regmap);
> +
> +	/* Disable chip interrupts before requesting irq */
> +	err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +			       sizeof(u16));
> +	if (err < 0)
> +		return err;
> +
> +	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +					_tcpci_irq,
>  					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -					dev_name(tcpci->dev), tcpci);
> +					dev_name(&client->dev), chip);
>  	if (err < 0)
>  		return err;
> 
> -	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -	return PTR_ERR_OR_ZERO(tcpci->port);
> +	chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +	if (PTR_ERR_OR_ZERO(chip->tcpci))
> +		return PTR_ERR(chip->tcpci);
> +
> +	i2c_set_clientdata(client, chip);
> +	return 0;
>  }
> 
>  static int tcpci_remove(struct i2c_client *client)  {
> -	struct tcpci *tcpci = i2c_get_clientdata(client);
> +	struct tcpci_chip *chip = i2c_get_clientdata(client);
> 
> -	tcpm_unregister_port(tcpci->port);
> +	tcpci_unregister_port(chip->tcpci);
> 
>  	return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE	BIT(0)
> 
>  #define TCPC_CC_STATUS			0x1d
> +#define TCPC_CC_STATUS_DRPRST		BIT(5)
>  #define TCPC_CC_STATUS_TERM		BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT	2
>  #define TCPC_CC_STATUS_CC2_MASK		0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG		0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG		0x78
> 
> +struct tcpci;
> +struct tcpci_data {
> +	struct regmap *regmap;
> +	int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +	int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +			 bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data); void tcpci_unregister_port(struct tcpci *tcpci); irqreturn_t
> +tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> --
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
> .kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cjun.li%40nxp.com
> %7C44d11af27e0244fa4d1108d5793c3dc4%7C686ea1d3bc2b4c6fa92cd99c
> 5c301635%7C0%7C1%7C636548222008905206&sdata=zn2ougKRvs%2BbmH
> Qg2c8Rjj7vNe0ZiiVKdar7GdPa%2B3o%3D&reserved=0

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-22 10:16   ` Jun Li
  0 siblings, 0 replies; 22+ messages in thread
From: Jun Li @ 2018-02-22 10:16 UTC (permalink / raw)
  To: ShuFanLee, heikki.krogerus, linux, greg
  Cc: shufan_lee, cy_huang, linux-kernel, linux-usb, dl-linux-imx

Hi,

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org
> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of ShuFanLee
> Sent: 2018年2月21日 23:02
> To: heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: shufan_lee@richtek.com; cy_huang@richtek.com;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
> Subject: [PATCH] staging: typec: handle vendor defined part and modify drp
> toggling flow
> 
> From: ShuFanLee <shufan_lee@richtek.com>
> 
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export
> tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not
> start DRP toggling until subsequently the TCPM writes to the COMMAND
> register to start DRP toggling.

My understanding of above statement is TCPM(this Linux driver) can enable
DRP and CC1/CC2 in one shot, but TCPC(your typec chip internal firmware)
needs wait until TCPM writes to COMMAND register to start drp toggling.

> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd

Why fixed to be Rd/Rd? in this case, it means the starting value:

Tcpci 4.4.5.2:
"When initiating autonomous DRP toggling, the TCPM shall write B6 (DRP) =1b
and the starting value of Rp/Rd to B3..0 (CC1/CC2) to indicate DRP autonomous
toggling mode to the TCPC."

>   - Write DRP = 1

What's your problem if combine above 2 in one shot?

>   - Set LOOK4CONNECTION command
> 
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
> ---
>  drivers/staging/typec/tcpci.c | 128
> +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
> 
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue
> driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before
> disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
> 
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
> 
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
> 
>  struct tcpci {
>  	struct device *dev;
> -	struct i2c_client *client;
> 
>  	struct tcpm_port *port;
> 
> @@ -30,6 +29,12 @@ struct tcpci {
>  	bool controls_vbus;
> 
>  	struct tcpc_dev tcpc;
> +	struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +	struct tcpci *tcpci;
> +	struct tcpci_data data;
>  };
> 
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,8
> +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>  	return container_of(tcpc, struct tcpci, tcpc);  }
> 
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -			u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16
> +*val)
>  {
>  	return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));  } @@
> -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> typec_cc_status cc)  static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>  				    enum typec_cc_status cc)
>  {
> +	int ret;
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -	unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +	unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC1_SHIFT) |
> +			   (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC2_SHIFT);
> 
>  	switch (cc) {
>  	default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>  		break;
>  	}
> 
> -	return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	usleep_range(500, 1000);

Why need a wait here? It seems you actually don't want to do autonomously toggling
from the very beginning, instead, you begin with a directly control on CC, keep it(Rd)
for some time, then switch to use autonomously toggling, why you need such kind of
sequence? I think it's special and not following tcpci spec.
 
> +	reg |= TCPC_ROLE_CTRL_DRP;
> +	ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +	if (ret < 0)
> +		return ret;
> +	ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +			   TCPC_CMD_LOOK4CONNECTION);
> +	if (ret < 0)
> +		return ret;
> +	return 0;
>  }
> 
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc,
> bool enable)
>  	struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>  	int ret;
> 
> +	/* Handle vendor set vconn */
> +	if (tcpci->data) {
> +		if (tcpci->data->set_vconn) {
> +			ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +						     enable);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>  			   enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>  	if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	if (time_after(jiffies, timeout))
>  		return -ETIMEDOUT;
> 
> +	/* Handle vendor init */
> +	if (tcpci->data) {
> +		if (tcpci->data->init) {
> +			ret = tcpci->data->init(tcpci, tcpci->data);
> +			if (ret < 0)
> +				return ret;
> +		}
> +	}
> +
>  	/* Clear all events */
>  	ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>  	if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>  	return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);  }
> 
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>  	struct tcpci *tcpci = dev_id;
> +
> +	return tcpci_irq(tcpci);
> +}
> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci) {
>  	u16 status;
> 
>  	tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,7 @@
> static irqreturn_t tcpci_irq(int irq, void *dev_id)
> 
>  	return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);

I don't catch the point of how you handle private events by above change,
maybe post your RT1711H part as a user in one series can make it clear,
I assume this can be done in existing tcpci_irq like above vender specific
handling as well:
      tcpci->data->priv_events(tcpci, tcpci->data);

Li Jun
> 
>  static const struct regmap_config tcpci_regmap_config = {
>  	.reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>  	return 0;
>  }
> 
> -static int tcpci_probe(struct i2c_client *client,
> -		       const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data)
>  {
>  	struct tcpci *tcpci;
>  	int err;
> 
> -	tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +	tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>  	if (!tcpci)
> -		return -ENOMEM;
> +		return ERR_PTR(-ENOMEM);
> 
> -	tcpci->client = client;
> -	tcpci->dev = &client->dev;
> -	i2c_set_clientdata(client, tcpci);
> -	tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -	if (IS_ERR(tcpci->regmap))
> -		return PTR_ERR(tcpci->regmap);
> +	tcpci->dev = dev;
> +	tcpci->data = data;
> +	tcpci->regmap = data->regmap;
> 
>  	tcpci->tcpc.init = tcpci_init;
>  	tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +507,63 @@ static
> int tcpci_probe(struct i2c_client *client,
> 
>  	err = tcpci_parse_config(tcpci);
>  	if (err < 0)
> -		return err;
> +		return ERR_PTR(err);
> +
> +	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +	if (PTR_ERR_OR_ZERO(tcpci->port))
> +		return ERR_CAST(tcpci->port);
> 
> -	/* Disable chip interrupts */
> -	tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +	return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci) {
> +	tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
> 
> -	err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -					tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +		       const struct i2c_device_id *i2c_id) {
> +	struct tcpci_chip *chip;
> +	int err;
> +	u16 val = 0;
> +
> +	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +	if (!chip)
> +		return -ENOMEM;
> +
> +	chip->data.regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> +	if (IS_ERR(chip->data.regmap))
> +		return PTR_ERR(chip->data.regmap);
> +
> +	/* Disable chip interrupts before requesting irq */
> +	err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +			       sizeof(u16));
> +	if (err < 0)
> +		return err;
> +
> +	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +					_tcpci_irq,
>  					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -					dev_name(tcpci->dev), tcpci);
> +					dev_name(&client->dev), chip);
>  	if (err < 0)
>  		return err;
> 
> -	tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -	return PTR_ERR_OR_ZERO(tcpci->port);
> +	chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +	if (PTR_ERR_OR_ZERO(chip->tcpci))
> +		return PTR_ERR(chip->tcpci);
> +
> +	i2c_set_clientdata(client, chip);
> +	return 0;
>  }
> 
>  static int tcpci_remove(struct i2c_client *client)  {
> -	struct tcpci *tcpci = i2c_get_clientdata(client);
> +	struct tcpci_chip *chip = i2c_get_clientdata(client);
> 
> -	tcpm_unregister_port(tcpci->port);
> +	tcpci_unregister_port(chip->tcpci);
> 
>  	return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE	BIT(0)
> 
>  #define TCPC_CC_STATUS			0x1d
> +#define TCPC_CC_STATUS_DRPRST		BIT(5)
>  #define TCPC_CC_STATUS_TERM		BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT	2
>  #define TCPC_CC_STATUS_CC2_MASK		0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG		0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG		0x78
> 
> +struct tcpci;
> +struct tcpci_data {
> +	struct regmap *regmap;
> +	int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +	int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +			 bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data); void tcpci_unregister_port(struct tcpci *tcpci); irqreturn_t
> +tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> --
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
> .kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cjun.li%40nxp.com
> %7C44d11af27e0244fa4d1108d5793c3dc4%7C686ea1d3bc2b4c6fa92cd99c
> 5c301635%7C0%7C1%7C636548222008905206&sdata=zn2ougKRvs%2BbmH
> Qg2c8Rjj7vNe0ZiiVKdar7GdPa%2B3o%3D&reserved=0

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
  2018-02-21 22:15   ` Guenter Roeck
  (?)
@ 2018-02-28  2:09   ` 李書帆
  -1 siblings, 0 replies; 22+ messages in thread
From: 李書帆 @ 2018-02-28  2:09 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: heikki.krogerus, Greg KH, shufan_lee, cy_huang, linux-kernel, linux-usb

[-- Attachment #1: Type: text/plain, Size: 12238 bytes --]

Hi Guenter,

  regmap_write returns a negative return code or 0, thus this can be
simplified to
        return regmap_write(...);

  Ok, I'll modify it in v4


Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

  Do you mean it maybe better to call vendor's set_vconn after normal
set_vconn is finished?
  If I understand correctly, I can also modify it in v4. For RT1711H, it
also works by enabling/disabling idle mode after set_vconn.


2018-02-22 6:15 GMT+08:00 Guenter Roeck <linux@roeck-us.net>:

> On Wed, Feb 21, 2018 at 11:02:23PM +0800, ShuFanLee wrote:
> > From: ShuFanLee <shufan_lee@richtek.com>
> >
> > Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export
> tcpci_irq.
> > More operations can be extended in tcpci_data if needed.
> > According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
> > TCPC shall not start DRP toggling until subsequently the TCPM
> > writes to the COMMAND register to start DRP toggling.
> > DRP toggling flow is chagned as following:
> >   - Write DRP = 0 & Rd/Rd
> >   - Write DRP = 1
> >   - Set LOOK4CONNECTION command
> >
> > Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
>
> Mostly loooks good to me. Couple of nitpicks below.
>
> Guenter
>
> > ---
> >  drivers/staging/typec/tcpci.c | 128 ++++++++++++++++++++++++++++++
> +++---------
> >  drivers/staging/typec/tcpci.h |  13 +++++
> >  2 files changed, 115 insertions(+), 26 deletions(-)
> >
> >  patch changelogs between v1 & v2
> >  - Remove unnecessary i2c_client in the structure of tcpci
> >  - Rename structure of tcpci_vendor_data to tcpci_data
> >  - Not exporting tcpci read/write wrappers but register i2c regmap in
> glue driver
> >  - Add set_vconn ops in tcpci_data
> >    (It is necessary for RT1711H to enable/disable idle mode before
> disabling/enabling vconn)
> >  - Export tcpci_irq so that vendor can call it in their own IRQ handler
> >
> >  patch changelogs between v2 & v3
> >  - Change the return type of tcpci_irq from int to irqreturn_t
> >
> > diff --git a/drivers/staging/typec/tcpci.c
> b/drivers/staging/typec/tcpci.c
> > index 9bd4412..4959c69 100644
> > --- a/drivers/staging/typec/tcpci.c
> > +++ b/drivers/staging/typec/tcpci.c
> > @@ -21,7 +21,6 @@
> >
> >  struct tcpci {
> >       struct device *dev;
> > -     struct i2c_client *client;
> >
> >       struct tcpm_port *port;
> >
> > @@ -30,6 +29,12 @@ struct tcpci {
> >       bool controls_vbus;
> >
> >       struct tcpc_dev tcpc;
> > +     struct tcpci_data *data;
> > +};
> > +
> > +struct tcpci_chip {
> > +     struct tcpci *tcpci;
> > +     struct tcpci_data data;
> >  };
> >
> >  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
> > @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct
> tcpc_dev *tcpc)
> >       return container_of(tcpc, struct tcpci, tcpc);
> >  }
> >
> > -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> > -                     u16 *val)
> > +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
> >  {
> >       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
> >  }
> > @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> typec_cc_status cc)
> >  static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
> >                                   enum typec_cc_status cc)
> >  {
> > +     int ret;
> >       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> > -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> > +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC1_SHIFT) |
> > +                        (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC2_SHIFT);
> >
> >       switch (cc) {
> >       default:
> > @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct
> tcpc_dev *tcpc,
> >               break;
> >       }
> >
> > -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     if (ret < 0)
> > +             return ret;
> > +     usleep_range(500, 1000);
> > +     reg |= TCPC_ROLE_CTRL_DRP;
> > +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> > +                        TCPC_CMD_LOOK4CONNECTION);
> > +     if (ret < 0)
> > +             return ret;
> > +     return 0;
>
> regmap_write returns a negative return code or 0, thus this can be
> simplified to
>         return regmap_write(...);
>
> >  }
> >
> >  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool
> sink)
> > @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc,
> bool enable)
> >       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> >       int ret;
> >
> > +     /* Handle vendor set vconn */
> > +     if (tcpci->data) {
> > +             if (tcpci->data->set_vconn) {
> > +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> > +                                                  enable);
> > +                     if (ret < 0)
> > +                             return ret;
> > +             }
> > +     }
> > +
> >       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
> >                          enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
> >       if (ret < 0)
> > @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> >       if (time_after(jiffies, timeout))
> >               return -ETIMEDOUT;
> >
> > +     /* Handle vendor init */
> > +     if (tcpci->data) {
> > +             if (tcpci->data->init) {
> > +                     ret = tcpci->data->init(tcpci, tcpci->data);
> > +                     if (ret < 0)
> > +                             return ret;
> > +             }
> > +     }
> > +
> >       /* Clear all events */
> >       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
> >       if (ret < 0)
> > @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> >       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
> >  }
> >
> > -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> > +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
> >  {
> >       struct tcpci *tcpci = dev_id;
> > +
> > +     return tcpci_irq(tcpci);
> > +}
>
> Hmm, normally I'd expect this function _after_ the function it calls.
> Guess that doesn't matter much here, so I am fine with it as long
> as Greg is ok with it as well.
>
> > +
> > +irqreturn_t tcpci_irq(struct tcpci *tcpci)
> > +{
> >       u16 status;
> >
> >       tcpci_read16(tcpci, TCPC_ALERT, &status);
> > @@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
> >
> >       return IRQ_HANDLED;
> >  }
> > +EXPORT_SYMBOL_GPL(tcpci_irq);
> >
> >  static const struct regmap_config tcpci_regmap_config = {
> >       .reg_bits = 8,
> > @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
> >       return 0;
> >  }
> >
> > -static int tcpci_probe(struct i2c_client *client,
> > -                    const struct i2c_device_id *i2c_id)
> > +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> *data)
> >  {
> >       struct tcpci *tcpci;
> >       int err;
> >
> > -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> > +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
> >       if (!tcpci)
> > -             return -ENOMEM;
> > +             return ERR_PTR(-ENOMEM);
> >
> > -     tcpci->client = client;
> > -     tcpci->dev = &client->dev;
> > -     i2c_set_clientdata(client, tcpci);
> > -     tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> > -     if (IS_ERR(tcpci->regmap))
> > -             return PTR_ERR(tcpci->regmap);
> > +     tcpci->dev = dev;
> > +     tcpci->data = data;
> > +     tcpci->regmap = data->regmap;
> >
> >       tcpci->tcpc.init = tcpci_init;
> >       tcpci->tcpc.get_vbus = tcpci_get_vbus;
> > @@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
> >
> >       err = tcpci_parse_config(tcpci);
> >       if (err < 0)
> > -             return err;
> > +             return ERR_PTR(err);
> > +
> > +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> > +     if (PTR_ERR_OR_ZERO(tcpci->port))
> > +             return ERR_CAST(tcpci->port);
> >
> > -     /* Disable chip interrupts */
> > -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> > +     return tcpci;
> > +}
> > +EXPORT_SYMBOL_GPL(tcpci_register_port);
> > +
> > +void tcpci_unregister_port(struct tcpci *tcpci)
> > +{
> > +     tcpm_unregister_port(tcpci->port);
> > +}
> > +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
> >
> > -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> > -                                     tcpci_irq,
> > +static int tcpci_probe(struct i2c_client *client,
> > +                    const struct i2c_device_id *i2c_id)
> > +{
> > +     struct tcpci_chip *chip;
> > +     int err;
> > +     u16 val = 0;
> > +
> > +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > +     if (!chip)
> > +             return -ENOMEM;
> > +
> > +     chip->data.regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> > +     if (IS_ERR(chip->data.regmap))
> > +             return PTR_ERR(chip->data.regmap);
> > +
> > +     /* Disable chip interrupts before requesting irq */
> > +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> > +                            sizeof(u16));
> > +     if (err < 0)
> > +             return err;
> > +
> > +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> > +                                     _tcpci_irq,
> >                                       IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> > -                                     dev_name(tcpci->dev), tcpci);
> > +                                     dev_name(&client->dev), chip);
> >       if (err < 0)
> >               return err;
> >
> > -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> > -     return PTR_ERR_OR_ZERO(tcpci->port);
> > +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> > +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> > +             return PTR_ERR(chip->tcpci);
> > +
> > +     i2c_set_clientdata(client, chip);
> > +     return 0;
> >  }
> >
> >  static int tcpci_remove(struct i2c_client *client)
> >  {
> > -     struct tcpci *tcpci = i2c_get_clientdata(client);
> > +     struct tcpci_chip *chip = i2c_get_clientdata(client);
> >
> > -     tcpm_unregister_port(tcpci->port);
> > +     tcpci_unregister_port(chip->tcpci);
> >
> >       return 0;
> >  }
> > diff --git a/drivers/staging/typec/tcpci.h
> b/drivers/staging/typec/tcpci.h
> > index fdfb06c..40025b2 100644
> > --- a/drivers/staging/typec/tcpci.h
> > +++ b/drivers/staging/typec/tcpci.h
> > @@ -59,6 +59,7 @@
> >  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
> >
> >  #define TCPC_CC_STATUS                       0x1d
> > +#define TCPC_CC_STATUS_DRPRST                BIT(5)
> >  #define TCPC_CC_STATUS_TERM          BIT(4)
> >  #define TCPC_CC_STATUS_CC2_SHIFT     2
> >  #define TCPC_CC_STATUS_CC2_MASK              0x3
> > @@ -121,4 +122,16 @@
> >  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
> >  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
> >
> > +struct tcpci;
> > +struct tcpci_data {
> > +     struct regmap *regmap;
> > +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> > +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> > +                      bool enable);
> > +};
> > +
> > +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> *data);
> > +void tcpci_unregister_port(struct tcpci *tcpci);
> > +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> > +
> >  #endif /* __LINUX_USB_TCPCI_H */
> > --
> > 1.9.1
> >
>



-- 
Best Regards,
書帆

[-- Attachment #2: Type: text/html, Size: 16288 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* 回覆: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-28  2:14     ` shufan_lee(李書帆)
  0 siblings, 0 replies; 22+ messages in thread
From: shufan_lee(李書帆) @ 2018-02-28  2:14 UTC (permalink / raw)
  To: Guenter Roeck, ShuFanLee
  Cc: heikki.krogerus, greg, cy_huang(黃啟原),
	linux-kernel, linux-usb

Hi Guenter,

  regmap_write returns a negative return code or 0, thus this can be
simplified to
        return regmap_write(...);

  Ok, I'll modify it in v4

Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

  Do you mean it maybe better to call vendor's set_vconn after normal set_vconn is finished?
  If I understand correctly, I can also modify it in v4. For RT1711H, it also works by enabling/disabling idle mode after set_vconn.

Best Regards,
*****************************************
Shu-Fan Lee
Richtek Technology Corporation
TEL: +886-3-5526789 #2359
FAX: +886-3-5526612
*****************************************

________________________________________
寄件者: Guenter Roeck <groeck7@gmail.com> 代表 Guenter Roeck <linux@roeck-us.net>
寄件日期: 2018年2月22日 上午 06:15
收件者: ShuFanLee
副本: heikki.krogerus@linux.intel.com; greg@kroah.com; shufan_lee(李書帆); cy_huang(黃啟原); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
主旨: Re: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow

On Wed, Feb 21, 2018 at 11:02:23PM +0800, ShuFanLee wrote:
> From: ShuFanLee <shufan_lee@richtek.com>
>
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
> TCPC shall not start DRP toggling until subsequently the TCPM
> writes to the COMMAND register to start DRP toggling.
> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd
>   - Write DRP = 1
>   - Set LOOK4CONNECTION command
>
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>

Mostly loooks good to me. Couple of nitpicks below.

Guenter

> ---
>  drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
>
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
>
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
>
>  struct tcpci {
>       struct device *dev;
> -     struct i2c_client *client;
>
>       struct tcpm_port *port;
>
> @@ -30,6 +29,12 @@ struct tcpci {
>       bool controls_vbus;
>
>       struct tcpc_dev tcpc;
> +     struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +     struct tcpci *tcpci;
> +     struct tcpci_data data;
>  };
>
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
> @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>       return container_of(tcpc, struct tcpci, tcpc);
>  }
>
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -                     u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
>  {
>       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
>  }
> @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
>  static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>                                   enum typec_cc_status cc)
>  {
> +     int ret;
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
> +                        (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
>
>       switch (cc) {
>       default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>               break;
>       }
>
> -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     usleep_range(500, 1000);
> +     reg |= TCPC_ROLE_CTRL_DRP;
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +                        TCPC_CMD_LOOK4CONNECTION);
> +     if (ret < 0)
> +             return ret;
> +     return 0;

regmap_write returns a negative return code or 0, thus this can be
simplified to
        return regmap_write(...);

>  }
>
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>       int ret;
>
> +     /* Handle vendor set vconn */
> +     if (tcpci->data) {
> +             if (tcpci->data->set_vconn) {
> +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +                                                  enable);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>                          enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>       if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       if (time_after(jiffies, timeout))
>               return -ETIMEDOUT;
>
> +     /* Handle vendor init */
> +     if (tcpci->data) {
> +             if (tcpci->data->init) {
> +                     ret = tcpci->data->init(tcpci, tcpci->data);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       /* Clear all events */
>       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>       if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
>  }
>
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>       struct tcpci *tcpci = dev_id;
> +
> +     return tcpci_irq(tcpci);
> +}

Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci)
> +{
>       u16 status;
>
>       tcpci_read16(tcpci, TCPC_ALERT, &status);
> @@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
>
>       return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);
>
>  static const struct regmap_config tcpci_regmap_config = {
>       .reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>       return 0;
>  }
>
> -static int tcpci_probe(struct i2c_client *client,
> -                    const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
>  {
>       struct tcpci *tcpci;
>       int err;
>
> -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>       if (!tcpci)
> -             return -ENOMEM;
> +             return ERR_PTR(-ENOMEM);
>
> -     tcpci->client = client;
> -     tcpci->dev = &client->dev;
> -     i2c_set_clientdata(client, tcpci);
> -     tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -     if (IS_ERR(tcpci->regmap))
> -             return PTR_ERR(tcpci->regmap);
> +     tcpci->dev = dev;
> +     tcpci->data = data;
> +     tcpci->regmap = data->regmap;
>
>       tcpci->tcpc.init = tcpci_init;
>       tcpci->tcpc.get_vbus = tcpci_get_vbus;
> @@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
>
>       err = tcpci_parse_config(tcpci);
>       if (err < 0)
> -             return err;
> +             return ERR_PTR(err);
> +
> +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +     if (PTR_ERR_OR_ZERO(tcpci->port))
> +             return ERR_CAST(tcpci->port);
>
> -     /* Disable chip interrupts */
> -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +     return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci)
> +{
> +     tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
>
> -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -                                     tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +                    const struct i2c_device_id *i2c_id)
> +{
> +     struct tcpci_chip *chip;
> +     int err;
> +     u16 val = 0;
> +
> +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +     if (!chip)
> +             return -ENOMEM;
> +
> +     chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> +     if (IS_ERR(chip->data.regmap))
> +             return PTR_ERR(chip->data.regmap);
> +
> +     /* Disable chip interrupts before requesting irq */
> +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +                            sizeof(u16));
> +     if (err < 0)
> +             return err;
> +
> +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +                                     _tcpci_irq,
>                                       IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -                                     dev_name(tcpci->dev), tcpci);
> +                                     dev_name(&client->dev), chip);
>       if (err < 0)
>               return err;
>
> -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -     return PTR_ERR_OR_ZERO(tcpci->port);
> +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> +             return PTR_ERR(chip->tcpci);
> +
> +     i2c_set_clientdata(client, chip);
> +     return 0;
>  }
>
>  static int tcpci_remove(struct i2c_client *client)
>  {
> -     struct tcpci *tcpci = i2c_get_clientdata(client);
> +     struct tcpci_chip *chip = i2c_get_clientdata(client);
>
> -     tcpm_unregister_port(tcpci->port);
> +     tcpci_unregister_port(chip->tcpci);
>
>       return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
>
>  #define TCPC_CC_STATUS                       0x1d
> +#define TCPC_CC_STATUS_DRPRST                BIT(5)
>  #define TCPC_CC_STATUS_TERM          BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT     2
>  #define TCPC_CC_STATUS_CC2_MASK              0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
>
> +struct tcpci;
> +struct tcpci_data {
> +     struct regmap *regmap;
> +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +                      bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
> +void tcpci_unregister_port(struct tcpci *tcpci);
> +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> --
> 1.9.1
>
************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-28  2:14     ` shufan_lee(李書帆)
  0 siblings, 0 replies; 22+ messages in thread
From: shufan_lee(李書帆) @ 2018-02-28  2:14 UTC (permalink / raw)
  To: Guenter Roeck, ShuFanLee
  Cc: heikki.krogerus, greg, cy_huang(黃啟原),
	linux-kernel, linux-usb

Hi Guenter,

  regmap_write returns a negative return code or 0, thus this can be
simplified to
        return regmap_write(...);

  Ok, I'll modify it in v4

Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

  Do you mean it maybe better to call vendor's set_vconn after normal set_vconn is finished?
  If I understand correctly, I can also modify it in v4. For RT1711H, it also works by enabling/disabling idle mode after set_vconn.

Best Regards,
*****************************************
Shu-Fan Lee
Richtek Technology Corporation
TEL: +886-3-5526789 #2359
FAX: +886-3-5526612
*****************************************

________________________________________
寄件者: Guenter Roeck <groeck7@gmail.com> 代表 Guenter Roeck <linux@roeck-us.net>
寄件日期: 2018年2月22日 上午 06:15
收件者: ShuFanLee
副本: heikki.krogerus@linux.intel.com; greg@kroah.com; shufan_lee(李書帆); cy_huang(黃啟原); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
主旨: Re: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow

On Wed, Feb 21, 2018 at 11:02:23PM +0800, ShuFanLee wrote:
> From: ShuFanLee <shufan_lee@richtek.com>
>
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL,
> TCPC shall not start DRP toggling until subsequently the TCPM
> writes to the COMMAND register to start DRP toggling.
> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd
>   - Write DRP = 1
>   - Set LOOK4CONNECTION command
>
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>

Mostly loooks good to me. Couple of nitpicks below.

Guenter

> ---
>  drivers/staging/typec/tcpci.c | 128 +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
>
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
>
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
>
>  struct tcpci {
>       struct device *dev;
> -     struct i2c_client *client;
>
>       struct tcpm_port *port;
>
> @@ -30,6 +29,12 @@ struct tcpci {
>       bool controls_vbus;
>
>       struct tcpc_dev tcpc;
> +     struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +     struct tcpci *tcpci;
> +     struct tcpci_data data;
>  };
>
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
> @@ -37,8 +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>       return container_of(tcpc, struct tcpci, tcpc);
>  }
>
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -                     u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16 *val)
>  {
>       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
>  }
> @@ -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
>  static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>                                   enum typec_cc_status cc)
>  {
> +     int ret;
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
> +                        (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
>
>       switch (cc) {
>       default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
>               break;
>       }
>
> -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     usleep_range(500, 1000);
> +     reg |= TCPC_ROLE_CTRL_DRP;
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +                        TCPC_CMD_LOOK4CONNECTION);
> +     if (ret < 0)
> +             return ret;
> +     return 0;

regmap_write returns a negative return code or 0, thus this can be
simplified to
        return regmap_write(...);

>  }
>
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>       int ret;
>
> +     /* Handle vendor set vconn */
> +     if (tcpci->data) {
> +             if (tcpci->data->set_vconn) {
> +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +                                                  enable);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>                          enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>       if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       if (time_after(jiffies, timeout))
>               return -ETIMEDOUT;
>
> +     /* Handle vendor init */
> +     if (tcpci->data) {
> +             if (tcpci->data->init) {
> +                     ret = tcpci->data->init(tcpci, tcpci->data);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       /* Clear all events */
>       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>       if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
>  }
>
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>       struct tcpci *tcpci = dev_id;
> +
> +     return tcpci_irq(tcpci);
> +}

Hmm, normally I'd expect this function _after_ the function it calls.
Guess that doesn't matter much here, so I am fine with it as long
as Greg is ok with it as well.

> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci)
> +{
>       u16 status;
>
>       tcpci_read16(tcpci, TCPC_ALERT, &status);
> @@ -412,6 +455,7 @@ static irqreturn_t tcpci_irq(int irq, void *dev_id)
>
>       return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);
>
>  static const struct regmap_config tcpci_regmap_config = {
>       .reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>       return 0;
>  }
>
> -static int tcpci_probe(struct i2c_client *client,
> -                    const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
>  {
>       struct tcpci *tcpci;
>       int err;
>
> -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>       if (!tcpci)
> -             return -ENOMEM;
> +             return ERR_PTR(-ENOMEM);
>
> -     tcpci->client = client;
> -     tcpci->dev = &client->dev;
> -     i2c_set_clientdata(client, tcpci);
> -     tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -     if (IS_ERR(tcpci->regmap))
> -             return PTR_ERR(tcpci->regmap);
> +     tcpci->dev = dev;
> +     tcpci->data = data;
> +     tcpci->regmap = data->regmap;
>
>       tcpci->tcpc.init = tcpci_init;
>       tcpci->tcpc.get_vbus = tcpci_get_vbus;
> @@ -467,27 +507,63 @@ static int tcpci_probe(struct i2c_client *client,
>
>       err = tcpci_parse_config(tcpci);
>       if (err < 0)
> -             return err;
> +             return ERR_PTR(err);
> +
> +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +     if (PTR_ERR_OR_ZERO(tcpci->port))
> +             return ERR_CAST(tcpci->port);
>
> -     /* Disable chip interrupts */
> -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +     return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci)
> +{
> +     tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
>
> -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -                                     tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +                    const struct i2c_device_id *i2c_id)
> +{
> +     struct tcpci_chip *chip;
> +     int err;
> +     u16 val = 0;
> +
> +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +     if (!chip)
> +             return -ENOMEM;
> +
> +     chip->data.regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> +     if (IS_ERR(chip->data.regmap))
> +             return PTR_ERR(chip->data.regmap);
> +
> +     /* Disable chip interrupts before requesting irq */
> +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +                            sizeof(u16));
> +     if (err < 0)
> +             return err;
> +
> +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +                                     _tcpci_irq,
>                                       IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -                                     dev_name(tcpci->dev), tcpci);
> +                                     dev_name(&client->dev), chip);
>       if (err < 0)
>               return err;
>
> -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -     return PTR_ERR_OR_ZERO(tcpci->port);
> +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> +             return PTR_ERR(chip->tcpci);
> +
> +     i2c_set_clientdata(client, chip);
> +     return 0;
>  }
>
>  static int tcpci_remove(struct i2c_client *client)
>  {
> -     struct tcpci *tcpci = i2c_get_clientdata(client);
> +     struct tcpci_chip *chip = i2c_get_clientdata(client);
>
> -     tcpm_unregister_port(tcpci->port);
> +     tcpci_unregister_port(chip->tcpci);
>
>       return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
>
>  #define TCPC_CC_STATUS                       0x1d
> +#define TCPC_CC_STATUS_DRPRST                BIT(5)
>  #define TCPC_CC_STATUS_TERM          BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT     2
>  #define TCPC_CC_STATUS_CC2_MASK              0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
>
> +struct tcpci;
> +struct tcpci_data {
> +     struct regmap *regmap;
> +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +                      bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data);
> +void tcpci_unregister_port(struct tcpci *tcpci);
> +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> --
> 1.9.1
>
************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* 回覆: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-28  3:40     ` shufan_lee(李書帆)
  0 siblings, 0 replies; 22+ messages in thread
From: shufan_lee(李書帆) @ 2018-02-28  3:40 UTC (permalink / raw)
  To: Jun Li, ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi Jun,

  For the questions of drp_toggling, our test is as following:

  According to TCPCI 4.4.5.2
It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling using
COMMAND.Look4Connection.

  We've encounter a situation while testing with RT1711H as following:
  We repeatedly plug in/out a device (with Rd), and not to provide VBUS(5V) while plugging in.
  If we plug out the device right after TCPC detects it and stops toggling, TCPM will try to restart drp_toggling.
  Here, we re-plug in the device before TCPM calls drp_toggling. Under this circumstance, RT1711H reports open/open after drp_toggling is called.
  For current TCPM, it stops if open/open is reported at drp_toggling state.

  The detailed flow that causes RT1711H reporting open/open is described as following:
  1. RT1711H detects the device, stops toggling and reports to TCPM.
  2. Rd is plugged out before set_cc is called. So, ROLE_CONTROL.DRP is still 1.
  3. Plug in the device before TCPM restarts drp_toggling
  4. The device is detected by RT1711H's internal firmware again(TCPC chip's internal firmware).
  5. TCPM calls drp_toggling before cc_change triggered by step 4 is handled.
  6. TCPM sets ROLE_CONTROL.DRP = 1, Rd/Rd and start drp_toggling.
According to TCPCI 4.4.5.2
The TCPM shall write B6 (DRP) = 0b and B3..0 (CC1/CC2) if it wishes to control the Rp/Rd
directly instead of having the TCPC perform DRP toggling autonomousl.
So, Rd/Rd set in step 6 will not work. (Because ROLE_CONTROL.DRP is 1 since the first step.)
  7. RT1711H will stop toggling immediately (Because it's internal firmware already detects device at step 4) and report open/open (Because CC1/CC2 will be changed to Rd by RT1711H after LOOK4CONNECTION is set. RT1711H sets to Rd and device is Rd so open is reported)
  8. TCPCI reports open/open to TCPM at drp_toggling state

  That's why we always set ROLE_CONTROL.DRP to 0 while setting Rd/Rd.
  If this circumstance is not a general case, we can also use a vendor ops to replace it.
========================================================================

I don't catch the point of how you handle private events by above change,
maybe post your RT1711H part as a user in one series can make it clear,
I assume this can be done in existing tcpci_irq like above vender specific
handling as well:

For every glue driver, it registers its own irq handler and calls tcpci_irq in the handler.

Take RT1711H as an example:
It registers its own irq handler in probe function and handle vendor defined interrupts before calling general tcpci_irq:

static irqreturn_t _tcpci_irq(int irq, void *dev_id)
{
        struct rt1711h_chip *chip = dev_id;

        /* handle vendor defined interrupts here */

        /* call general tcpci_irq */
        return tcpci_irq(chip->tcpci);
}

static int rt1711h_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id)
{
        ....
        ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
                                          _tcpci_irq,
                                          IRQF_ONESHOT | IRQF_TRIGGER_LOW,
                                          dev_name(&client->dev), chip);
}


Best Regards,
*****************************************
Shu-Fan Lee
Richtek Technology Corporation
TEL: +886-3-5526789 #2359
FAX: +886-3-5526612
*****************************************

________________________________________
寄件者: Jun Li <jun.li@nxp.com>
寄件日期: 2018年2月22日 下午 06:16
收件者: ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
副本: shufan_lee(李書帆); cy_huang(黃啟原); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
主旨: RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow

Hi,

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org
> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of ShuFanLee
> Sent: 2018年2月21日 23:02
> To: heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: shufan_lee@richtek.com; cy_huang@richtek.com;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
> Subject: [PATCH] staging: typec: handle vendor defined part and modify drp
> toggling flow
>
> From: ShuFanLee <shufan_lee@richtek.com>
>
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export
> tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not
> start DRP toggling until subsequently the TCPM writes to the COMMAND
> register to start DRP toggling.

My understanding of above statement is TCPM(this Linux driver) can enable
DRP and CC1/CC2 in one shot, but TCPC(your typec chip internal firmware)
needs wait until TCPM writes to COMMAND register to start drp toggling.

> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd

Why fixed to be Rd/Rd? in this case, it means the starting value:

Tcpci 4.4.5.2:
"When initiating autonomous DRP toggling, the TCPM shall write B6 (DRP) =1b
and the starting value of Rp/Rd to B3..0 (CC1/CC2) to indicate DRP autonomous
toggling mode to the TCPC."

>   - Write DRP = 1

What's your problem if combine above 2 in one shot?

>   - Set LOOK4CONNECTION command
>
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
> ---
>  drivers/staging/typec/tcpci.c | 128
> +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
>
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue
> driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before
> disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
>
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
>
>  struct tcpci {
>       struct device *dev;
> -     struct i2c_client *client;
>
>       struct tcpm_port *port;
>
> @@ -30,6 +29,12 @@ struct tcpci {
>       bool controls_vbus;
>
>       struct tcpc_dev tcpc;
> +     struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +     struct tcpci *tcpci;
> +     struct tcpci_data data;
>  };
>
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,8
> +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>       return container_of(tcpc, struct tcpci, tcpc);  }
>
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -                     u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16
> +*val)
>  {
>       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));  } @@
> -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> typec_cc_status cc)  static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>                                   enum typec_cc_status cc)
>  {
> +     int ret;
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC1_SHIFT) |
> +                        (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC2_SHIFT);
>
>       switch (cc) {
>       default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>               break;
>       }
>
> -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     usleep_range(500, 1000);

Why need a wait here? It seems you actually don't want to do autonomously toggling
from the very beginning, instead, you begin with a directly control on CC, keep it(Rd)
for some time, then switch to use autonomously toggling, why you need such kind of
sequence? I think it's special and not following tcpci spec.

> +     reg |= TCPC_ROLE_CTRL_DRP;
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +                        TCPC_CMD_LOOK4CONNECTION);
> +     if (ret < 0)
> +             return ret;
> +     return 0;
>  }
>
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc,
> bool enable)
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>       int ret;
>
> +     /* Handle vendor set vconn */
> +     if (tcpci->data) {
> +             if (tcpci->data->set_vconn) {
> +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +                                                  enable);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>                          enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>       if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       if (time_after(jiffies, timeout))
>               return -ETIMEDOUT;
>
> +     /* Handle vendor init */
> +     if (tcpci->data) {
> +             if (tcpci->data->init) {
> +                     ret = tcpci->data->init(tcpci, tcpci->data);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       /* Clear all events */
>       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>       if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);  }
>
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>       struct tcpci *tcpci = dev_id;
> +
> +     return tcpci_irq(tcpci);
> +}
> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci) {
>       u16 status;
>
>       tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,7 @@
> static irqreturn_t tcpci_irq(int irq, void *dev_id)
>
>       return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);

I don't catch the point of how you handle private events by above change,
maybe post your RT1711H part as a user in one series can make it clear,
I assume this can be done in existing tcpci_irq like above vender specific
handling as well:
      tcpci->data->priv_events(tcpci, tcpci->data);

Li Jun
>
>  static const struct regmap_config tcpci_regmap_config = {
>       .reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>       return 0;
>  }
>
> -static int tcpci_probe(struct i2c_client *client,
> -                    const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data)
>  {
>       struct tcpci *tcpci;
>       int err;
>
> -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>       if (!tcpci)
> -             return -ENOMEM;
> +             return ERR_PTR(-ENOMEM);
>
> -     tcpci->client = client;
> -     tcpci->dev = &client->dev;
> -     i2c_set_clientdata(client, tcpci);
> -     tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -     if (IS_ERR(tcpci->regmap))
> -             return PTR_ERR(tcpci->regmap);
> +     tcpci->dev = dev;
> +     tcpci->data = data;
> +     tcpci->regmap = data->regmap;
>
>       tcpci->tcpc.init = tcpci_init;
>       tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +507,63 @@ static
> int tcpci_probe(struct i2c_client *client,
>
>       err = tcpci_parse_config(tcpci);
>       if (err < 0)
> -             return err;
> +             return ERR_PTR(err);
> +
> +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +     if (PTR_ERR_OR_ZERO(tcpci->port))
> +             return ERR_CAST(tcpci->port);
>
> -     /* Disable chip interrupts */
> -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +     return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci) {
> +     tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
>
> -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -                                     tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +                    const struct i2c_device_id *i2c_id) {
> +     struct tcpci_chip *chip;
> +     int err;
> +     u16 val = 0;
> +
> +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +     if (!chip)
> +             return -ENOMEM;
> +
> +     chip->data.regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> +     if (IS_ERR(chip->data.regmap))
> +             return PTR_ERR(chip->data.regmap);
> +
> +     /* Disable chip interrupts before requesting irq */
> +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +                            sizeof(u16));
> +     if (err < 0)
> +             return err;
> +
> +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +                                     _tcpci_irq,
>                                       IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -                                     dev_name(tcpci->dev), tcpci);
> +                                     dev_name(&client->dev), chip);
>       if (err < 0)
>               return err;
>
> -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -     return PTR_ERR_OR_ZERO(tcpci->port);
> +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> +             return PTR_ERR(chip->tcpci);
> +
> +     i2c_set_clientdata(client, chip);
> +     return 0;
>  }
>
>  static int tcpci_remove(struct i2c_client *client)  {
> -     struct tcpci *tcpci = i2c_get_clientdata(client);
> +     struct tcpci_chip *chip = i2c_get_clientdata(client);
>
> -     tcpm_unregister_port(tcpci->port);
> +     tcpci_unregister_port(chip->tcpci);
>
>       return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
>
>  #define TCPC_CC_STATUS                       0x1d
> +#define TCPC_CC_STATUS_DRPRST                BIT(5)
>  #define TCPC_CC_STATUS_TERM          BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT     2
>  #define TCPC_CC_STATUS_CC2_MASK              0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
>
> +struct tcpci;
> +struct tcpci_data {
> +     struct regmap *regmap;
> +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +                      bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data); void tcpci_unregister_port(struct tcpci *tcpci); irqreturn_t
> +tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
> .kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cjun.li%40nxp.com
> %7C44d11af27e0244fa4d1108d5793c3dc4%7C686ea1d3bc2b4c6fa92cd99c
> 5c301635%7C0%7C1%7C636548222008905206&sdata=zn2ougKRvs%2BbmH
> Qg2c8Rjj7vNe0ZiiVKdar7GdPa%2B3o%3D&reserved=0
************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-02-28  3:40     ` shufan_lee(李書帆)
  0 siblings, 0 replies; 22+ messages in thread
From: shufan_lee(李書帆) @ 2018-02-28  3:40 UTC (permalink / raw)
  To: Jun Li, ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi Jun,

  For the questions of drp_toggling, our test is as following:

  According to TCPCI 4.4.5.2
It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling using
COMMAND.Look4Connection.

  We've encounter a situation while testing with RT1711H as following:
  We repeatedly plug in/out a device (with Rd), and not to provide VBUS(5V) while plugging in.
  If we plug out the device right after TCPC detects it and stops toggling, TCPM will try to restart drp_toggling.
  Here, we re-plug in the device before TCPM calls drp_toggling. Under this circumstance, RT1711H reports open/open after drp_toggling is called.
  For current TCPM, it stops if open/open is reported at drp_toggling state.

  The detailed flow that causes RT1711H reporting open/open is described as following:
  1. RT1711H detects the device, stops toggling and reports to TCPM.
  2. Rd is plugged out before set_cc is called. So, ROLE_CONTROL.DRP is still 1.
  3. Plug in the device before TCPM restarts drp_toggling
  4. The device is detected by RT1711H's internal firmware again(TCPC chip's internal firmware).
  5. TCPM calls drp_toggling before cc_change triggered by step 4 is handled.
  6. TCPM sets ROLE_CONTROL.DRP = 1, Rd/Rd and start drp_toggling.
According to TCPCI 4.4.5.2
The TCPM shall write B6 (DRP) = 0b and B3..0 (CC1/CC2) if it wishes to control the Rp/Rd
directly instead of having the TCPC perform DRP toggling autonomousl.
So, Rd/Rd set in step 6 will not work. (Because ROLE_CONTROL.DRP is 1 since the first step.)
  7. RT1711H will stop toggling immediately (Because it's internal firmware already detects device at step 4) and report open/open (Because CC1/CC2 will be changed to Rd by RT1711H after LOOK4CONNECTION is set. RT1711H sets to Rd and device is Rd so open is reported)
  8. TCPCI reports open/open to TCPM at drp_toggling state

  That's why we always set ROLE_CONTROL.DRP to 0 while setting Rd/Rd.
  If this circumstance is not a general case, we can also use a vendor ops to replace it.
========================================================================

I don't catch the point of how you handle private events by above change,
maybe post your RT1711H part as a user in one series can make it clear,
I assume this can be done in existing tcpci_irq like above vender specific
handling as well:

For every glue driver, it registers its own irq handler and calls tcpci_irq in the handler.

Take RT1711H as an example:
It registers its own irq handler in probe function and handle vendor defined interrupts before calling general tcpci_irq:

static irqreturn_t _tcpci_irq(int irq, void *dev_id)
{
        struct rt1711h_chip *chip = dev_id;

        /* handle vendor defined interrupts here */

        /* call general tcpci_irq */
        return tcpci_irq(chip->tcpci);
}

static int rt1711h_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id)
{
        ....
        ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
                                          _tcpci_irq,
                                          IRQF_ONESHOT | IRQF_TRIGGER_LOW,
                                          dev_name(&client->dev), chip);
}


Best Regards,
*****************************************
Shu-Fan Lee
Richtek Technology Corporation
TEL: +886-3-5526789 #2359
FAX: +886-3-5526612
*****************************************

________________________________________
寄件者: Jun Li <jun.li@nxp.com>
寄件日期: 2018年2月22日 下午 06:16
收件者: ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
副本: shufan_lee(李書帆); cy_huang(黃啟原); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
主旨: RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow

Hi,

> -----Original Message-----
> From: linux-usb-owner@vger.kernel.org
> [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of ShuFanLee
> Sent: 2018年2月21日 23:02
> To: heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: shufan_lee@richtek.com; cy_huang@richtek.com;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
> Subject: [PATCH] staging: typec: handle vendor defined part and modify drp
> toggling flow
>
> From: ShuFanLee <shufan_lee@richtek.com>
>
> Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and export
> tcpci_irq.
> More operations can be extended in tcpci_data if needed.
> According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not
> start DRP toggling until subsequently the TCPM writes to the COMMAND
> register to start DRP toggling.

My understanding of above statement is TCPM(this Linux driver) can enable
DRP and CC1/CC2 in one shot, but TCPC(your typec chip internal firmware)
needs wait until TCPM writes to COMMAND register to start drp toggling.

> DRP toggling flow is chagned as following:
>   - Write DRP = 0 & Rd/Rd

Why fixed to be Rd/Rd? in this case, it means the starting value:

Tcpci 4.4.5.2:
"When initiating autonomous DRP toggling, the TCPM shall write B6 (DRP) =1b
and the starting value of Rp/Rd to B3..0 (CC1/CC2) to indicate DRP autonomous
toggling mode to the TCPC."

>   - Write DRP = 1

What's your problem if combine above 2 in one shot?

>   - Set LOOK4CONNECTION command
>
> Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
> ---
>  drivers/staging/typec/tcpci.c | 128
> +++++++++++++++++++++++++++++++++---------
>  drivers/staging/typec/tcpci.h |  13 +++++
>  2 files changed, 115 insertions(+), 26 deletions(-)
>
>  patch changelogs between v1 & v2
>  - Remove unnecessary i2c_client in the structure of tcpci
>  - Rename structure of tcpci_vendor_data to tcpci_data
>  - Not exporting tcpci read/write wrappers but register i2c regmap in glue
> driver
>  - Add set_vconn ops in tcpci_data
>    (It is necessary for RT1711H to enable/disable idle mode before
> disabling/enabling vconn)
>  - Export tcpci_irq so that vendor can call it in their own IRQ handler
>
>  patch changelogs between v2 & v3
>  - Change the return type of tcpci_irq from int to irqreturn_t
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
> index 9bd4412..4959c69 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -21,7 +21,6 @@
>
>  struct tcpci {
>       struct device *dev;
> -     struct i2c_client *client;
>
>       struct tcpm_port *port;
>
> @@ -30,6 +29,12 @@ struct tcpci {
>       bool controls_vbus;
>
>       struct tcpc_dev tcpc;
> +     struct tcpci_data *data;
> +};
> +
> +struct tcpci_chip {
> +     struct tcpci *tcpci;
> +     struct tcpci_data data;
>  };
>
>  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@ -37,8
> +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
>       return container_of(tcpc, struct tcpci, tcpc);  }
>
> -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> -                     u16 *val)
> +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16
> +*val)
>  {
>       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));  } @@
> -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> typec_cc_status cc)  static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>                                   enum typec_cc_status cc)
>  {
> +     int ret;
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC1_SHIFT) |
> +                        (TCPC_ROLE_CTRL_CC_RD <<
> TCPC_ROLE_CTRL_CC2_SHIFT);
>
>       switch (cc) {
>       default:
> @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct tcpc_dev
> *tcpc,
>               break;
>       }
>
> -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     usleep_range(500, 1000);

Why need a wait here? It seems you actually don't want to do autonomously toggling
from the very beginning, instead, you begin with a directly control on CC, keep it(Rd)
for some time, then switch to use autonomously toggling, why you need such kind of
sequence? I think it's special and not following tcpci spec.

> +     reg |= TCPC_ROLE_CTRL_DRP;
> +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +     if (ret < 0)
> +             return ret;
> +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> +                        TCPC_CMD_LOOK4CONNECTION);
> +     if (ret < 0)
> +             return ret;
> +     return 0;
>  }
>
>  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
> @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc,
> bool enable)
>       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>       int ret;
>
> +     /* Handle vendor set vconn */
> +     if (tcpci->data) {
> +             if (tcpci->data->set_vconn) {
> +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> +                                                  enable);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
>                          enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
>       if (ret < 0)
> @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       if (time_after(jiffies, timeout))
>               return -ETIMEDOUT;
>
> +     /* Handle vendor init */
> +     if (tcpci->data) {
> +             if (tcpci->data->init) {
> +                     ret = tcpci->data->init(tcpci, tcpci->data);
> +                     if (ret < 0)
> +                             return ret;
> +             }
> +     }
> +
>       /* Clear all events */
>       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
>       if (ret < 0)
> @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
>       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);  }
>
> -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
>  {
>       struct tcpci *tcpci = dev_id;
> +
> +     return tcpci_irq(tcpci);
> +}
> +
> +irqreturn_t tcpci_irq(struct tcpci *tcpci) {
>       u16 status;
>
>       tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,7 @@
> static irqreturn_t tcpci_irq(int irq, void *dev_id)
>
>       return IRQ_HANDLED;
>  }
> +EXPORT_SYMBOL_GPL(tcpci_irq);

I don't catch the point of how you handle private events by above change,
maybe post your RT1711H part as a user in one series can make it clear,
I assume this can be done in existing tcpci_irq like above vender specific
handling as well:
      tcpci->data->priv_events(tcpci, tcpci->data);

Li Jun
>
>  static const struct regmap_config tcpci_regmap_config = {
>       .reg_bits = 8,
> @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
>       return 0;
>  }
>
> -static int tcpci_probe(struct i2c_client *client,
> -                    const struct i2c_device_id *i2c_id)
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data)
>  {
>       struct tcpci *tcpci;
>       int err;
>
> -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
>       if (!tcpci)
> -             return -ENOMEM;
> +             return ERR_PTR(-ENOMEM);
>
> -     tcpci->client = client;
> -     tcpci->dev = &client->dev;
> -     i2c_set_clientdata(client, tcpci);
> -     tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
> -     if (IS_ERR(tcpci->regmap))
> -             return PTR_ERR(tcpci->regmap);
> +     tcpci->dev = dev;
> +     tcpci->data = data;
> +     tcpci->regmap = data->regmap;
>
>       tcpci->tcpc.init = tcpci_init;
>       tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +507,63 @@ static
> int tcpci_probe(struct i2c_client *client,
>
>       err = tcpci_parse_config(tcpci);
>       if (err < 0)
> -             return err;
> +             return ERR_PTR(err);
> +
> +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> +     if (PTR_ERR_OR_ZERO(tcpci->port))
> +             return ERR_CAST(tcpci->port);
>
> -     /* Disable chip interrupts */
> -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> +     return tcpci;
> +}
> +EXPORT_SYMBOL_GPL(tcpci_register_port);
> +
> +void tcpci_unregister_port(struct tcpci *tcpci) {
> +     tcpm_unregister_port(tcpci->port);
> +}
> +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
>
> -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> -                                     tcpci_irq,
> +static int tcpci_probe(struct i2c_client *client,
> +                    const struct i2c_device_id *i2c_id) {
> +     struct tcpci_chip *chip;
> +     int err;
> +     u16 val = 0;
> +
> +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> +     if (!chip)
> +             return -ENOMEM;
> +
> +     chip->data.regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> +     if (IS_ERR(chip->data.regmap))
> +             return PTR_ERR(chip->data.regmap);
> +
> +     /* Disable chip interrupts before requesting irq */
> +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
> +                            sizeof(u16));
> +     if (err < 0)
> +             return err;
> +
> +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> +                                     _tcpci_irq,
>                                       IRQF_ONESHOT | IRQF_TRIGGER_LOW,
> -                                     dev_name(tcpci->dev), tcpci);
> +                                     dev_name(&client->dev), chip);
>       if (err < 0)
>               return err;
>
> -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> -     return PTR_ERR_OR_ZERO(tcpci->port);
> +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> +             return PTR_ERR(chip->tcpci);
> +
> +     i2c_set_clientdata(client, chip);
> +     return 0;
>  }
>
>  static int tcpci_remove(struct i2c_client *client)  {
> -     struct tcpci *tcpci = i2c_get_clientdata(client);
> +     struct tcpci_chip *chip = i2c_get_clientdata(client);
>
> -     tcpm_unregister_port(tcpci->port);
> +     tcpci_unregister_port(chip->tcpci);
>
>       return 0;
>  }
> diff --git a/drivers/staging/typec/tcpci.h b/drivers/staging/typec/tcpci.h
> index fdfb06c..40025b2 100644
> --- a/drivers/staging/typec/tcpci.h
> +++ b/drivers/staging/typec/tcpci.h
> @@ -59,6 +59,7 @@
>  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
>
>  #define TCPC_CC_STATUS                       0x1d
> +#define TCPC_CC_STATUS_DRPRST                BIT(5)
>  #define TCPC_CC_STATUS_TERM          BIT(4)
>  #define TCPC_CC_STATUS_CC2_SHIFT     2
>  #define TCPC_CC_STATUS_CC2_MASK              0x3
> @@ -121,4 +122,16 @@
>  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
>  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
>
> +struct tcpci;
> +struct tcpci_data {
> +     struct regmap *regmap;
> +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> +                      bool enable);
> +};
> +
> +struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data
> +*data); void tcpci_unregister_port(struct tcpci *tcpci); irqreturn_t
> +tcpci_irq(struct tcpci *tcpci);
> +
>  #endif /* __LINUX_USB_TCPCI_H */
> --
> 1.9.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in the
> body of a message to majordomo@vger.kernel.org More majordomo info at
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
> .kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cjun.li%40nxp.com
> %7C44d11af27e0244fa4d1108d5793c3dc4%7C686ea1d3bc2b4c6fa92cd99c
> 5c301635%7C0%7C1%7C636548222008905206&sdata=zn2ougKRvs%2BbmH
> Qg2c8Rjj7vNe0ZiiVKdar7GdPa%2B3o%3D&reserved=0
************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
  2018-02-28  3:40     ` shufan_lee(李書帆)
  (?)
@ 2018-03-01  5:34     ` Jun Li
  2018-03-01  8:49       ` shufan_lee(李��帆)
  -1 siblings, 1 reply; 22+ messages in thread
From: Jun Li @ 2018-03-01  5:34 UTC (permalink / raw)
  To: shufan_lee(李��帆),
	ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(�S�⒃�),
	linux-kernel, linux-usb, dl-linux-imx

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 20060 bytes --]

Hi
> -----Original Message-----
> From: shufan_lee(Àî•ø·«) [mailto:shufan_lee@richtek.com]
> Sent: 2018Äê2ÔÂ28ÈÕ 11:41
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(üS†¢Ô­) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: »Ø¸²: [PATCH] staging: typec: handle vendor defined part and
> modify drp toggling flow
> 
> Hi Jun,
> 
>   For the questions of drp_toggling, our test is as following:
> 
>   According to TCPCI 4.4.5.2
> It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
> POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> using COMMAND.Look4Connection.
> 
>   We've encounter a situation while testing with RT1711H as following:
>   We repeatedly plug in/out a device (with Rd), and not to provide VBUS(5V)
> while plugging in.
>   If we plug out the device right after TCPC detects it and stops toggling,
> TCPM will try to restart drp_toggling.
>   Here, we re-plug in the device before TCPM calls drp_toggling. Under this
> circumstance, RT1711H reports open/open after drp_toggling is called.

Why RT1711H reports open/open after drp_toggling is enabled?
This open/open is for you plug out the device, right?
Why RT1711H can't report new cc change events after you plug in the device?

Please use tcpm log to show all the events and state transitions for your
above corner case.
cat /sys/kernel/debug/tcpm/xxxxx

>   For current TCPM, it stops if open/open is reported at drp_toggling state.
> 
>   The detailed flow that causes RT1711H reporting open/open is described
> as following:
>   1. RT1711H detects the device, stops toggling and reports to TCPM.
>   2. Rd is plugged out before set_cc is called. So, ROLE_CONTROL.DRP is
> still 1.

So open/open cc change will generate.
 
>   3. Plug in the device before TCPM restarts drp_toggling
>   4. The device is detected by RT1711H's internal firmware again(TCPC
> chip's internal firmware).

What cc change event tcpc will report on step 4?

>   5. TCPM calls drp_toggling before cc_change triggered by step 4 is
> handled.
>   6. TCPM sets ROLE_CONTROL.DRP = 1, Rd/Rd and start drp_toggling.
> According to TCPCI 4.4.5.2
> The TCPM shall write B6 (DRP) = 0b and B3..0 (CC1/CC2) if it wishes to
> control the Rp/Rd directly instead of having the TCPC perform DRP toggling
> autonomousl.
> So, Rd/Rd set in step 6 will not work. (Because ROLE_CONTROL.DRP is 1
> since the first step.)
>   7. RT1711H will stop toggling immediately (Because it's internal firmware
> already detects device at step 4) and report open/open (Because CC1/CC2
> will be changed to Rd by RT1711H after LOOK4CONNECTION is set. RT1711H
> sets to Rd and device is Rd so open is reported)
>   8. TCPCI reports open/open to TCPM at drp_toggling state
> 
>   That's why we always set ROLE_CONTROL.DRP to 0 while setting Rd/Rd.
>   If this circumstance is not a general case, we can also use a vendor ops to
> replace it.

Thanks for the detailed description, the tcpm full log is required to know
what's going on here, you can apply my drp_toggling change patch[1] and
run your problem case again, then post the full tcpm log. 

Generally, I think you need check further this is a problem on the current
tcpm _or_ your tcpc chip, if the problem on the tcpm, you should resolve
this issue by improve tcpm, if the problem on your tcpc chip, you can add
a vendor ops.

I tested my tcpc HW with my drp_toggling change patch[1] (w/o your change)
by quickly pulg-in & plug-out a sink, no problem found.
Did you verify your change can pass the typec compliance test?

[1] https://www.spinics.net/lists/devicetree/msg216851.html
> ==============================================================
> ==========
> 
> I don't catch the point of how you handle private events by above change,
> maybe post your RT1711H part as a user in one series can make it clear, I
> assume this can be done in existing tcpci_irq like above vender specific
> handling as well:
> 
> For every glue driver, it registers its own irq handler and calls tcpci_irq in the
> handler.
> 
> Take RT1711H as an example:
> It registers its own irq handler in probe function and handle vendor defined
> interrupts before calling general tcpci_irq:
> 
> static irqreturn_t _tcpci_irq(int irq, void *dev_id) {
>         struct rt1711h_chip *chip = dev_id;
> 
>         /* handle vendor defined interrupts here */
> 
>         /* call general tcpci_irq */
>         return tcpci_irq(chip->tcpci);
> }
> 
> static int rt1711h_probe(struct i2c_client *client, const struct i2c_device_id
> *i2c_id) {
>         ....
>         ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
>                                           _tcpci_irq,
>                                           IRQF_ONESHOT |
> IRQF_TRIGGER_LOW,
>                                           dev_name(&client->dev),
> chip); }
> 
> 
Get it, thanks.

> Best Regards,
> *****************************************
> Shu-Fan Lee
> Richtek Technology Corporation
> TEL: +886-3-5526789 #2359
> FAX: +886-3-5526612
> *****************************************
> 
> ________________________________________
> ¼Ä¼þÕß: Jun Li <jun.li@nxp.com>
> ¼Ä¼þÈÕÆÚ: 2018Äê2ÔÂ22ÈÕ ÏÂÎç 06:16
> ÊÕ¼þÕß: ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net;
> greg@kroah.com
> ¸±±¾: shufan_lee(Àî•ø·«); cy_huang(üS†¢Ô­); linux-kernel@vger.kernel.org;
> linux-usb@vger.kernel.org; dl-linux-imx
> Ö÷Ö¼: RE: [PATCH] staging: typec: handle vendor defined part and modify drp
> toggling flow
> 
> Hi,
> 
> > -----Original Message-----
> > From: linux-usb-owner@vger.kernel.org
> > [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of ShuFanLee
> > Sent: 2018Äê2ÔÂ21ÈÕ 23:02
> > To: heikki.krogerus@linux.intel.com; linux@roeck-us.net;
> > greg@kroah.com
> > Cc: shufan_lee@richtek.com; cy_huang@richtek.com;
> > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
> > Subject: [PATCH] staging: typec: handle vendor defined part and modify
> > drp toggling flow
> >
> > From: ShuFanLee <shufan_lee@richtek.com>
> >
> > Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and
> > export tcpci_irq.
> > More operations can be extended in tcpci_data if needed.
> > According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall not
> > start DRP toggling until subsequently the TCPM writes to the COMMAND
> > register to start DRP toggling.
> 
> My understanding of above statement is TCPM(this Linux driver) can enable
> DRP and CC1/CC2 in one shot, but TCPC(your typec chip internal firmware)
> needs wait until TCPM writes to COMMAND register to start drp toggling.
> 
> > DRP toggling flow is chagned as following:
> >   - Write DRP = 0 & Rd/Rd
> 
> Why fixed to be Rd/Rd? in this case, it means the starting value:
> 
> Tcpci 4.4.5.2:
> "When initiating autonomous DRP toggling, the TCPM shall write B6 (DRP)
> =1b and the starting value of Rp/Rd to B3..0 (CC1/CC2) to indicate DRP
> autonomous toggling mode to the TCPC."
> 
> >   - Write DRP = 1
> 
> What's your problem if combine above 2 in one shot?
> 
> >   - Set LOOK4CONNECTION command
> >
> > Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
> > ---
> >  drivers/staging/typec/tcpci.c | 128
> > +++++++++++++++++++++++++++++++++---------
> >  drivers/staging/typec/tcpci.h |  13 +++++
> >  2 files changed, 115 insertions(+), 26 deletions(-)
> >
> >  patch changelogs between v1 & v2
> >  - Remove unnecessary i2c_client in the structure of tcpci
> >  - Rename structure of tcpci_vendor_data to tcpci_data
> >  - Not exporting tcpci read/write wrappers but register i2c regmap in
> > glue driver
> >  - Add set_vconn ops in tcpci_data
> >    (It is necessary for RT1711H to enable/disable idle mode before
> > disabling/enabling vconn)
> >  - Export tcpci_irq so that vendor can call it in their own IRQ
> > handler
> >
> >  patch changelogs between v2 & v3
> >  - Change the return type of tcpci_irq from int to irqreturn_t
> >
> > diff --git a/drivers/staging/typec/tcpci.c
> > b/drivers/staging/typec/tcpci.c index 9bd4412..4959c69 100644
> > --- a/drivers/staging/typec/tcpci.c
> > +++ b/drivers/staging/typec/tcpci.c
> > @@ -21,7 +21,6 @@
> >
> >  struct tcpci {
> >       struct device *dev;
> > -     struct i2c_client *client;
> >
> >       struct tcpm_port *port;
> >
> > @@ -30,6 +29,12 @@ struct tcpci {
> >       bool controls_vbus;
> >
> >       struct tcpc_dev tcpc;
> > +     struct tcpci_data *data;
> > +};
> > +
> > +struct tcpci_chip {
> > +     struct tcpci *tcpci;
> > +     struct tcpci_data data;
> >  };
> >
> >  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@
> > -37,8
> > +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev
> > +*tcpc)
> >       return container_of(tcpc, struct tcpci, tcpc);  }
> >
> > -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> > -                     u16 *val)
> > +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16
> > +*val)
> >  {
> >       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));  }
> > @@
> > -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> > typec_cc_status cc)  static int tcpci_start_drp_toggling(struct
> > tcpc_dev *tcpc,
> >                                   enum typec_cc_status cc)  {
> > +     int ret;
> >       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> > -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> > +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> > TCPC_ROLE_CTRL_CC1_SHIFT) |
> > +                        (TCPC_ROLE_CTRL_CC_RD <<
> > TCPC_ROLE_CTRL_CC2_SHIFT);
> >
> >       switch (cc) {
> >       default:
> > @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct
> > tcpc_dev *tcpc,
> >               break;
> >       }
> >
> > -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     if (ret < 0)
> > +             return ret;
> > +     usleep_range(500, 1000);
> 
> Why need a wait here? It seems you actually don't want to do autonomously
> toggling from the very beginning, instead, you begin with a directly control
> on CC, keep it(Rd) for some time, then switch to use autonomously toggling,
> why you need such kind of sequence? I think it's special and not following
> tcpci spec.
> 
> > +     reg |= TCPC_ROLE_CTRL_DRP;
> > +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> > +                        TCPC_CMD_LOOK4CONNECTION);
> > +     if (ret < 0)
> > +             return ret;
> > +     return 0;
> >  }
> >
> >  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool
> > sink) @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct tcpc_dev
> > *tcpc, bool enable)
> >       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> >       int ret;
> >
> > +     /* Handle vendor set vconn */
> > +     if (tcpci->data) {
> > +             if (tcpci->data->set_vconn) {
> > +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> > +                                                  enable);
> > +                     if (ret < 0)
> > +                             return ret;
> > +             }
> > +     }
> > +
> >       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
> >                          enable ?
> TCPC_POWER_CTRL_VCONN_ENABLE : 0);
> >       if (ret < 0)
> > @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> >       if (time_after(jiffies, timeout))
> >               return -ETIMEDOUT;
> >
> > +     /* Handle vendor init */
> > +     if (tcpci->data) {
> > +             if (tcpci->data->init) {
> > +                     ret = tcpci->data->init(tcpci, tcpci->data);
> > +                     if (ret < 0)
> > +                             return ret;
> > +             }
> > +     }
> > +
> >       /* Clear all events */
> >       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
> >       if (ret < 0)
> > @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> >       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);  }
> >
> > -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> > +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
> >  {
> >       struct tcpci *tcpci = dev_id;
> > +
> > +     return tcpci_irq(tcpci);
> > +}
> > +
> > +irqreturn_t tcpci_irq(struct tcpci *tcpci) {
> >       u16 status;
> >
> >       tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,7 @@
> > static irqreturn_t tcpci_irq(int irq, void *dev_id)
> >
> >       return IRQ_HANDLED;
> >  }
> > +EXPORT_SYMBOL_GPL(tcpci_irq);
> 
> I don't catch the point of how you handle private events by above change,
> maybe post your RT1711H part as a user in one series can make it clear, I
> assume this can be done in existing tcpci_irq like above vender specific
> handling as well:
>       tcpci->data->priv_events(tcpci, tcpci->data);
> 
> Li Jun
> >
> >  static const struct regmap_config tcpci_regmap_config = {
> >       .reg_bits = 8,
> > @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
> >       return 0;
> >  }
> >
> > -static int tcpci_probe(struct i2c_client *client,
> > -                    const struct i2c_device_id *i2c_id)
> > +struct tcpci *tcpci_register_port(struct device *dev, struct
> > +tcpci_data
> > +*data)
> >  {
> >       struct tcpci *tcpci;
> >       int err;
> >
> > -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> > +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
> >       if (!tcpci)
> > -             return -ENOMEM;
> > +             return ERR_PTR(-ENOMEM);
> >
> > -     tcpci->client = client;
> > -     tcpci->dev = &client->dev;
> > -     i2c_set_clientdata(client, tcpci);
> > -     tcpci->regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> > -     if (IS_ERR(tcpci->regmap))
> > -             return PTR_ERR(tcpci->regmap);
> > +     tcpci->dev = dev;
> > +     tcpci->data = data;
> > +     tcpci->regmap = data->regmap;
> >
> >       tcpci->tcpc.init = tcpci_init;
> >       tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +507,63 @@
> > static int tcpci_probe(struct i2c_client *client,
> >
> >       err = tcpci_parse_config(tcpci);
> >       if (err < 0)
> > -             return err;
> > +             return ERR_PTR(err);
> > +
> > +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> > +     if (PTR_ERR_OR_ZERO(tcpci->port))
> > +             return ERR_CAST(tcpci->port);
> >
> > -     /* Disable chip interrupts */
> > -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> > +     return tcpci;
> > +}
> > +EXPORT_SYMBOL_GPL(tcpci_register_port);
> > +
> > +void tcpci_unregister_port(struct tcpci *tcpci) {
> > +     tcpm_unregister_port(tcpci->port);
> > +}
> > +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
> >
> > -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> > -                                     tcpci_irq,
> > +static int tcpci_probe(struct i2c_client *client,
> > +                    const struct i2c_device_id *i2c_id) {
> > +     struct tcpci_chip *chip;
> > +     int err;
> > +     u16 val = 0;
> > +
> > +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > +     if (!chip)
> > +             return -ENOMEM;
> > +
> > +     chip->data.regmap = devm_regmap_init_i2c(client,
> > &tcpci_regmap_config);
> > +     if (IS_ERR(chip->data.regmap))
> > +             return PTR_ERR(chip->data.regmap);
> > +
> > +     /* Disable chip interrupts before requesting irq */
> > +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK,
> &val,
> > +                            sizeof(u16));
> > +     if (err < 0)
> > +             return err;
> > +
> > +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> > +                                     _tcpci_irq,
> >                                       IRQF_ONESHOT |
> IRQF_TRIGGER_LOW,
> > -                                     dev_name(tcpci->dev),
> tcpci);
> > +                                     dev_name(&client->dev),
> chip);
> >       if (err < 0)
> >               return err;
> >
> > -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> > -     return PTR_ERR_OR_ZERO(tcpci->port);
> > +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> > +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> > +             return PTR_ERR(chip->tcpci);
> > +
> > +     i2c_set_clientdata(client, chip);
> > +     return 0;
> >  }
> >
> >  static int tcpci_remove(struct i2c_client *client)  {
> > -     struct tcpci *tcpci = i2c_get_clientdata(client);
> > +     struct tcpci_chip *chip = i2c_get_clientdata(client);
> >
> > -     tcpm_unregister_port(tcpci->port);
> > +     tcpci_unregister_port(chip->tcpci);
> >
> >       return 0;
> >  }
> > diff --git a/drivers/staging/typec/tcpci.h
> > b/drivers/staging/typec/tcpci.h index fdfb06c..40025b2 100644
> > --- a/drivers/staging/typec/tcpci.h
> > +++ b/drivers/staging/typec/tcpci.h
> > @@ -59,6 +59,7 @@
> >  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
> >
> >  #define TCPC_CC_STATUS                       0x1d
> > +#define TCPC_CC_STATUS_DRPRST                BIT(5)
> >  #define TCPC_CC_STATUS_TERM          BIT(4)
> >  #define TCPC_CC_STATUS_CC2_SHIFT     2
> >  #define TCPC_CC_STATUS_CC2_MASK              0x3
> > @@ -121,4 +122,16 @@
> >  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
> >  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
> >
> > +struct tcpci;
> > +struct tcpci_data {
> > +     struct regmap *regmap;
> > +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> > +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> > +                      bool enable);
> > +};
> > +
> > +struct tcpci *tcpci_register_port(struct device *dev, struct
> > +tcpci_data *data); void tcpci_unregister_port(struct tcpci *tcpci);
> > +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> > +
> >  #endif /* __LINUX_USB_TCPCI_H */
> > --
> > 1.9.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-usb"
> > in the body of a message to majordomo@vger.kernel.org More
> majordomo
> > info at
> >
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
> > .kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cjun.li%40nxp.co
> m
> > %7C44d11af27e0244fa4d1108d5793c3dc4%7C686ea1d3bc2b4c6fa92cd99
> c
> >
> 5c301635%7C0%7C1%7C636548222008905206&sdata=zn2ougKRvs%2BbmH
> > Qg2c8Rjj7vNe0ZiiVKdar7GdPa%2B3o%3D&reserved=0
> ************* Email Confidentiality Notice ********************
> 
> The information contained in this e-mail message (including any attachments)
> may be confidential, proprietary, privileged, or otherwise exempt from
> disclosure under applicable laws. It is intended to be conveyed only to the
> designated recipient(s). Any use, dissemination, distribution, printing,
> retaining or copying of this e-mail (including its attachments) by unintended
> recipient(s) is strictly prohibited and may be unlawful. If you are not an
> intended recipient of this e-mail, or believe that you have received this
> e-mail in error, please notify the sender immediately (by replying to this
> e-mail), delete any and all copies of this e-mail (including any attachments)
> from your system, and do not disclose the content of this e-mail to any other
> person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
  2018-03-01  5:34     ` [PATCH] " Jun Li
@ 2018-03-01  8:49       ` shufan_lee(李��帆)
  2018-03-01 10:06           ` Jun Li
  0 siblings, 1 reply; 22+ messages in thread
From: shufan_lee(李��帆) @ 2018-03-01  8:49 UTC (permalink / raw)
  To: 'Jun Li', ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(�S�⒃�),
	linux-kernel, linux-usb, dl-linux-imx

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="gb2312", Size: 24526 bytes --]

Hi Jun,

  The attachment is waveform of the condition we met but I'm not sure whether you can download the attachment.
  I add log in RT1711H it shows as following:
[ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler
[ 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 = Open
=> Device(Rd) is plugged out

[ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0
[ 914.963011] typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0
[ 914.968407] typec_rt1711h 2-004e: tcpm_set_vbus chg is already 0
[ 914.974541] typec_rt1711h 2-004e: tcpm_set_vconn vconn is already 0
[ 914.980921] typec_rt1711h 2-004e: tcpm_set_current_limit 0 ma, 0 mv (not implemented)
[ 914.988894] typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1
[ 915.003201] typec_rt1711h 2-004e: tcpm_set_roles Source Host
[ 915.009264] typec_rt1711h 2-004e: tcpm_start_drp_toggling
=> state_machine_work of TCPM calls start_drp_toggling function but does not set LOOK4CONNECTION command yet
=> (Note1) Device(Rd) is plugged in (RT1711H's internal firmware detects Rd plugged in. cc_change is triggered and it will be vRd-connected at this moment)
=> TCPM writes LOOK4CONNECTION command
- Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while writing Rd/Rd to RC.CC1/RC.CC2.
- (Note2) Right after LOOK4CONNECTION command is written, RT1711H pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling (because device(Rd) is already connected) and CC status will be open/open now (because RT1711H presents Rd and device is connected(Rd))

[ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 = Open
=> Enter RT1711H's irq handler and it reports open/open

I think the point is to write RC.DRP = 0 at the beginning of drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing Rd/Rd to RC.CC1/RC.CC2
This operation will make RT1711H's internal firmware restarts from disconnected state and toggles correctly.

According to TCPCI spec (4.4.5.2):
It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling using COMMAND.Look4Connection
Restart DRP Toggling
=> It is recommended the TCPM write ROLE_CONTROL.DRP=0 here
Set PC.AutoDischargeDisconnect=0b
Set RC.DRP=1b (DRP)
Set RC.RpValue=00b (smallest Rp to save power)
Set RC.CC1=01b
Set RC.CC2=01bCOMMAND.Look4ConnectionNo

It seems like it is not a general case here (because it is only recommended but not necessary), we can move it to vendor_ops in the next patch.

For your question:
Why RT1711H reports open/open after drp_toggling is enabled?
=> See Note2 above.
This open/open is for you plug out the device, right?
=> No, see Note2 above.
Why RT1711H can't report new cc change events after you plug in the device?
=> RT1711H can generate new cc change events after plugging in the device.
What cc change event tcpc will report on step 4?
=> See Note1 above
Did you verify your change can pass the typec compliance test?
=> We didn't test it yet but try to make all functions work correctly first.

Best Regards,
*****************************
Shu-Fan Lee
Richtek Technology Corporation
TEL: +886-3-5526789 #2359
FAX: +886-3-5526612
*****************************

-----Original Message-----
From: Jun Li [mailto:jun.li@nxp.com]
Sent: Thursday, March 01, 2018 1:35 PM
To: shufan_lee(Àî•ø·«); ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
Cc: cy_huang(üS†¢Ô­); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow

Hi
> -----Original Message-----
> From: shufan_lee(Àî•ø·«) [mailto:shufan_lee@richtek.com]
> Sent: 2018Äê2ÔÂ28ÈÕ 11:41
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(üS†¢Ô­) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: »Ø¸²: [PATCH] staging: typec: handle vendor defined part and
> modify drp toggling flow
>
> Hi Jun,
>
>   For the questions of drp_toggling, our test is as following:
>
>   According to TCPCI 4.4.5.2
> It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
> POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> using COMMAND.Look4Connection.
>
>   We've encounter a situation while testing with RT1711H as following:
>   We repeatedly plug in/out a device (with Rd), and not to provide
> VBUS(5V) while plugging in.
>   If we plug out the device right after TCPC detects it and stops
> toggling, TCPM will try to restart drp_toggling.
>   Here, we re-plug in the device before TCPM calls drp_toggling. Under
> this circumstance, RT1711H reports open/open after drp_toggling is called.

Why RT1711H reports open/open after drp_toggling is enabled?
This open/open is for you plug out the device, right?
Why RT1711H can't report new cc change events after you plug in the device?

Please use tcpm log to show all the events and state transitions for your above corner case.
cat /sys/kernel/debug/tcpm/xxxxx

>   For current TCPM, it stops if open/open is reported at drp_toggling state.
>
>   The detailed flow that causes RT1711H reporting open/open is
> described as following:
>   1. RT1711H detects the device, stops toggling and reports to TCPM.
>   2. Rd is plugged out before set_cc is called. So, ROLE_CONTROL.DRP
> is still 1.

So open/open cc change will generate.

>   3. Plug in the device before TCPM restarts drp_toggling
>   4. The device is detected by RT1711H's internal firmware again(TCPC
> chip's internal firmware).

What cc change event tcpc will report on step 4?

>   5. TCPM calls drp_toggling before cc_change triggered by step 4 is
> handled.
>   6. TCPM sets ROLE_CONTROL.DRP = 1, Rd/Rd and start drp_toggling.
> According to TCPCI 4.4.5.2
> The TCPM shall write B6 (DRP) = 0b and B3..0 (CC1/CC2) if it wishes to
> control the Rp/Rd directly instead of having the TCPC perform DRP
> toggling autonomousl.
> So, Rd/Rd set in step 6 will not work. (Because ROLE_CONTROL.DRP is 1
> since the first step.)
>   7. RT1711H will stop toggling immediately (Because it's internal
> firmware already detects device at step 4) and report open/open
> (Because CC1/CC2 will be changed to Rd by RT1711H after
> LOOK4CONNECTION is set. RT1711H sets to Rd and device is Rd so open is reported)
>   8. TCPCI reports open/open to TCPM at drp_toggling state
>
>   That's why we always set ROLE_CONTROL.DRP to 0 while setting Rd/Rd.
>   If this circumstance is not a general case, we can also use a vendor
> ops to replace it.

Thanks for the detailed description, the tcpm full log is required to know what's going on here, you can apply my drp_toggling change patch[1] and run your problem case again, then post the full tcpm log.

Generally, I think you need check further this is a problem on the current tcpm _or_ your tcpc chip, if the problem on the tcpm, you should resolve this issue by improve tcpm, if the problem on your tcpc chip, you can add a vendor ops.

I tested my tcpc HW with my drp_toggling change patch[1] (w/o your change) by quickly pulg-in & plug-out a sink, no problem found.
Did you verify your change can pass the typec compliance test?

[1] https://www.spinics.net/lists/devicetree/msg216851.html
> ==============================================================
> ==========
>
> I don't catch the point of how you handle private events by above
> change, maybe post your RT1711H part as a user in one series can make
> it clear, I assume this can be done in existing tcpci_irq like above
> vender specific handling as well:
>
> For every glue driver, it registers its own irq handler and calls
> tcpci_irq in the handler.
>
> Take RT1711H as an example:
> It registers its own irq handler in probe function and handle vendor
> defined interrupts before calling general tcpci_irq:
>
> static irqreturn_t _tcpci_irq(int irq, void *dev_id) {
>         struct rt1711h_chip *chip = dev_id;
>
>         /* handle vendor defined interrupts here */
>
>         /* call general tcpci_irq */
>         return tcpci_irq(chip->tcpci); }
>
> static int rt1711h_probe(struct i2c_client *client, const struct
> i2c_device_id
> *i2c_id) {
>         ....
>         ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
>                                           _tcpci_irq,
>                                           IRQF_ONESHOT |
> IRQF_TRIGGER_LOW,
>                                           dev_name(&client->dev),
> chip); }
>
>
Get it, thanks.

> Best Regards,
> *****************************************
> Shu-Fan Lee
> Richtek Technology Corporation
> TEL: +886-3-5526789 #2359
> FAX: +886-3-5526612
> *****************************************
>
> ________________________________________
> ¼Ä¼þÕß: Jun Li <jun.li@nxp.com>
> ¼Ä¼þÈÕÆÚ: 2018Äê2ÔÂ22ÈÕ ÏÂÎç 06:16
> ÊÕ¼þÕß: ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net;
> greg@kroah.com
> ¸±±¾: shufan_lee(Àî•ø·«); cy_huang(üS†¢Ô­); linux-kernel@vger.kernel.org;
> linux-usb@vger.kernel.org; dl-linux-imx
> Ö÷Ö¼: RE: [PATCH] staging: typec: handle vendor defined part and modify
> drp toggling flow
>
> Hi,
>
> > -----Original Message-----
> > From: linux-usb-owner@vger.kernel.org
> > [mailto:linux-usb-owner@vger.kernel.org] On Behalf Of ShuFanLee
> > Sent: 2018Äê2ÔÂ21ÈÕ 23:02
> > To: heikki.krogerus@linux.intel.com; linux@roeck-us.net;
> > greg@kroah.com
> > Cc: shufan_lee@richtek.com; cy_huang@richtek.com;
> > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org
> > Subject: [PATCH] staging: typec: handle vendor defined part and
> > modify drp toggling flow
> >
> > From: ShuFanLee <shufan_lee@richtek.com>
> >
> > Handle vendor defined behavior in tcpci_init, tcpci_set_vconn and
> > export tcpci_irq.
> > More operations can be extended in tcpci_data if needed.
> > According to TCPCI specification, 4.4.5.2 ROLE_CONTROL, TCPC shall
> > not start DRP toggling until subsequently the TCPM writes to the
> > COMMAND register to start DRP toggling.
>
> My understanding of above statement is TCPM(this Linux driver) can
> enable DRP and CC1/CC2 in one shot, but TCPC(your typec chip internal
> firmware) needs wait until TCPM writes to COMMAND register to start drp toggling.
>
> > DRP toggling flow is chagned as following:
> >   - Write DRP = 0 & Rd/Rd
>
> Why fixed to be Rd/Rd? in this case, it means the starting value:
>
> Tcpci 4.4.5.2:
> "When initiating autonomous DRP toggling, the TCPM shall write B6
> (DRP) =1b and the starting value of Rp/Rd to B3..0 (CC1/CC2) to
> indicate DRP autonomous toggling mode to the TCPC."
>
> >   - Write DRP = 1
>
> What's your problem if combine above 2 in one shot?
>
> >   - Set LOOK4CONNECTION command
> >
> > Signed-off-by: ShuFanLee <shufan_lee@richtek.com>
> > ---
> >  drivers/staging/typec/tcpci.c | 128
> > +++++++++++++++++++++++++++++++++---------
> >  drivers/staging/typec/tcpci.h |  13 +++++
> >  2 files changed, 115 insertions(+), 26 deletions(-)
> >
> >  patch changelogs between v1 & v2
> >  - Remove unnecessary i2c_client in the structure of tcpci
> >  - Rename structure of tcpci_vendor_data to tcpci_data
> >  - Not exporting tcpci read/write wrappers but register i2c regmap
> > in glue driver
> >  - Add set_vconn ops in tcpci_data
> >    (It is necessary for RT1711H to enable/disable idle mode before
> > disabling/enabling vconn)
> >  - Export tcpci_irq so that vendor can call it in their own IRQ
> > handler
> >
> >  patch changelogs between v2 & v3
> >  - Change the return type of tcpci_irq from int to irqreturn_t
> >
> > diff --git a/drivers/staging/typec/tcpci.c
> > b/drivers/staging/typec/tcpci.c index 9bd4412..4959c69 100644
> > --- a/drivers/staging/typec/tcpci.c
> > +++ b/drivers/staging/typec/tcpci.c
> > @@ -21,7 +21,6 @@
> >
> >  struct tcpci {
> >       struct device *dev;
> > -     struct i2c_client *client;
> >
> >       struct tcpm_port *port;
> >
> > @@ -30,6 +29,12 @@ struct tcpci {
> >       bool controls_vbus;
> >
> >       struct tcpc_dev tcpc;
> > +     struct tcpci_data *data;
> > +};
> > +
> > +struct tcpci_chip {
> > +     struct tcpci *tcpci;
> > +     struct tcpci_data data;
> >  };
> >
> >  static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) @@
> > -37,8
> > +42,7 @@ static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev
> > +*tcpc)
> >       return container_of(tcpc, struct tcpci, tcpc);  }
> >
> > -static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
> > -                     u16 *val)
> > +static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, u16
> > +*val)
> >  {
> >       return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
> > } @@
> > -98,8 +102,10 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum
> > typec_cc_status cc)  static int tcpci_start_drp_toggling(struct
> > tcpc_dev *tcpc,
> >                                   enum typec_cc_status cc)  {
> > +     int ret;
> >       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> > -     unsigned int reg = TCPC_ROLE_CTRL_DRP;
> > +     unsigned int reg = (TCPC_ROLE_CTRL_CC_RD <<
> > TCPC_ROLE_CTRL_CC1_SHIFT) |
> > +                        (TCPC_ROLE_CTRL_CC_RD <<
> > TCPC_ROLE_CTRL_CC2_SHIFT);
> >
> >       switch (cc) {
> >       default:
> > @@ -117,7 +123,19 @@ static int tcpci_start_drp_toggling(struct
> > tcpc_dev *tcpc,
> >               break;
> >       }
> >
> > -     return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     if (ret < 0)
> > +             return ret;
> > +     usleep_range(500, 1000);
>
> Why need a wait here? It seems you actually don't want to do
> autonomously toggling from the very beginning, instead, you begin with
> a directly control on CC, keep it(Rd) for some time, then switch to
> use autonomously toggling, why you need such kind of sequence? I think
> it's special and not following tcpci spec.
>
> > +     reg |= TCPC_ROLE_CTRL_DRP;
> > +     ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +     if (ret < 0)
> > +             return ret;
> > +     ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
> > +                        TCPC_CMD_LOOK4CONNECTION);
> > +     if (ret < 0)
> > +             return ret;
> > +     return 0;
> >  }
> >
> >  static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool
> > sink) @@ -178,6 +196,16 @@ static int tcpci_set_vconn(struct
> > tcpc_dev *tcpc, bool enable)
> >       struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> >       int ret;
> >
> > +     /* Handle vendor set vconn */
> > +     if (tcpci->data) {
> > +             if (tcpci->data->set_vconn) {
> > +                     ret = tcpci->data->set_vconn(tcpci, tcpci->data,
> > +                                                  enable);
> > +                     if (ret < 0)
> > +                             return ret;
> > +             }
> > +     }
> > +
> >       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
> >                          enable ?
> TCPC_POWER_CTRL_VCONN_ENABLE : 0);
> >       if (ret < 0)
> > @@ -323,6 +351,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> >       if (time_after(jiffies, timeout))
> >               return -ETIMEDOUT;
> >
> > +     /* Handle vendor init */
> > +     if (tcpci->data) {
> > +             if (tcpci->data->init) {
> > +                     ret = tcpci->data->init(tcpci, tcpci->data);
> > +                     if (ret < 0)
> > +                             return ret;
> > +             }
> > +     }
> > +
> >       /* Clear all events */
> >       ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
> >       if (ret < 0)
> > @@ -344,9 +381,15 @@ static int tcpci_init(struct tcpc_dev *tcpc)
> >       return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);  }
> >
> > -static irqreturn_t tcpci_irq(int irq, void *dev_id)
> > +static irqreturn_t _tcpci_irq(int irq, void *dev_id)
> >  {
> >       struct tcpci *tcpci = dev_id;
> > +
> > +     return tcpci_irq(tcpci);
> > +}
> > +
> > +irqreturn_t tcpci_irq(struct tcpci *tcpci) {
> >       u16 status;
> >
> >       tcpci_read16(tcpci, TCPC_ALERT, &status); @@ -412,6 +455,7 @@
> > static irqreturn_t tcpci_irq(int irq, void *dev_id)
> >
> >       return IRQ_HANDLED;
> >  }
> > +EXPORT_SYMBOL_GPL(tcpci_irq);
>
> I don't catch the point of how you handle private events by above
> change, maybe post your RT1711H part as a user in one series can make
> it clear, I assume this can be done in existing tcpci_irq like above
> vender specific handling as well:
>       tcpci->data->priv_events(tcpci, tcpci->data);
>
> Li Jun
> >
> >  static const struct regmap_config tcpci_regmap_config = {
> >       .reg_bits = 8,
> > @@ -435,22 +479,18 @@ static int tcpci_parse_config(struct tcpci *tcpci)
> >       return 0;
> >  }
> >
> > -static int tcpci_probe(struct i2c_client *client,
> > -                    const struct i2c_device_id *i2c_id)
> > +struct tcpci *tcpci_register_port(struct device *dev, struct
> > +tcpci_data
> > +*data)
> >  {
> >       struct tcpci *tcpci;
> >       int err;
> >
> > -     tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
> > +     tcpci = devm_kzalloc(dev, sizeof(*tcpci), GFP_KERNEL);
> >       if (!tcpci)
> > -             return -ENOMEM;
> > +             return ERR_PTR(-ENOMEM);
> >
> > -     tcpci->client = client;
> > -     tcpci->dev = &client->dev;
> > -     i2c_set_clientdata(client, tcpci);
> > -     tcpci->regmap = devm_regmap_init_i2c(client,
> &tcpci_regmap_config);
> > -     if (IS_ERR(tcpci->regmap))
> > -             return PTR_ERR(tcpci->regmap);
> > +     tcpci->dev = dev;
> > +     tcpci->data = data;
> > +     tcpci->regmap = data->regmap;
> >
> >       tcpci->tcpc.init = tcpci_init;
> >       tcpci->tcpc.get_vbus = tcpci_get_vbus; @@ -467,27 +507,63 @@
> > static int tcpci_probe(struct i2c_client *client,
> >
> >       err = tcpci_parse_config(tcpci);
> >       if (err < 0)
> > -             return err;
> > +             return ERR_PTR(err);
> > +
> > +     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> > +     if (PTR_ERR_OR_ZERO(tcpci->port))
> > +             return ERR_CAST(tcpci->port);
> >
> > -     /* Disable chip interrupts */
> > -     tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
> > +     return tcpci;
> > +}
> > +EXPORT_SYMBOL_GPL(tcpci_register_port);
> > +
> > +void tcpci_unregister_port(struct tcpci *tcpci) {
> > +     tcpm_unregister_port(tcpci->port);
> > +}
> > +EXPORT_SYMBOL_GPL(tcpci_unregister_port);
> >
> > -     err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
> > -                                     tcpci_irq,
> > +static int tcpci_probe(struct i2c_client *client,
> > +                    const struct i2c_device_id *i2c_id) {
> > +     struct tcpci_chip *chip;
> > +     int err;
> > +     u16 val = 0;
> > +
> > +     chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
> > +     if (!chip)
> > +             return -ENOMEM;
> > +
> > +     chip->data.regmap = devm_regmap_init_i2c(client,
> > &tcpci_regmap_config);
> > +     if (IS_ERR(chip->data.regmap))
> > +             return PTR_ERR(chip->data.regmap);
> > +
> > +     /* Disable chip interrupts before requesting irq */
> > +     err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK,
> &val,
> > +                            sizeof(u16));
> > +     if (err < 0)
> > +             return err;
> > +
> > +     err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> > +                                     _tcpci_irq,
> >                                       IRQF_ONESHOT |
> IRQF_TRIGGER_LOW,
> > -                                     dev_name(tcpci->dev),
> tcpci);
> > +                                     dev_name(&client->dev),
> chip);
> >       if (err < 0)
> >               return err;
> >
> > -     tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
> > -     return PTR_ERR_OR_ZERO(tcpci->port);
> > +     chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
> > +     if (PTR_ERR_OR_ZERO(chip->tcpci))
> > +             return PTR_ERR(chip->tcpci);
> > +
> > +     i2c_set_clientdata(client, chip);
> > +     return 0;
> >  }
> >
> >  static int tcpci_remove(struct i2c_client *client)  {
> > -     struct tcpci *tcpci = i2c_get_clientdata(client);
> > +     struct tcpci_chip *chip = i2c_get_clientdata(client);
> >
> > -     tcpm_unregister_port(tcpci->port);
> > +     tcpci_unregister_port(chip->tcpci);
> >
> >       return 0;
> >  }
> > diff --git a/drivers/staging/typec/tcpci.h
> > b/drivers/staging/typec/tcpci.h index fdfb06c..40025b2 100644
> > --- a/drivers/staging/typec/tcpci.h
> > +++ b/drivers/staging/typec/tcpci.h
> > @@ -59,6 +59,7 @@
> >  #define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
> >
> >  #define TCPC_CC_STATUS                       0x1d
> > +#define TCPC_CC_STATUS_DRPRST                BIT(5)
> >  #define TCPC_CC_STATUS_TERM          BIT(4)
> >  #define TCPC_CC_STATUS_CC2_SHIFT     2
> >  #define TCPC_CC_STATUS_CC2_MASK              0x3
> > @@ -121,4 +122,16 @@
> >  #define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG               0x76
> >  #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG               0x78
> >
> > +struct tcpci;
> > +struct tcpci_data {
> > +     struct regmap *regmap;
> > +     int (*init)(struct tcpci *tcpci, struct tcpci_data *data);
> > +     int (*set_vconn)(struct tcpci *tcpci, struct tcpci_data *data,
> > +                      bool enable); };
> > +
> > +struct tcpci *tcpci_register_port(struct device *dev, struct
> > +tcpci_data *data); void tcpci_unregister_port(struct tcpci *tcpci);
> > +irqreturn_t tcpci_irq(struct tcpci *tcpci);
> > +
> >  #endif /* __LINUX_USB_TCPCI_H */
> > --
> > 1.9.1
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-usb"
> > in the body of a message to majordomo@vger.kernel.org More
> majordomo
> > info at
> >
> https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fvger
> > .kernel.org%2Fmajordomo-info.html&data=02%7C01%7Cjun.li%40nxp.co
> m
> > %7C44d11af27e0244fa4d1108d5793c3dc4%7C686ea1d3bc2b4c6fa92cd99
> c
> >
> 5c301635%7C0%7C1%7C636548222008905206&sdata=zn2ougKRvs%2BbmH
> > Qg2c8Rjj7vNe0ZiiVKdar7GdPa%2B3o%3D&reserved=0
> ************* Email Confidentiality Notice ********************
>
> The information contained in this e-mail message (including any
> attachments) may be confidential, proprietary, privileged, or
> otherwise exempt from disclosure under applicable laws. It is intended
> to be conveyed only to the designated recipient(s). Any use,
> dissemination, distribution, printing, retaining or copying of this
> e-mail (including its attachments) by unintended
> recipient(s) is strictly prohibited and may be unlawful. If you are
> not an intended recipient of this e-mail, or believe that you have
> received this e-mail in error, please notify the sender immediately
> (by replying to this e-mail), delete any and all copies of this e-mail
> (including any attachments) from your system, and do not disclose the
> content of this e-mail to any other person. Thank you!
************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

[-- Attachment #2: rt1711h_Rd_plug_test.png --]
[-- Type: image/png, Size: 122951 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-01 10:06           ` Jun Li
  0 siblings, 0 replies; 22+ messages in thread
From: Jun Li @ 2018-03-01 10:06 UTC (permalink / raw)
  To: shufan_lee(李書帆),
	ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi Shufan

Please don't top posting

> -----Original Message-----
> From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> Sent: 2018年3月1日 16:49
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify
> drp toggling flow
> 
> Hi Jun,
> 
>   The attachment is waveform of the condition we met but I'm not sure
> whether you can download the attachment.
>   I add log in RT1711H it shows as following:

You don't need add log by your own.
There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can
show all the events and state transitions, you can get it by below command
as I commented:

cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)

> [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [ 914.943838]
> typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 = Open => Device(Rd)
> is plugged out
> 
> [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
> typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407] typec_rt1711h
> 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h 2-004e:
> tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
> tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
> typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
> typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
> typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work of
> TCPM calls start_drp_toggling function but does not set
> LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
> (RT1711H's internal firmware detects Rd plugged in. cc_change is triggered
> and it will be vRd-connected at this moment) => TCPM writes
> LOOK4CONNECTION command
> - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while writing
> Rd/Rd to RC.CC1/RC.CC2.
> - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
> pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling (because
> device(Rd) is already connected) and CC status will be open/open now
> (because RT1711H presents Rd and device is connected(Rd))
> 
> [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> Open => Enter RT1711H's irq handler and it reports open/open
> 
> I think the point is to write RC.DRP = 0 at the beginning of drp_toggling so
> that RT1711H will pull cc1/cc2 to Rd while writing Rd/Rd to RC.CC1/RC.CC2
> This operation will make RT1711H's internal firmware restarts from
> disconnected state and toggles correctly.
> 
> According to TCPCI spec (4.4.5.2):
> It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
> POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> using COMMAND.Look4Connection Restart DRP Toggling => It is
> recommended the TCPM write ROLE_CONTROL.DRP=0 here Set

This statement is_not_ recommend you do this(RC.DRP=0) for start drp toggling,
Please carefully check the whole sentence:
"... as shown in Figure 4-16, "
If you look at "Figure 4-16. DRP Initialization and Connection Detection"
It gives clear drp toggling start operations:

Set TCPC to DRP
- Read PS.TCPCInitializationStatus
- Write ROLE_CONTROL
- RC.DRP = 1b
- RC.CC2=01b or 10b
- RC.CC1=01b or 10b
- RC.CC1=RC.CC2
- Write COMMAND.Look4ConnectionPS.

Above is all operations required to start drp toggling. You also
can see RC.CCx = 01b or 10b, not fixed to be Rd, right?

Go on to check the Figure 4-16 
After debounce, we need do following:

ConnectionDetermine CC & VCONN
- Write RC.CC1 & RC.CC2 per decision
- Write RC.DRP=0
- Write TCPC_CONTROl.PlugOrientation
- Write PC.AutoDischargeDisconnect=1
 & PC.EnableVconnConnection

Current existing tcpm+tcpci will not clear RC.DRP after attach,
That means RC.DRP clear may be done after attach, not in start_drp_toggling.
I am not sure if this can resolve your problem, but I think it deserve
a try, you can follow above operation sequence while entering
attach state, refer to my patch[2]:

[2] https://www.spinics.net/lists/devicetree/msg216852.html

diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
index 530a5d7..7145771 100644
--- a/drivers/staging/typec/tcpci.c
+++ b/drivers/staging/typec/tcpci.c
@@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
                              enum typec_cc_polarity polarity)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       unsigned int reg;
        int ret;

        ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
@@ -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
        if (ret < 0)
                return ret;

+       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
+       if (ret < 0)
+               return ret;
+
+       if (polarity == TYPEC_POLARITY_CC2)
+               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
+       else
+               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
+       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
+       reg &= ~TCPC_ROLE_CTRL_DRP;
+       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }

> PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
> (smallest Rp to save power) Set RC.CC1=01b Set
> RC.CC2=01bCOMMAND.Look4ConnectionNo
> 
> It seems like it is not a general case here (because it is only recommended
> but not necessary), we can move it to vendor_ops in the next patch.

The TCPM should be able to cover all cases, and we should follow
the recommended sequence(if what you are trying to do is really
as spec says).
 
> 
> For your question:
> Why RT1711H reports open/open after drp_toggling is enabled?
> => See Note2 above.
> This open/open is for you plug out the device, right?
> => No, see Note2 above.
> Why RT1711H can't report new cc change events after you plug in the
> device?
> => RT1711H can generate new cc change events after plugging in the device.
> What cc change event tcpc will report on step 4?
> => See Note1 above
> Did you verify your change can pass the typec compliance test?
> => We didn't test it yet but try to make all functions work correctly first.
> 
> Best Regards,
> *****************************
> Shu-Fan Lee
> Richtek Technology Corporation
> TEL: +886-3-5526789 #2359
> FAX: +886-3-5526612
> *****************************
> 

^ permalink raw reply related	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-01 10:06           ` Jun Li
  0 siblings, 0 replies; 22+ messages in thread
From: Jun Li @ 2018-03-01 10:06 UTC (permalink / raw)
  To: shufan_lee(李書帆),
	ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi Shufan

Please don't top posting

> -----Original Message-----
> From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> Sent: 2018年3月1日 16:49
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify
> drp toggling flow
> 
> Hi Jun,
> 
>   The attachment is waveform of the condition we met but I'm not sure
> whether you can download the attachment.
>   I add log in RT1711H it shows as following:

You don't need add log by your own.
There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can
show all the events and state transitions, you can get it by below command
as I commented:

cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)

> [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [ 914.943838]
> typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 = Open => Device(Rd)
> is plugged out
> 
> [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
> typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407] typec_rt1711h
> 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h 2-004e:
> tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
> tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
> typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
> typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
> typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work of
> TCPM calls start_drp_toggling function but does not set
> LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
> (RT1711H's internal firmware detects Rd plugged in. cc_change is triggered
> and it will be vRd-connected at this moment) => TCPM writes
> LOOK4CONNECTION command
> - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while writing
> Rd/Rd to RC.CC1/RC.CC2.
> - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
> pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling (because
> device(Rd) is already connected) and CC status will be open/open now
> (because RT1711H presents Rd and device is connected(Rd))
> 
> [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> Open => Enter RT1711H's irq handler and it reports open/open
> 
> I think the point is to write RC.DRP = 0 at the beginning of drp_toggling so
> that RT1711H will pull cc1/cc2 to Rd while writing Rd/Rd to RC.CC1/RC.CC2
> This operation will make RT1711H's internal firmware restarts from
> disconnected state and toggles correctly.
> 
> According to TCPCI spec (4.4.5.2):
> It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
> POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> using COMMAND.Look4Connection Restart DRP Toggling => It is
> recommended the TCPM write ROLE_CONTROL.DRP=0 here Set

This statement is_not_ recommend you do this(RC.DRP=0) for start drp toggling,
Please carefully check the whole sentence:
"... as shown in Figure 4-16, "
If you look at "Figure 4-16. DRP Initialization and Connection Detection"
It gives clear drp toggling start operations:

Set TCPC to DRP
- Read PS.TCPCInitializationStatus
- Write ROLE_CONTROL
- RC.DRP = 1b
- RC.CC2=01b or 10b
- RC.CC1=01b or 10b
- RC.CC1=RC.CC2
- Write COMMAND.Look4ConnectionPS.

Above is all operations required to start drp toggling. You also
can see RC.CCx = 01b or 10b, not fixed to be Rd, right?

Go on to check the Figure 4-16 
After debounce, we need do following:

ConnectionDetermine CC & VCONN
- Write RC.CC1 & RC.CC2 per decision
- Write RC.DRP=0
- Write TCPC_CONTROl.PlugOrientation
- Write PC.AutoDischargeDisconnect=1
 & PC.EnableVconnConnection

Current existing tcpm+tcpci will not clear RC.DRP after attach,
That means RC.DRP clear may be done after attach, not in start_drp_toggling.
I am not sure if this can resolve your problem, but I think it deserve
a try, you can follow above operation sequence while entering
attach state, refer to my patch[2]:

[2] https://www.spinics.net/lists/devicetree/msg216852.html

> PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
> (smallest Rp to save power) Set RC.CC1=01b Set
> RC.CC2=01bCOMMAND.Look4ConnectionNo
> 
> It seems like it is not a general case here (because it is only recommended
> but not necessary), we can move it to vendor_ops in the next patch.

The TCPM should be able to cover all cases, and we should follow
the recommended sequence(if what you are trying to do is really
as spec says).
 
> 
> For your question:
> Why RT1711H reports open/open after drp_toggling is enabled?
> => See Note2 above.
> This open/open is for you plug out the device, right?
> => No, see Note2 above.
> Why RT1711H can't report new cc change events after you plug in the
> device?
> => RT1711H can generate new cc change events after plugging in the device.
> What cc change event tcpc will report on step 4?
> => See Note1 above
> Did you verify your change can pass the typec compliance test?
> => We didn't test it yet but try to make all functions work correctly first.
> 
> Best Regards,
> *****************************
> Shu-Fan Lee
> Richtek Technology Corporation
> TEL: +886-3-5526789 #2359
> FAX: +886-3-5526612
> *****************************
>

diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c
index 530a5d7..7145771 100644
--- a/drivers/staging/typec/tcpci.c
+++ b/drivers/staging/typec/tcpci.c
@@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
                              enum typec_cc_polarity polarity)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       unsigned int reg;
        int ret;

        ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
@@ -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
        if (ret < 0)
                return ret;

+       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
+       if (ret < 0)
+               return ret;
+
+       if (polarity == TYPEC_POLARITY_CC2)
+               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
+       else
+               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
+       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
+       reg &= ~TCPC_ROLE_CTRL_DRP;
+       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-01 11:53             ` shufan_lee(李書帆)
  0 siblings, 0 replies; 22+ messages in thread
From: shufan_lee(李書帆) @ 2018-03-01 11:53 UTC (permalink / raw)
  To: 'Jun Li', ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi Jun,

> -----Original Message-----
> From: Jun Li [mailto:jun.li@nxp.com]
> Sent: Thursday, March 01, 2018 6:06 PM
> To: shufan_lee(李書帆); ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
>
> Hi Shufan
>
> Please don't top posting
>
> -----Original Message-----
> From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> Sent: 2018年3月1日 16:49
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> modify drp toggling flow
>
> Hi Jun,
>
>   The attachment is waveform of the condition we met but I'm not sure
> whether you can download the attachment.
>   I add log in RT1711H it shows as following:
>
> You don't need add log by your own.
> There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can show all the events and state transitions, you can get it by below command as I commented:
>
> cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)
>
After applying your patch[2], TCPM log is as following:

[   53.050602] CC1: 0 -> 2, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0, connected]
[   53.050613] state change DRP_TOGGLING -> SRC_ATTACH_WAIT
[   53.050678] pending state change SRC_ATTACH_WAIT -> SNK_TRY @ 200 ms
=> Rd is plugged out
[   53.178804] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_ATTACH_WAIT, polarity 0, disconnected]
[   53.178815] state change SRC_ATTACH_WAIT -> SRC_UNATTACHED
=> Rd is plugged in
[   53.178874] Start DRP toggling
[   53.188472] CC1: 0 -> 0, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0, disconnected]

If TCPM does not enter SRC_ATTACHED state, RC.DRP will not be cleared.
When TCPM writes Rd/Rd or Rp/Rp in the drp_toggling function, it does not take effect until LOOK4CONNECTION command is set.
The above condition causes RT1711H reports open/open at [53.188472]

> [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [
> 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 = Open
> => Device(Rd) is plugged out
>
> [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
> typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407]
> typec_rt1711h
> 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h 2-004e:
> tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
> tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
> typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
> typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
> typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work of
> TCPM calls start_drp_toggling function but does not set
> LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
> (RT1711H's internal firmware detects Rd plugged in. cc_change is
> triggered and it will be vRd-connected at this moment) => TCPM writes
> LOOK4CONNECTION command
> - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while
> writing Rd/Rd to RC.CC1/RC.CC2.
> - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
> pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling
> (because
> device(Rd) is already connected) and CC status will be open/open now
> (because RT1711H presents Rd and device is connected(Rd))
>
> [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> Open => Enter RT1711H's irq handler and it reports open/open
>
> I think the point is to write RC.DRP = 0 at the beginning of
> drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing
> Rd/Rd to RC.CC1/RC.CC2 This operation will make RT1711H's internal
> firmware restarts from disconnected state and toggles correctly.
>
> According to TCPCI spec (4.4.5.2):
> It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
> POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> using COMMAND.Look4Connection Restart DRP Toggling => It is
> recommended the TCPM write ROLE_CONTROL.DRP=0 here Set
>
> This statement is_not_ recommend you do this(RC.DRP=0) for start drp toggling, Please carefully check the whole sentence:
> "... as shown in Figure 4-16, "
> If you look at "Figure 4-16. DRP Initialization and Connection Detection"
> It gives clear drp toggling start operations:
>
> Set TCPC to DRP
> - Read PS.TCPCInitializationStatus
> - Write ROLE_CONTROL
> - RC.DRP = 1b
> - RC.CC2=01b or 10b
> - RC.CC1=01b or 10b
> - RC.CC1=RC.CC2
> - Write COMMAND.Look4ConnectionPS.
>
> Above is all operations required to start drp toggling. You also can see RC.CCx = 01b or 10b, not fixed to be Rd, right?
Yes, this one should be like your patch[07/12]. Write Rd or Rp to RC.CCx according to the cc parameter of drp_toggling function.
>
> Go on to check the Figure 4-16
> After debounce, we need do following:
>
> ConnectionDetermine CC & VCONN
> - Write RC.CC1 & RC.CC2 per decision
> - Write RC.DRP=0
> - Write TCPC_CONTROl.PlugOrientation
> - Write PC.AutoDischargeDisconnect=1
>  & PC.EnableVconnConnection
>
> Current existing tcpm+tcpci will not clear RC.DRP after attach, That means RC.DRP clear may be done after attach, not in start_drp_toggling.
> I am not sure if this can resolve your problem, but I think it deserve a try, you can follow above operation sequence while entering attach state, refer to my patch[2]:
>
> [2] https://www.spinics.net/lists/devicetree/msg216852.html
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 530a5d7..7145771 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>                               enum typec_cc_polarity polarity)  {
>         struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> +       unsigned int reg;
>         int ret;
>
>         ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, @@ -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>         if (ret < 0)
>                 return ret;
>
> +       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (polarity == TYPEC_POLARITY_CC2)
> +               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
> +       else
> +               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
> +       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
> +       reg &= ~TCPC_ROLE_CTRL_DRP;
> +       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +       if (ret < 0)
> +               return ret;
> +
>         return 0;
>  }
>
> PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
> (smallest Rp to save power) Set RC.CC1=01b Set
> RC.CC2=01bCOMMAND.Look4ConnectionNo
>
> It seems like it is not a general case here (because it is only
> recommended but not necessary), we can move it to vendor_ops in the next patch.
>
> The TCPM should be able to cover all cases, and we should follow the recommended sequence(if what you are trying to do is really as spec says).
Agree!
My understanding is that we need to set RC.DRP to 0 every time before TCPM restarts toggling but not just for attached.
For RT1711H, it follows above flow. If it is not correct, this operation should be moved to vendor_ops.
>
> For your question:
> Why RT1711H reports open/open after drp_toggling is enabled?
> => See Note2 above.
> This open/open is for you plug out the device, right?
> => No, see Note2 above.
> Why RT1711H can't report new cc change events after you plug in the
> device?
> => RT1711H can generate new cc change events after plugging in the device.
> What cc change event tcpc will report on step 4?
> => See Note1 above
> Did you verify your change can pass the typec compliance test?
> => We didn't test it yet but try to make all functions work correctly first.
>
> Best Regards,
> *****************************
> Shu-Fan Lee
> Richtek Technology Corporation
> TEL: +886-3-5526789 #2359
> FAX: +886-3-5526612
> *****************************
>

************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-01 11:53             ` shufan_lee(李書帆)
  0 siblings, 0 replies; 22+ messages in thread
From: shufan_lee(李書帆) @ 2018-03-01 11:53 UTC (permalink / raw)
  To: 'Jun Li', ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi Jun,

> -----Original Message-----
> From: Jun Li [mailto:jun.li@nxp.com]
> Sent: Thursday, March 01, 2018 6:06 PM
> To: shufan_lee(李書帆); ShuFanLee; heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原); linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
>
> Hi Shufan
>
> Please don't top posting
>
> -----Original Message-----
> From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> Sent: 2018年3月1日 16:49
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> modify drp toggling flow
>
> Hi Jun,
>
>   The attachment is waveform of the condition we met but I'm not sure
> whether you can download the attachment.
>   I add log in RT1711H it shows as following:
>
> You don't need add log by your own.
> There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can show all the events and state transitions, you can get it by below command as I commented:
>
> cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)
>
After applying your patch[2], TCPM log is as following:

[   53.050602] CC1: 0 -> 2, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0, connected]
[   53.050613] state change DRP_TOGGLING -> SRC_ATTACH_WAIT
[   53.050678] pending state change SRC_ATTACH_WAIT -> SNK_TRY @ 200 ms
=> Rd is plugged out
[   53.178804] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_ATTACH_WAIT, polarity 0, disconnected]
[   53.178815] state change SRC_ATTACH_WAIT -> SRC_UNATTACHED
=> Rd is plugged in
[   53.178874] Start DRP toggling
[   53.188472] CC1: 0 -> 0, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0, disconnected]

If TCPM does not enter SRC_ATTACHED state, RC.DRP will not be cleared.
When TCPM writes Rd/Rd or Rp/Rp in the drp_toggling function, it does not take effect until LOOK4CONNECTION command is set.
The above condition causes RT1711H reports open/open at [53.188472]

> [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [
> 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 = Open
> => Device(Rd) is plugged out
>
> [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
> typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407]
> typec_rt1711h
> 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h 2-004e:
> tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
> tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
> typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
> typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
> typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work of
> TCPM calls start_drp_toggling function but does not set
> LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
> (RT1711H's internal firmware detects Rd plugged in. cc_change is
> triggered and it will be vRd-connected at this moment) => TCPM writes
> LOOK4CONNECTION command
> - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while
> writing Rd/Rd to RC.CC1/RC.CC2.
> - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
> pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling
> (because
> device(Rd) is already connected) and CC status will be open/open now
> (because RT1711H presents Rd and device is connected(Rd))
>
> [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> Open => Enter RT1711H's irq handler and it reports open/open
>
> I think the point is to write RC.DRP = 0 at the beginning of
> drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing
> Rd/Rd to RC.CC1/RC.CC2 This operation will make RT1711H's internal
> firmware restarts from disconnected state and toggles correctly.
>
> According to TCPCI spec (4.4.5.2):
> It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing to
> POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> using COMMAND.Look4Connection Restart DRP Toggling => It is
> recommended the TCPM write ROLE_CONTROL.DRP=0 here Set
>
> This statement is_not_ recommend you do this(RC.DRP=0) for start drp toggling, Please carefully check the whole sentence:
> "... as shown in Figure 4-16, "
> If you look at "Figure 4-16. DRP Initialization and Connection Detection"
> It gives clear drp toggling start operations:
>
> Set TCPC to DRP
> - Read PS.TCPCInitializationStatus
> - Write ROLE_CONTROL
> - RC.DRP = 1b
> - RC.CC2=01b or 10b
> - RC.CC1=01b or 10b
> - RC.CC1=RC.CC2
> - Write COMMAND.Look4ConnectionPS.
>
> Above is all operations required to start drp toggling. You also can see RC.CCx = 01b or 10b, not fixed to be Rd, right?
Yes, this one should be like your patch[07/12]. Write Rd or Rp to RC.CCx according to the cc parameter of drp_toggling function.
>
> Go on to check the Figure 4-16
> After debounce, we need do following:
>
> ConnectionDetermine CC & VCONN
> - Write RC.CC1 & RC.CC2 per decision
> - Write RC.DRP=0
> - Write TCPC_CONTROl.PlugOrientation
> - Write PC.AutoDischargeDisconnect=1
>  & PC.EnableVconnConnection
>
> Current existing tcpm+tcpci will not clear RC.DRP after attach, That means RC.DRP clear may be done after attach, not in start_drp_toggling.
> I am not sure if this can resolve your problem, but I think it deserve a try, you can follow above operation sequence while entering attach state, refer to my patch[2]:
>
> [2] https://www.spinics.net/lists/devicetree/msg216852.html
>
> diff --git a/drivers/staging/typec/tcpci.c b/drivers/staging/typec/tcpci.c index 530a5d7..7145771 100644
> --- a/drivers/staging/typec/tcpci.c
> +++ b/drivers/staging/typec/tcpci.c
> @@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>                               enum typec_cc_polarity polarity)  {
>         struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> +       unsigned int reg;
>         int ret;
>
>         ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, @@ -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>         if (ret < 0)
>                 return ret;
>
> +       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
> +       if (ret < 0)
> +               return ret;
> +
> +       if (polarity == TYPEC_POLARITY_CC2)
> +               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
> +       else
> +               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
> +       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
> +       reg &= ~TCPC_ROLE_CTRL_DRP;
> +       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> +       if (ret < 0)
> +               return ret;
> +
>         return 0;
>  }
>
> PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
> (smallest Rp to save power) Set RC.CC1=01b Set
> RC.CC2=01bCOMMAND.Look4ConnectionNo
>
> It seems like it is not a general case here (because it is only
> recommended but not necessary), we can move it to vendor_ops in the next patch.
>
> The TCPM should be able to cover all cases, and we should follow the recommended sequence(if what you are trying to do is really as spec says).
Agree!
My understanding is that we need to set RC.DRP to 0 every time before TCPM restarts toggling but not just for attached.
For RT1711H, it follows above flow. If it is not correct, this operation should be moved to vendor_ops.
>
> For your question:
> Why RT1711H reports open/open after drp_toggling is enabled?
> => See Note2 above.
> This open/open is for you plug out the device, right?
> => No, see Note2 above.
> Why RT1711H can't report new cc change events after you plug in the
> device?
> => RT1711H can generate new cc change events after plugging in the device.
> What cc change event tcpc will report on step 4?
> => See Note1 above
> Did you verify your change can pass the typec compliance test?
> => We didn't test it yet but try to make all functions work correctly first.
>
> Best Regards,
> *****************************
> Shu-Fan Lee
> Richtek Technology Corporation
> TEL: +886-3-5526789 #2359
> FAX: +886-3-5526612
> *****************************
>

************* Email Confidentiality Notice ********************

The information contained in this e-mail message (including any attachments) may be confidential, proprietary, privileged, or otherwise exempt from disclosure under applicable laws. It is intended to be conveyed only to the designated recipient(s). Any use, dissemination, distribution, printing, retaining or copying of this e-mail (including its attachments) by unintended recipient(s) is strictly prohibited and may be unlawful. If you are not an intended recipient of this e-mail, or believe that you have received this e-mail in error, please notify the sender immediately (by replying to this e-mail), delete any and all copies of this e-mail (including any attachments) from your system, and do not disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* RE: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-02 14:38               ` Jun Li
  0 siblings, 0 replies; 22+ messages in thread
From: Jun Li @ 2018-03-02 14:38 UTC (permalink / raw)
  To: shufan_lee(李書帆),
	ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi
> -----Original Message-----
> From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> Sent: 2018年3月1日 19:54
> To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> <linux-imx@nxp.com>
> Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify
> drp toggling flow
> 
> Hi Jun,
> 
> > -----Original Message-----
> > From: Jun Li [mailto:jun.li@nxp.com]
> > Sent: Thursday, March 01, 2018 6:06 PM
> > To: shufan_lee(李書帆); ShuFanLee; heikki.krogerus@linux.intel.com;
> > linux@roeck-us.net; greg@kroah.com
> > Cc: cy_huang(黃啟原); linux-kernel@vger.kernel.org;
> > linux-usb@vger.kernel.org; dl-linux-imx
> > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> > modify drp toggling flow
> >
> > Hi Shufan
> >
> > Please don't top posting
> >
> > -----Original Message-----
> > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> > Sent: 2018年3月1日 16:49
> > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> > <linux-imx@nxp.com>
> > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> > modify drp toggling flow
> >
> > Hi Jun,
> >
> >   The attachment is waveform of the condition we met but I'm not sure
> > whether you can download the attachment.
> >   I add log in RT1711H it shows as following:
> >
> > You don't need add log by your own.
> > There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can
> show all the events and state transitions, you can get it by below command
> as I commented:
> >
> > cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)
> >
> After applying your patch[2], TCPM log is as following:

I assume you also applied my patch [1].
[1] https://www.spinics.net/lists/devicetree/msg216851.html

> 
> [   53.050602] CC1: 0 -> 2, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
> connected]
> [   53.050613] state change DRP_TOGGLING -> SRC_ATTACH_WAIT
> [   53.050678] pending state change SRC_ATTACH_WAIT -> SNK_TRY @
> 200 ms
> => Rd is plugged out
> [   53.178804] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_ATTACH_WAIT, polarity 0,
> disconnected]
> [   53.178815] state change SRC_ATTACH_WAIT -> SRC_UNATTACHED
> => Rd is plugged in
> [   53.178874] Start DRP toggling
> [   53.188472] CC1: 0 -> 0, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
> disconnected]

1. The plug out and then plug in happens in 10ms? (53.188472 - 53.178804)
Was this done manually? Or by some special test method?
2. This is all tcpm log if you finally keep the Rd-device connected on typec
port? There is no more tcpm log after 53.188472 if you plug in Rd-device
and don't remove it? 
3. If the answer of Q2 is yes, then I must ask why you tcpc chip+internal firmware
can't report further cc change event after your drp toggling starts to present Rp(I know
it firstly present Rd after you write to LOOK4CONNECTION, but then it should change
to present Rp, so it should be able to detect the Rd-device finally)

> 
> If TCPM does not enter SRC_ATTACHED state, RC.DRP will not be cleared.

In this case, you don’t need clear RC.DRP, see TCPCI spec:
"Figure 4-18. Sink Disconnect"
TCPM sink doesn't clear it in whole sequence, just directly set it:
Restart DRP Toggling
PC.AutoDischargeDisconnect=0b
Set RC.DRP=1b (DRP)
Set RC.CC1=10b (Rd)
Set RC.CC2=10b (Rd)
COMMAND.Look4Connection (DRP toggle)

> When TCPM writes Rd/Rd or Rp/Rp in the drp_toggling function, it does not
> take effect until LOOK4CONNECTION command is set.
> The above condition causes RT1711H reports open/open at [53.188472]
> 
> > [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [
> > 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> Open
> > => Device(Rd) is plugged out
> >
> > [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
> > typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407]
> > typec_rt1711h
> > 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h
> 2-004e:
> > tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
> > tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
> > typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
> > typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
> > typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work
> of
> > TCPM calls start_drp_toggling function but does not set
> > LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
> > (RT1711H's internal firmware detects Rd plugged in. cc_change is
> > triggered and it will be vRd-connected at this moment) => TCPM writes
> > LOOK4CONNECTION command
> > - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while
> > writing Rd/Rd to RC.CC1/RC.CC2.
> > - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
> > pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling
> > (because
> > device(Rd) is already connected) and CC status will be open/open now
> > (because RT1711H presents Rd and device is connected(Rd))
> >
> > [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> > Open => Enter RT1711H's irq handler and it reports open/open
> >
> > I think the point is to write RC.DRP = 0 at the beginning of
> > drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing
> > Rd/Rd to RC.CC1/RC.CC2 This operation will make RT1711H's internal
> > firmware restarts from disconnected state and toggles correctly.
> >
> > According to TCPCI spec (4.4.5.2):
> > It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing
> to
> > POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> > using COMMAND.Look4Connection Restart DRP Toggling => It is
> > recommended the TCPM write ROLE_CONTROL.DRP=0 here Set
> >
> > This statement is_not_ recommend you do this(RC.DRP=0) for start drp
> toggling, Please carefully check the whole sentence:
> > "... as shown in Figure 4-16, "
> > If you look at "Figure 4-16. DRP Initialization and Connection Detection"
> > It gives clear drp toggling start operations:
> >
> > Set TCPC to DRP
> > - Read PS.TCPCInitializationStatus
> > - Write ROLE_CONTROL
> > - RC.DRP = 1b
> > - RC.CC2=01b or 10b
> > - RC.CC1=01b or 10b
> > - RC.CC1=RC.CC2
> > - Write COMMAND.Look4ConnectionPS.
> >
> > Above is all operations required to start drp toggling. You also can see
> RC.CCx = 01b or 10b, not fixed to be Rd, right?
> Yes, this one should be like your patch[07/12]. Write Rd or Rp to RC.CCx
> according to the cc parameter of drp_toggling function.
> >
> > Go on to check the Figure 4-16
> > After debounce, we need do following:
> >
> > ConnectionDetermine CC & VCONN
> > - Write RC.CC1 & RC.CC2 per decision
> > - Write RC.DRP=0
> > - Write TCPC_CONTROl.PlugOrientation
> > - Write PC.AutoDischargeDisconnect=1
> >  & PC.EnableVconnConnection
> >
> > Current existing tcpm+tcpci will not clear RC.DRP after attach, That means
> RC.DRP clear may be done after attach, not in start_drp_toggling.
> > I am not sure if this can resolve your problem, but I think it deserve a try,
> you can follow above operation sequence while entering attach state, refer
> to my patch[2]:
> >
> > [2]
> >
> https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fw
> ww
> > .spinics.net%2Flists%2Fdevicetree%2Fmsg216852.html&data=02%7C01%7
> Cjun.
> >
> li%40nxp.com%7C9117425550d24ddc86d808d57f6b1b4e%7C686ea1d3bc2b
> 4c6fa92c
> >
> d99c5c301635%7C0%7C0%7C636555020366483456&sdata=9%2BywYl%2BR
> PYtk60Wg6p
> > R63cCW2AnRXs%2BrINvvqUpqL18%3D&reserved=0
> >
> > diff --git a/drivers/staging/typec/tcpci.c
> > b/drivers/staging/typec/tcpci.c index 530a5d7..7145771 100644
> > --- a/drivers/staging/typec/tcpci.c
> > +++ b/drivers/staging/typec/tcpci.c
> > @@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
> >                               enum typec_cc_polarity polarity)  {
> >         struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> > +       unsigned int reg;
> >         int ret;
> >
> >         ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, @@
> -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
> >         if (ret < 0)
> >                 return ret;
> >
> > +       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
> > +       if (ret < 0)
> > +               return ret;
> > +
> > +       if (polarity == TYPEC_POLARITY_CC2)
> > +               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
> > +       else
> > +               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
> > +       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
> > +       reg &= ~TCPC_ROLE_CTRL_DRP;
> > +       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > +       if (ret < 0)
> > +               return ret;
> > +
> >         return 0;
> >  }
> >
> > PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
> > (smallest Rp to save power) Set RC.CC1=01b Set
> > RC.CC2=01bCOMMAND.Look4ConnectionNo
> >
> > It seems like it is not a general case here (because it is only
> > recommended but not necessary), we can move it to vendor_ops in the
> next patch.
> >
> > The TCPM should be able to cover all cases, and we should follow the
> recommended sequence(if what you are trying to do is really as spec says).
> Agree!
> My understanding is that we need to set RC.DRP to 0 every time before
> TCPM restarts toggling but not just for attached.

Actually I have no objection on adding a RC.DRP clear, the question is
where is the right place to do this, till now I don’t see how this DRP bit keep set
while start drp toggling is causing problem, You want to start present Rd after write
CC1/CC2 to be Rd/Rd and before write to LOOK4CONNECTION, this is not required
per tcpci spec.

-Behavior after your patch:
//begin with Open as RC.DRP = 1
RC.CCx=Rd & RC.DRP = 0; //Start present Rd
Wait 1ms; // Still Rd
RC.CCx=Rd & RC.DRP = 1; //Open?
Look4CONNECTION = 1; //DRP toggling continue preset Rd

Is my above CC state description correct? Is this what you want?

-Only apply my patches:
//begin with Open as RC.DRP = 1
RC.CCx=Rd & RC.DRP = 1; //still Open
Look4Connection = 1; //Start preset Rd

> For RT1711H, it follows above flow. If it is not correct, this operation should
> be moved to vendor_ops.
> >
> > For your question:
> > Why RT1711H reports open/open after drp_toggling is enabled?
> > => See Note2 above.
> > This open/open is for you plug out the device, right?
> > => No, see Note2 above.
> > Why RT1711H can't report new cc change events after you plug in the
> > device?
> > => RT1711H can generate new cc change events after plugging in the
> device.
> > What cc change event tcpc will report on step 4?
> > => See Note1 above
> > Did you verify your change can pass the typec compliance test?
> > => We didn't test it yet but try to make all functions work correctly first.
> >
> > Best Regards,
> > *****************************
> > Shu-Fan Lee
> > Richtek Technology Corporation
> > TEL: +886-3-5526789 #2359
> > FAX: +886-3-5526612
> > *****************************
> >
> 
> ************* Email Confidentiality Notice ********************
> 
> The information contained in this e-mail message (including any attachments)
> may be confidential, proprietary, privileged, or otherwise exempt from
> disclosure under applicable laws. It is intended to be conveyed only to the
> designated recipient(s). Any use, dissemination, distribution, printing,
> retaining or copying of this e-mail (including its attachments) by unintended
> recipient(s) is strictly prohibited and may be unlawful. If you are not an
> intended recipient of this e-mail, or believe that you have received this
> e-mail in error, please notify the sender immediately (by replying to this
> e-mail), delete any and all copies of this e-mail (including any attachments)
> from your system, and do not disclose the content of this e-mail to any other
> person. Thank you!

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-02 14:38               ` Jun Li
  0 siblings, 0 replies; 22+ messages in thread
From: Jun Li @ 2018-03-02 14:38 UTC (permalink / raw)
  To: shufan_lee(李書帆),
	ShuFanLee, heikki.krogerus, linux, greg
  Cc: cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

SGkNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogc2h1ZmFuX2xlZSjmnY7m
m7jluIYpIFttYWlsdG86c2h1ZmFuX2xlZUByaWNodGVrLmNvbV0NCj4gU2VudDogMjAxOOW5tDPm
nIgx5pelIDE5OjU0DQo+IFRvOiBKdW4gTGkgPGp1bi5saUBueHAuY29tPjsgU2h1RmFuTGVlIDxs
ZWVjaHU3MjlAZ21haWwuY29tPjsNCj4gaGVpa2tpLmtyb2dlcnVzQGxpbnV4LmludGVsLmNvbTsg
bGludXhAcm9lY2stdXMubmV0OyBncmVnQGtyb2FoLmNvbQ0KPiBDYzogY3lfaHVhbmco6buD5ZWf
5Y6fKSA8Y3lfaHVhbmdAcmljaHRlay5jb20+Ow0KPiBsaW51eC1rZXJuZWxAdmdlci5rZXJuZWwu
b3JnOyBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnOyBkbC1saW51eC1pbXgNCj4gPGxpbnV4LWlt
eEBueHAuY29tPg0KPiBTdWJqZWN0OiBSRTogW1BBVENIXSBzdGFnaW5nOiB0eXBlYzogaGFuZGxl
IHZlbmRvciBkZWZpbmVkIHBhcnQgYW5kIG1vZGlmeQ0KPiBkcnAgdG9nZ2xpbmcgZmxvdw0KPiAN
Cj4gSGkgSnVuLA0KPiANCj4gPiAtLS0tLU9yaWdpbmFsIE1lc3NhZ2UtLS0tLQ0KPiA+IEZyb206
IEp1biBMaSBbbWFpbHRvOmp1bi5saUBueHAuY29tXQ0KPiA+IFNlbnQ6IFRodXJzZGF5LCBNYXJj
aCAwMSwgMjAxOCA2OjA2IFBNDQo+ID4gVG86IHNodWZhbl9sZWUo5p2O5pu45biGKTsgU2h1RmFu
TGVlOyBoZWlra2kua3JvZ2VydXNAbGludXguaW50ZWwuY29tOw0KPiA+IGxpbnV4QHJvZWNrLXVz
Lm5ldDsgZ3JlZ0Brcm9haC5jb20NCj4gPiBDYzogY3lfaHVhbmco6buD5ZWf5Y6fKTsgbGludXgt
a2VybmVsQHZnZXIua2VybmVsLm9yZzsNCj4gPiBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnOyBk
bC1saW51eC1pbXgNCj4gPiBTdWJqZWN0OiBSRTogW1BBVENIXSBzdGFnaW5nOiB0eXBlYzogaGFu
ZGxlIHZlbmRvciBkZWZpbmVkIHBhcnQgYW5kDQo+ID4gbW9kaWZ5IGRycCB0b2dnbGluZyBmbG93
DQo+ID4NCj4gPiBIaSBTaHVmYW4NCj4gPg0KPiA+IFBsZWFzZSBkb24ndCB0b3AgcG9zdGluZw0K
PiA+DQo+ID4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gPiBGcm9tOiBzaHVmYW5fbGVl
KOadjuabuOW4hikgW21haWx0bzpzaHVmYW5fbGVlQHJpY2h0ZWsuY29tXQ0KPiA+IFNlbnQ6IDIw
MTjlubQz5pyIMeaXpSAxNjo0OQ0KPiA+IFRvOiBKdW4gTGkgPGp1bi5saUBueHAuY29tPjsgU2h1
RmFuTGVlIDxsZWVjaHU3MjlAZ21haWwuY29tPjsNCj4gPiBoZWlra2kua3JvZ2VydXNAbGludXgu
aW50ZWwuY29tOyBsaW51eEByb2Vjay11cy5uZXQ7IGdyZWdAa3JvYWguY29tDQo+ID4gQ2M6IGN5
X2h1YW5nKOm7g+WVn+WOnykgPGN5X2h1YW5nQHJpY2h0ZWsuY29tPjsNCj4gPiBsaW51eC1rZXJu
ZWxAdmdlci5rZXJuZWwub3JnOyBsaW51eC11c2JAdmdlci5rZXJuZWwub3JnOyBkbC1saW51eC1p
bXgNCj4gPiA8bGludXgtaW14QG54cC5jb20+DQo+ID4gU3ViamVjdDogUkU6IFtQQVRDSF0gc3Rh
Z2luZzogdHlwZWM6IGhhbmRsZSB2ZW5kb3IgZGVmaW5lZCBwYXJ0IGFuZA0KPiA+IG1vZGlmeSBk
cnAgdG9nZ2xpbmcgZmxvdw0KPiA+DQo+ID4gSGkgSnVuLA0KPiA+DQo+ID4gICBUaGUgYXR0YWNo
bWVudCBpcyB3YXZlZm9ybSBvZiB0aGUgY29uZGl0aW9uIHdlIG1ldCBidXQgSSdtIG5vdCBzdXJl
DQo+ID4gd2hldGhlciB5b3UgY2FuIGRvd25sb2FkIHRoZSBhdHRhY2htZW50Lg0KPiA+ICAgSSBh
ZGQgbG9nIGluIFJUMTcxMUggaXQgc2hvd3MgYXMgZm9sbG93aW5nOg0KPiA+DQo+ID4gWW91IGRv
bid0IG5lZWQgYWRkIGxvZyBieSB5b3VyIG93bi4NCj4gPiBUaGVyZSBpcyB0Y3BtKC4vZHJpdmVy
cy91c2IvdHlwZWMvdGNwbS5jKSBsb2cgZm9yIGRlYnVnIGFscmVhZHksIHdoaWNoIGNhbg0KPiBz
aG93IGFsbCB0aGUgZXZlbnRzIGFuZCBzdGF0ZSB0cmFuc2l0aW9ucywgeW91IGNhbiBnZXQgaXQg
YnkgYmVsb3cgY29tbWFuZA0KPiBhcyBJIGNvbW1lbnRlZDoNCj4gPg0KPiA+IGNhdCAvc3lzL2tl
cm5lbC9kZWJ1Zy90Y3BtL3h4eHh4KHlvdXIgdGNwYyBpMmMgZGV2aWNlKQ0KPiA+DQo+IEFmdGVy
IGFwcGx5aW5nIHlvdXIgcGF0Y2hbMl0sIFRDUE0gbG9nIGlzIGFzIGZvbGxvd2luZzoNCg0KSSBh
c3N1bWUgeW91IGFsc28gYXBwbGllZCBteSBwYXRjaCBbMV0uDQpbMV0gaHR0cHM6Ly93d3cuc3Bp
bmljcy5uZXQvbGlzdHMvZGV2aWNldHJlZS9tc2cyMTY4NTEuaHRtbA0KDQo+IA0KPiBbICAgNTMu
MDUwNjAyXSBDQzE6IDAgLT4gMiwgQ0MyOiAwIC0+IDAgW3N0YXRlIERSUF9UT0dHTElORywgcG9s
YXJpdHkgMCwNCj4gY29ubmVjdGVkXQ0KPiBbICAgNTMuMDUwNjEzXSBzdGF0ZSBjaGFuZ2UgRFJQ
X1RPR0dMSU5HIC0+IFNSQ19BVFRBQ0hfV0FJVA0KPiBbICAgNTMuMDUwNjc4XSBwZW5kaW5nIHN0
YXRlIGNoYW5nZSBTUkNfQVRUQUNIX1dBSVQgLT4gU05LX1RSWSBADQo+IDIwMCBtcw0KPiA9PiBS
ZCBpcyBwbHVnZ2VkIG91dA0KPiBbICAgNTMuMTc4ODA0XSBDQzE6IDIgLT4gMCwgQ0MyOiAwIC0+
IDAgW3N0YXRlIFNSQ19BVFRBQ0hfV0FJVCwgcG9sYXJpdHkgMCwNCj4gZGlzY29ubmVjdGVkXQ0K
PiBbICAgNTMuMTc4ODE1XSBzdGF0ZSBjaGFuZ2UgU1JDX0FUVEFDSF9XQUlUIC0+IFNSQ19VTkFU
VEFDSEVEDQo+ID0+IFJkIGlzIHBsdWdnZWQgaW4NCj4gWyAgIDUzLjE3ODg3NF0gU3RhcnQgRFJQ
IHRvZ2dsaW5nDQo+IFsgICA1My4xODg0NzJdIENDMTogMCAtPiAwLCBDQzI6IDAgLT4gMCBbc3Rh
dGUgRFJQX1RPR0dMSU5HLCBwb2xhcml0eSAwLA0KPiBkaXNjb25uZWN0ZWRdDQoNCjEuIFRoZSBw
bHVnIG91dCBhbmQgdGhlbiBwbHVnIGluIGhhcHBlbnMgaW4gMTBtcz8gKDUzLjE4ODQ3MiAtIDUz
LjE3ODgwNCkNCldhcyB0aGlzIGRvbmUgbWFudWFsbHk/IE9yIGJ5IHNvbWUgc3BlY2lhbCB0ZXN0
IG1ldGhvZD8NCjIuIFRoaXMgaXMgYWxsIHRjcG0gbG9nIGlmIHlvdSBmaW5hbGx5IGtlZXAgdGhl
IFJkLWRldmljZSBjb25uZWN0ZWQgb24gdHlwZWMNCnBvcnQ/IFRoZXJlIGlzIG5vIG1vcmUgdGNw
bSBsb2cgYWZ0ZXIgNTMuMTg4NDcyIGlmIHlvdSBwbHVnIGluIFJkLWRldmljZQ0KYW5kIGRvbid0
IHJlbW92ZSBpdD8gDQozLiBJZiB0aGUgYW5zd2VyIG9mIFEyIGlzIHllcywgdGhlbiBJIG11c3Qg
YXNrIHdoeSB5b3UgdGNwYyBjaGlwK2ludGVybmFsIGZpcm13YXJlDQpjYW4ndCByZXBvcnQgZnVy
dGhlciBjYyBjaGFuZ2UgZXZlbnQgYWZ0ZXIgeW91ciBkcnAgdG9nZ2xpbmcgc3RhcnRzIHRvIHBy
ZXNlbnQgUnAoSSBrbm93DQppdCBmaXJzdGx5IHByZXNlbnQgUmQgYWZ0ZXIgeW91IHdyaXRlIHRv
IExPT0s0Q09OTkVDVElPTiwgYnV0IHRoZW4gaXQgc2hvdWxkIGNoYW5nZQ0KdG8gcHJlc2VudCBS
cCwgc28gaXQgc2hvdWxkIGJlIGFibGUgdG8gZGV0ZWN0IHRoZSBSZC1kZXZpY2UgZmluYWxseSkN
Cg0KPiANCj4gSWYgVENQTSBkb2VzIG5vdCBlbnRlciBTUkNfQVRUQUNIRUQgc3RhdGUsIFJDLkRS
UCB3aWxsIG5vdCBiZSBjbGVhcmVkLg0KDQpJbiB0aGlzIGNhc2UsIHlvdSBkb27igJl0IG5lZWQg
Y2xlYXIgUkMuRFJQLCBzZWUgVENQQ0kgc3BlYzoNCiJGaWd1cmUgNC0xOC4gU2luayBEaXNjb25u
ZWN0Ig0KVENQTSBzaW5rIGRvZXNuJ3QgY2xlYXIgaXQgaW4gd2hvbGUgc2VxdWVuY2UsIGp1c3Qg
ZGlyZWN0bHkgc2V0IGl0Og0KUmVzdGFydCBEUlAgVG9nZ2xpbmcNClBDLkF1dG9EaXNjaGFyZ2VE
aXNjb25uZWN0PTBiDQpTZXQgUkMuRFJQPTFiIChEUlApDQpTZXQgUkMuQ0MxPTEwYiAoUmQpDQpT
ZXQgUkMuQ0MyPTEwYiAoUmQpDQpDT01NQU5ELkxvb2s0Q29ubmVjdGlvbiAoRFJQIHRvZ2dsZSkN
Cg0KPiBXaGVuIFRDUE0gd3JpdGVzIFJkL1JkIG9yIFJwL1JwIGluIHRoZSBkcnBfdG9nZ2xpbmcg
ZnVuY3Rpb24sIGl0IGRvZXMgbm90DQo+IHRha2UgZWZmZWN0IHVudGlsIExPT0s0Q09OTkVDVElP
TiBjb21tYW5kIGlzIHNldC4NCj4gVGhlIGFib3ZlIGNvbmRpdGlvbiBjYXVzZXMgUlQxNzExSCBy
ZXBvcnRzIG9wZW4vb3BlbiBhdCBbNTMuMTg4NDcyXQ0KPiANCj4gPiBbIDkxNC45MzczNDBdIHR5
cGVjX3J0MTcxMWggMi0wMDRlOiBfX3J0MTcxMWhfaXJxX2hhbmRsZXIgWw0KPiA+IDkxNC45NDM4
MzhdIHR5cGVjX3J0MTcxMWggMi0wMDRlOiBfX3RjcG1fZ2V0X2NjIGNjMSA9IE9wZW4sIGNjMiA9
DQo+IE9wZW4NCj4gPiA9PiBEZXZpY2UoUmQpIGlzIHBsdWdnZWQgb3V0DQo+ID4NCj4gPiBbIDkx
NC45NTgwNDFdIHR5cGVjX3J0MTcxMWggMi0wMDRlOiB0Y3BtX3NldF9wZF9yeCAwIFsgOTE0Ljk2
MzAxMV0NCj4gPiB0eXBlY19ydDE3MTFoIDItMDA0ZTogdGNwbV9zZXRfdmJ1cyB2YnVzID0gMCBb
IDkxNC45Njg0MDddDQo+ID4gdHlwZWNfcnQxNzExaA0KPiA+IDItMDA0ZTogdGNwbV9zZXRfdmJ1
cyBjaGcgaXMgYWxyZWFkeSAwIFsgOTE0Ljk3NDU0MV0gdHlwZWNfcnQxNzExaA0KPiAyLTAwNGU6
DQo+ID4gdGNwbV9zZXRfdmNvbm4gdmNvbm4gaXMgYWxyZWFkeSAwIFsgOTE0Ljk4MDkyMV0gdHlw
ZWNfcnQxNzExaCAyLTAwNGU6DQo+ID4gdGNwbV9zZXRfY3VycmVudF9saW1pdCAwIG1hLCAwIG12
IChub3QgaW1wbGVtZW50ZWQpIFsgOTE0Ljk4ODg5NF0NCj4gPiB0eXBlY19ydDE3MTFoIDItMDA0
ZTogdGNwbV9zZXRfcG9sYXJpdHkgUG9sYXJpdHlfQ0MxIFsgOTE1LjAwMzIwMV0NCj4gPiB0eXBl
Y19ydDE3MTFoIDItMDA0ZTogdGNwbV9zZXRfcm9sZXMgU291cmNlIEhvc3QgWyA5MTUuMDA5MjY0
XQ0KPiA+IHR5cGVjX3J0MTcxMWggMi0wMDRlOiB0Y3BtX3N0YXJ0X2RycF90b2dnbGluZyA9PiBz
dGF0ZV9tYWNoaW5lX3dvcmsNCj4gb2YNCj4gPiBUQ1BNIGNhbGxzIHN0YXJ0X2RycF90b2dnbGlu
ZyBmdW5jdGlvbiBidXQgZG9lcyBub3Qgc2V0DQo+ID4gTE9PSzRDT05ORUNUSU9OIGNvbW1hbmQg
eWV0ID0+IChOb3RlMSkgRGV2aWNlKFJkKSBpcyBwbHVnZ2VkIGluDQo+ID4gKFJUMTcxMUgncyBp
bnRlcm5hbCBmaXJtd2FyZSBkZXRlY3RzIFJkIHBsdWdnZWQgaW4uIGNjX2NoYW5nZSBpcw0KPiA+
IHRyaWdnZXJlZCBhbmQgaXQgd2lsbCBiZSB2UmQtY29ubmVjdGVkIGF0IHRoaXMgbW9tZW50KSA9
PiBUQ1BNIHdyaXRlcw0KPiA+IExPT0s0Q09OTkVDVElPTiBjb21tYW5kDQo+ID4gLSBCZWNhdXNl
IFJDLkRSUCBpcyBzdGlsbCAxLCBSVDE3MTFIIHdpbGwgbm90IHB1bGwgY2MxL2NjMiB0byBSZCB3
aGlsZQ0KPiA+IHdyaXRpbmcgUmQvUmQgdG8gUkMuQ0MxL1JDLkNDMi4NCj4gPiAtIChOb3RlMikg
UmlnaHQgYWZ0ZXIgTE9PSzRDT05ORUNUSU9OIGNvbW1hbmQgaXMgd3JpdHRlbiwgUlQxNzExSA0K
PiA+IHB1bGxzIENDIHRvIFJkJ3MgbGV2ZWwgKGJlY2F1c2UgUkMuUm9sZSBpcyBSZC9SZCksIHN0
b3AgdG9nZ2xpbmcNCj4gPiAoYmVjYXVzZQ0KPiA+IGRldmljZShSZCkgaXMgYWxyZWFkeSBjb25u
ZWN0ZWQpIGFuZCBDQyBzdGF0dXMgd2lsbCBiZSBvcGVuL29wZW4gbm93DQo+ID4gKGJlY2F1c2Ug
UlQxNzExSCBwcmVzZW50cyBSZCBhbmQgZGV2aWNlIGlzIGNvbm5lY3RlZChSZCkpDQo+ID4NCj4g
PiBbIDkxNS4wMzcyNjNdIHR5cGVjX3J0MTcxMWggMi0wMDRlOiBfX3RjcG1fZ2V0X2NjIGNjMSA9
IE9wZW4sIGNjMiA9DQo+ID4gT3BlbiA9PiBFbnRlciBSVDE3MTFIJ3MgaXJxIGhhbmRsZXIgYW5k
IGl0IHJlcG9ydHMgb3Blbi9vcGVuDQo+ID4NCj4gPiBJIHRoaW5rIHRoZSBwb2ludCBpcyB0byB3
cml0ZSBSQy5EUlAgPSAwIGF0IHRoZSBiZWdpbm5pbmcgb2YNCj4gPiBkcnBfdG9nZ2xpbmcgc28g
dGhhdCBSVDE3MTFIIHdpbGwgcHVsbCBjYzEvY2MyIHRvIFJkIHdoaWxlIHdyaXRpbmcNCj4gPiBS
ZC9SZCB0byBSQy5DQzEvUkMuQ0MyIFRoaXMgb3BlcmF0aW9uIHdpbGwgbWFrZSBSVDE3MTFIJ3Mg
aW50ZXJuYWwNCj4gPiBmaXJtd2FyZSByZXN0YXJ0cyBmcm9tIGRpc2Nvbm5lY3RlZCBzdGF0ZSBh
bmQgdG9nZ2xlcyBjb3JyZWN0bHkuDQo+ID4NCj4gPiBBY2NvcmRpbmcgdG8gVENQQ0kgc3BlYyAo
NC40LjUuMik6DQo+ID4gSXQgaXMgcmVjb21tZW5kZWQgdGhlIFRDUE0gd3JpdGUgUk9MRV9DT05U
Uk9MLkRSUD0wIGJlZm9yZSB3cml0aW5nDQo+IHRvDQo+ID4gUE9XRVJfQ09OVFJPTC5BdXRvRGlz
Y2hhcmdlRGlzY29ubmVjdCBhbmQgc3RhcnRpbmcgdGhlIERSUCB0b2dnbGluZw0KPiA+IHVzaW5n
IENPTU1BTkQuTG9vazRDb25uZWN0aW9uIFJlc3RhcnQgRFJQIFRvZ2dsaW5nID0+IEl0IGlzDQo+
ID4gcmVjb21tZW5kZWQgdGhlIFRDUE0gd3JpdGUgUk9MRV9DT05UUk9MLkRSUD0wIGhlcmUgU2V0
DQo+ID4NCj4gPiBUaGlzIHN0YXRlbWVudCBpc19ub3RfIHJlY29tbWVuZCB5b3UgZG8gdGhpcyhS
Qy5EUlA9MCkgZm9yIHN0YXJ0IGRycA0KPiB0b2dnbGluZywgUGxlYXNlIGNhcmVmdWxseSBjaGVj
ayB0aGUgd2hvbGUgc2VudGVuY2U6DQo+ID4gIi4uLiBhcyBzaG93biBpbiBGaWd1cmUgNC0xNiwg
Ig0KPiA+IElmIHlvdSBsb29rIGF0ICJGaWd1cmUgNC0xNi4gRFJQIEluaXRpYWxpemF0aW9uIGFu
ZCBDb25uZWN0aW9uIERldGVjdGlvbiINCj4gPiBJdCBnaXZlcyBjbGVhciBkcnAgdG9nZ2xpbmcg
c3RhcnQgb3BlcmF0aW9uczoNCj4gPg0KPiA+IFNldCBUQ1BDIHRvIERSUA0KPiA+IC0gUmVhZCBQ
Uy5UQ1BDSW5pdGlhbGl6YXRpb25TdGF0dXMNCj4gPiAtIFdyaXRlIFJPTEVfQ09OVFJPTA0KPiA+
IC0gUkMuRFJQID0gMWINCj4gPiAtIFJDLkNDMj0wMWIgb3IgMTBiDQo+ID4gLSBSQy5DQzE9MDFi
IG9yIDEwYg0KPiA+IC0gUkMuQ0MxPVJDLkNDMg0KPiA+IC0gV3JpdGUgQ09NTUFORC5Mb29rNENv
bm5lY3Rpb25QUy4NCj4gPg0KPiA+IEFib3ZlIGlzIGFsbCBvcGVyYXRpb25zIHJlcXVpcmVkIHRv
IHN0YXJ0IGRycCB0b2dnbGluZy4gWW91IGFsc28gY2FuIHNlZQ0KPiBSQy5DQ3ggPSAwMWIgb3Ig
MTBiLCBub3QgZml4ZWQgdG8gYmUgUmQsIHJpZ2h0Pw0KPiBZZXMsIHRoaXMgb25lIHNob3VsZCBi
ZSBsaWtlIHlvdXIgcGF0Y2hbMDcvMTJdLiBXcml0ZSBSZCBvciBScCB0byBSQy5DQ3gNCj4gYWNj
b3JkaW5nIHRvIHRoZSBjYyBwYXJhbWV0ZXIgb2YgZHJwX3RvZ2dsaW5nIGZ1bmN0aW9uLg0KPiA+
DQo+ID4gR28gb24gdG8gY2hlY2sgdGhlIEZpZ3VyZSA0LTE2DQo+ID4gQWZ0ZXIgZGVib3VuY2Us
IHdlIG5lZWQgZG8gZm9sbG93aW5nOg0KPiA+DQo+ID4gQ29ubmVjdGlvbkRldGVybWluZSBDQyAm
IFZDT05ODQo+ID4gLSBXcml0ZSBSQy5DQzEgJiBSQy5DQzIgcGVyIGRlY2lzaW9uDQo+ID4gLSBX
cml0ZSBSQy5EUlA9MA0KPiA+IC0gV3JpdGUgVENQQ19DT05UUk9sLlBsdWdPcmllbnRhdGlvbg0K
PiA+IC0gV3JpdGUgUEMuQXV0b0Rpc2NoYXJnZURpc2Nvbm5lY3Q9MQ0KPiA+ICAmIFBDLkVuYWJs
ZVZjb25uQ29ubmVjdGlvbg0KPiA+DQo+ID4gQ3VycmVudCBleGlzdGluZyB0Y3BtK3RjcGNpIHdp
bGwgbm90IGNsZWFyIFJDLkRSUCBhZnRlciBhdHRhY2gsIFRoYXQgbWVhbnMNCj4gUkMuRFJQIGNs
ZWFyIG1heSBiZSBkb25lIGFmdGVyIGF0dGFjaCwgbm90IGluIHN0YXJ0X2RycF90b2dnbGluZy4N
Cj4gPiBJIGFtIG5vdCBzdXJlIGlmIHRoaXMgY2FuIHJlc29sdmUgeW91ciBwcm9ibGVtLCBidXQg
SSB0aGluayBpdCBkZXNlcnZlIGEgdHJ5LA0KPiB5b3UgY2FuIGZvbGxvdyBhYm92ZSBvcGVyYXRp
b24gc2VxdWVuY2Ugd2hpbGUgZW50ZXJpbmcgYXR0YWNoIHN0YXRlLCByZWZlcg0KPiB0byBteSBw
YXRjaFsyXToNCj4gPg0KPiA+IFsyXQ0KPiA+DQo+IGh0dHBzOi8vZW1lYTAxLnNhZmVsaW5rcy5w
cm90ZWN0aW9uLm91dGxvb2suY29tLz91cmw9aHR0cHMlM0ElMkYlMkZ3DQo+IHd3DQo+ID4gLnNw
aW5pY3MubmV0JTJGbGlzdHMlMkZkZXZpY2V0cmVlJTJGbXNnMjE2ODUyLmh0bWwmZGF0YT0wMiU3
QzAxJTcNCj4gQ2p1bi4NCj4gPg0KPiBsaSU0MG54cC5jb20lN0M5MTE3NDI1NTUwZDI0ZGRjODZk
ODA4ZDU3ZjZiMWI0ZSU3QzY4NmVhMWQzYmMyYg0KPiA0YzZmYTkyYw0KPiA+DQo+IGQ5OWM1YzMw
MTYzNSU3QzAlN0MwJTdDNjM2NTU1MDIwMzY2NDgzNDU2JnNkYXRhPTklMkJ5d1lsJTJCUg0KPiBQ
WXRrNjBXZzZwDQo+ID4gUjYzY0NXMkFuUlhzJTJCcklOdnZxVXBxTDE4JTNEJnJlc2VydmVkPTAN
Cj4gPg0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3N0YWdpbmcvdHlwZWMvdGNwY2kuYw0KPiA+
IGIvZHJpdmVycy9zdGFnaW5nL3R5cGVjL3RjcGNpLmMgaW5kZXggNTMwYTVkNy4uNzE0NTc3MSAx
MDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL3N0YWdpbmcvdHlwZWMvdGNwY2kuYw0KPiA+ICsrKyBi
L2RyaXZlcnMvc3RhZ2luZy90eXBlYy90Y3BjaS5jDQo+ID4gQEAgLTE4NCw2ICsxODQsNyBAQCBz
dGF0aWMgaW50IHRjcGNpX3NldF9wb2xhcml0eShzdHJ1Y3QgdGNwY19kZXYgKnRjcGMsDQo+ID4g
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW51bSB0eXBlY19jY19wb2xhcml0eSBwb2xh
cml0eSkgIHsNCj4gPiAgICAgICAgIHN0cnVjdCB0Y3BjaSAqdGNwY2kgPSB0Y3BjX3RvX3RjcGNp
KHRjcGMpOw0KPiA+ICsgICAgICAgdW5zaWduZWQgaW50IHJlZzsNCj4gPiAgICAgICAgIGludCBy
ZXQ7DQo+ID4NCj4gPiAgICAgICAgIHJldCA9IHJlZ21hcF93cml0ZSh0Y3BjaS0+cmVnbWFwLCBU
Q1BDX1RDUENfQ1RSTCwgQEANCj4gLTE5Miw2ICsxOTMsMjAgQEAgc3RhdGljIGludCB0Y3BjaV9z
ZXRfcG9sYXJpdHkoc3RydWN0IHRjcGNfZGV2ICp0Y3BjLA0KPiA+ICAgICAgICAgaWYgKHJldCA8
IDApDQo+ID4gICAgICAgICAgICAgICAgIHJldHVybiByZXQ7DQo+ID4NCj4gPiArICAgICAgIHJl
dCA9IHJlZ21hcF9yZWFkKHRjcGNpLT5yZWdtYXAsIFRDUENfUk9MRV9DVFJMLCAmcmVnKTsNCj4g
PiArICAgICAgIGlmIChyZXQgPCAwKQ0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gcmV0Ow0K
PiA+ICsNCj4gPiArICAgICAgIGlmIChwb2xhcml0eSA9PSBUWVBFQ19QT0xBUklUWV9DQzIpDQo+
ID4gKyAgICAgICAgICAgICAgIHJldCA9IFRDUENfUk9MRV9DVFJMX0NDMV9TSElGVDsNCj4gPiAr
ICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgcmV0ID0gVENQQ19ST0xFX0NUUkxfQ0My
X1NISUZUOw0KPiA+ICsgICAgICAgcmVnIHw9IFRDUENfUk9MRV9DVFJMX0NDX09QRU4gPDwgcmV0
Ow0KPiA+ICsgICAgICAgcmVnICY9IH5UQ1BDX1JPTEVfQ1RSTF9EUlA7DQo+ID4gKyAgICAgICBy
ZXQgPSByZWdtYXBfd3JpdGUodGNwY2ktPnJlZ21hcCwgVENQQ19ST0xFX0NUUkwsIHJlZyk7DQo+
ID4gKyAgICAgICBpZiAocmV0IDwgMCkNCj4gPiArICAgICAgICAgICAgICAgcmV0dXJuIHJldDsN
Cj4gPiArDQo+ID4gICAgICAgICByZXR1cm4gMDsNCj4gPiAgfQ0KPiA+DQo+ID4gUEMuQXV0b0Rp
c2NoYXJnZURpc2Nvbm5lY3Q9MGIgU2V0IFJDLkRSUD0xYiAoRFJQKSBTZXQgUkMuUnBWYWx1ZT0w
MGINCj4gPiAoc21hbGxlc3QgUnAgdG8gc2F2ZSBwb3dlcikgU2V0IFJDLkNDMT0wMWIgU2V0DQo+
ID4gUkMuQ0MyPTAxYkNPTU1BTkQuTG9vazRDb25uZWN0aW9uTm8NCj4gPg0KPiA+IEl0IHNlZW1z
IGxpa2UgaXQgaXMgbm90IGEgZ2VuZXJhbCBjYXNlIGhlcmUgKGJlY2F1c2UgaXQgaXMgb25seQ0K
PiA+IHJlY29tbWVuZGVkIGJ1dCBub3QgbmVjZXNzYXJ5KSwgd2UgY2FuIG1vdmUgaXQgdG8gdmVu
ZG9yX29wcyBpbiB0aGUNCj4gbmV4dCBwYXRjaC4NCj4gPg0KPiA+IFRoZSBUQ1BNIHNob3VsZCBi
ZSBhYmxlIHRvIGNvdmVyIGFsbCBjYXNlcywgYW5kIHdlIHNob3VsZCBmb2xsb3cgdGhlDQo+IHJl
Y29tbWVuZGVkIHNlcXVlbmNlKGlmIHdoYXQgeW91IGFyZSB0cnlpbmcgdG8gZG8gaXMgcmVhbGx5
IGFzIHNwZWMgc2F5cykuDQo+IEFncmVlIQ0KPiBNeSB1bmRlcnN0YW5kaW5nIGlzIHRoYXQgd2Ug
bmVlZCB0byBzZXQgUkMuRFJQIHRvIDAgZXZlcnkgdGltZSBiZWZvcmUNCj4gVENQTSByZXN0YXJ0
cyB0b2dnbGluZyBidXQgbm90IGp1c3QgZm9yIGF0dGFjaGVkLg0KDQpBY3R1YWxseSBJIGhhdmUg
bm8gb2JqZWN0aW9uIG9uIGFkZGluZyBhIFJDLkRSUCBjbGVhciwgdGhlIHF1ZXN0aW9uIGlzDQp3
aGVyZSBpcyB0aGUgcmlnaHQgcGxhY2UgdG8gZG8gdGhpcywgdGlsbCBub3cgSSBkb27igJl0IHNl
ZSBob3cgdGhpcyBEUlAgYml0IGtlZXAgc2V0DQp3aGlsZSBzdGFydCBkcnAgdG9nZ2xpbmcgaXMg
Y2F1c2luZyBwcm9ibGVtLCBZb3Ugd2FudCB0byBzdGFydCBwcmVzZW50IFJkIGFmdGVyIHdyaXRl
DQpDQzEvQ0MyIHRvIGJlIFJkL1JkIGFuZCBiZWZvcmUgd3JpdGUgdG8gTE9PSzRDT05ORUNUSU9O
LCB0aGlzIGlzIG5vdCByZXF1aXJlZA0KcGVyIHRjcGNpIHNwZWMuDQoNCi1CZWhhdmlvciBhZnRl
ciB5b3VyIHBhdGNoOg0KLy9iZWdpbiB3aXRoIE9wZW4gYXMgUkMuRFJQID0gMQ0KUkMuQ0N4PVJk
ICYgUkMuRFJQID0gMDsgLy9TdGFydCBwcmVzZW50IFJkDQpXYWl0IDFtczsgLy8gU3RpbGwgUmQN
ClJDLkNDeD1SZCAmIFJDLkRSUCA9IDE7IC8vT3Blbj8NCkxvb2s0Q09OTkVDVElPTiA9IDE7IC8v
RFJQIHRvZ2dsaW5nIGNvbnRpbnVlIHByZXNldCBSZA0KDQpJcyBteSBhYm92ZSBDQyBzdGF0ZSBk
ZXNjcmlwdGlvbiBjb3JyZWN0PyBJcyB0aGlzIHdoYXQgeW91IHdhbnQ/DQoNCi1Pbmx5IGFwcGx5
IG15IHBhdGNoZXM6DQovL2JlZ2luIHdpdGggT3BlbiBhcyBSQy5EUlAgPSAxDQpSQy5DQ3g9UmQg
JiBSQy5EUlAgPSAxOyAvL3N0aWxsIE9wZW4NCkxvb2s0Q29ubmVjdGlvbiA9IDE7IC8vU3RhcnQg
cHJlc2V0IFJkDQoNCj4gRm9yIFJUMTcxMUgsIGl0IGZvbGxvd3MgYWJvdmUgZmxvdy4gSWYgaXQg
aXMgbm90IGNvcnJlY3QsIHRoaXMgb3BlcmF0aW9uIHNob3VsZA0KPiBiZSBtb3ZlZCB0byB2ZW5k
b3Jfb3BzLg0KPiA+DQo+ID4gRm9yIHlvdXIgcXVlc3Rpb246DQo+ID4gV2h5IFJUMTcxMUggcmVw
b3J0cyBvcGVuL29wZW4gYWZ0ZXIgZHJwX3RvZ2dsaW5nIGlzIGVuYWJsZWQ/DQo+ID4gPT4gU2Vl
IE5vdGUyIGFib3ZlLg0KPiA+IFRoaXMgb3Blbi9vcGVuIGlzIGZvciB5b3UgcGx1ZyBvdXQgdGhl
IGRldmljZSwgcmlnaHQ/DQo+ID4gPT4gTm8sIHNlZSBOb3RlMiBhYm92ZS4NCj4gPiBXaHkgUlQx
NzExSCBjYW4ndCByZXBvcnQgbmV3IGNjIGNoYW5nZSBldmVudHMgYWZ0ZXIgeW91IHBsdWcgaW4g
dGhlDQo+ID4gZGV2aWNlPw0KPiA+ID0+IFJUMTcxMUggY2FuIGdlbmVyYXRlIG5ldyBjYyBjaGFu
Z2UgZXZlbnRzIGFmdGVyIHBsdWdnaW5nIGluIHRoZQ0KPiBkZXZpY2UuDQo+ID4gV2hhdCBjYyBj
aGFuZ2UgZXZlbnQgdGNwYyB3aWxsIHJlcG9ydCBvbiBzdGVwIDQ/DQo+ID4gPT4gU2VlIE5vdGUx
IGFib3ZlDQo+ID4gRGlkIHlvdSB2ZXJpZnkgeW91ciBjaGFuZ2UgY2FuIHBhc3MgdGhlIHR5cGVj
IGNvbXBsaWFuY2UgdGVzdD8NCj4gPiA9PiBXZSBkaWRuJ3QgdGVzdCBpdCB5ZXQgYnV0IHRyeSB0
byBtYWtlIGFsbCBmdW5jdGlvbnMgd29yayBjb3JyZWN0bHkgZmlyc3QuDQo+ID4NCj4gPiBCZXN0
IFJlZ2FyZHMsDQo+ID4gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCj4gPiBTaHUtRmFu
IExlZQ0KPiA+IFJpY2h0ZWsgVGVjaG5vbG9neSBDb3Jwb3JhdGlvbg0KPiA+IFRFTDogKzg4Ni0z
LTU1MjY3ODkgIzIzNTkNCj4gPiBGQVg6ICs4ODYtMy01NTI2NjEyDQo+ID4gKioqKioqKioqKioq
KioqKioqKioqKioqKioqKioNCj4gPg0KPiANCj4gKioqKioqKioqKioqKiBFbWFpbCBDb25maWRl
bnRpYWxpdHkgTm90aWNlICoqKioqKioqKioqKioqKioqKioqDQo+IA0KPiBUaGUgaW5mb3JtYXRp
b24gY29udGFpbmVkIGluIHRoaXMgZS1tYWlsIG1lc3NhZ2UgKGluY2x1ZGluZyBhbnkgYXR0YWNo
bWVudHMpDQo+IG1heSBiZSBjb25maWRlbnRpYWwsIHByb3ByaWV0YXJ5LCBwcml2aWxlZ2VkLCBv
ciBvdGhlcndpc2UgZXhlbXB0IGZyb20NCj4gZGlzY2xvc3VyZSB1bmRlciBhcHBsaWNhYmxlIGxh
d3MuIEl0IGlzIGludGVuZGVkIHRvIGJlIGNvbnZleWVkIG9ubHkgdG8gdGhlDQo+IGRlc2lnbmF0
ZWQgcmVjaXBpZW50KHMpLiBBbnkgdXNlLCBkaXNzZW1pbmF0aW9uLCBkaXN0cmlidXRpb24sIHBy
aW50aW5nLA0KPiByZXRhaW5pbmcgb3IgY29weWluZyBvZiB0aGlzIGUtbWFpbCAoaW5jbHVkaW5n
IGl0cyBhdHRhY2htZW50cykgYnkgdW5pbnRlbmRlZA0KPiByZWNpcGllbnQocykgaXMgc3RyaWN0
bHkgcHJvaGliaXRlZCBhbmQgbWF5IGJlIHVubGF3ZnVsLiBJZiB5b3UgYXJlIG5vdCBhbg0KPiBp
bnRlbmRlZCByZWNpcGllbnQgb2YgdGhpcyBlLW1haWwsIG9yIGJlbGlldmUgdGhhdCB5b3UgaGF2
ZSByZWNlaXZlZCB0aGlzDQo+IGUtbWFpbCBpbiBlcnJvciwgcGxlYXNlIG5vdGlmeSB0aGUgc2Vu
ZGVyIGltbWVkaWF0ZWx5IChieSByZXBseWluZyB0byB0aGlzDQo+IGUtbWFpbCksIGRlbGV0ZSBh
bnkgYW5kIGFsbCBjb3BpZXMgb2YgdGhpcyBlLW1haWwgKGluY2x1ZGluZyBhbnkgYXR0YWNobWVu
dHMpDQo+IGZyb20geW91ciBzeXN0ZW0sIGFuZCBkbyBub3QgZGlzY2xvc2UgdGhlIGNvbnRlbnQg
b2YgdGhpcyBlLW1haWwgdG8gYW55IG90aGVyDQo+IHBlcnNvbi4gVGhhbmsgeW91IQ0K
---
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
  2018-03-02 14:38               ` Jun Li
  (?)
@ 2018-03-02 18:39               ` 李書帆
  2018-03-02 18:43                   ` ShuFanLee
  -1 siblings, 1 reply; 22+ messages in thread
From: 李書帆 @ 2018-03-02 18:39 UTC (permalink / raw)
  To: Jun Li
  Cc: shufan_lee(李書帆),
	heikki.krogerus, linux, greg, cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

[-- Attachment #1: Type: text/plain, Size: 15552 bytes --]

Hi Jun,

  I think this operation should be moved to vendor's operation after
rechecking the specification.

2018-03-02 22:38 GMT+08:00 Jun Li <jun.li@nxp.com>:

> Hi
> > -----Original Message-----
> > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> > Sent: 2018年3月1日 19:54
> > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> > <linux-imx@nxp.com>
> > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> modify
> > drp toggling flow
> >
> > Hi Jun,
> >
> > > -----Original Message-----
> > > From: Jun Li [mailto:jun.li@nxp.com]
> > > Sent: Thursday, March 01, 2018 6:06 PM
> > > To: shufan_lee(李書帆); ShuFanLee; heikki.krogerus@linux.intel.com;
> > > linux@roeck-us.net; greg@kroah.com
> > > Cc: cy_huang(黃啟原); linux-kernel@vger.kernel.org;
> > > linux-usb@vger.kernel.org; dl-linux-imx
> > > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> > > modify drp toggling flow
> > >
> > > Hi Shufan
> > >
> > > Please don't top posting
> > >
> > > -----Original Message-----
> > > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
> > > Sent: 2018年3月1日 16:49
> > > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
> > > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
> > > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
> > > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
> > > <linux-imx@nxp.com>
> > > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
> > > modify drp toggling flow
> > >
> > > Hi Jun,
> > >
> > >   The attachment is waveform of the condition we met but I'm not sure
> > > whether you can download the attachment.
> > >   I add log in RT1711H it shows as following:
> > >
> > > You don't need add log by your own.
> > > There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already,
> which can
> > show all the events and state transitions, you can get it by below
> command
> > as I commented:
> > >
> > > cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)
> > >
> > After applying your patch[2], TCPM log is as following:
>
> I assume you also applied my patch [1].
> [1] https://www.spinics.net/lists/devicetree/msg216851.html
>
> Yes, this patch is also applied.

> >
> > [   53.050602] CC1: 0 -> 2, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
> > connected]
> > [   53.050613] state change DRP_TOGGLING -> SRC_ATTACH_WAIT
> > [   53.050678] pending state change SRC_ATTACH_WAIT -> SNK_TRY @
> > 200 ms
> > => Rd is plugged out
> > [   53.178804] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_ATTACH_WAIT, polarity
> 0,
> > disconnected]
> > [   53.178815] state change SRC_ATTACH_WAIT -> SRC_UNATTACHED
> > => Rd is plugged in
> > [   53.178874] Start DRP toggling
> > [   53.188472] CC1: 0 -> 0, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
> > disconnected]
>
> 1. The plug out and then plug in happens in 10ms? (53.188472 - 53.178804)
> Was this done manually? Or by some special test method?
>
It's done manually. If you can download the waveform attached in previous
email, you can see Rd is plugged out/in within ms level.
We connect a bridge board with test points of CC1, CC2 and GND to our
platform's Typec receptacle. Then we can simulate a device plugging in/out
by connecting/disconnecting a 5.1k resistor between CC1 and GND.


> 2. This is all tcpm log if you finally keep the Rd-device connected on
> typec
> port? There is no more tcpm log after 53.188472 if you plug in Rd-device

and don't remove it?
>
Yes, RT1711H reports open/open to TCPM in drp_toggling state and stops
toggling. Currently, TCPM does not restart drp_toggling if it receives
open/open in drp_toggling state.
I remember the specification of TypeC does not depict what TCPM should do
if it receives open/open in drp_toggling state.
Maybe restart toggling is an option.

3. If the answer of Q2 is yes, then I must ask why you tcpc chip+internal
> firmware
> can't report further cc change event after your drp toggling starts to
> present Rp(I know
> it firstly present Rd after you write to LOOK4CONNECTION, but then it
> should change
> to present Rp, so it should be able to detect the Rd-device finally)
>
Because RT1711H's internal firmware changes to attached state when Rd is
re-plugged in(cc level is default Rp (around 400mV) now).
Then, LOOK4CONNECTION is set and RT1711H changes CCx to Rd that makes it
reports open/open(because cc level changes from default Rp(around 400mV) to
0mV)

>
> >
> > If TCPM does not enter SRC_ATTACHED state, RC.DRP will not be cleared.
>
> In this case, you don’t need clear RC.DRP, see TCPCI spec:
> "Figure 4-18. Sink Disconnect"
> TCPM sink doesn't clear it in whole sequence, just directly set it:
> Restart DRP Toggling
> PC.AutoDischargeDisconnect=0b
> Set RC.DRP=1b (DRP)
> Set RC.CC1=10b (Rd)
> Set RC.CC2=10b (Rd)
> COMMAND.Look4Connection (DRP toggle)


> > When TCPM writes Rd/Rd or Rp/Rp in the drp_toggling function, it does not
> > take effect until LOOK4CONNECTION command is set.
> > The above condition causes RT1711H reports open/open at [53.188472]
> >
> > > [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [
> > > 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> > Open
> > > => Device(Rd) is plugged out
> > >
> > > [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
> > > typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407]
> > > typec_rt1711h
> > > 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h
> > 2-004e:
> > > tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
> > > tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
> > > typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
> > > typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
> > > typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work
> > of
> > > TCPM calls start_drp_toggling function but does not set
> > > LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
> > > (RT1711H's internal firmware detects Rd plugged in. cc_change is
> > > triggered and it will be vRd-connected at this moment) => TCPM writes
> > > LOOK4CONNECTION command
> > > - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while
> > > writing Rd/Rd to RC.CC1/RC.CC2.
> > > - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
> > > pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling
> > > (because
> > > device(Rd) is already connected) and CC status will be open/open now
> > > (because RT1711H presents Rd and device is connected(Rd))
> > >
> > > [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
> > > Open => Enter RT1711H's irq handler and it reports open/open
> > >
> > > I think the point is to write RC.DRP = 0 at the beginning of
> > > drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing
> > > Rd/Rd to RC.CC1/RC.CC2 This operation will make RT1711H's internal
> > > firmware restarts from disconnected state and toggles correctly.
> > >
> > > According to TCPCI spec (4.4.5.2):
> > > It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing
> > to
> > > POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
> > > using COMMAND.Look4Connection Restart DRP Toggling => It is
> > > recommended the TCPM write ROLE_CONTROL.DRP=0 here Set
> > >
> > > This statement is_not_ recommend you do this(RC.DRP=0) for start drp
> > toggling, Please carefully check the whole sentence:
> > > "... as shown in Figure 4-16, "
> > > If you look at "Figure 4-16. DRP Initialization and Connection
> Detection"
> > > It gives clear drp toggling start operations:
> > >
> > > Set TCPC to DRP
> > > - Read PS.TCPCInitializationStatus
> > > - Write ROLE_CONTROL
> > > - RC.DRP = 1b
> > > - RC.CC2=01b or 10b
> > > - RC.CC1=01b or 10b
> > > - RC.CC1=RC.CC2
> > > - Write COMMAND.Look4ConnectionPS.
> > >
> > > Above is all operations required to start drp toggling. You also can
> see
> > RC.CCx = 01b or 10b, not fixed to be Rd, right?
> > Yes, this one should be like your patch[07/12]. Write Rd or Rp to RC.CCx
> > according to the cc parameter of drp_toggling function.
> > >
> > > Go on to check the Figure 4-16
> > > After debounce, we need do following:
> > >
> > > ConnectionDetermine CC & VCONN
> > > - Write RC.CC1 & RC.CC2 per decision
> > > - Write RC.DRP=0
> > > - Write TCPC_CONTROl.PlugOrientation
> > > - Write PC.AutoDischargeDisconnect=1
> > >  & PC.EnableVconnConnection
> > >
> > > Current existing tcpm+tcpci will not clear RC.DRP after attach, That
> means
> > RC.DRP clear may be done after attach, not in start_drp_toggling.
> > > I am not sure if this can resolve your problem, but I think it deserve
> a try,
> > you can follow above operation sequence while entering attach state,
> refer
> > to my patch[2]:
> > >
> > > [2]
> > >
> > https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fw
> > ww
> > > .spinics.net%2Flists%2Fdevicetree%2Fmsg216852.html&data=02%7C01%7
> > Cjun.
> > >
> > li%40nxp.com%7C9117425550d24ddc86d808d57f6b1b4e%7C686ea1d3bc2b
> > 4c6fa92c
> > >
> > d99c5c301635%7C0%7C0%7C636555020366483456&sdata=9%2BywYl%2BR
> > PYtk60Wg6p
> > > R63cCW2AnRXs%2BrINvvqUpqL18%3D&reserved=0
> > >
> > > diff --git a/drivers/staging/typec/tcpci.c
> > > b/drivers/staging/typec/tcpci.c index 530a5d7..7145771 100644
> > > --- a/drivers/staging/typec/tcpci.c
> > > +++ b/drivers/staging/typec/tcpci.c
> > > @@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev
> *tcpc,
> > >                               enum typec_cc_polarity polarity)  {
> > >         struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
> > > +       unsigned int reg;
> > >         int ret;
> > >
> > >         ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, @@
> > -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
> > >         if (ret < 0)
> > >                 return ret;
> > >
> > > +       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
> > > +       if (ret < 0)
> > > +               return ret;
> > > +
> > > +       if (polarity == TYPEC_POLARITY_CC2)
> > > +               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
> > > +       else
> > > +               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
> > > +       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
> > > +       reg &= ~TCPC_ROLE_CTRL_DRP;
> > > +       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
> > > +       if (ret < 0)
> > > +               return ret;
> > > +
> > >         return 0;
> > >  }
> > >
> > > PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
> > > (smallest Rp to save power) Set RC.CC1=01b Set
> > > RC.CC2=01bCOMMAND.Look4ConnectionNo
> > >
> > > It seems like it is not a general case here (because it is only
> > > recommended but not necessary), we can move it to vendor_ops in the
> > next patch.
> > >
> > > The TCPM should be able to cover all cases, and we should follow the
> > recommended sequence(if what you are trying to do is really as spec
> says).
> > Agree!
> > My understanding is that we need to set RC.DRP to 0 every time before
> > TCPM restarts toggling but not just for attached.
>
> Actually I have no objection on adding a RC.DRP clear, the question is
> where is the right place to do this, till now I don’t see how this DRP bit
> keep set
> while start drp toggling is causing problem, You want to start present Rd
> after write
> CC1/CC2 to be Rd/Rd and before write to LOOK4CONNECTION, this is not
> required
> per tcpci spec.
>
According to TCPCI's specification, it is recommended the TCPM write RC.DRP
= 0 before changing AutoDischargeDisconnecd.
Maybe, an interface for controlling AutoDischargeDisconnecd can be added.
Then clear RC.DRP in the beginning of that interface.

>
> -Behavior after your patch:
> //begin with Open as RC.DRP = 1
> RC.CCx=Rd & RC.DRP = 0; //Start present Rd
> Wait 1ms; // Still Rd
> RC.CCx=Rd & RC.DRP = 1; //Open?
> Look4CONNECTION = 1; //DRP toggling continue preset Rd
>
> Is my above CC state description correct? Is this what you want?
>
Correct. But the purpose of setting RC.CCx = Rd & RC.DRP = 0 is to make
RT1711H's internal firmware leave attached state.
Because RT1711H is still presenting Rp after the device is plugged out,
it's internal firmware enters attached state when the device re-plugged in.
When we write RC.CCx = Rd & RC.DRP = 0, RT1711H's internal firmware leaves
attached state. So it will keep toggling from Rd to Rp but not report
open/open when LOOK4CONNECTION is set.
After rechecking the specification of TCPCI, I think TCPC's internal
firmware should start toggling from detached state when LOOK4CONNECTION is
set even if RC.DRP is not cleared before
I've discussed with my colleagues, we think this should be in vendor ops.
I'll update it in the patch v6.
Could I also apply your patch [1] in the patch v6?
Thank you for your time to clarify this condition.

>
> -Only apply my patches:
> //begin with Open as RC.DRP = 1
> RC.CCx=Rd & RC.DRP = 1; //still Open
> Look4Connection = 1; //Start preset Rd
>
> > For RT1711H, it follows above flow. If it is not correct, this operation
> should
> > be moved to vendor_ops.
> > >
> > > For your question:
> > > Why RT1711H reports open/open after drp_toggling is enabled?
> > > => See Note2 above.
> > > This open/open is for you plug out the device, right?
> > > => No, see Note2 above.
> > > Why RT1711H can't report new cc change events after you plug in the
> > > device?
> > > => RT1711H can generate new cc change events after plugging in the
> > device.
> > > What cc change event tcpc will report on step 4?
> > > => See Note1 above
> > > Did you verify your change can pass the typec compliance test?
> > > => We didn't test it yet but try to make all functions work correctly
> first.
> > >
> > > Best Regards,
> > > *****************************
> > > Shu-Fan Lee
> > > Richtek Technology Corporation
> > > TEL: +886-3-5526789 #2359
> > > FAX: +886-3-5526612
> > > *****************************
> > >
> >
> > ************* Email Confidentiality Notice ********************
> >
> > The information contained in this e-mail message (including any
> attachments)
> > may be confidential, proprietary, privileged, or otherwise exempt from
> > disclosure under applicable laws. It is intended to be conveyed only to
> the
> > designated recipient(s). Any use, dissemination, distribution, printing,
> > retaining or copying of this e-mail (including its attachments) by
> unintended
> > recipient(s) is strictly prohibited and may be unlawful. If you are not
> an
> > intended recipient of this e-mail, or believe that you have received this
> > e-mail in error, please notify the sender immediately (by replying to
> this
> > e-mail), delete any and all copies of this e-mail (including any
> attachments)
> > from your system, and do not disclose the content of this e-mail to any
> other
> > person. Thank you!
>



-- 
Best Regards,
書帆

[-- Attachment #2: Type: text/html, Size: 21419 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-02 18:43                   ` ShuFanLee
  0 siblings, 0 replies; 22+ messages in thread
From: 李書帆 @ 2018-03-02 18:43 UTC (permalink / raw)
  To: Jun Li
  Cc: shufan_lee(李書帆),
	heikki.krogerus, linux, greg, cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi,

  Sorry, I modify it to plain text mode and send again

2018-03-03 2:39 GMT+08:00 李書帆 <leechu729@gmail.com>:
>
> Hi Jun,
>
>   I think this operation should be moved to vendor's operation after rechecking the specification.
>
> 2018-03-02 22:38 GMT+08:00 Jun Li <jun.li@nxp.com>:
>>
>> Hi
>> > -----Original Message-----
>> > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
>> > Sent: 2018年3月1日 19:54
>> > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
>> > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
>> > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
>> > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
>> > <linux-imx@nxp.com>
>> > Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify
>> > drp toggling flow
>> >
>> > Hi Jun,
>> >
>> > > -----Original Message-----
>> > > From: Jun Li [mailto:jun.li@nxp.com]
>> > > Sent: Thursday, March 01, 2018 6:06 PM
>> > > To: shufan_lee(李書帆); ShuFanLee; heikki.krogerus@linux.intel.com;
>> > > linux@roeck-us.net; greg@kroah.com
>> > > Cc: cy_huang(黃啟原); linux-kernel@vger.kernel.org;
>> > > linux-usb@vger.kernel.org; dl-linux-imx
>> > > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
>> > > modify drp toggling flow
>> > >
>> > > Hi Shufan
>> > >
>> > > Please don't top posting
>> > >
>> > > -----Original Message-----
>> > > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
>> > > Sent: 2018年3月1日 16:49
>> > > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
>> > > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
>> > > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
>> > > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
>> > > <linux-imx@nxp.com>
>> > > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
>> > > modify drp toggling flow
>> > >
>> > > Hi Jun,
>> > >
>> > >   The attachment is waveform of the condition we met but I'm not sure
>> > > whether you can download the attachment.
>> > >   I add log in RT1711H it shows as following:
>> > >
>> > > You don't need add log by your own.
>> > > There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can
>> > show all the events and state transitions, you can get it by below command
>> > as I commented:
>> > >
>> > > cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)
>> > >
>> > After applying your patch[2], TCPM log is as following:
>>
>> I assume you also applied my patch [1].
>> [1] https://www.spinics.net/lists/devicetree/msg216851.html
>>
> Yes, this patch is also applied.
>>
>> >
>> > [   53.050602] CC1: 0 -> 2, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
>> > connected]
>> > [   53.050613] state change DRP_TOGGLING -> SRC_ATTACH_WAIT
>> > [   53.050678] pending state change SRC_ATTACH_WAIT -> SNK_TRY @
>> > 200 ms
>> > => Rd is plugged out
>> > [   53.178804] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_ATTACH_WAIT, polarity 0,
>> > disconnected]
>> > [   53.178815] state change SRC_ATTACH_WAIT -> SRC_UNATTACHED
>> > => Rd is plugged in
>> > [   53.178874] Start DRP toggling
>> > [   53.188472] CC1: 0 -> 0, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
>> > disconnected]
>>
>> 1. The plug out and then plug in happens in 10ms? (53.188472 - 53.178804)
>> Was this done manually? Or by some special test method?
>
> It's done manually. If you can download the waveform attached in previous email, you can see Rd is plugged out/in within ms level.
> We connect a bridge board with test points of CC1, CC2 and GND to our platform's Typec receptacle. Then we can simulate a device plugging in/out by connecting/disconnecting a 5.1k resistor between CC1 and GND.
>
>>
>> 2. This is all tcpm log if you finally keep the Rd-device connected on typec
>> port? There is no more tcpm log after 53.188472 if you plug in Rd-device
>>
>> and don't remove it?
>
> Yes, RT1711H reports open/open to TCPM in drp_toggling state and stops toggling. Currently, TCPM does not restart drp_toggling if it receives open/open in drp_toggling state.
> I remember the specification of TypeC does not depict what TCPM should do if it receives open/open in drp_toggling state.
> Maybe restart toggling is an option.
>
>> 3. If the answer of Q2 is yes, then I must ask why you tcpc chip+internal firmware
>> can't report further cc change event after your drp toggling starts to present Rp(I know
>> it firstly present Rd after you write to LOOK4CONNECTION, but then it should change
>> to present Rp, so it should be able to detect the Rd-device finally)
>
> Because RT1711H's internal firmware changes to attached state when Rd is re-plugged in(cc level is default Rp (around 400mV) now).
> Then, LOOK4CONNECTION is set and RT1711H changes CCx to Rd that makes it reports open/open(because cc level changes from default Rp(around 400mV) to 0mV)
>>
>>
>> >
>> > If TCPM does not enter SRC_ATTACHED state, RC.DRP will not be cleared.
>>
>> In this case, you don’t need clear RC.DRP, see TCPCI spec:
>> "Figure 4-18. Sink Disconnect"
>> TCPM sink doesn't clear it in whole sequence, just directly set it:
>> Restart DRP Toggling
>> PC.AutoDischargeDisconnect=0b
>> Set RC.DRP=1b (DRP)
>> Set RC.CC1=10b (Rd)
>> Set RC.CC2=10b (Rd)
>> COMMAND.Look4Connection (DRP toggle)
>>
>>
>> > When TCPM writes Rd/Rd or Rp/Rp in the drp_toggling function, it does not
>> > take effect until LOOK4CONNECTION command is set.
>> > The above condition causes RT1711H reports open/open at [53.188472]
>> >
>> > > [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [
>> > > 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
>> > Open
>> > > => Device(Rd) is plugged out
>> > >
>> > > [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
>> > > typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407]
>> > > typec_rt1711h
>> > > 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h
>> > 2-004e:
>> > > tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
>> > > tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
>> > > typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
>> > > typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
>> > > typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work
>> > of
>> > > TCPM calls start_drp_toggling function but does not set
>> > > LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
>> > > (RT1711H's internal firmware detects Rd plugged in. cc_change is
>> > > triggered and it will be vRd-connected at this moment) => TCPM writes
>> > > LOOK4CONNECTION command
>> > > - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while
>> > > writing Rd/Rd to RC.CC1/RC.CC2.
>> > > - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
>> > > pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling
>> > > (because
>> > > device(Rd) is already connected) and CC status will be open/open now
>> > > (because RT1711H presents Rd and device is connected(Rd))
>> > >
>> > > [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
>> > > Open => Enter RT1711H's irq handler and it reports open/open
>> > >
>> > > I think the point is to write RC.DRP = 0 at the beginning of
>> > > drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing
>> > > Rd/Rd to RC.CC1/RC.CC2 This operation will make RT1711H's internal
>> > > firmware restarts from disconnected state and toggles correctly.
>> > >
>> > > According to TCPCI spec (4.4.5.2):
>> > > It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing
>> > to
>> > > POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
>> > > using COMMAND.Look4Connection Restart DRP Toggling => It is
>> > > recommended the TCPM write ROLE_CONTROL.DRP=0 here Set
>> > >
>> > > This statement is_not_ recommend you do this(RC.DRP=0) for start drp
>> > toggling, Please carefully check the whole sentence:
>> > > "... as shown in Figure 4-16, "
>> > > If you look at "Figure 4-16. DRP Initialization and Connection Detection"
>> > > It gives clear drp toggling start operations:
>> > >
>> > > Set TCPC to DRP
>> > > - Read PS.TCPCInitializationStatus
>> > > - Write ROLE_CONTROL
>> > > - RC.DRP = 1b
>> > > - RC.CC2=01b or 10b
>> > > - RC.CC1=01b or 10b
>> > > - RC.CC1=RC.CC2
>> > > - Write COMMAND.Look4ConnectionPS.
>> > >
>> > > Above is all operations required to start drp toggling. You also can see
>> > RC.CCx = 01b or 10b, not fixed to be Rd, right?
>> > Yes, this one should be like your patch[07/12]. Write Rd or Rp to RC.CCx
>> > according to the cc parameter of drp_toggling function.
>> > >
>> > > Go on to check the Figure 4-16
>> > > After debounce, we need do following:
>> > >
>> > > ConnectionDetermine CC & VCONN
>> > > - Write RC.CC1 & RC.CC2 per decision
>> > > - Write RC.DRP=0
>> > > - Write TCPC_CONTROl.PlugOrientation
>> > > - Write PC.AutoDischargeDisconnect=1
>> > >  & PC.EnableVconnConnection
>> > >
>> > > Current existing tcpm+tcpci will not clear RC.DRP after attach, That means
>> > RC.DRP clear may be done after attach, not in start_drp_toggling.
>> > > I am not sure if this can resolve your problem, but I think it deserve a try,
>> > you can follow above operation sequence while entering attach state, refer
>> > to my patch[2]:
>> > >
>> > > [2]
>> > >
>> > https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fw
>> > ww
>> > > .spinics.net%2Flists%2Fdevicetree%2Fmsg216852.html&data=02%7C01%7
>> > Cjun.
>> > >
>> > li%40nxp.com%7C9117425550d24ddc86d808d57f6b1b4e%7C686ea1d3bc2b
>> > 4c6fa92c
>> > >
>> > d99c5c301635%7C0%7C0%7C636555020366483456&sdata=9%2BywYl%2BR
>> > PYtk60Wg6p
>> > > R63cCW2AnRXs%2BrINvvqUpqL18%3D&reserved=0
>> > >
>> > > diff --git a/drivers/staging/typec/tcpci.c
>> > > b/drivers/staging/typec/tcpci.c index 530a5d7..7145771 100644
>> > > --- a/drivers/staging/typec/tcpci.c
>> > > +++ b/drivers/staging/typec/tcpci.c
>> > > @@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>> > >                               enum typec_cc_polarity polarity)  {
>> > >         struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>> > > +       unsigned int reg;
>> > >         int ret;
>> > >
>> > >         ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, @@
>> > -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>> > >         if (ret < 0)
>> > >                 return ret;
>> > >
>> > > +       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
>> > > +       if (ret < 0)
>> > > +               return ret;
>> > > +
>> > > +       if (polarity == TYPEC_POLARITY_CC2)
>> > > +               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
>> > > +       else
>> > > +               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
>> > > +       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
>> > > +       reg &= ~TCPC_ROLE_CTRL_DRP;
>> > > +       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
>> > > +       if (ret < 0)
>> > > +               return ret;
>> > > +
>> > >         return 0;
>> > >  }
>> > >
>> > > PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
>> > > (smallest Rp to save power) Set RC.CC1=01b Set
>> > > RC.CC2=01bCOMMAND.Look4ConnectionNo
>> > >
>> > > It seems like it is not a general case here (because it is only
>> > > recommended but not necessary), we can move it to vendor_ops in the
>> > next patch.
>> > >
>> > > The TCPM should be able to cover all cases, and we should follow the
>> > recommended sequence(if what you are trying to do is really as spec says).
>> > Agree!
>> > My understanding is that we need to set RC.DRP to 0 every time before
>> > TCPM restarts toggling but not just for attached.
>>
>> Actually I have no objection on adding a RC.DRP clear, the question is
>> where is the right place to do this, till now I don’t see how this DRP bit keep set
>> while start drp toggling is causing problem, You want to start present Rd after write
>> CC1/CC2 to be Rd/Rd and before write to LOOK4CONNECTION, this is not required
>> per tcpci spec.
>
> According to TCPCI's specification, it is recommended the TCPM write RC.DRP = 0 before changing AutoDischargeDisconnecd.
> Maybe, an interface for controlling AutoDischargeDisconnecd can be added. Then clear RC.DRP in the beginning of that interface.
>>
>>
>> -Behavior after your patch:
>> //begin with Open as RC.DRP = 1
>> RC.CCx=Rd & RC.DRP = 0; //Start present Rd
>> Wait 1ms; // Still Rd
>> RC.CCx=Rd & RC.DRP = 1; //Open?
>> Look4CONNECTION = 1; //DRP toggling continue preset Rd
>>
>> Is my above CC state description correct? Is this what you want?
>
> Correct. But the purpose of setting RC.CCx = Rd & RC.DRP = 0 is to make RT1711H's internal firmware leave attached state.
> Because RT1711H is still presenting Rp after the device is plugged out, it's internal firmware enters attached state when the device re-plugged in.
> When we write RC.CCx = Rd & RC.DRP = 0, RT1711H's internal firmware leaves attached state. So it will keep toggling from Rd to Rp but not report open/open when LOOK4CONNECTION is set.
> After rechecking the specification of TCPCI, I think TCPC's internal firmware should start toggling from detached state when LOOK4CONNECTION is set even if RC.DRP is not cleared before
> I've discussed with my colleagues, we think this should be in vendor ops. I'll update it in the patch v6.
> Could I also apply your patch [1] in the patch v6?
> Thank you for your time to clarify this condition.
>>
>>
>> -Only apply my patches:
>> //begin with Open as RC.DRP = 1
>> RC.CCx=Rd & RC.DRP = 1; //still Open
>> Look4Connection = 1; //Start preset Rd
>>
>> > For RT1711H, it follows above flow. If it is not correct, this operation should
>> > be moved to vendor_ops.
>> > >
>> > > For your question:
>> > > Why RT1711H reports open/open after drp_toggling is enabled?
>> > > => See Note2 above.
>> > > This open/open is for you plug out the device, right?
>> > > => No, see Note2 above.
>> > > Why RT1711H can't report new cc change events after you plug in the
>> > > device?
>> > > => RT1711H can generate new cc change events after plugging in the
>> > device.
>> > > What cc change event tcpc will report on step 4?
>> > > => See Note1 above
>> > > Did you verify your change can pass the typec compliance test?
>> > > => We didn't test it yet but try to make all functions work correctly first.
>> > >
>> > > Best Regards,
>> > > *****************************
>> > > Shu-Fan Lee
>> > > Richtek Technology Corporation
>> > > TEL: +886-3-5526789 #2359
>> > > FAX: +886-3-5526612
>> > > *****************************
>> > >
>> >
>> > ************* Email Confidentiality Notice ********************
>> >
>> > The information contained in this e-mail message (including any attachments)
>> > may be confidential, proprietary, privileged, or otherwise exempt from
>> > disclosure under applicable laws. It is intended to be conveyed only to the
>> > designated recipient(s). Any use, dissemination, distribution, printing,
>> > retaining or copying of this e-mail (including its attachments) by unintended
>> > recipient(s) is strictly prohibited and may be unlawful. If you are not an
>> > intended recipient of this e-mail, or believe that you have received this
>> > e-mail in error, please notify the sender immediately (by replying to this
>> > e-mail), delete any and all copies of this e-mail (including any attachments)
>> > from your system, and do not disclose the content of this e-mail to any other
>> > person. Thank you!
>
>
>
>
> --
> Best Regards,
> 書帆




-- 
Best Regards,
書帆

^ permalink raw reply	[flat|nested] 22+ messages in thread

* staging: typec: handle vendor defined part and modify drp toggling flow
@ 2018-03-02 18:43                   ` ShuFanLee
  0 siblings, 0 replies; 22+ messages in thread
From: ShuFanLee @ 2018-03-02 18:43 UTC (permalink / raw)
  To: Jun Li
  Cc: shufan_lee(李書帆),
	heikki.krogerus, linux, greg, cy_huang(黃啟原),
	linux-kernel, linux-usb, dl-linux-imx

Hi,

  Sorry, I modify it to plain text mode and send again

2018-03-03 2:39 GMT+08:00 李書帆 <leechu729@gmail.com>:
>
> Hi Jun,
>
>   I think this operation should be moved to vendor's operation after rechecking the specification.
>
> 2018-03-02 22:38 GMT+08:00 Jun Li <jun.li@nxp.com>:
>>
>> Hi
>> > -----Original Message-----
>> > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
>> > Sent: 2018年3月1日 19:54
>> > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
>> > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
>> > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
>> > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
>> > <linux-imx@nxp.com>
>> > Subject: RE: [PATCH] staging: typec: handle vendor defined part and modify
>> > drp toggling flow
>> >
>> > Hi Jun,
>> >
>> > > -----Original Message-----
>> > > From: Jun Li [mailto:jun.li@nxp.com]
>> > > Sent: Thursday, March 01, 2018 6:06 PM
>> > > To: shufan_lee(李書帆); ShuFanLee; heikki.krogerus@linux.intel.com;
>> > > linux@roeck-us.net; greg@kroah.com
>> > > Cc: cy_huang(黃啟原); linux-kernel@vger.kernel.org;
>> > > linux-usb@vger.kernel.org; dl-linux-imx
>> > > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
>> > > modify drp toggling flow
>> > >
>> > > Hi Shufan
>> > >
>> > > Please don't top posting
>> > >
>> > > -----Original Message-----
>> > > From: shufan_lee(李書帆) [mailto:shufan_lee@richtek.com]
>> > > Sent: 2018年3月1日 16:49
>> > > To: Jun Li <jun.li@nxp.com>; ShuFanLee <leechu729@gmail.com>;
>> > > heikki.krogerus@linux.intel.com; linux@roeck-us.net; greg@kroah.com
>> > > Cc: cy_huang(黃啟原) <cy_huang@richtek.com>;
>> > > linux-kernel@vger.kernel.org; linux-usb@vger.kernel.org; dl-linux-imx
>> > > <linux-imx@nxp.com>
>> > > Subject: RE: [PATCH] staging: typec: handle vendor defined part and
>> > > modify drp toggling flow
>> > >
>> > > Hi Jun,
>> > >
>> > >   The attachment is waveform of the condition we met but I'm not sure
>> > > whether you can download the attachment.
>> > >   I add log in RT1711H it shows as following:
>> > >
>> > > You don't need add log by your own.
>> > > There is tcpm(./drivers/usb/typec/tcpm.c) log for debug already, which can
>> > show all the events and state transitions, you can get it by below command
>> > as I commented:
>> > >
>> > > cat /sys/kernel/debug/tcpm/xxxxx(your tcpc i2c device)
>> > >
>> > After applying your patch[2], TCPM log is as following:
>>
>> I assume you also applied my patch [1].
>> [1] https://www.spinics.net/lists/devicetree/msg216851.html
>>
> Yes, this patch is also applied.
>>
>> >
>> > [   53.050602] CC1: 0 -> 2, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
>> > connected]
>> > [   53.050613] state change DRP_TOGGLING -> SRC_ATTACH_WAIT
>> > [   53.050678] pending state change SRC_ATTACH_WAIT -> SNK_TRY @
>> > 200 ms
>> > => Rd is plugged out
>> > [   53.178804] CC1: 2 -> 0, CC2: 0 -> 0 [state SRC_ATTACH_WAIT, polarity 0,
>> > disconnected]
>> > [   53.178815] state change SRC_ATTACH_WAIT -> SRC_UNATTACHED
>> > => Rd is plugged in
>> > [   53.178874] Start DRP toggling
>> > [   53.188472] CC1: 0 -> 0, CC2: 0 -> 0 [state DRP_TOGGLING, polarity 0,
>> > disconnected]
>>
>> 1. The plug out and then plug in happens in 10ms? (53.188472 - 53.178804)
>> Was this done manually? Or by some special test method?
>
> It's done manually. If you can download the waveform attached in previous email, you can see Rd is plugged out/in within ms level.
> We connect a bridge board with test points of CC1, CC2 and GND to our platform's Typec receptacle. Then we can simulate a device plugging in/out by connecting/disconnecting a 5.1k resistor between CC1 and GND.
>
>>
>> 2. This is all tcpm log if you finally keep the Rd-device connected on typec
>> port? There is no more tcpm log after 53.188472 if you plug in Rd-device
>>
>> and don't remove it?
>
> Yes, RT1711H reports open/open to TCPM in drp_toggling state and stops toggling. Currently, TCPM does not restart drp_toggling if it receives open/open in drp_toggling state.
> I remember the specification of TypeC does not depict what TCPM should do if it receives open/open in drp_toggling state.
> Maybe restart toggling is an option.
>
>> 3. If the answer of Q2 is yes, then I must ask why you tcpc chip+internal firmware
>> can't report further cc change event after your drp toggling starts to present Rp(I know
>> it firstly present Rd after you write to LOOK4CONNECTION, but then it should change
>> to present Rp, so it should be able to detect the Rd-device finally)
>
> Because RT1711H's internal firmware changes to attached state when Rd is re-plugged in(cc level is default Rp (around 400mV) now).
> Then, LOOK4CONNECTION is set and RT1711H changes CCx to Rd that makes it reports open/open(because cc level changes from default Rp(around 400mV) to 0mV)
>>
>>
>> >
>> > If TCPM does not enter SRC_ATTACHED state, RC.DRP will not be cleared.
>>
>> In this case, you don’t need clear RC.DRP, see TCPCI spec:
>> "Figure 4-18. Sink Disconnect"
>> TCPM sink doesn't clear it in whole sequence, just directly set it:
>> Restart DRP Toggling
>> PC.AutoDischargeDisconnect=0b
>> Set RC.DRP=1b (DRP)
>> Set RC.CC1=10b (Rd)
>> Set RC.CC2=10b (Rd)
>> COMMAND.Look4Connection (DRP toggle)
>>
>>
>> > When TCPM writes Rd/Rd or Rp/Rp in the drp_toggling function, it does not
>> > take effect until LOOK4CONNECTION command is set.
>> > The above condition causes RT1711H reports open/open at [53.188472]
>> >
>> > > [ 914.937340] typec_rt1711h 2-004e: __rt1711h_irq_handler [
>> > > 914.943838] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
>> > Open
>> > > => Device(Rd) is plugged out
>> > >
>> > > [ 914.958041] typec_rt1711h 2-004e: tcpm_set_pd_rx 0 [ 914.963011]
>> > > typec_rt1711h 2-004e: tcpm_set_vbus vbus = 0 [ 914.968407]
>> > > typec_rt1711h
>> > > 2-004e: tcpm_set_vbus chg is already 0 [ 914.974541] typec_rt1711h
>> > 2-004e:
>> > > tcpm_set_vconn vconn is already 0 [ 914.980921] typec_rt1711h 2-004e:
>> > > tcpm_set_current_limit 0 ma, 0 mv (not implemented) [ 914.988894]
>> > > typec_rt1711h 2-004e: tcpm_set_polarity Polarity_CC1 [ 915.003201]
>> > > typec_rt1711h 2-004e: tcpm_set_roles Source Host [ 915.009264]
>> > > typec_rt1711h 2-004e: tcpm_start_drp_toggling => state_machine_work
>> > of
>> > > TCPM calls start_drp_toggling function but does not set
>> > > LOOK4CONNECTION command yet => (Note1) Device(Rd) is plugged in
>> > > (RT1711H's internal firmware detects Rd plugged in. cc_change is
>> > > triggered and it will be vRd-connected at this moment) => TCPM writes
>> > > LOOK4CONNECTION command
>> > > - Because RC.DRP is still 1, RT1711H will not pull cc1/cc2 to Rd while
>> > > writing Rd/Rd to RC.CC1/RC.CC2.
>> > > - (Note2) Right after LOOK4CONNECTION command is written, RT1711H
>> > > pulls CC to Rd's level (because RC.Role is Rd/Rd), stop toggling
>> > > (because
>> > > device(Rd) is already connected) and CC status will be open/open now
>> > > (because RT1711H presents Rd and device is connected(Rd))
>> > >
>> > > [ 915.037263] typec_rt1711h 2-004e: __tcpm_get_cc cc1 = Open, cc2 =
>> > > Open => Enter RT1711H's irq handler and it reports open/open
>> > >
>> > > I think the point is to write RC.DRP = 0 at the beginning of
>> > > drp_toggling so that RT1711H will pull cc1/cc2 to Rd while writing
>> > > Rd/Rd to RC.CC1/RC.CC2 This operation will make RT1711H's internal
>> > > firmware restarts from disconnected state and toggles correctly.
>> > >
>> > > According to TCPCI spec (4.4.5.2):
>> > > It is recommended the TCPM write ROLE_CONTROL.DRP=0 before writing
>> > to
>> > > POWER_CONTROL.AutoDischargeDisconnect and starting the DRP toggling
>> > > using COMMAND.Look4Connection Restart DRP Toggling => It is
>> > > recommended the TCPM write ROLE_CONTROL.DRP=0 here Set
>> > >
>> > > This statement is_not_ recommend you do this(RC.DRP=0) for start drp
>> > toggling, Please carefully check the whole sentence:
>> > > "... as shown in Figure 4-16, "
>> > > If you look at "Figure 4-16. DRP Initialization and Connection Detection"
>> > > It gives clear drp toggling start operations:
>> > >
>> > > Set TCPC to DRP
>> > > - Read PS.TCPCInitializationStatus
>> > > - Write ROLE_CONTROL
>> > > - RC.DRP = 1b
>> > > - RC.CC2=01b or 10b
>> > > - RC.CC1=01b or 10b
>> > > - RC.CC1=RC.CC2
>> > > - Write COMMAND.Look4ConnectionPS.
>> > >
>> > > Above is all operations required to start drp toggling. You also can see
>> > RC.CCx = 01b or 10b, not fixed to be Rd, right?
>> > Yes, this one should be like your patch[07/12]. Write Rd or Rp to RC.CCx
>> > according to the cc parameter of drp_toggling function.
>> > >
>> > > Go on to check the Figure 4-16
>> > > After debounce, we need do following:
>> > >
>> > > ConnectionDetermine CC & VCONN
>> > > - Write RC.CC1 & RC.CC2 per decision
>> > > - Write RC.DRP=0
>> > > - Write TCPC_CONTROl.PlugOrientation
>> > > - Write PC.AutoDischargeDisconnect=1
>> > >  & PC.EnableVconnConnection
>> > >
>> > > Current existing tcpm+tcpci will not clear RC.DRP after attach, That means
>> > RC.DRP clear may be done after attach, not in start_drp_toggling.
>> > > I am not sure if this can resolve your problem, but I think it deserve a try,
>> > you can follow above operation sequence while entering attach state, refer
>> > to my patch[2]:
>> > >
>> > > [2]
>> > >
>> > https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fw
>> > ww
>> > > .spinics.net%2Flists%2Fdevicetree%2Fmsg216852.html&data=02%7C01%7
>> > Cjun.
>> > >
>> > li%40nxp.com%7C9117425550d24ddc86d808d57f6b1b4e%7C686ea1d3bc2b
>> > 4c6fa92c
>> > >
>> > d99c5c301635%7C0%7C0%7C636555020366483456&sdata=9%2BywYl%2BR
>> > PYtk60Wg6p
>> > > R63cCW2AnRXs%2BrINvvqUpqL18%3D&reserved=0
>> > >
>> > > diff --git a/drivers/staging/typec/tcpci.c
>> > > b/drivers/staging/typec/tcpci.c index 530a5d7..7145771 100644
>> > > --- a/drivers/staging/typec/tcpci.c
>> > > +++ b/drivers/staging/typec/tcpci.c
>> > > @@ -184,6 +184,7 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>> > >                               enum typec_cc_polarity polarity)  {
>> > >         struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
>> > > +       unsigned int reg;
>> > >         int ret;
>> > >
>> > >         ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, @@
>> > -192,6 +193,20 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
>> > >         if (ret < 0)
>> > >                 return ret;
>> > >
>> > > +       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
>> > > +       if (ret < 0)
>> > > +               return ret;
>> > > +
>> > > +       if (polarity == TYPEC_POLARITY_CC2)
>> > > +               ret = TCPC_ROLE_CTRL_CC1_SHIFT;
>> > > +       else
>> > > +               ret = TCPC_ROLE_CTRL_CC2_SHIFT;
>> > > +       reg |= TCPC_ROLE_CTRL_CC_OPEN << ret;
>> > > +       reg &= ~TCPC_ROLE_CTRL_DRP;
>> > > +       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
>> > > +       if (ret < 0)
>> > > +               return ret;
>> > > +
>> > >         return 0;
>> > >  }
>> > >
>> > > PC.AutoDischargeDisconnect=0b Set RC.DRP=1b (DRP) Set RC.RpValue=00b
>> > > (smallest Rp to save power) Set RC.CC1=01b Set
>> > > RC.CC2=01bCOMMAND.Look4ConnectionNo
>> > >
>> > > It seems like it is not a general case here (because it is only
>> > > recommended but not necessary), we can move it to vendor_ops in the
>> > next patch.
>> > >
>> > > The TCPM should be able to cover all cases, and we should follow the
>> > recommended sequence(if what you are trying to do is really as spec says).
>> > Agree!
>> > My understanding is that we need to set RC.DRP to 0 every time before
>> > TCPM restarts toggling but not just for attached.
>>
>> Actually I have no objection on adding a RC.DRP clear, the question is
>> where is the right place to do this, till now I don’t see how this DRP bit keep set
>> while start drp toggling is causing problem, You want to start present Rd after write
>> CC1/CC2 to be Rd/Rd and before write to LOOK4CONNECTION, this is not required
>> per tcpci spec.
>
> According to TCPCI's specification, it is recommended the TCPM write RC.DRP = 0 before changing AutoDischargeDisconnecd.
> Maybe, an interface for controlling AutoDischargeDisconnecd can be added. Then clear RC.DRP in the beginning of that interface.
>>
>>
>> -Behavior after your patch:
>> //begin with Open as RC.DRP = 1
>> RC.CCx=Rd & RC.DRP = 0; //Start present Rd
>> Wait 1ms; // Still Rd
>> RC.CCx=Rd & RC.DRP = 1; //Open?
>> Look4CONNECTION = 1; //DRP toggling continue preset Rd
>>
>> Is my above CC state description correct? Is this what you want?
>
> Correct. But the purpose of setting RC.CCx = Rd & RC.DRP = 0 is to make RT1711H's internal firmware leave attached state.
> Because RT1711H is still presenting Rp after the device is plugged out, it's internal firmware enters attached state when the device re-plugged in.
> When we write RC.CCx = Rd & RC.DRP = 0, RT1711H's internal firmware leaves attached state. So it will keep toggling from Rd to Rp but not report open/open when LOOK4CONNECTION is set.
> After rechecking the specification of TCPCI, I think TCPC's internal firmware should start toggling from detached state when LOOK4CONNECTION is set even if RC.DRP is not cleared before
> I've discussed with my colleagues, we think this should be in vendor ops. I'll update it in the patch v6.
> Could I also apply your patch [1] in the patch v6?
> Thank you for your time to clarify this condition.
>>
>>
>> -Only apply my patches:
>> //begin with Open as RC.DRP = 1
>> RC.CCx=Rd & RC.DRP = 1; //still Open
>> Look4Connection = 1; //Start preset Rd
>>
>> > For RT1711H, it follows above flow. If it is not correct, this operation should
>> > be moved to vendor_ops.
>> > >
>> > > For your question:
>> > > Why RT1711H reports open/open after drp_toggling is enabled?
>> > > => See Note2 above.
>> > > This open/open is for you plug out the device, right?
>> > > => No, see Note2 above.
>> > > Why RT1711H can't report new cc change events after you plug in the
>> > > device?
>> > > => RT1711H can generate new cc change events after plugging in the
>> > device.
>> > > What cc change event tcpc will report on step 4?
>> > > => See Note1 above
>> > > Did you verify your change can pass the typec compliance test?
>> > > => We didn't test it yet but try to make all functions work correctly first.
>> > >
>> > > Best Regards,
>> > > *****************************
>> > > Shu-Fan Lee
>> > > Richtek Technology Corporation
>> > > TEL: +886-3-5526789 #2359
>> > > FAX: +886-3-5526612
>> > > *****************************
>> > >
>> >
>> > ************* Email Confidentiality Notice ********************
>> >
>> > The information contained in this e-mail message (including any attachments)
>> > may be confidential, proprietary, privileged, or otherwise exempt from
>> > disclosure under applicable laws. It is intended to be conveyed only to the
>> > designated recipient(s). Any use, dissemination, distribution, printing,
>> > retaining or copying of this e-mail (including its attachments) by unintended
>> > recipient(s) is strictly prohibited and may be unlawful. If you are not an
>> > intended recipient of this e-mail, or believe that you have received this
>> > e-mail in error, please notify the sender immediately (by replying to this
>> > e-mail), delete any and all copies of this e-mail (including any attachments)
>> > from your system, and do not disclose the content of this e-mail to any other
>> > person. Thank you!
>
>
>
>
> --
> Best Regards,
> 書帆

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2018-03-02 18:43 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-21 15:02 [PATCH] staging: typec: handle vendor defined part and modify drp toggling flow ShuFanLee
2018-02-21 15:02 ` ShuFanLee
2018-02-21 22:15 ` [PATCH] " Guenter Roeck
2018-02-21 22:15   ` Guenter Roeck
2018-02-28  2:09   ` [PATCH] " 李書帆
2018-02-28  2:14   ` 回覆: " shufan_lee(李書帆)
2018-02-28  2:14     ` shufan_lee(李書帆)
2018-02-22 10:16 ` [PATCH] " Jun Li
2018-02-22 10:16   ` Jun Li
2018-02-28  3:40   ` 回覆: [PATCH] " shufan_lee(李書帆)
2018-02-28  3:40     ` shufan_lee(李書帆)
2018-03-01  5:34     ` [PATCH] " Jun Li
2018-03-01  8:49       ` shufan_lee(李��帆)
2018-03-01 10:06         ` Jun Li
2018-03-01 10:06           ` Jun Li
2018-03-01 11:53           ` [PATCH] " shufan_lee(李書帆)
2018-03-01 11:53             ` shufan_lee(李書帆)
2018-03-02 14:38             ` [PATCH] " Jun Li
2018-03-02 14:38               ` Jun Li
2018-03-02 18:39               ` [PATCH] " 李書帆
2018-03-02 18:43                 ` 李書帆
2018-03-02 18:43                   ` ShuFanLee

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.