linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] usb: gadget: pxa27x: add phy notifier event handler
@ 2016-07-08 20:09 Robert Jarzmik
  2016-07-08 20:09 ` [PATCH 2/3] usb: phy: generic: cope with initial state Robert Jarzmik
  2016-07-08 20:09 ` [PATCH 3/3] usb: phy: generic: remove the vbus dependency Robert Jarzmik
  0 siblings, 2 replies; 3+ messages in thread
From: Robert Jarzmik @ 2016-07-08 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

In the legacy behavior, and USB phy, upon detection a VBus signal, was
calling usb_gadget_vbus_(dis)connect().

This model doesn't work if the phy is generic and doesn't have an
adherence to the gadget API.

Instead of relying on the phy to call the gadget API, hook up the phy
notifier to report the VBus event, and upon it call the usb gadget API
ourselves.

This brings a new ordering problem, as before even if the usb_get_phy()
was failing because the UDC was probed before the phy, the phy would
call the gadget anyway, making the VBus connection event forwarded to
the gadget. Now we rely on the notifier, we have to ensure the
xxx_get_phy() does indeed work.

In order to cope with this, it is assumed that :
 - for legacy platform_data machine, as the ordering cannot be ensured,
   the phy must call usb_gadget_vbus_(dis)connect, such as
   phy-gpio-vbus-usb.c
 - for new devicetree platforms, we'll rely on the probe deferral, and
   the phy can be gadget API agnostic.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 drivers/usb/gadget/udc/pxa27x_udc.c | 51 +++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index 001a3b74a993..79643e25a5bb 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -33,6 +33,7 @@
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/phy.h>
 
 #include "pxa27x_udc.h"
 
@@ -1655,6 +1656,37 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 	return -EOPNOTSUPP;
 }
 
+/**
+ * pxa_udc_phy_event - Called by phy upon VBus event
+ * @nb: notifier block
+ * @action: phy action, is vbus connect or disconnect
+ * @data: the usb_gadget structure in pxa_udc
+ *
+ * Called by the USB Phy when a cable connect or disconnect is sensed.
+ *
+ * Returns 0
+ */
+static int pxa_udc_phy_event(struct notifier_block *nb, unsigned long action,
+			     void *data)
+{
+	struct usb_gadget *gadget = data;
+
+	switch (action) {
+	case USB_EVENT_VBUS:
+		usb_gadget_vbus_connect(gadget);
+		return NOTIFY_OK;
+	case USB_EVENT_NONE:
+		usb_gadget_vbus_disconnect(gadget);
+		return NOTIFY_OK;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static struct notifier_block pxa27x_udc_phy = {
+	.notifier_call = pxa_udc_phy_event,
+};
+
 static int pxa27x_udc_start(struct usb_gadget *g,
 		struct usb_gadget_driver *driver);
 static int pxa27x_udc_stop(struct usb_gadget *g);
@@ -2435,7 +2467,14 @@ static int pxa_udc_probe(struct platform_device *pdev)
 		return udc->irq;
 
 	udc->dev = &pdev->dev;
-	udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	if (of_have_populated_dt()) {
+		udc->transceiver =
+			devm_usb_get_phy_by_phandle(udc->dev, "phys", 0);
+		if (IS_ERR(udc->transceiver))
+			return PTR_ERR(udc->transceiver);
+	} else {
+		udc->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+	}
 
 	if (IS_ERR(udc->gpiod)) {
 		dev_err(&pdev->dev, "Couldn't find or request D+ gpio : %ld\n",
@@ -2468,14 +2507,20 @@ static int pxa_udc_probe(struct platform_device *pdev)
 		goto err;
 	}
 
+	if (!IS_ERR_OR_NULL(udc->transceiver))
+		usb_register_notifier(udc->transceiver, &pxa27x_udc_phy);
 	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
 	if (retval)
-		goto err;
+		goto err_add_gadget;
 
 	pxa_init_debugfs(udc);
 	if (should_enable_udc(udc))
 		udc_enable(udc);
 	return 0;
+
+err_add_gadget:
+	if (!IS_ERR_OR_NULL(udc->transceiver))
+		usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
 err:
 	clk_unprepare(udc->clk);
 	return retval;
@@ -2492,6 +2537,8 @@ static int pxa_udc_remove(struct platform_device *_dev)
 	usb_del_gadget_udc(&udc->gadget);
 	pxa_cleanup_debugfs(udc);
 
+	if (!IS_ERR_OR_NULL(udc->transceiver))
+		usb_unregister_notifier(udc->transceiver, &pxa27x_udc_phy);
 	usb_put_phy(udc->transceiver);
 
 	udc->transceiver = NULL;
-- 
2.1.4

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

* [PATCH 2/3] usb: phy: generic: cope with initial state
  2016-07-08 20:09 [PATCH 1/3] usb: gadget: pxa27x: add phy notifier event handler Robert Jarzmik
@ 2016-07-08 20:09 ` Robert Jarzmik
  2016-07-08 20:09 ` [PATCH 3/3] usb: phy: generic: remove the vbus dependency Robert Jarzmik
  1 sibling, 0 replies; 3+ messages in thread
From: Robert Jarzmik @ 2016-07-08 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

In the gpio based case, the status of the phy is known at start by
reading the VBus gpio.

Actually, this is a fix, as this initial state, when not set up,
prevents a gadget to answer to the enumeration phase, as there is no
notification in this case (the VBus is already high when kernel boots)
so no interrupt is triggered, and the flow is :
 - gadget initializes
 - gadget gets its phy-generic with a xxx_get_phy_xxx() call type
 - gadget does a "set_peripheral()" call type
   => here if the otg->state is correctly filled, the proper vbus
   handling will be called, and the gadget will be aware it should
   answer enumeration and go forth

Without this fix, the USB cable must be removed and replugged for any
gadget relying on phy-generic and its gpio vbus handling to work.

The problem was seen on a pxa27x architecture based board on a
devicetree build.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 drivers/usb/phy/phy-generic.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 980c9dee09eb..41b8aff9b925 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -322,6 +322,8 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
 				gpiod_to_irq(nop->gpiod_vbus), err);
 			return err;
 		}
+		nop->phy.otg->state = gpiod_get_value(nop->gpiod_vbus) ?
+			OTG_STATE_B_PERIPHERAL : OTG_STATE_B_IDLE;
 	}
 
 	nop->phy.init		= usb_gen_phy_init;
-- 
2.1.4

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

* [PATCH 3/3] usb: phy: generic: remove the vbus dependency
  2016-07-08 20:09 [PATCH 1/3] usb: gadget: pxa27x: add phy notifier event handler Robert Jarzmik
  2016-07-08 20:09 ` [PATCH 2/3] usb: phy: generic: cope with initial state Robert Jarzmik
@ 2016-07-08 20:09 ` Robert Jarzmik
  1 sibling, 0 replies; 3+ messages in thread
From: Robert Jarzmik @ 2016-07-08 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

As the last known user, ie. pxa27x_udc relying on calls to
usb_gadget_xxx() was amended to use the phy notifier, remove a bit the
USB stack adherence.

Actually the driver still uses the gadget API for structures definition,
but the implementation of USB gadget specific function usb_gadget_*() is
not necessary anymore.

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
---
 drivers/usb/phy/phy-generic.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index 41b8aff9b925..c14e767a3fbf 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -118,8 +118,6 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
 		status = USB_EVENT_VBUS;
 		otg->state = OTG_STATE_B_PERIPHERAL;
 		nop->phy.last_event = status;
-		if (otg->gadget)
-			usb_gadget_vbus_connect(otg->gadget);
 
 		/* drawing a "unit load" is *always* OK, except for OTG */
 		nop_set_vbus_draw(nop, 100);
@@ -129,8 +127,6 @@ static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
 	} else {
 		nop_set_vbus_draw(nop, 0);
 
-		if (otg->gadget)
-			usb_gadget_vbus_disconnect(otg->gadget);
 		status = USB_EVENT_NONE;
 		otg->state = OTG_STATE_B_IDLE;
 		nop->phy.last_event = status;
@@ -187,7 +183,8 @@ static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
 
 	otg->gadget = gadget;
 	if (otg->state == OTG_STATE_B_PERIPHERAL)
-		usb_gadget_vbus_connect(gadget);
+		atomic_notifier_call_chain(&otg->usb_phy->notifier,
+					   USB_EVENT_VBUS, otg->gadget);
 	else
 		otg->state = OTG_STATE_B_IDLE;
 	return 0;
-- 
2.1.4

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

end of thread, other threads:[~2016-07-08 20:09 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-08 20:09 [PATCH 1/3] usb: gadget: pxa27x: add phy notifier event handler Robert Jarzmik
2016-07-08 20:09 ` [PATCH 2/3] usb: phy: generic: cope with initial state Robert Jarzmik
2016-07-08 20:09 ` [PATCH 3/3] usb: phy: generic: remove the vbus dependency Robert Jarzmik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).