All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
To: mathias.nyman@intel.com, gregkh@linuxfoundation.org
Cc: linux-usb@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Subject: [PATCH/RFC] usb: host: xhci-plat and rcar: reinitialize the xhci when the mode changes
Date: Thu, 11 Jan 2018 17:52:58 +0900	[thread overview]
Message-ID: <1515660778-11043-1-git-send-email-yoshihiro.shimoda.uh@renesas.com> (raw)

This patch adds extcon notifier to reinitialize the xhci when the mode
of R-Car USB 3.0 controller changes from peripheral to host. Otherwise,
the host controller cannot detect Super Speed after changed the mode
because the PORTSC.PLS for usb3.0 will be set to Disabled.

TODO in this RFC version:
 - Needs to avoid double usb_remove_hcd() calling by rmmod or unbind and
   the xhci_rcar_work().
 - Needs to divide this patch (this patch has many feature changes).

If this approach is acceptable for upstream, I'll improve the patch.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/usb/host/xhci-plat.c | 21 +++++++++++++++++++++
 drivers/usb/host/xhci-plat.h | 13 +++++++++++++
 drivers/usb/host/xhci-rcar.c | 37 +++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-rcar.h |  7 +++++++
 4 files changed, 78 insertions(+)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 6f03830..231f4a4 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -10,6 +10,7 @@
 
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
+#include <linux/extcon.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/of.h>
@@ -108,6 +109,7 @@ static int xhci_plat_start(struct usb_hcd *hcd)
 	.init_quirk = xhci_rcar_init_quirk,
 	.plat_start = xhci_rcar_start,
 	.resume_quirk = xhci_rcar_resume_quirk,
+	.notifier = xhci_rcar_notifier,
 };
 
 static const struct of_device_id usb_xhci_of_match[] = {
@@ -274,6 +276,25 @@ static int xhci_plat_probe(struct platform_device *pdev)
 	device_property_read_u32(sysdev, "imod-interval-ns",
 				 &xhci->imod_interval);
 
+	if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
+		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+		priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+		if (IS_ERR(priv->edev)) {
+			ret = PTR_ERR(priv->edev);
+			goto put_usb3_hcd;
+		}
+		priv->nb.notifier_call = priv->notifier;
+		priv->hcd = hcd;
+		priv->shared_hcd = xhci->shared_hcd;
+		priv->irq = irq;
+		ret = devm_extcon_register_notifier(&pdev->dev, priv->edev,
+						    EXTCON_USB_HOST,
+						    &priv->nb);
+		if (ret < 0)
+			dev_err(&pdev->dev, "no notifier registered\n");
+	}
+
 	hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
 	if (IS_ERR(hcd->usb_phy)) {
 		ret = PTR_ERR(hcd->usb_phy);
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index ae29f22..6807809 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -8,13 +8,26 @@
 #ifndef _XHCI_PLAT_H
 #define _XHCI_PLAT_H
 
+#include <linux/extcon.h>
+#include <linux/usb/hcd.h>
+#include <linux/workqueue.h>
 #include "xhci.h"	/* for hcd_to_xhci() */
 
 struct xhci_plat_priv {
+	struct extcon_dev *edev;
+	struct notifier_block nb;
+	struct usb_hcd *hcd;		/* for rcar */
+	struct usb_hcd *shared_hcd;	/* for rcar */
+	int irq;			/* for rcar */
+	unsigned long event;		/* for rcar */
+	struct work_struct work;	/* for rcar */
+	bool halted_by_peri;		/* for rcar */
 	const char *firmware_name;
 	void (*plat_start)(struct usb_hcd *);
 	int (*init_quirk)(struct usb_hcd *);
 	int (*resume_quirk)(struct usb_hcd *);
+	int (*notifier)(struct notifier_block *nb, unsigned long event,
+			void *data);
 };
 
 #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index f0b5596..9cdb631 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 #include <linux/usb/phy.h>
 #include <linux/sys_soc.h>
+#include <linux/workqueue.h>
 
 #include "xhci.h"
 #include "xhci-plat.h"
@@ -242,3 +243,39 @@ int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
 
 	return ret;
 }
+
+static void xhci_rcar_work(struct work_struct *work)
+{
+	struct xhci_plat_priv *priv = container_of(work, struct xhci_plat_priv,
+						   work);
+	struct usb_hcd *hcd = priv->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	int irq = priv->irq;
+	int ret;
+
+	if (!priv->event) {
+		xhci->xhc_state |= XHCI_STATE_REMOVING;
+		usb_remove_hcd(xhci->shared_hcd);
+		usb_phy_shutdown(hcd->usb_phy);
+		usb_remove_hcd(hcd);
+		priv->halted_by_peri = true;
+	} else if (priv->halted_by_peri) {
+		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+		xhci->shared_hcd = priv->shared_hcd;
+		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+		priv->halted_by_peri = 0;
+	}
+}
+
+int xhci_rcar_notifier(struct notifier_block *nb, unsigned long event,
+		       void *data)
+{
+	struct xhci_plat_priv *priv = container_of(nb, struct xhci_plat_priv,
+						   nb);
+
+	priv->event = event;
+	INIT_WORK(&priv->work, xhci_rcar_work);
+	schedule_work(&priv->work);
+
+	return NOTIFY_OK;
+}
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h
index 804b6ab..3fbc69f 100644
--- a/drivers/usb/host/xhci-rcar.h
+++ b/drivers/usb/host/xhci-rcar.h
@@ -16,6 +16,8 @@
 void xhci_rcar_start(struct usb_hcd *hcd);
 int xhci_rcar_init_quirk(struct usb_hcd *hcd);
 int xhci_rcar_resume_quirk(struct usb_hcd *hcd);
+int xhci_rcar_notifier(struct notifier_block *nb, unsigned long event,
+		       void *data);
 #else
 static inline void xhci_rcar_start(struct usb_hcd *hcd)
 {
@@ -30,5 +32,10 @@ static inline int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
 {
 	return 0;
 }
+static inline int xhci_rcar_notifier(struct notifier_block *nb,
+				     unsigned long event, void *data)
+{
+	return 0;
+}
 #endif
 #endif /* _XHCI_RCAR_H */
-- 
1.9.1

WARNING: multiple messages have this Message-ID (diff)
From: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
To: mathias.nyman@intel.com, gregkh@linuxfoundation.org
Cc: linux-usb@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
	Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Subject: [PATCH/RFC] usb: host: xhci-plat and rcar: reinitialize the xhci when the mode changes
Date: Thu, 11 Jan 2018 17:52:58 +0900	[thread overview]
Message-ID: <1515660778-11043-1-git-send-email-yoshihiro.shimoda.uh@renesas.com> (raw)

This patch adds extcon notifier to reinitialize the xhci when the mode
of R-Car USB 3.0 controller changes from peripheral to host. Otherwise,
the host controller cannot detect Super Speed after changed the mode
because the PORTSC.PLS for usb3.0 will be set to Disabled.

TODO in this RFC version:
 - Needs to avoid double usb_remove_hcd() calling by rmmod or unbind and
   the xhci_rcar_work().
 - Needs to divide this patch (this patch has many feature changes).

If this approach is acceptable for upstream, I'll improve the patch.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 drivers/usb/host/xhci-plat.c | 21 +++++++++++++++++++++
 drivers/usb/host/xhci-plat.h | 13 +++++++++++++
 drivers/usb/host/xhci-rcar.c | 37 +++++++++++++++++++++++++++++++++++++
 drivers/usb/host/xhci-rcar.h |  7 +++++++
 4 files changed, 78 insertions(+)

diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 6f03830..231f4a4 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -10,6 +10,7 @@
 
 #include <linux/clk.h>
 #include <linux/dma-mapping.h>
+#include <linux/extcon.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/of.h>
@@ -108,6 +109,7 @@ static int xhci_plat_start(struct usb_hcd *hcd)
 	.init_quirk = xhci_rcar_init_quirk,
 	.plat_start = xhci_rcar_start,
 	.resume_quirk = xhci_rcar_resume_quirk,
+	.notifier = xhci_rcar_notifier,
 };
 
 static const struct of_device_id usb_xhci_of_match[] = {
@@ -274,6 +276,25 @@ static int xhci_plat_probe(struct platform_device *pdev)
 	device_property_read_u32(sysdev, "imod-interval-ns",
 				 &xhci->imod_interval);
 
+	if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
+		struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
+
+		priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+		if (IS_ERR(priv->edev)) {
+			ret = PTR_ERR(priv->edev);
+			goto put_usb3_hcd;
+		}
+		priv->nb.notifier_call = priv->notifier;
+		priv->hcd = hcd;
+		priv->shared_hcd = xhci->shared_hcd;
+		priv->irq = irq;
+		ret = devm_extcon_register_notifier(&pdev->dev, priv->edev,
+						    EXTCON_USB_HOST,
+						    &priv->nb);
+		if (ret < 0)
+			dev_err(&pdev->dev, "no notifier registered\n");
+	}
+
 	hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
 	if (IS_ERR(hcd->usb_phy)) {
 		ret = PTR_ERR(hcd->usb_phy);
diff --git a/drivers/usb/host/xhci-plat.h b/drivers/usb/host/xhci-plat.h
index ae29f22..6807809 100644
--- a/drivers/usb/host/xhci-plat.h
+++ b/drivers/usb/host/xhci-plat.h
@@ -8,13 +8,26 @@
 #ifndef _XHCI_PLAT_H
 #define _XHCI_PLAT_H
 
+#include <linux/extcon.h>
+#include <linux/usb/hcd.h>
+#include <linux/workqueue.h>
 #include "xhci.h"	/* for hcd_to_xhci() */
 
 struct xhci_plat_priv {
+	struct extcon_dev *edev;
+	struct notifier_block nb;
+	struct usb_hcd *hcd;		/* for rcar */
+	struct usb_hcd *shared_hcd;	/* for rcar */
+	int irq;			/* for rcar */
+	unsigned long event;		/* for rcar */
+	struct work_struct work;	/* for rcar */
+	bool halted_by_peri;		/* for rcar */
 	const char *firmware_name;
 	void (*plat_start)(struct usb_hcd *);
 	int (*init_quirk)(struct usb_hcd *);
 	int (*resume_quirk)(struct usb_hcd *);
+	int (*notifier)(struct notifier_block *nb, unsigned long event,
+			void *data);
 };
 
 #define hcd_to_xhci_priv(h) ((struct xhci_plat_priv *)hcd_to_xhci(h)->priv)
diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c
index f0b5596..9cdb631 100644
--- a/drivers/usb/host/xhci-rcar.c
+++ b/drivers/usb/host/xhci-rcar.c
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 #include <linux/usb/phy.h>
 #include <linux/sys_soc.h>
+#include <linux/workqueue.h>
 
 #include "xhci.h"
 #include "xhci-plat.h"
@@ -242,3 +243,39 @@ int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
 
 	return ret;
 }
+
+static void xhci_rcar_work(struct work_struct *work)
+{
+	struct xhci_plat_priv *priv = container_of(work, struct xhci_plat_priv,
+						   work);
+	struct usb_hcd *hcd = priv->hcd;
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	int irq = priv->irq;
+	int ret;
+
+	if (!priv->event) {
+		xhci->xhc_state |= XHCI_STATE_REMOVING;
+		usb_remove_hcd(xhci->shared_hcd);
+		usb_phy_shutdown(hcd->usb_phy);
+		usb_remove_hcd(hcd);
+		priv->halted_by_peri = true;
+	} else if (priv->halted_by_peri) {
+		ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+		xhci->shared_hcd = priv->shared_hcd;
+		ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+		priv->halted_by_peri = 0;
+	}
+}
+
+int xhci_rcar_notifier(struct notifier_block *nb, unsigned long event,
+		       void *data)
+{
+	struct xhci_plat_priv *priv = container_of(nb, struct xhci_plat_priv,
+						   nb);
+
+	priv->event = event;
+	INIT_WORK(&priv->work, xhci_rcar_work);
+	schedule_work(&priv->work);
+
+	return NOTIFY_OK;
+}
diff --git a/drivers/usb/host/xhci-rcar.h b/drivers/usb/host/xhci-rcar.h
index 804b6ab..3fbc69f 100644
--- a/drivers/usb/host/xhci-rcar.h
+++ b/drivers/usb/host/xhci-rcar.h
@@ -16,6 +16,8 @@
 void xhci_rcar_start(struct usb_hcd *hcd);
 int xhci_rcar_init_quirk(struct usb_hcd *hcd);
 int xhci_rcar_resume_quirk(struct usb_hcd *hcd);
+int xhci_rcar_notifier(struct notifier_block *nb, unsigned long event,
+		       void *data);
 #else
 static inline void xhci_rcar_start(struct usb_hcd *hcd)
 {
@@ -30,5 +32,10 @@ static inline int xhci_rcar_resume_quirk(struct usb_hcd *hcd)
 {
 	return 0;
 }
+static inline int xhci_rcar_notifier(struct notifier_block *nb,
+				     unsigned long event, void *data)
+{
+	return 0;
+}
 #endif
 #endif /* _XHCI_RCAR_H */

             reply	other threads:[~2018-01-11  8:57 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-11  8:52 Yoshihiro Shimoda [this message]
2018-01-11  8:52 ` [PATCH/RFC] usb: host: xhci-plat and rcar: reinitialize the xhci when the mode changes Yoshihiro Shimoda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1515660778-11043-1-git-send-email-yoshihiro.shimoda.uh@renesas.com \
    --to=yoshihiro.shimoda.uh@renesas.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-renesas-soc@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.