Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH v2 1/2] usb: chipidea: replace ci_role with usb_role
@ 2019-08-07  7:23 jun.li
  2019-08-07  7:23 ` [PATCH v2 2/2] usb: chipidea: add role switch class support jun.li
  0 siblings, 1 reply; 7+ messages in thread
From: jun.li @ 2019-08-07  7:23 UTC (permalink / raw)
  To: Peter.Chen; +Cc: gregkh, jun.li, linux-imx, linux-usb

From: Li Jun <jun.li@nxp.com>

Since there is usb_role which has similar definition like ci_role,
switch to use usb_role, then we can directly compare usb role
with a common definition, this can benifit on usb role switch
class support.

Signed-off-by: Li Jun <jun.li@nxp.com>
---
v1 -> v2
No change for this patch.

 drivers/usb/chipidea/ci.h      | 28 ++++++++++++----------------
 drivers/usb/chipidea/core.c    | 34 +++++++++++++++++-----------------
 drivers/usb/chipidea/debug.c   | 12 ++++++------
 drivers/usb/chipidea/host.c    |  6 +++---
 drivers/usb/chipidea/otg.c     | 14 +++++++-------
 drivers/usb/chipidea/otg.h     |  2 +-
 drivers/usb/chipidea/otg_fsm.c |  4 ++--
 drivers/usb/chipidea/udc.c     |  6 +++---
 8 files changed, 51 insertions(+), 55 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 6a2cc5c..82b86cd 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -16,6 +16,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg-fsm.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/role.h>
 #include <linux/ulpi/interface.h>
 
 /******************************************************************************
@@ -102,12 +103,6 @@ struct ci_hw_ep {
 	struct td_node				*pending_td;
 };
 
-enum ci_role {
-	CI_ROLE_HOST = 0,
-	CI_ROLE_GADGET,
-	CI_ROLE_END,
-};
-
 enum ci_revision {
 	CI_REVISION_1X = 10,	/* Revision 1.x */
 	CI_REVISION_20 = 20, /* Revision 2.0 */
@@ -208,8 +203,8 @@ struct ci_hdrc {
 	spinlock_t			lock;
 	struct hw_bank			hw_bank;
 	int				irq;
-	struct ci_role_driver		*roles[CI_ROLE_END];
-	enum ci_role			role;
+	struct ci_role_driver		*roles[USB_ROLE_DEVICE + 1];
+	enum usb_role			role;
 	bool				is_otg;
 	struct usb_otg			otg;
 	struct otg_fsm			fsm;
@@ -258,15 +253,16 @@ struct ci_hdrc {
 
 static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci)
 {
-	BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
+	WARN_ON((ci->role != USB_ROLE_HOST && ci->role != USB_ROLE_DEVICE) ||
+	       !ci->roles[ci->role]);
 	return ci->roles[ci->role];
 }
 
-static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
+static inline int ci_role_start(struct ci_hdrc *ci, enum usb_role role)
 {
 	int ret;
 
-	if (role >= CI_ROLE_END)
+	if (role != USB_ROLE_HOST && role != USB_ROLE_DEVICE)
 		return -EINVAL;
 
 	if (!ci->roles[role])
@@ -280,12 +276,12 @@ static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role)
 
 static inline void ci_role_stop(struct ci_hdrc *ci)
 {
-	enum ci_role role = ci->role;
+	enum usb_role role = ci->role;
 
-	if (role == CI_ROLE_END)
+	if (role == USB_ROLE_NONE)
 		return;
 
-	ci->role = CI_ROLE_END;
+	ci->role = USB_ROLE_NONE;
 
 	ci->roles[role]->stop(ci);
 }
@@ -416,8 +412,8 @@ static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci)
 #ifdef CONFIG_USB_OTG_FSM
 	struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
 
-	return ci->is_otg && ci->roles[CI_ROLE_HOST] &&
-		ci->roles[CI_ROLE_GADGET] && (otg_caps->srp_support ||
+	return ci->is_otg && ci->roles[USB_ROLE_HOST] &&
+		ci->roles[USB_ROLE_DEVICE] && (otg_caps->srp_support ||
 		otg_caps->hnp_support || otg_caps->adp_support);
 #else
 	return false;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 26062d6..bc24c5b 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -581,7 +581,7 @@ static irqreturn_t ci_irq(int irq, void *data)
 	}
 
 	/* Handle device/host interrupt */
-	if (ci->role != CI_ROLE_END)
+	if (ci->role != USB_ROLE_NONE)
 		ret = ci_role(ci)->irq(ci);
 
 	return ret;
@@ -835,7 +835,7 @@ static inline void ci_role_destroy(struct ci_hdrc *ci)
 {
 	ci_hdrc_gadget_destroy(ci);
 	ci_hdrc_host_destroy(ci);
-	if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
+	if (ci->is_otg && ci->roles[USB_ROLE_DEVICE])
 		ci_hdrc_otg_destroy(ci);
 }
 
@@ -860,7 +860,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
 {
 	struct ci_hdrc *ci = dev_get_drvdata(dev);
 
-	if (ci->role != CI_ROLE_END)
+	if (ci->role != USB_ROLE_NONE)
 		return sprintf(buf, "%s\n", ci_role(ci)->name);
 
 	return 0;
@@ -870,27 +870,27 @@ static ssize_t role_store(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t n)
 {
 	struct ci_hdrc *ci = dev_get_drvdata(dev);
-	enum ci_role role;
+	enum usb_role role;
 	int ret;
 
-	if (!(ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])) {
+	if (!(ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE])) {
 		dev_warn(dev, "Current configuration is not dual-role, quit\n");
 		return -EPERM;
 	}
 
-	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+	for (role = USB_ROLE_DEVICE; role > USB_ROLE_NONE; role--)
 		if (!strncmp(buf, ci->roles[role]->name,
 			     strlen(ci->roles[role]->name)))
 			break;
 
-	if (role == CI_ROLE_END || role == ci->role)
+	if (role == USB_ROLE_NONE || role == ci->role)
 		return -EINVAL;
 
 	pm_runtime_get_sync(dev);
 	disable_irq(ci->irq);
 	ci_role_stop(ci);
 	ret = ci_role_start(ci, role);
-	if (!ret && ci->role == CI_ROLE_GADGET)
+	if (!ret && ci->role == USB_ROLE_DEVICE)
 		ci_handle_vbus_change(ci);
 	enable_irq(ci->irq);
 	pm_runtime_put_sync(dev);
@@ -1037,13 +1037,13 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
+	if (!ci->roles[USB_ROLE_HOST] && !ci->roles[USB_ROLE_DEVICE]) {
 		dev_err(dev, "no supported roles\n");
 		ret = -ENODEV;
 		goto deinit_gadget;
 	}
 
-	if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) {
+	if (ci->is_otg && ci->roles[USB_ROLE_DEVICE]) {
 		ret = ci_hdrc_otg_init(ci);
 		if (ret) {
 			dev_err(dev, "init otg fails, ret = %d\n", ret);
@@ -1051,7 +1051,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
 		if (ci->is_otg) {
 			ci->role = ci_otg_role(ci);
 			/* Enable ID change irq */
@@ -1062,17 +1062,17 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 			 * role switch, the defalt role is gadget, and the
 			 * user can switch it through debugfs.
 			 */
-			ci->role = CI_ROLE_GADGET;
+			ci->role = USB_ROLE_DEVICE;
 		}
 	} else {
-		ci->role = ci->roles[CI_ROLE_HOST]
-			? CI_ROLE_HOST
-			: CI_ROLE_GADGET;
+		ci->role = ci->roles[USB_ROLE_HOST]
+			? USB_ROLE_HOST
+			: USB_ROLE_DEVICE;
 	}
 
 	if (!ci_otg_is_fsm_mode(ci)) {
 		/* only update vbus status for peripheral */
-		if (ci->role == CI_ROLE_GADGET)
+		if (ci->role == USB_ROLE_DEVICE)
 			ci_handle_vbus_change(ci);
 
 		ret = ci_role_start(ci, ci->role);
@@ -1115,7 +1115,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 remove_debug:
 	dbg_remove_files(ci);
 stop:
-	if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
+	if (ci->is_otg && ci->roles[USB_ROLE_DEVICE])
 		ci_hdrc_otg_destroy(ci);
 deinit_gadget:
 	ci_hdrc_gadget_destroy(ci);
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index fcc91a3..a3c022e 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -124,7 +124,7 @@ static int ci_qheads_show(struct seq_file *s, void *data)
 	unsigned long flags;
 	unsigned i, j;
 
-	if (ci->role != CI_ROLE_GADGET) {
+	if (ci->role != USB_ROLE_DEVICE) {
 		seq_printf(s, "not in gadget mode\n");
 		return 0;
 	}
@@ -158,7 +158,7 @@ static int ci_requests_show(struct seq_file *s, void *data)
 	struct td_node *node, *tmpnode;
 	unsigned i, j, qsize = sizeof(struct ci_hw_td)/sizeof(u32);
 
-	if (ci->role != CI_ROLE_GADGET) {
+	if (ci->role != USB_ROLE_DEVICE) {
 		seq_printf(s, "not in gadget mode\n");
 		return 0;
 	}
@@ -251,7 +251,7 @@ static int ci_role_show(struct seq_file *s, void *data)
 {
 	struct ci_hdrc *ci = s->private;
 
-	if (ci->role != CI_ROLE_END)
+	if (ci->role != USB_ROLE_NONE)
 		seq_printf(s, "%s\n", ci_role(ci)->name);
 
 	return 0;
@@ -262,20 +262,20 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
 {
 	struct seq_file *s = file->private_data;
 	struct ci_hdrc *ci = s->private;
-	enum ci_role role;
+	enum usb_role role;
 	char buf[8];
 	int ret;
 
 	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
 		return -EFAULT;
 
-	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+	for (role = USB_ROLE_DEVICE; role > USB_ROLE_NONE; role--)
 		if (ci->roles[role] &&
 		    !strncmp(buf, ci->roles[role]->name,
 			     strlen(ci->roles[role]->name)))
 			break;
 
-	if (role == CI_ROLE_END || role == ci->role)
+	if (role == USB_ROLE_NONE || role == ci->role)
 		return -EINVAL;
 
 	pm_runtime_get_sync(ci->dev);
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index b45ceb9..dcce43d 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -198,7 +198,7 @@ static void host_stop(struct ci_hdrc *ci)
 			ci->platdata->notify_event(ci,
 				CI_HDRC_CONTROLLER_STOPPED_EVENT);
 		usb_remove_hcd(hcd);
-		ci->role = CI_ROLE_END;
+		ci->role = USB_ROLE_NONE;
 		synchronize_irq(ci->irq);
 		usb_put_hcd(hcd);
 		if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci) &&
@@ -216,7 +216,7 @@ static void host_stop(struct ci_hdrc *ci)
 
 void ci_hdrc_host_destroy(struct ci_hdrc *ci)
 {
-	if (ci->role == CI_ROLE_HOST && ci->hcd)
+	if (ci->role == USB_ROLE_HOST && ci->hcd)
 		host_stop(ci);
 }
 
@@ -362,7 +362,7 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
 	rdrv->stop	= host_stop;
 	rdrv->irq	= host_irq;
 	rdrv->name	= "host";
-	ci->roles[CI_ROLE_HOST] = rdrv;
+	ci->roles[USB_ROLE_HOST] = rdrv;
 
 	return 0;
 }
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index f25d482..5bde0b5 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -117,11 +117,11 @@ void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
  * ci_otg_role - pick role based on ID pin state
  * @ci: the controller
  */
-enum ci_role ci_otg_role(struct ci_hdrc *ci)
+enum usb_role ci_otg_role(struct ci_hdrc *ci)
 {
-	enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)
-		? CI_ROLE_GADGET
-		: CI_ROLE_HOST;
+	enum usb_role role = hw_read_otgsc(ci, OTGSC_ID)
+		? USB_ROLE_DEVICE
+		: USB_ROLE_HOST;
 
 	return role;
 }
@@ -164,7 +164,7 @@ static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci)
 
 static void ci_handle_id_switch(struct ci_hdrc *ci)
 {
-	enum ci_role role = ci_otg_role(ci);
+	enum usb_role role = ci_otg_role(ci);
 
 	if (role != ci->role) {
 		dev_dbg(ci->dev, "switching from %s to %s\n",
@@ -172,7 +172,7 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
 
 		ci_role_stop(ci);
 
-		if (role == CI_ROLE_GADGET &&
+		if (role == USB_ROLE_DEVICE &&
 				IS_ERR(ci->platdata->vbus_extcon.edev))
 			/*
 			 * Wait vbus lower than OTGSC_BSV before connecting
@@ -185,7 +185,7 @@ static void ci_handle_id_switch(struct ci_hdrc *ci)
 
 		ci_role_start(ci, role);
 		/* vbus change may have already occurred */
-		if (role == CI_ROLE_GADGET)
+		if (role == USB_ROLE_DEVICE)
 			ci_handle_vbus_change(ci);
 	}
 }
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index 4f8b817..f64bfc6 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -12,7 +12,7 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask);
 void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data);
 int ci_hdrc_otg_init(struct ci_hdrc *ci);
 void ci_hdrc_otg_destroy(struct ci_hdrc *ci);
-enum ci_role ci_otg_role(struct ci_hdrc *ci);
+enum usb_role ci_otg_role(struct ci_hdrc *ci);
 void ci_handle_vbus_change(struct ci_hdrc *ci);
 static inline void ci_otg_queue_work(struct ci_hdrc *ci)
 {
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 6ed4b00..78c96a1 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -547,10 +547,10 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
 
 	if (on) {
 		ci_role_stop(ci);
-		ci_role_start(ci, CI_ROLE_HOST);
+		ci_role_start(ci, USB_ROLE_HOST);
 	} else {
 		ci_role_stop(ci);
-		ci_role_start(ci, CI_ROLE_GADGET);
+		ci_role_start(ci, USB_ROLE_DEVICE);
 	}
 	return 0;
 }
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 6a5ee8e..e1d745f7 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1606,7 +1606,7 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
 	 * Data+ pullup controlled by OTG state machine in OTG fsm mode;
 	 * and don't touch Data+ in host mode for dual role config.
 	 */
-	if (ci_otg_is_fsm_mode(ci) || ci->role == CI_ROLE_HOST)
+	if (ci_otg_is_fsm_mode(ci) || ci->role == USB_ROLE_DEVICE)
 		return 0;
 
 	pm_runtime_get_sync(&ci->gadget.dev);
@@ -1973,7 +1973,7 @@ static int udc_start(struct ci_hdrc *ci)
  */
 void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
 {
-	if (!ci->roles[CI_ROLE_GADGET])
+	if (!ci->roles[USB_ROLE_DEVICE])
 		return;
 
 	usb_del_gadget_udc(&ci->gadget);
@@ -2039,7 +2039,7 @@ int ci_hdrc_gadget_init(struct ci_hdrc *ci)
 
 	ret = udc_start(ci);
 	if (!ret)
-		ci->roles[CI_ROLE_GADGET] = rdrv;
+		ci->roles[USB_ROLE_DEVICE] = rdrv;
 
 	return ret;
 }
-- 
2.7.4


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

* [PATCH v2 2/2] usb: chipidea: add role switch class support
  2019-08-07  7:23 [PATCH v2 1/2] usb: chipidea: replace ci_role with usb_role jun.li
@ 2019-08-07  7:23 ` jun.li
  2019-08-07 18:39   ` kbuild test robot
                     ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: jun.li @ 2019-08-07  7:23 UTC (permalink / raw)
  To: Peter.Chen; +Cc: gregkh, jun.li, linux-imx, linux-usb

From: Li Jun <jun.li@nxp.com>

USB role is fully controlled by usb role switch consumer(e.g. typec),
usb port can be at host mode(USB_ROLE_HOST), device mode connected to
host(USB_ROLE_DEVICE), or not connecting any parter(USB_ROLE_NONE).

Signed-off-by: Li Jun <jun.li@nxp.com>
---

Change for v2:
- Support USB_ROLE_NONE, which for usb port not connecting any
  device or host, and will be in low power mode.

 drivers/usb/chipidea/ci.h   |   3 ++
 drivers/usb/chipidea/core.c | 120 +++++++++++++++++++++++++++++++++-----------
 drivers/usb/chipidea/otg.c  |  20 ++++++++
 3 files changed, 114 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 82b86cd..f0aec1d 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -205,6 +205,7 @@ struct ci_hdrc {
 	int				irq;
 	struct ci_role_driver		*roles[USB_ROLE_DEVICE + 1];
 	enum usb_role			role;
+	enum usb_role			target_role;
 	bool				is_otg;
 	struct usb_otg			otg;
 	struct otg_fsm			fsm;
@@ -212,6 +213,7 @@ struct ci_hdrc {
 	ktime_t				hr_timeouts[NUM_OTG_FSM_TIMERS];
 	unsigned			enabled_otg_timer_bits;
 	enum otg_fsm_timer		next_otg_timer;
+	struct usb_role_switch		*role_switch;
 	struct work_struct		work;
 	struct workqueue_struct		*wq;
 
@@ -244,6 +246,7 @@ struct ci_hdrc {
 	struct dentry			*debugfs;
 	bool				id_event;
 	bool				b_sess_valid_event;
+	bool				role_switch_event;
 	bool				imx28_write_fix;
 	bool				supports_runtime_pm;
 	bool				in_lpm;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index bc24c5b..965ce17 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -587,6 +587,42 @@ static irqreturn_t ci_irq(int irq, void *data)
 	return ret;
 }
 
+static int ci_usb_role_switch_set(struct device *dev, enum usb_role role)
+{
+	struct ci_hdrc *ci = dev_get_drvdata(dev);
+	unsigned long flags;
+
+	if (ci->role == role)
+		return 0;
+
+	spin_lock_irqsave(&ci->lock, flags);
+	ci->role_switch_event = true;
+	ci->target_role = role;
+	spin_unlock_irqrestore(&ci->lock, flags);
+
+	ci_otg_queue_work(ci);
+
+	return 0;
+}
+
+static enum usb_role ci_usb_role_switch_get(struct device *dev)
+{
+	struct ci_hdrc *ci = dev_get_drvdata(dev);
+	unsigned long flags;
+	enum usb_role role;
+
+	spin_lock_irqsave(&ci->lock, flags);
+	role = ci->role;
+	spin_unlock_irqrestore(&ci->lock, flags);
+
+	return role;
+}
+
+static struct usb_role_switch_desc ci_role_switch = {
+	.set = ci_usb_role_switch_set,
+	.get = ci_usb_role_switch_get,
+};
+
 static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
 			     void *ptr)
 {
@@ -689,6 +725,9 @@ static int ci_get_platdata(struct device *dev,
 	if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
 		platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
 
+	if (device_property_read_bool(dev, "usb-role-switch"))
+		ci_role_switch.fwnode = dev->fwnode;
+
 	ext_id = ERR_PTR(-ENODEV);
 	ext_vbus = ERR_PTR(-ENODEV);
 	if (of_property_read_bool(dev->of_node, "extcon")) {
@@ -908,6 +947,43 @@ static const struct attribute_group ci_attr_group = {
 	.attrs = ci_attrs,
 };
 
+static int ci_start_initial_role(struct ci_hdrc *ci)
+{
+	int ret = 0;
+
+	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
+		if (ci->is_otg) {
+			ci->role = ci_otg_role(ci);
+			/* Enable ID change irq */
+			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
+		} else {
+			/*
+			 * If the controller is not OTG capable, but support
+			 * role switch, the defalt role is gadget, and the
+			 * user can switch it through debugfs.
+			 */
+			ci->role = USB_ROLE_DEVICE;
+		}
+	} else {
+		ci->role = ci->roles[USB_ROLE_HOST]
+			? USB_ROLE_HOST
+			: USB_ROLE_DEVICE;
+	}
+
+	if (!ci_otg_is_fsm_mode(ci)) {
+		/* only update vbus status for peripheral */
+		if (ci->role == USB_ROLE_DEVICE)
+			ci_handle_vbus_change(ci);
+
+		ret = ci_role_start(ci, ci->role);
+		if (ret)
+			dev_err(ci->dev, "can't start %s role\n",
+						ci_role(ci)->name);
+	}
+
+	return ret;
+}
+
 static int ci_hdrc_probe(struct platform_device *pdev)
 {
 	struct device	*dev = &pdev->dev;
@@ -1051,36 +1127,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 		}
 	}
 
-	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
-		if (ci->is_otg) {
-			ci->role = ci_otg_role(ci);
-			/* Enable ID change irq */
-			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
-		} else {
-			/*
-			 * If the controller is not OTG capable, but support
-			 * role switch, the defalt role is gadget, and the
-			 * user can switch it through debugfs.
-			 */
-			ci->role = USB_ROLE_DEVICE;
-		}
-	} else {
-		ci->role = ci->roles[USB_ROLE_HOST]
-			? USB_ROLE_HOST
-			: USB_ROLE_DEVICE;
-	}
-
-	if (!ci_otg_is_fsm_mode(ci)) {
-		/* only update vbus status for peripheral */
-		if (ci->role == USB_ROLE_DEVICE)
-			ci_handle_vbus_change(ci);
-
-		ret = ci_role_start(ci, ci->role);
-		if (ret) {
-			dev_err(dev, "can't start %s role\n",
-						ci_role(ci)->name);
+	if (!ci_role_switch.fwnode) {
+		ret = ci_start_initial_role(ci);
+		if (ret)
 			goto stop;
-		}
 	}
 
 	ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
@@ -1092,6 +1142,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	if (ret)
 		goto stop;
 
+	if (ci_role_switch.fwnode) {
+		ci->role_switch = usb_role_switch_register(dev,
+					&ci_role_switch);
+		if (IS_ERR(ci->role_switch)) {
+			ret = PTR_ERR(ci->role_switch);
+			goto stop;
+		}
+	}
+
 	if (ci->supports_runtime_pm) {
 		pm_runtime_set_active(&pdev->dev);
 		pm_runtime_enable(&pdev->dev);
@@ -1133,6 +1192,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
 {
 	struct ci_hdrc *ci = platform_get_drvdata(pdev);
 
+	if (ci->role_switch)
+		usb_role_switch_unregister(ci->role_switch);
+
 	if (ci->supports_runtime_pm) {
 		pm_runtime_get_sync(&pdev->dev);
 		pm_runtime_disable(&pdev->dev);
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 5bde0b5..03675b6 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -214,6 +214,26 @@ static void ci_otg_work(struct work_struct *work)
 		ci_handle_vbus_change(ci);
 	}
 
+	if (ci->role_switch_event) {
+		ci->role_switch_event = false;
+
+		/* Stop current role */
+		if (ci->role == USB_ROLE_DEVICE) {
+			usb_gadget_vbus_disconnect(&ci->gadget);
+			ci->role = USB_ROLE_NONE;
+		} else if (ci->role == USB_ROLE_HOST) {
+			ci_role_stop(ci);
+		}
+
+		/* Start target role */
+		if (ci->target_role == USB_ROLE_DEVICE) {
+			usb_gadget_vbus_connect(&ci->gadget);
+			ci->role = USB_ROLE_DEVICE;
+		} else if (ci->target_role == USB_ROLE_HOST) {
+			ci_role_start(ci, USB_ROLE_HOST);
+		}
+	}
+
 	pm_runtime_put_sync(ci->dev);
 
 	enable_irq(ci->irq);
-- 
2.7.4


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

* Re: [PATCH v2 2/2] usb: chipidea: add role switch class support
  2019-08-07  7:23 ` [PATCH v2 2/2] usb: chipidea: add role switch class support jun.li
@ 2019-08-07 18:39   ` kbuild test robot
  2019-08-08  8:22   ` kbuild test robot
  2019-08-08  9:30   ` Peter Chen
  2 siblings, 0 replies; 7+ messages in thread
From: kbuild test robot @ 2019-08-07 18:39 UTC (permalink / raw)
  To: jun.li; +Cc: kbuild-all, Peter.Chen, gregkh, jun.li, linux-imx, linux-usb

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

Hi,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.3-rc3 next-20190807]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/jun-li-nxp-com/usb-chipidea-replace-ci_role-with-usb_role/20190807-185922
config: arm-imx_v6_v7_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 7.4.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        GCC_VERSION=7.4.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   drivers/usb/chipidea/core.o: In function `ci_hdrc_remove':
>> core.c:(.text+0x900): undefined reference to `usb_role_switch_unregister'
   drivers/usb/chipidea/core.o: In function `ci_hdrc_probe':
>> core.c:(.text+0x152c): undefined reference to `usb_role_switch_register'

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 36386 bytes --]

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

* Re: [PATCH v2 2/2] usb: chipidea: add role switch class support
  2019-08-07  7:23 ` [PATCH v2 2/2] usb: chipidea: add role switch class support jun.li
  2019-08-07 18:39   ` kbuild test robot
@ 2019-08-08  8:22   ` kbuild test robot
  2019-08-08  9:30   ` Peter Chen
  2 siblings, 0 replies; 7+ messages in thread
From: kbuild test robot @ 2019-08-08  8:22 UTC (permalink / raw)
  To: jun.li; +Cc: kbuild-all, Peter.Chen, gregkh, jun.li, linux-imx, linux-usb

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

Hi,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.3-rc3 next-20190807]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/jun-li-nxp-com/usb-chipidea-replace-ci_role-with-usb_role/20190807-185922
config: x86_64-randconfig-c002-201931 (attached as .config)
compiler: gcc-7 (Debian 7.4.0-10) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   ld: drivers/usb/chipidea/core.o: in function `ci_hdrc_remove':
>> drivers/usb/chipidea/core.c:1196: undefined reference to `usb_role_switch_unregister'
   ld: drivers/usb/chipidea/core.o: in function `ci_hdrc_probe':
>> drivers/usb/chipidea/core.c:1146: undefined reference to `usb_role_switch_register'

vim +1196 drivers/usb/chipidea/core.c

   986	
   987	static int ci_hdrc_probe(struct platform_device *pdev)
   988	{
   989		struct device	*dev = &pdev->dev;
   990		struct ci_hdrc	*ci;
   991		struct resource	*res;
   992		void __iomem	*base;
   993		int		ret;
   994		enum usb_dr_mode dr_mode;
   995	
   996		if (!dev_get_platdata(dev)) {
   997			dev_err(dev, "platform data missing\n");
   998			return -ENODEV;
   999		}
  1000	
  1001		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  1002		base = devm_ioremap_resource(dev, res);
  1003		if (IS_ERR(base))
  1004			return PTR_ERR(base);
  1005	
  1006		ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
  1007		if (!ci)
  1008			return -ENOMEM;
  1009	
  1010		spin_lock_init(&ci->lock);
  1011		ci->dev = dev;
  1012		ci->platdata = dev_get_platdata(dev);
  1013		ci->imx28_write_fix = !!(ci->platdata->flags &
  1014			CI_HDRC_IMX28_WRITE_FIX);
  1015		ci->supports_runtime_pm = !!(ci->platdata->flags &
  1016			CI_HDRC_SUPPORTS_RUNTIME_PM);
  1017		platform_set_drvdata(pdev, ci);
  1018	
  1019		ret = hw_device_init(ci, base);
  1020		if (ret < 0) {
  1021			dev_err(dev, "can't initialize hardware\n");
  1022			return -ENODEV;
  1023		}
  1024	
  1025		ret = ci_ulpi_init(ci);
  1026		if (ret)
  1027			return ret;
  1028	
  1029		if (ci->platdata->phy) {
  1030			ci->phy = ci->platdata->phy;
  1031		} else if (ci->platdata->usb_phy) {
  1032			ci->usb_phy = ci->platdata->usb_phy;
  1033		} else {
  1034			/* Look for a generic PHY first */
  1035			ci->phy = devm_phy_get(dev->parent, "usb-phy");
  1036	
  1037			if (PTR_ERR(ci->phy) == -EPROBE_DEFER) {
  1038				ret = -EPROBE_DEFER;
  1039				goto ulpi_exit;
  1040			} else if (IS_ERR(ci->phy)) {
  1041				ci->phy = NULL;
  1042			}
  1043	
  1044			/* Look for a legacy USB PHY from device-tree next */
  1045			if (!ci->phy) {
  1046				ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent,
  1047									  "phys", 0);
  1048	
  1049				if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) {
  1050					ret = -EPROBE_DEFER;
  1051					goto ulpi_exit;
  1052				} else if (IS_ERR(ci->usb_phy)) {
  1053					ci->usb_phy = NULL;
  1054				}
  1055			}
  1056	
  1057			/* Look for any registered legacy USB PHY as last resort */
  1058			if (!ci->phy && !ci->usb_phy) {
  1059				ci->usb_phy = devm_usb_get_phy(dev->parent,
  1060							       USB_PHY_TYPE_USB2);
  1061	
  1062				if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) {
  1063					ret = -EPROBE_DEFER;
  1064					goto ulpi_exit;
  1065				} else if (IS_ERR(ci->usb_phy)) {
  1066					ci->usb_phy = NULL;
  1067				}
  1068			}
  1069	
  1070			/* No USB PHY was found in the end */
  1071			if (!ci->phy && !ci->usb_phy) {
  1072				ret = -ENXIO;
  1073				goto ulpi_exit;
  1074			}
  1075		}
  1076	
  1077		ret = ci_usb_phy_init(ci);
  1078		if (ret) {
  1079			dev_err(dev, "unable to init phy: %d\n", ret);
  1080			return ret;
  1081		}
  1082	
  1083		ci->hw_bank.phys = res->start;
  1084	
  1085		ci->irq = platform_get_irq(pdev, 0);
  1086		if (ci->irq < 0) {
  1087			dev_err(dev, "missing IRQ\n");
  1088			ret = ci->irq;
  1089			goto deinit_phy;
  1090		}
  1091	
  1092		ci_get_otg_capable(ci);
  1093	
  1094		dr_mode = ci->platdata->dr_mode;
  1095		/* initialize role(s) before the interrupt is requested */
  1096		if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
  1097			ret = ci_hdrc_host_init(ci);
  1098			if (ret) {
  1099				if (ret == -ENXIO)
  1100					dev_info(dev, "doesn't support host\n");
  1101				else
  1102					goto deinit_phy;
  1103			}
  1104		}
  1105	
  1106		if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
  1107			ret = ci_hdrc_gadget_init(ci);
  1108			if (ret) {
  1109				if (ret == -ENXIO)
  1110					dev_info(dev, "doesn't support gadget\n");
  1111				else
  1112					goto deinit_host;
  1113			}
  1114		}
  1115	
  1116		if (!ci->roles[USB_ROLE_HOST] && !ci->roles[USB_ROLE_DEVICE]) {
  1117			dev_err(dev, "no supported roles\n");
  1118			ret = -ENODEV;
  1119			goto deinit_gadget;
  1120		}
  1121	
  1122		if (ci->is_otg && ci->roles[USB_ROLE_DEVICE]) {
  1123			ret = ci_hdrc_otg_init(ci);
  1124			if (ret) {
  1125				dev_err(dev, "init otg fails, ret = %d\n", ret);
  1126				goto deinit_gadget;
  1127			}
  1128		}
  1129	
  1130		if (!ci_role_switch.fwnode) {
  1131			ret = ci_start_initial_role(ci);
  1132			if (ret)
  1133				goto stop;
  1134		}
  1135	
  1136		ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
  1137				ci->platdata->name, ci);
  1138		if (ret)
  1139			goto stop;
  1140	
  1141		ret = ci_extcon_register(ci);
  1142		if (ret)
  1143			goto stop;
  1144	
  1145		if (ci_role_switch.fwnode) {
> 1146			ci->role_switch = usb_role_switch_register(dev,
  1147						&ci_role_switch);
  1148			if (IS_ERR(ci->role_switch)) {
  1149				ret = PTR_ERR(ci->role_switch);
  1150				goto stop;
  1151			}
  1152		}
  1153	
  1154		if (ci->supports_runtime_pm) {
  1155			pm_runtime_set_active(&pdev->dev);
  1156			pm_runtime_enable(&pdev->dev);
  1157			pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
  1158			pm_runtime_mark_last_busy(ci->dev);
  1159			pm_runtime_use_autosuspend(&pdev->dev);
  1160		}
  1161	
  1162		if (ci_otg_is_fsm_mode(ci))
  1163			ci_hdrc_otg_fsm_start(ci);
  1164	
  1165		device_set_wakeup_capable(&pdev->dev, true);
  1166		dbg_create_files(ci);
  1167	
  1168		ret = sysfs_create_group(&dev->kobj, &ci_attr_group);
  1169		if (ret)
  1170			goto remove_debug;
  1171	
  1172		return 0;
  1173	
  1174	remove_debug:
  1175		dbg_remove_files(ci);
  1176	stop:
  1177		if (ci->is_otg && ci->roles[USB_ROLE_DEVICE])
  1178			ci_hdrc_otg_destroy(ci);
  1179	deinit_gadget:
  1180		ci_hdrc_gadget_destroy(ci);
  1181	deinit_host:
  1182		ci_hdrc_host_destroy(ci);
  1183	deinit_phy:
  1184		ci_usb_phy_exit(ci);
  1185	ulpi_exit:
  1186		ci_ulpi_exit(ci);
  1187	
  1188		return ret;
  1189	}
  1190	
  1191	static int ci_hdrc_remove(struct platform_device *pdev)
  1192	{
  1193		struct ci_hdrc *ci = platform_get_drvdata(pdev);
  1194	
  1195		if (ci->role_switch)
> 1196			usb_role_switch_unregister(ci->role_switch);
  1197	
  1198		if (ci->supports_runtime_pm) {
  1199			pm_runtime_get_sync(&pdev->dev);
  1200			pm_runtime_disable(&pdev->dev);
  1201			pm_runtime_put_noidle(&pdev->dev);
  1202		}
  1203	
  1204		dbg_remove_files(ci);
  1205		sysfs_remove_group(&ci->dev->kobj, &ci_attr_group);
  1206		ci_role_destroy(ci);
  1207		ci_hdrc_enter_lpm(ci, true);
  1208		ci_usb_phy_exit(ci);
  1209		ci_ulpi_exit(ci);
  1210	
  1211		return 0;
  1212	}
  1213	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 36907 bytes --]

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

* RE: [PATCH v2 2/2] usb: chipidea: add role switch class support
  2019-08-07  7:23 ` [PATCH v2 2/2] usb: chipidea: add role switch class support jun.li
  2019-08-07 18:39   ` kbuild test robot
  2019-08-08  8:22   ` kbuild test robot
@ 2019-08-08  9:30   ` Peter Chen
  2019-08-09  7:29     ` Jun Li
  2 siblings, 1 reply; 7+ messages in thread
From: Peter Chen @ 2019-08-08  9:30 UTC (permalink / raw)
  To: Jun Li; +Cc: gregkh, Jun Li, dl-linux-imx, linux-usb

 
> USB role is fully controlled by usb role switch consumer(e.g. typec), usb port can be
> at host mode(USB_ROLE_HOST), device mode connected to
> host(USB_ROLE_DEVICE), or not connecting any parter(USB_ROLE_NONE).
> 

%s/parter/partner ?

Are there any ways you could get external cable status from usb-switch or type-c like external
connector? If there are, you could update otgsc value for otgsc_read, or change cable status,
and avoid changing common handling, like ci_hdrc_probe and  ci_otg_work. And it could
benefit for other use cases, like booting with cable connected and switch role through /sys.

Peter

> Signed-off-by: Li Jun <jun.li@nxp.com>
> ---
> 
> Change for v2:
> - Support USB_ROLE_NONE, which for usb port not connecting any
>   device or host, and will be in low power mode.
> 
>  drivers/usb/chipidea/ci.h   |   3 ++
>  drivers/usb/chipidea/core.c | 120 +++++++++++++++++++++++++++++++++-------
> ----
>  drivers/usb/chipidea/otg.c  |  20 ++++++++
>  3 files changed, 114 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index
> 82b86cd..f0aec1d 100644
> --- a/drivers/usb/chipidea/ci.h
> +++ b/drivers/usb/chipidea/ci.h
> @@ -205,6 +205,7 @@ struct ci_hdrc {
>  	int				irq;
>  	struct ci_role_driver		*roles[USB_ROLE_DEVICE + 1];
>  	enum usb_role			role;
> +	enum usb_role			target_role;
>  	bool				is_otg;
>  	struct usb_otg			otg;
>  	struct otg_fsm			fsm;
> @@ -212,6 +213,7 @@ struct ci_hdrc {
>  	ktime_t
> 	hr_timeouts[NUM_OTG_FSM_TIMERS];
>  	unsigned			enabled_otg_timer_bits;
>  	enum otg_fsm_timer		next_otg_timer;
> +	struct usb_role_switch		*role_switch;
>  	struct work_struct		work;
>  	struct workqueue_struct		*wq;
> 
> @@ -244,6 +246,7 @@ struct ci_hdrc {
>  	struct dentry			*debugfs;
>  	bool				id_event;
>  	bool				b_sess_valid_event;
> +	bool				role_switch_event;
>  	bool				imx28_write_fix;
>  	bool				supports_runtime_pm;
>  	bool				in_lpm;
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index
> bc24c5b..965ce17 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -587,6 +587,42 @@ static irqreturn_t ci_irq(int irq, void *data)
>  	return ret;
>  }
> 
> +static int ci_usb_role_switch_set(struct device *dev, enum usb_role
> +role) {
> +	struct ci_hdrc *ci = dev_get_drvdata(dev);
> +	unsigned long flags;
> +
> +	if (ci->role == role)
> +		return 0;
> +
> +	spin_lock_irqsave(&ci->lock, flags);
> +	ci->role_switch_event = true;
> +	ci->target_role = role;
> +	spin_unlock_irqrestore(&ci->lock, flags);
> +
> +	ci_otg_queue_work(ci);
> +
> +	return 0;
> +}
> +
> +static enum usb_role ci_usb_role_switch_get(struct device *dev) {
> +	struct ci_hdrc *ci = dev_get_drvdata(dev);
> +	unsigned long flags;
> +	enum usb_role role;
> +
> +	spin_lock_irqsave(&ci->lock, flags);
> +	role = ci->role;
> +	spin_unlock_irqrestore(&ci->lock, flags);
> +
> +	return role;
> +}
> +
> +static struct usb_role_switch_desc ci_role_switch = {
> +	.set = ci_usb_role_switch_set,
> +	.get = ci_usb_role_switch_get,
> +};
> +
>  static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
>  			     void *ptr)
>  {
> @@ -689,6 +725,9 @@ static int ci_get_platdata(struct device *dev,
>  	if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
>  		platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
> 
> +	if (device_property_read_bool(dev, "usb-role-switch"))
> +		ci_role_switch.fwnode = dev->fwnode;
> +
>  	ext_id = ERR_PTR(-ENODEV);
>  	ext_vbus = ERR_PTR(-ENODEV);
>  	if (of_property_read_bool(dev->of_node, "extcon")) { @@ -908,6 +947,43
> @@ static const struct attribute_group ci_attr_group = {
>  	.attrs = ci_attrs,
>  };
> 
> +static int ci_start_initial_role(struct ci_hdrc *ci) {
> +	int ret = 0;
> +
> +	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
> +		if (ci->is_otg) {
> +			ci->role = ci_otg_role(ci);
> +			/* Enable ID change irq */
> +			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
> +		} else {
> +			/*
> +			 * If the controller is not OTG capable, but support
> +			 * role switch, the defalt role is gadget, and the
> +			 * user can switch it through debugfs.
> +			 */
> +			ci->role = USB_ROLE_DEVICE;
> +		}
> +	} else {
> +		ci->role = ci->roles[USB_ROLE_HOST]
> +			? USB_ROLE_HOST
> +			: USB_ROLE_DEVICE;
> +	}
> +
> +	if (!ci_otg_is_fsm_mode(ci)) {
> +		/* only update vbus status for peripheral */
> +		if (ci->role == USB_ROLE_DEVICE)
> +			ci_handle_vbus_change(ci);
> +
> +		ret = ci_role_start(ci, ci->role);
> +		if (ret)
> +			dev_err(ci->dev, "can't start %s role\n",
> +						ci_role(ci)->name);
> +	}
> +
> +	return ret;
> +}
> +
>  static int ci_hdrc_probe(struct platform_device *pdev)  {
>  	struct device	*dev = &pdev->dev;
> @@ -1051,36 +1127,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
>  		}
>  	}
> 
> -	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
> -		if (ci->is_otg) {
> -			ci->role = ci_otg_role(ci);
> -			/* Enable ID change irq */
> -			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
> -		} else {
> -			/*
> -			 * If the controller is not OTG capable, but support
> -			 * role switch, the defalt role is gadget, and the
> -			 * user can switch it through debugfs.
> -			 */
> -			ci->role = USB_ROLE_DEVICE;
> -		}
> -	} else {
> -		ci->role = ci->roles[USB_ROLE_HOST]
> -			? USB_ROLE_HOST
> -			: USB_ROLE_DEVICE;
> -	}
> -
> -	if (!ci_otg_is_fsm_mode(ci)) {
> -		/* only update vbus status for peripheral */
> -		if (ci->role == USB_ROLE_DEVICE)
> -			ci_handle_vbus_change(ci);
> -
> -		ret = ci_role_start(ci, ci->role);
> -		if (ret) {
> -			dev_err(dev, "can't start %s role\n",
> -						ci_role(ci)->name);
> +	if (!ci_role_switch.fwnode) {
> +		ret = ci_start_initial_role(ci);
> +		if (ret)
>  			goto stop;
> -		}
>  	}
> 
>  	ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, @@ -1092,6
> +1142,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto stop;
> 
> +	if (ci_role_switch.fwnode) {
> +		ci->role_switch = usb_role_switch_register(dev,
> +					&ci_role_switch);
> +		if (IS_ERR(ci->role_switch)) {
> +			ret = PTR_ERR(ci->role_switch);
> +			goto stop;
> +		}
> +	}
> +
>  	if (ci->supports_runtime_pm) {
>  		pm_runtime_set_active(&pdev->dev);
>  		pm_runtime_enable(&pdev->dev);
> @@ -1133,6 +1192,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)
> {
>  	struct ci_hdrc *ci = platform_get_drvdata(pdev);
> 
> +	if (ci->role_switch)
> +		usb_role_switch_unregister(ci->role_switch);
> +
>  	if (ci->supports_runtime_pm) {
>  		pm_runtime_get_sync(&pdev->dev);
>  		pm_runtime_disable(&pdev->dev);
> diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index
> 5bde0b5..03675b6 100644
> --- a/drivers/usb/chipidea/otg.c
> +++ b/drivers/usb/chipidea/otg.c
> @@ -214,6 +214,26 @@ static void ci_otg_work(struct work_struct *work)
>  		ci_handle_vbus_change(ci);
>  	}
> 
> +	if (ci->role_switch_event) {
> +		ci->role_switch_event = false;
> +
> +		/* Stop current role */
> +		if (ci->role == USB_ROLE_DEVICE) {
> +			usb_gadget_vbus_disconnect(&ci->gadget);
> +			ci->role = USB_ROLE_NONE;
> +		} else if (ci->role == USB_ROLE_HOST) {
> +			ci_role_stop(ci);
> +		}
> +
> +		/* Start target role */
> +		if (ci->target_role == USB_ROLE_DEVICE) {
> +			usb_gadget_vbus_connect(&ci->gadget);
> +			ci->role = USB_ROLE_DEVICE;
> +		} else if (ci->target_role == USB_ROLE_HOST) {
> +			ci_role_start(ci, USB_ROLE_HOST);
> +		}
> +	}
> +
>  	pm_runtime_put_sync(ci->dev);
> 
>  	enable_irq(ci->irq);
> --
> 2.7.4


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

* RE: [PATCH v2 2/2] usb: chipidea: add role switch class support
  2019-08-08  9:30   ` Peter Chen
@ 2019-08-09  7:29     ` Jun Li
  2019-08-09 10:11       ` Peter Chen
  0 siblings, 1 reply; 7+ messages in thread
From: Jun Li @ 2019-08-09  7:29 UTC (permalink / raw)
  To: Peter Chen; +Cc: gregkh, dl-linux-imx, linux-usb


> -----Original Message-----
> From: Peter Chen
> Sent: 2019Äê8ÔÂ8ÈÕ 17:31
> To: Jun Li <jun.li@nxp.com>
> Cc: gregkh@linuxfoundation.org; Jun Li <jun.li@nxp.com>; dl-linux-imx
> <linux-imx@nxp.com>; linux-usb@vger.kernel.org
> Subject: RE: [PATCH v2 2/2] usb: chipidea: add role switch class support
> 
> 
> > USB role is fully controlled by usb role switch consumer(e.g. typec),
> > usb port can be at host mode(USB_ROLE_HOST), device mode connected to
> > host(USB_ROLE_DEVICE), or not connecting any parter(USB_ROLE_NONE).
> >
> 
> %s/parter/partner ?

Yes, I will update.

> 
> Are there any ways you could get external cable status from usb-switch or type-c like
> external connector? If there are, you could update otgsc value for otgsc_read, or change
> cable status, and avoid changing common handling, like ci_hdrc_probe and  ci_otg_work.
> And it could benefit for other use cases, like booting with cable connected and switch role
> through /sys.

The new role switch class has nothing to do with extcon, it's using graph bindings
to link the connection, so there is no extcon_dev, change for ci_hdrc_probe() is
required as property usb-role-switch has to be specified, there may be some code
reuse if still touch the external cable even no extcon dev, but that will make existing
external cable complicated and not clean.

On the other hand, a new GPIO based role switch driver is on review:
https://patchwork.kernel.org/patch/11056379/
Seems this is the direction to move out from extcon.

Li Jun
> 
> Peter
> 
> > Signed-off-by: Li Jun <jun.li@nxp.com>
> > ---
> >
> > Change for v2:
> > - Support USB_ROLE_NONE, which for usb port not connecting any
> >   device or host, and will be in low power mode.
> >
> >  drivers/usb/chipidea/ci.h   |   3 ++
> >  drivers/usb/chipidea/core.c | 120
> > +++++++++++++++++++++++++++++++++-------
> > ----
> >  drivers/usb/chipidea/otg.c  |  20 ++++++++
> >  3 files changed, 114 insertions(+), 29 deletions(-)
> >
> > diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
> > index 82b86cd..f0aec1d 100644
> > --- a/drivers/usb/chipidea/ci.h
> > +++ b/drivers/usb/chipidea/ci.h
> > @@ -205,6 +205,7 @@ struct ci_hdrc {
> >  	int				irq;
> >  	struct ci_role_driver		*roles[USB_ROLE_DEVICE + 1];
> >  	enum usb_role			role;
> > +	enum usb_role			target_role;
> >  	bool				is_otg;
> >  	struct usb_otg			otg;
> >  	struct otg_fsm			fsm;
> > @@ -212,6 +213,7 @@ struct ci_hdrc {
> >  	ktime_t
> > 	hr_timeouts[NUM_OTG_FSM_TIMERS];
> >  	unsigned			enabled_otg_timer_bits;
> >  	enum otg_fsm_timer		next_otg_timer;
> > +	struct usb_role_switch		*role_switch;
> >  	struct work_struct		work;
> >  	struct workqueue_struct		*wq;
> >
> > @@ -244,6 +246,7 @@ struct ci_hdrc {
> >  	struct dentry			*debugfs;
> >  	bool				id_event;
> >  	bool				b_sess_valid_event;
> > +	bool				role_switch_event;
> >  	bool				imx28_write_fix;
> >  	bool				supports_runtime_pm;
> >  	bool				in_lpm;
> > diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> > index
> > bc24c5b..965ce17 100644
> > --- a/drivers/usb/chipidea/core.c
> > +++ b/drivers/usb/chipidea/core.c
> > @@ -587,6 +587,42 @@ static irqreturn_t ci_irq(int irq, void *data)
> >  	return ret;
> >  }
> >
> > +static int ci_usb_role_switch_set(struct device *dev, enum usb_role
> > +role) {
> > +	struct ci_hdrc *ci = dev_get_drvdata(dev);
> > +	unsigned long flags;
> > +
> > +	if (ci->role == role)
> > +		return 0;
> > +
> > +	spin_lock_irqsave(&ci->lock, flags);
> > +	ci->role_switch_event = true;
> > +	ci->target_role = role;
> > +	spin_unlock_irqrestore(&ci->lock, flags);
> > +
> > +	ci_otg_queue_work(ci);
> > +
> > +	return 0;
> > +}
> > +
> > +static enum usb_role ci_usb_role_switch_get(struct device *dev) {
> > +	struct ci_hdrc *ci = dev_get_drvdata(dev);
> > +	unsigned long flags;
> > +	enum usb_role role;
> > +
> > +	spin_lock_irqsave(&ci->lock, flags);
> > +	role = ci->role;
> > +	spin_unlock_irqrestore(&ci->lock, flags);
> > +
> > +	return role;
> > +}
> > +
> > +static struct usb_role_switch_desc ci_role_switch = {
> > +	.set = ci_usb_role_switch_set,
> > +	.get = ci_usb_role_switch_get,
> > +};
> > +
> >  static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
> >  			     void *ptr)
> >  {
> > @@ -689,6 +725,9 @@ static int ci_get_platdata(struct device *dev,
> >  	if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
> >  		platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
> >
> > +	if (device_property_read_bool(dev, "usb-role-switch"))
> > +		ci_role_switch.fwnode = dev->fwnode;
> > +
> >  	ext_id = ERR_PTR(-ENODEV);
> >  	ext_vbus = ERR_PTR(-ENODEV);
> >  	if (of_property_read_bool(dev->of_node, "extcon")) { @@ -908,6
> > +947,43 @@ static const struct attribute_group ci_attr_group = {
> >  	.attrs = ci_attrs,
> >  };
> >
> > +static int ci_start_initial_role(struct ci_hdrc *ci) {
> > +	int ret = 0;
> > +
> > +	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
> > +		if (ci->is_otg) {
> > +			ci->role = ci_otg_role(ci);
> > +			/* Enable ID change irq */
> > +			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
> > +		} else {
> > +			/*
> > +			 * If the controller is not OTG capable, but support
> > +			 * role switch, the defalt role is gadget, and the
> > +			 * user can switch it through debugfs.
> > +			 */
> > +			ci->role = USB_ROLE_DEVICE;
> > +		}
> > +	} else {
> > +		ci->role = ci->roles[USB_ROLE_HOST]
> > +			? USB_ROLE_HOST
> > +			: USB_ROLE_DEVICE;
> > +	}
> > +
> > +	if (!ci_otg_is_fsm_mode(ci)) {
> > +		/* only update vbus status for peripheral */
> > +		if (ci->role == USB_ROLE_DEVICE)
> > +			ci_handle_vbus_change(ci);
> > +
> > +		ret = ci_role_start(ci, ci->role);
> > +		if (ret)
> > +			dev_err(ci->dev, "can't start %s role\n",
> > +						ci_role(ci)->name);
> > +	}
> > +
> > +	return ret;
> > +}
> > +
> >  static int ci_hdrc_probe(struct platform_device *pdev)  {
> >  	struct device	*dev = &pdev->dev;
> > @@ -1051,36 +1127,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
> >  		}
> >  	}
> >
> > -	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
> > -		if (ci->is_otg) {
> > -			ci->role = ci_otg_role(ci);
> > -			/* Enable ID change irq */
> > -			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
> > -		} else {
> > -			/*
> > -			 * If the controller is not OTG capable, but support
> > -			 * role switch, the defalt role is gadget, and the
> > -			 * user can switch it through debugfs.
> > -			 */
> > -			ci->role = USB_ROLE_DEVICE;
> > -		}
> > -	} else {
> > -		ci->role = ci->roles[USB_ROLE_HOST]
> > -			? USB_ROLE_HOST
> > -			: USB_ROLE_DEVICE;
> > -	}
> > -
> > -	if (!ci_otg_is_fsm_mode(ci)) {
> > -		/* only update vbus status for peripheral */
> > -		if (ci->role == USB_ROLE_DEVICE)
> > -			ci_handle_vbus_change(ci);
> > -
> > -		ret = ci_role_start(ci, ci->role);
> > -		if (ret) {
> > -			dev_err(dev, "can't start %s role\n",
> > -						ci_role(ci)->name);
> > +	if (!ci_role_switch.fwnode) {
> > +		ret = ci_start_initial_role(ci);
> > +		if (ret)
> >  			goto stop;
> > -		}
> >  	}
> >
> >  	ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, @@ -1092,6
> > +1142,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
> >  	if (ret)
> >  		goto stop;
> >
> > +	if (ci_role_switch.fwnode) {
> > +		ci->role_switch = usb_role_switch_register(dev,
> > +					&ci_role_switch);
> > +		if (IS_ERR(ci->role_switch)) {
> > +			ret = PTR_ERR(ci->role_switch);
> > +			goto stop;
> > +		}
> > +	}
> > +
> >  	if (ci->supports_runtime_pm) {
> >  		pm_runtime_set_active(&pdev->dev);
> >  		pm_runtime_enable(&pdev->dev);
> > @@ -1133,6 +1192,9 @@ static int ci_hdrc_remove(struct platform_device
> > *pdev) {
> >  	struct ci_hdrc *ci = platform_get_drvdata(pdev);
> >
> > +	if (ci->role_switch)
> > +		usb_role_switch_unregister(ci->role_switch);
> > +
> >  	if (ci->supports_runtime_pm) {
> >  		pm_runtime_get_sync(&pdev->dev);
> >  		pm_runtime_disable(&pdev->dev);
> > diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
> > index
> > 5bde0b5..03675b6 100644
> > --- a/drivers/usb/chipidea/otg.c
> > +++ b/drivers/usb/chipidea/otg.c
> > @@ -214,6 +214,26 @@ static void ci_otg_work(struct work_struct *work)
> >  		ci_handle_vbus_change(ci);
> >  	}
> >
> > +	if (ci->role_switch_event) {
> > +		ci->role_switch_event = false;
> > +
> > +		/* Stop current role */
> > +		if (ci->role == USB_ROLE_DEVICE) {
> > +			usb_gadget_vbus_disconnect(&ci->gadget);
> > +			ci->role = USB_ROLE_NONE;
> > +		} else if (ci->role == USB_ROLE_HOST) {
> > +			ci_role_stop(ci);
> > +		}
> > +
> > +		/* Start target role */
> > +		if (ci->target_role == USB_ROLE_DEVICE) {
> > +			usb_gadget_vbus_connect(&ci->gadget);
> > +			ci->role = USB_ROLE_DEVICE;
> > +		} else if (ci->target_role == USB_ROLE_HOST) {
> > +			ci_role_start(ci, USB_ROLE_HOST);
> > +		}
> > +	}
> > +
> >  	pm_runtime_put_sync(ci->dev);
> >
> >  	enable_irq(ci->irq);
> > --
> > 2.7.4


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

* RE: [PATCH v2 2/2] usb: chipidea: add role switch class support
  2019-08-09  7:29     ` Jun Li
@ 2019-08-09 10:11       ` Peter Chen
  0 siblings, 0 replies; 7+ messages in thread
From: Peter Chen @ 2019-08-09 10:11 UTC (permalink / raw)
  To: Jun Li; +Cc: gregkh, dl-linux-imx, linux-usb

 
> > > USB role is fully controlled by usb role switch consumer(e.g.
> > > typec), usb port can be at host mode(USB_ROLE_HOST), device mode
> > > connected to host(USB_ROLE_DEVICE), or not connecting any
> parter(USB_ROLE_NONE).
> > >
> >
> > %s/parter/partner ?
> 
> Yes, I will update.
> 
> >
> > Are there any ways you could get external cable status from usb-switch
> > or type-c like external connector? If there are, you could update
> > otgsc value for otgsc_read, or change cable status, and avoid changing common
> handling, like ci_hdrc_probe and  ci_otg_work.
> > And it could benefit for other use cases, like booting with cable
> > connected and switch role through /sys.
> 
> The new role switch class has nothing to do with extcon, it's using graph bindings to
> link the connection, so there is no extcon_dev, change for ci_hdrc_probe() is
> required as property usb-role-switch has to be specified, there may be some code
> reuse if still touch the external cable even no extcon dev, but that will make existing
> external cable complicated and not clean.
> 

I don't mean using extcon directly.

At ci_usb_role_switch_set, you could know current "id" and "vbus" status.
as well as if "id" and "vbus" has changed. So, you could update ci->id_event
or ci->vbus_event. And at otgsc_read, you could return correct vbus and id value.

So, you may not need to change main function for ci_otg_work, for ci_hdrc_probe,
you could only need to register usb-switch class.

Surely, you may need to introduce some structures or variables for usb switch, but
it could keep main structure not changing, and just differentiate the way to get
id and vbus.


> On the other hand, a new GPIO based role switch driver is on review:
> https://patchwork.kernel.org/patch/11056379/
> Seems this is the direction to move out from extcon.
> 

If external connector is given up, we need to use that.

When you update the v3, please fix the build error reported by kbuild test robot.

Peter	

> Li Jun
> >
> > Peter
> >
> > > Signed-off-by: Li Jun <jun.li@nxp.com>
> > > ---
> > >
> > > Change for v2:
> > > - Support USB_ROLE_NONE, which for usb port not connecting any
> > >   device or host, and will be in low power mode.
> > >
> > >  drivers/usb/chipidea/ci.h   |   3 ++
> > >  drivers/usb/chipidea/core.c | 120
> > > +++++++++++++++++++++++++++++++++-------
> > > ----
> > >  drivers/usb/chipidea/otg.c  |  20 ++++++++
> > >  3 files changed, 114 insertions(+), 29 deletions(-)
> > >
> > > diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
> > > index 82b86cd..f0aec1d 100644
> > > --- a/drivers/usb/chipidea/ci.h
> > > +++ b/drivers/usb/chipidea/ci.h
> > > @@ -205,6 +205,7 @@ struct ci_hdrc {
> > >  	int				irq;
> > >  	struct ci_role_driver		*roles[USB_ROLE_DEVICE + 1];
> > >  	enum usb_role			role;
> > > +	enum usb_role			target_role;
> > >  	bool				is_otg;
> > >  	struct usb_otg			otg;
> > >  	struct otg_fsm			fsm;
> > > @@ -212,6 +213,7 @@ struct ci_hdrc {
> > >  	ktime_t
> > > 	hr_timeouts[NUM_OTG_FSM_TIMERS];
> > >  	unsigned			enabled_otg_timer_bits;
> > >  	enum otg_fsm_timer		next_otg_timer;
> > > +	struct usb_role_switch		*role_switch;
> > >  	struct work_struct		work;
> > >  	struct workqueue_struct		*wq;
> > >
> > > @@ -244,6 +246,7 @@ struct ci_hdrc {
> > >  	struct dentry			*debugfs;
> > >  	bool				id_event;
> > >  	bool				b_sess_valid_event;
> > > +	bool				role_switch_event;
> > >  	bool				imx28_write_fix;
> > >  	bool				supports_runtime_pm;
> > >  	bool				in_lpm;
> > > diff --git a/drivers/usb/chipidea/core.c
> > > b/drivers/usb/chipidea/core.c index
> > > bc24c5b..965ce17 100644
> > > --- a/drivers/usb/chipidea/core.c
> > > +++ b/drivers/usb/chipidea/core.c
> > > @@ -587,6 +587,42 @@ static irqreturn_t ci_irq(int irq, void *data)
> > >  	return ret;
> > >  }
> > >
> > > +static int ci_usb_role_switch_set(struct device *dev, enum usb_role
> > > +role) {
> > > +	struct ci_hdrc *ci = dev_get_drvdata(dev);
> > > +	unsigned long flags;
> > > +
> > > +	if (ci->role == role)
> > > +		return 0;
> > > +
> > > +	spin_lock_irqsave(&ci->lock, flags);
> > > +	ci->role_switch_event = true;
> > > +	ci->target_role = role;
> > > +	spin_unlock_irqrestore(&ci->lock, flags);
> > > +
> > > +	ci_otg_queue_work(ci);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static enum usb_role ci_usb_role_switch_get(struct device *dev) {
> > > +	struct ci_hdrc *ci = dev_get_drvdata(dev);
> > > +	unsigned long flags;
> > > +	enum usb_role role;
> > > +
> > > +	spin_lock_irqsave(&ci->lock, flags);
> > > +	role = ci->role;
> > > +	spin_unlock_irqrestore(&ci->lock, flags);
> > > +
> > > +	return role;
> > > +}
> > > +
> > > +static struct usb_role_switch_desc ci_role_switch = {
> > > +	.set = ci_usb_role_switch_set,
> > > +	.get = ci_usb_role_switch_get,
> > > +};
> > > +
> > >  static int ci_cable_notifier(struct notifier_block *nb, unsigned long event,
> > >  			     void *ptr)
> > >  {
> > > @@ -689,6 +725,9 @@ static int ci_get_platdata(struct device *dev,
> > >  	if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL))
> > >  		platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA;
> > >
> > > +	if (device_property_read_bool(dev, "usb-role-switch"))
> > > +		ci_role_switch.fwnode = dev->fwnode;
> > > +
> > >  	ext_id = ERR_PTR(-ENODEV);
> > >  	ext_vbus = ERR_PTR(-ENODEV);
> > >  	if (of_property_read_bool(dev->of_node, "extcon")) { @@ -908,6
> > > +947,43 @@ static const struct attribute_group ci_attr_group = {
> > >  	.attrs = ci_attrs,
> > >  };
> > >
> > > +static int ci_start_initial_role(struct ci_hdrc *ci) {
> > > +	int ret = 0;
> > > +
> > > +	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
> > > +		if (ci->is_otg) {
> > > +			ci->role = ci_otg_role(ci);
> > > +			/* Enable ID change irq */
> > > +			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
> > > +		} else {
> > > +			/*
> > > +			 * If the controller is not OTG capable, but support
> > > +			 * role switch, the defalt role is gadget, and the
> > > +			 * user can switch it through debugfs.
> > > +			 */
> > > +			ci->role = USB_ROLE_DEVICE;
> > > +		}
> > > +	} else {
> > > +		ci->role = ci->roles[USB_ROLE_HOST]
> > > +			? USB_ROLE_HOST
> > > +			: USB_ROLE_DEVICE;
> > > +	}
> > > +
> > > +	if (!ci_otg_is_fsm_mode(ci)) {
> > > +		/* only update vbus status for peripheral */
> > > +		if (ci->role == USB_ROLE_DEVICE)
> > > +			ci_handle_vbus_change(ci);
> > > +
> > > +		ret = ci_role_start(ci, ci->role);
> > > +		if (ret)
> > > +			dev_err(ci->dev, "can't start %s role\n",
> > > +						ci_role(ci)->name);
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > > +
> > >  static int ci_hdrc_probe(struct platform_device *pdev)  {
> > >  	struct device	*dev = &pdev->dev;
> > > @@ -1051,36 +1127,10 @@ static int ci_hdrc_probe(struct platform_device
> *pdev)
> > >  		}
> > >  	}
> > >
> > > -	if (ci->roles[USB_ROLE_HOST] && ci->roles[USB_ROLE_DEVICE]) {
> > > -		if (ci->is_otg) {
> > > -			ci->role = ci_otg_role(ci);
> > > -			/* Enable ID change irq */
> > > -			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);
> > > -		} else {
> > > -			/*
> > > -			 * If the controller is not OTG capable, but support
> > > -			 * role switch, the defalt role is gadget, and the
> > > -			 * user can switch it through debugfs.
> > > -			 */
> > > -			ci->role = USB_ROLE_DEVICE;
> > > -		}
> > > -	} else {
> > > -		ci->role = ci->roles[USB_ROLE_HOST]
> > > -			? USB_ROLE_HOST
> > > -			: USB_ROLE_DEVICE;
> > > -	}
> > > -
> > > -	if (!ci_otg_is_fsm_mode(ci)) {
> > > -		/* only update vbus status for peripheral */
> > > -		if (ci->role == USB_ROLE_DEVICE)
> > > -			ci_handle_vbus_change(ci);
> > > -
> > > -		ret = ci_role_start(ci, ci->role);
> > > -		if (ret) {
> > > -			dev_err(dev, "can't start %s role\n",
> > > -						ci_role(ci)->name);
> > > +	if (!ci_role_switch.fwnode) {
> > > +		ret = ci_start_initial_role(ci);
> > > +		if (ret)
> > >  			goto stop;
> > > -		}
> > >  	}
> > >
> > >  	ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, @@
> > > -1092,6
> > > +1142,15 @@ static int ci_hdrc_probe(struct platform_device *pdev)
> > >  	if (ret)
> > >  		goto stop;
> > >
> > > +	if (ci_role_switch.fwnode) {
> > > +		ci->role_switch = usb_role_switch_register(dev,
> > > +					&ci_role_switch);
> > > +		if (IS_ERR(ci->role_switch)) {
> > > +			ret = PTR_ERR(ci->role_switch);
> > > +			goto stop;
> > > +		}
> > > +	}
> > > +
> > >  	if (ci->supports_runtime_pm) {
> > >  		pm_runtime_set_active(&pdev->dev);
> > >  		pm_runtime_enable(&pdev->dev);
> > > @@ -1133,6 +1192,9 @@ static int ci_hdrc_remove(struct
> > > platform_device
> > > *pdev) {
> > >  	struct ci_hdrc *ci = platform_get_drvdata(pdev);
> > >
> > > +	if (ci->role_switch)
> > > +		usb_role_switch_unregister(ci->role_switch);
> > > +
> > >  	if (ci->supports_runtime_pm) {
> > >  		pm_runtime_get_sync(&pdev->dev);
> > >  		pm_runtime_disable(&pdev->dev);
> > > diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
> > > index
> > > 5bde0b5..03675b6 100644
> > > --- a/drivers/usb/chipidea/otg.c
> > > +++ b/drivers/usb/chipidea/otg.c
> > > @@ -214,6 +214,26 @@ static void ci_otg_work(struct work_struct *work)
> > >  		ci_handle_vbus_change(ci);
> > >  	}
> > >
> > > +	if (ci->role_switch_event) {
> > > +		ci->role_switch_event = false;
> > > +
> > > +		/* Stop current role */
> > > +		if (ci->role == USB_ROLE_DEVICE) {
> > > +			usb_gadget_vbus_disconnect(&ci->gadget);
> > > +			ci->role = USB_ROLE_NONE;
> > > +		} else if (ci->role == USB_ROLE_HOST) {
> > > +			ci_role_stop(ci);
> > > +		}
> > > +
> > > +		/* Start target role */
> > > +		if (ci->target_role == USB_ROLE_DEVICE) {
> > > +			usb_gadget_vbus_connect(&ci->gadget);
> > > +			ci->role = USB_ROLE_DEVICE;
> > > +		} else if (ci->target_role == USB_ROLE_HOST) {
> > > +			ci_role_start(ci, USB_ROLE_HOST);
> > > +		}
> > > +	}
> > > +
> > >  	pm_runtime_put_sync(ci->dev);
> > >
> > >  	enable_irq(ci->irq);
> > > --
> > > 2.7.4


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

end of thread, back to index

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-07  7:23 [PATCH v2 1/2] usb: chipidea: replace ci_role with usb_role jun.li
2019-08-07  7:23 ` [PATCH v2 2/2] usb: chipidea: add role switch class support jun.li
2019-08-07 18:39   ` kbuild test robot
2019-08-08  8:22   ` kbuild test robot
2019-08-08  9:30   ` Peter Chen
2019-08-09  7:29     ` Jun Li
2019-08-09 10:11       ` Peter Chen

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org linux-usb@archiver.kernel.org
	public-inbox-index linux-usb


Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/ public-inbox