All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations
@ 2014-04-16 13:16 Laurent Pinchart
  2014-04-16 13:16 ` [PATCH v3 1/4] USB: OHCI: Export the OHCI hub control and status_data functions Laurent Pinchart
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Laurent Pinchart @ 2014-04-16 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

The PXA27x OHCI implementation doesn't perform automatic control of port power
supplies for all ports. While the PPS and LSDA bits of the HcRhPortStatus
register are implemented, only a subset of ports have an external power enable
pin controlled by the port status register. Other ports need their power supply
to be controlled manually.

In order to do so I've implemented manual regulator control in the ohci-pxa27x
driver. This requires overriding the default behaviour of the CLEAR_FEATURE
and SET_FEATURE requests for USB_PORT_FEAT_POWER with a custom hub control
operation. In turn this requires calling the currently static ohci_hub_control
function from the ohci-pxa27x driver.

The ohci-at91 and ohci-s3c2410 drivers already implement a similar feature,
and access the ohci_hub_control and ohci_hub_status_data functions by saving
the struct hc_driver hub_control and hub_status_data values to a variables
right after calling ohci_init_driver. This vtable-like implementation can be
optimized by exporting the ohci_hub_control and ohci_hub_status_data functions
and calling them directly. As the ohci-pxa27x driver needs to override hub
control operations as well I've decided to export the functions.

For the sake of completeness I've also exported the ehci_hub_control function
and modified the ehci-tegra driver to call it directly.

As a side note regarding the ohci-at91 driver, the "atmel,vbus-gpio" DT
property should really have referenced a regulator instead of a GPIO. Fixing
this in a backward-compatible way would be messy :-(

Please note that I haven't been able to test the third and fourth patches due
to lack of hardware. I've however tested a similar implementation for OHCI on
an out of tree PXA270 board.

Changes compared to v2:

- Export ohci_hub_status_data()
- Call ohci_hub_status_data() directly from ohci-at91 and ohci-s3c2410

Changes compared to v1:

- Export ehci_hub_control()
- Call ehci_hub_control() directly from ehci-tegra
- Call ohci_hub_control() directly from ohci-at91

Laurent Pinchart (4):
  USB: OHCI: Export the OHCI hub control and status_data functions
  USB: EHCI: Export the ehci_hub_control function
  USB: ohci-pxa27x: Add support for external vbus regulators
  ARM: pxa: zeus: Replace OHCI init/exit functions with a regulator

 arch/arm/mach-pxa/zeus.c        | 89 ++++++++++++++++++++++-------------------
 drivers/usb/host/ehci-hub.c     | 12 +-----
 drivers/usb/host/ehci-tegra.c   |  8 +---
 drivers/usb/host/ehci.h         |  3 ++
 drivers/usb/host/ohci-at91.c    | 11 +----
 drivers/usb/host/ohci-hub.c     |  8 ++--
 drivers/usb/host/ohci-pxa27x.c  | 67 +++++++++++++++++++++++++++++++
 drivers/usb/host/ohci-s3c2410.c | 13 ++----
 drivers/usb/host/ohci.h         |  3 ++
 9 files changed, 133 insertions(+), 81 deletions(-)

-- 
Regards,

Laurent Pinchart

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

* [PATCH v3 1/4] USB: OHCI: Export the OHCI hub control and status_data functions
  2014-04-16 13:16 [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Laurent Pinchart
@ 2014-04-16 13:16 ` Laurent Pinchart
  2014-04-16 13:16 ` [PATCH v3 2/4] USB: EHCI: Export the ehci_hub_control function Laurent Pinchart
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Laurent Pinchart @ 2014-04-16 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

Platform drivers sometimes need to perform specific handling of hub
control requests and status data. Make this possible by exporting the
ohci_hub_control() and ohci_hub_status_data() functions which can then
be called from custom hub operations in the default case.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/usb/host/ohci-at91.c    | 11 ++---------
 drivers/usb/host/ohci-hub.c     |  8 ++++----
 drivers/usb/host/ohci-s3c2410.c | 13 +++----------
 drivers/usb/host/ohci.h         |  3 +++
 4 files changed, 12 insertions(+), 23 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 091ae49..e49eb4f 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -46,9 +46,6 @@ static const char hcd_name[] = "ohci-atmel";
 
 static struct hc_driver __read_mostly ohci_at91_hc_driver;
 static int clocked;
-static int (*orig_ohci_hub_control)(struct usb_hcd  *hcd, u16 typeReq,
-			u16 wValue, u16 wIndex, char *buf, u16 wLength);
-static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf);
 
 extern int usb_disabled(void);
 
@@ -262,7 +259,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
 static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
 	struct at91_usbh_data *pdata = hcd->self.controller->platform_data;
-	int length = orig_ohci_hub_status_data(hcd, buf);
+	int length = ohci_hub_status_data(hcd, buf);
 	int port;
 
 	at91_for_each_port(port) {
@@ -340,8 +337,7 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		break;
 	}
 
-	ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex + 1,
-				buf, wLength);
+	ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength);
 	if (ret)
 		goto out;
 
@@ -690,9 +686,6 @@ static int __init ohci_at91_init(void)
 	 * too easy.
 	 */
 
-	orig_ohci_hub_control = ohci_at91_hc_driver.hub_control;
-	orig_ohci_hub_status_data = ohci_at91_hc_driver.hub_status_data;
-
 	ohci_at91_hc_driver.hub_status_data	= ohci_at91_hub_status_data;
 	ohci_at91_hc_driver.hub_control		= ohci_at91_hub_control;
 
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index c81c872..3d53208 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -438,8 +438,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
 
 /* build "status change" packet (one or two bytes) from HC registers */
 
-static int
-ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
+int ohci_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		i, changed = 0, length = 1;
@@ -504,6 +503,7 @@ done:
 
 	return changed ? length : 0;
 }
+EXPORT_SYMBOL_GPL(ohci_hub_status_data);
 
 /*-------------------------------------------------------------------------*/
 
@@ -646,7 +646,7 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
 	return 0;
 }
 
-static int ohci_hub_control (
+int ohci_hub_control(
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		wValue,
@@ -772,4 +772,4 @@ error:
 	}
 	return retval;
 }
-
+EXPORT_SYMBOL_GPL(ohci_hub_control);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index ff7c8f1..3d753a9 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -45,10 +45,6 @@ static struct clk *usb_clk;
 
 /* forward definitions */
 
-static int (*orig_ohci_hub_control)(struct usb_hcd  *hcd, u16 typeReq,
-			u16 wValue, u16 wIndex, char *buf, u16 wLength);
-static int (*orig_ohci_hub_status_data)(struct usb_hcd *hcd, char *buf);
-
 static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc);
 
 /* conversion functions */
@@ -110,7 +106,7 @@ ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf)
 	int orig;
 	int portno;
 
-	orig = orig_ohci_hub_status_data(hcd, buf);
+	orig = ohci_hub_status_data(hcd, buf);
 
 	if (info == NULL)
 		return orig;
@@ -181,7 +177,7 @@ static int ohci_s3c2410_hub_control(
 	 * process the request straight away and exit */
 
 	if (info == NULL) {
-		ret = orig_ohci_hub_control(hcd, typeReq, wValue,
+		ret = ohci_hub_control(hcd, typeReq, wValue,
 				       wIndex, buf, wLength);
 		goto out;
 	}
@@ -231,7 +227,7 @@ static int ohci_s3c2410_hub_control(
 		break;
 	}
 
-	ret = orig_ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+	ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
 	if (ret)
 		goto out;
 
@@ -489,9 +485,6 @@ static int __init ohci_s3c2410_init(void)
 	 * override these functions by making it too easy.
 	 */
 
-	orig_ohci_hub_control = ohci_s3c2410_hc_driver.hub_control;
-	orig_ohci_hub_status_data = ohci_s3c2410_hc_driver.hub_status_data;
-
 	ohci_s3c2410_hc_driver.hub_status_data	= ohci_s3c2410_hub_status_data;
 	ohci_s3c2410_hc_driver.hub_control	= ohci_s3c2410_hub_control;
 
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 9250cad..a116583 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -727,3 +727,6 @@ extern int	ohci_setup(struct usb_hcd *hcd);
 extern int	ohci_suspend(struct usb_hcd *hcd, bool do_wakeup);
 extern int	ohci_resume(struct usb_hcd *hcd, bool hibernated);
 #endif
+extern int	ohci_hub_control(struct usb_hcd	*hcd, u16 typeReq, u16 wValue,
+				 u16 wIndex, char *buf, u16 wLength);
+extern int	ohci_hub_status_data(struct usb_hcd *hcd, char *buf);
-- 
1.8.3.2

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

* [PATCH v3 2/4] USB: EHCI: Export the ehci_hub_control function
  2014-04-16 13:16 [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Laurent Pinchart
  2014-04-16 13:16 ` [PATCH v3 1/4] USB: OHCI: Export the OHCI hub control and status_data functions Laurent Pinchart
@ 2014-04-16 13:16 ` Laurent Pinchart
  2014-04-16 13:16 ` [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators Laurent Pinchart
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Laurent Pinchart @ 2014-04-16 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

Platform drivers sometimes need to perform specific handling of hub
control requests. Make this possible by exporting the ehci_hub_control()
function which can then be called from a custom hub control handler in
the default case.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/usb/host/ehci-hub.c   | 12 ++----------
 drivers/usb/host/ehci-tegra.c |  8 +-------
 drivers/usb/host/ehci.h       |  3 +++
 3 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 7ae0c4d..cc305c7 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -33,15 +33,6 @@
 
 #ifdef	CONFIG_PM
 
-static int ehci_hub_control(
-	struct usb_hcd	*hcd,
-	u16		typeReq,
-	u16		wValue,
-	u16		wIndex,
-	char		*buf,
-	u16		wLength
-);
-
 static int persist_enabled_on_companion(struct usb_device *udev, void *unused)
 {
 	return !udev->maxchild && udev->persist_enabled &&
@@ -865,7 +856,7 @@ cleanup:
 #endif /* CONFIG_USB_HCD_TEST_MODE */
 /*-------------------------------------------------------------------------*/
 
-static int ehci_hub_control (
+int ehci_hub_control(
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		wValue,
@@ -1285,6 +1276,7 @@ error_exit:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(ehci_hub_control);
 
 static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
 {
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index af28b74..f64653f 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -55,10 +55,6 @@ struct tegra_ehci_soc_config {
 	bool has_hostpc;
 };
 
-static int (*orig_hub_control)(struct usb_hcd *hcd,
-				u16 typeReq, u16 wValue, u16 wIndex,
-				char *buf, u16 wLength);
-
 struct tegra_ehci_hcd {
 	struct tegra_usb_phy *phy;
 	struct clk *clk;
@@ -240,7 +236,7 @@ static int tegra_ehci_hub_control(
 	spin_unlock_irqrestore(&ehci->lock, flags);
 
 	/* Handle the hub control events here */
-	return orig_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+	return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
 
 done:
 	spin_unlock_irqrestore(&ehci->lock, flags);
@@ -535,8 +531,6 @@ static int __init ehci_tegra_init(void)
 	 * too easy.
 	 */
 
-	orig_hub_control = tegra_ehci_hc_driver.hub_control;
-
 	tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma;
 	tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma;
 	tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 9dfc6c1..eee228a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -872,4 +872,7 @@ extern int	ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
 extern int	ehci_resume(struct usb_hcd *hcd, bool hibernated);
 #endif	/* CONFIG_PM */
 
+extern int	ehci_hub_control(struct usb_hcd	*hcd, u16 typeReq, u16 wValue,
+				 u16 wIndex, char *buf, u16 wLength);
+
 #endif /* __LINUX_EHCI_HCD_H */
-- 
1.8.3.2

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

* [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators
  2014-04-16 13:16 [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Laurent Pinchart
  2014-04-16 13:16 ` [PATCH v3 1/4] USB: OHCI: Export the OHCI hub control and status_data functions Laurent Pinchart
  2014-04-16 13:16 ` [PATCH v3 2/4] USB: EHCI: Export the ehci_hub_control function Laurent Pinchart
@ 2014-04-16 13:16 ` Laurent Pinchart
  2014-04-16 15:07   ` Alan Stern
  2014-04-16 13:16 ` [PATCH v3 4/4] ARM: pxa: zeus: Replace OHCI init/exit functions with a regulator Laurent Pinchart
  2014-04-16 15:01 ` [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Alan Stern
  4 siblings, 1 reply; 8+ messages in thread
From: Laurent Pinchart @ 2014-04-16 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

Override the hub control operation to enable and disable external
regulators for the ports vbus power supply in response to clear/set
USB_PORT_FEAT_POWER requests.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/usb/host/ohci-pxa27x.c | 67 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index d21d5fe..0c31265 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -30,6 +30,7 @@
 #include <linux/platform_data/usb-ohci-pxa27x.h>
 #include <linux/platform_data/usb-pxa3xx-ulpi.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/signal.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -120,6 +121,8 @@ static struct hc_driver __read_mostly ohci_pxa27x_hc_driver;
 struct pxa27x_ohci {
 	struct clk	*clk;
 	void __iomem	*mmio_base;
+	struct regulator *vbus[3];
+	bool		vbus_enabled[3];
 };
 
 #define to_pxa27x_ohci(hcd)	(struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv)
@@ -166,6 +169,52 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode)
 	return 0;
 }
 
+static int pxa27x_ohci_set_vbus_power(struct pxa27x_ohci *pxa_ohci,
+				      unsigned int port, bool enable)
+{
+	struct regulator *vbus = pxa_ohci->vbus[port];
+	int ret = 0;
+
+	if (IS_ERR_OR_NULL(vbus))
+		return 0;
+
+	if (enable && !pxa_ohci->vbus_enabled[port])
+		ret = regulator_enable(vbus);
+	else if (!enable && pxa_ohci->vbus_enabled[port])
+		ret = regulator_disable(vbus);
+
+	if (ret < 0)
+		return ret;
+
+	pxa_ohci->vbus_enabled[port] = enable;
+
+	return 0;
+}
+
+static int pxa27x_ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+				   u16 wIndex, char *buf, u16 wLength)
+{
+	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
+	int ret;
+
+	switch (typeReq) {
+	case SetPortFeature:
+	case ClearPortFeature:
+		if (!wIndex || wIndex > 3)
+			return -EPIPE;
+
+		if (wValue != USB_PORT_FEAT_POWER)
+			break;
+
+		ret = pxa27x_ohci_set_vbus_power(pxa_ohci, wIndex - 1,
+						 typeReq == SetPortFeature);
+		if (ret)
+			return ret;
+		break;
+	}
+
+	return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+}
 /*-------------------------------------------------------------------------*/
 
 static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci,
@@ -372,6 +421,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
 	struct ohci_hcd *ohci;
 	struct resource *r;
 	struct clk *usb_clk;
+	unsigned int i;
 
 	retval = ohci_pxa_of_init(pdev);
 	if (retval)
@@ -417,6 +467,16 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
 	pxa_ohci->clk = usb_clk;
 	pxa_ohci->mmio_base = (void __iomem *)hcd->regs;
 
+	for (i = 0; i < 3; ++i) {
+		char name[6];
+
+		if (!(inf->flags & (ENABLE_PORT1 << i)))
+			continue;
+
+		sprintf(name, "vbus%u", i + 1);
+		pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name);
+	}
+
 	retval = pxa27x_start_hc(pxa_ohci, &pdev->dev);
 	if (retval < 0) {
 		pr_debug("pxa27x_start_hc failed");
@@ -462,6 +522,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
 void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 {
 	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
+	unsigned int i;
+
+	for (i = 0; i < 3; ++i)
+		pxa27x_ohci_set_vbus_power(pxa_ohci, i, false);
 
 	usb_remove_hcd(hcd);
 	pxa27x_stop_hc(pxa_ohci, &pdev->dev);
@@ -563,7 +627,10 @@ static int __init ohci_pxa27x_init(void)
 		return -ENODEV;
 
 	pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+
 	ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides);
+	ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control;
+
 	return platform_driver_register(&ohci_hcd_pxa27x_driver);
 }
 module_init(ohci_pxa27x_init);
-- 
1.8.3.2

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

* [PATCH v3 4/4] ARM: pxa: zeus: Replace OHCI init/exit functions with a regulator
  2014-04-16 13:16 [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Laurent Pinchart
                   ` (2 preceding siblings ...)
  2014-04-16 13:16 ` [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators Laurent Pinchart
@ 2014-04-16 13:16 ` Laurent Pinchart
  2014-04-16 15:01 ` [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Alan Stern
  4 siblings, 0 replies; 8+ messages in thread
From: Laurent Pinchart @ 2014-04-16 13:16 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 arch/arm/mach-pxa/zeus.c | 89 ++++++++++++++++++++++++++----------------------
 1 file changed, 48 insertions(+), 41 deletions(-)

diff --git a/arch/arm/mach-pxa/zeus.c b/arch/arm/mach-pxa/zeus.c
index b19d1c3..205f9bf 100644
--- a/arch/arm/mach-pxa/zeus.c
+++ b/arch/arm/mach-pxa/zeus.c
@@ -413,7 +413,7 @@ static struct fixed_voltage_config can_regulator_pdata = {
 
 static struct platform_device can_regulator_device = {
 	.name	= "reg-fixed-volage",
-	.id	= -1,
+	.id	= 0,
 	.dev	= {
 		.platform_data	= &can_regulator_pdata,
 	},
@@ -510,18 +510,6 @@ struct platform_device zeus_max6369_device = {
 	.num_resources	= 1,
 };
 
-static struct platform_device *zeus_devices[] __initdata = {
-	&zeus_serial_device,
-	&zeus_mtd_devices[0],
-	&zeus_dm9k0_device,
-	&zeus_dm9k1_device,
-	&zeus_sram_device,
-	&zeus_leds_device,
-	&zeus_pcmcia_device,
-	&zeus_max6369_device,
-	&can_regulator_device,
-};
-
 /* AC'97 */
 static pxa2xx_audio_ops_t zeus_ac97_info = {
 	.reset_gpio = 95,
@@ -532,44 +520,50 @@ static pxa2xx_audio_ops_t zeus_ac97_info = {
  * USB host
  */
 
-static int zeus_ohci_init(struct device *dev)
-{
-	int err;
-
-	/* Switch on port 2. */
-	if ((err = gpio_request(ZEUS_USB2_PWREN_GPIO, "USB2_PWREN"))) {
-		dev_err(dev, "Can't request USB2_PWREN\n");
-		return err;
-	}
-
-	if ((err = gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 1))) {
-		gpio_free(ZEUS_USB2_PWREN_GPIO);
-		dev_err(dev, "Can't enable USB2_PWREN\n");
-		return err;
-	}
+static struct regulator_consumer_supply zeus_ohci_regulator_supplies[] = {
+	REGULATOR_SUPPLY("vbus2", "pxa27x-ohci"),
+};
 
-	/* Port 2 is shared between host and client interface. */
-	UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE;
+static struct regulator_init_data zeus_ohci_regulator_data = {
+	.constraints = {
+		.valid_ops_mask		= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(zeus_ohci_regulator_supplies),
+	.consumer_supplies	= zeus_ohci_regulator_supplies,
+};
 
-	return 0;
-}
+static struct fixed_voltage_config zeus_ohci_regulator_config = {
+	.supply_name		= "vbus2",
+	.microvolts		= 5000000, /* 5.0V */
+	.gpio			= ZEUS_USB2_PWREN_GPIO,
+	.enable_high		= 1,
+	.startup_delay		= 0,
+	.init_data		= &zeus_ohci_regulator_data,
+};
 
-static void zeus_ohci_exit(struct device *dev)
-{
-	/* Power-off port 2 */
-	gpio_direction_output(ZEUS_USB2_PWREN_GPIO, 0);
-	gpio_free(ZEUS_USB2_PWREN_GPIO);
-}
+static struct platform_device zeus_ohci_regulator_device = {
+	.name		= "reg-fixed-voltage",
+	.id		= 1,
+	.dev = {
+		.platform_data = &zeus_ohci_regulator_config,
+	},
+};
 
 static struct pxaohci_platform_data zeus_ohci_platform_data = {
 	.port_mode	= PMM_NPS_MODE,
 	/* Clear Power Control Polarity Low and set Power Sense
 	 * Polarity Low. Supply power to USB ports. */
 	.flags		= ENABLE_PORT_ALL | POWER_SENSE_LOW,
-	.init		= zeus_ohci_init,
-	.exit		= zeus_ohci_exit,
 };
 
+static void zeus_register_ohci(void)
+{
+	/* Port 2 is shared between host and client interface. */
+	UP2OCR = UP2OCR_HXOE | UP2OCR_HXS | UP2OCR_DMPDE | UP2OCR_DPPDE;
+
+	pxa_set_ohci_info(&zeus_ohci_platform_data);
+}
+
 /*
  * Flat Panel
  */
@@ -677,6 +671,19 @@ static struct pxa2xx_udc_mach_info zeus_udc_info = {
 	.udc_command = zeus_udc_command,
 };
 
+static struct platform_device *zeus_devices[] __initdata = {
+	&zeus_serial_device,
+	&zeus_mtd_devices[0],
+	&zeus_dm9k0_device,
+	&zeus_dm9k1_device,
+	&zeus_sram_device,
+	&zeus_leds_device,
+	&zeus_pcmcia_device,
+	&zeus_max6369_device,
+	&can_regulator_device,
+	&zeus_ohci_regulator_device,
+};
+
 #ifdef CONFIG_PM
 static void zeus_power_off(void)
 {
@@ -847,7 +854,7 @@ static void __init zeus_init(void)
 
 	platform_add_devices(zeus_devices, ARRAY_SIZE(zeus_devices));
 
-	pxa_set_ohci_info(&zeus_ohci_platform_data);
+	zeus_register_ohci();
 
 	if (zeus_setup_fb_gpios())
 		pr_err("Failed to setup fb gpios\n");
-- 
1.8.3.2

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

* [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations
  2014-04-16 13:16 [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Laurent Pinchart
                   ` (3 preceding siblings ...)
  2014-04-16 13:16 ` [PATCH v3 4/4] ARM: pxa: zeus: Replace OHCI init/exit functions with a regulator Laurent Pinchart
@ 2014-04-16 15:01 ` Alan Stern
  4 siblings, 0 replies; 8+ messages in thread
From: Alan Stern @ 2014-04-16 15:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 16 Apr 2014, Laurent Pinchart wrote:

> Hello,
> 
> The PXA27x OHCI implementation doesn't perform automatic control of port power
> supplies for all ports. While the PPS and LSDA bits of the HcRhPortStatus
> register are implemented, only a subset of ports have an external power enable
> pin controlled by the port status register. Other ports need their power supply
> to be controlled manually.
> 
> In order to do so I've implemented manual regulator control in the ohci-pxa27x
> driver. This requires overriding the default behaviour of the CLEAR_FEATURE
> and SET_FEATURE requests for USB_PORT_FEAT_POWER with a custom hub control
> operation. In turn this requires calling the currently static ohci_hub_control
> function from the ohci-pxa27x driver.
> 
> The ohci-at91 and ohci-s3c2410 drivers already implement a similar feature,
> and access the ohci_hub_control and ohci_hub_status_data functions by saving
> the struct hc_driver hub_control and hub_status_data values to a variables
> right after calling ohci_init_driver. This vtable-like implementation can be
> optimized by exporting the ohci_hub_control and ohci_hub_status_data functions
> and calling them directly. As the ohci-pxa27x driver needs to override hub
> control operations as well I've decided to export the functions.
> 
> For the sake of completeness I've also exported the ehci_hub_control function
> and modified the ehci-tegra driver to call it directly.
> 
> As a side note regarding the ohci-at91 driver, the "atmel,vbus-gpio" DT
> property should really have referenced a regulator instead of a GPIO. Fixing
> this in a backward-compatible way would be messy :-(
> 
> Please note that I haven't been able to test the third and fourth patches due
> to lack of hardware. I've however tested a similar implementation for OHCI on
> an out of tree PXA270 board.
> 
> Changes compared to v2:
> 
> - Export ohci_hub_status_data()
> - Call ohci_hub_status_data() directly from ohci-at91 and ohci-s3c2410
> 
> Changes compared to v1:
> 
> - Export ehci_hub_control()
> - Call ehci_hub_control() directly from ehci-tegra
> - Call ohci_hub_control() directly from ohci-at91

For patches 1 and 2:

Acked-by: Alan Stern <stern@rowland.harvard.edu>

Comments on patch 3 sent separately.

Alan Stern

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

* [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators
  2014-04-16 13:16 ` [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators Laurent Pinchart
@ 2014-04-16 15:07   ` Alan Stern
  2014-04-16 15:40     ` Laurent Pinchart
  0 siblings, 1 reply; 8+ messages in thread
From: Alan Stern @ 2014-04-16 15:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 16 Apr 2014, Laurent Pinchart wrote:

> Override the hub control operation to enable and disable external
> regulators for the ports vbus power supply in response to clear/set
> USB_PORT_FEAT_POWER requests.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> @@ -417,6 +467,16 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
>  	pxa_ohci->clk = usb_clk;
>  	pxa_ohci->mmio_base = (void __iomem *)hcd->regs;
>  
> +	for (i = 0; i < 3; ++i) {
> +		char name[6];
> +
> +		if (!(inf->flags & (ENABLE_PORT1 << i)))
> +			continue;
> +
> +		sprintf(name, "vbus%u", i + 1);
> +		pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name);
> +	}
> +
>  	retval = pxa27x_start_hc(pxa_ohci, &pdev->dev);
>  	if (retval < 0) {
>  		pr_debug("pxa27x_start_hc failed");
> @@ -462,6 +522,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
>  void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
>  {
>  	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
> +	unsigned int i;
> +
> +	for (i = 0; i < 3; ++i)
> +		pxa27x_ohci_set_vbus_power(pxa_ohci, i, false);
>  
>  	usb_remove_hcd(hcd);
>  	pxa27x_stop_hc(pxa_ohci, &pdev->dev);

You probably should leave the port power enabled until after 
usb_remove_hcd() returns.  Apart from that,

Acked-by: Alan Stern <stern@rowland.harvard.edu>

Alan Stern

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

* [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators
  2014-04-16 15:07   ` Alan Stern
@ 2014-04-16 15:40     ` Laurent Pinchart
  0 siblings, 0 replies; 8+ messages in thread
From: Laurent Pinchart @ 2014-04-16 15:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Alan,

On Wednesday 16 April 2014 11:07:34 Alan Stern wrote:
> On Wed, 16 Apr 2014, Laurent Pinchart wrote:
> > Override the hub control operation to enable and disable external
> > regulators for the ports vbus power supply in response to clear/set
> > USB_PORT_FEAT_POWER requests.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > @@ -417,6 +467,16 @@ int usb_hcd_pxa27x_probe (const struct hc_driver
> > *driver, struct platform_device> 
> >  	pxa_ohci->clk = usb_clk;
> >  	pxa_ohci->mmio_base = (void __iomem *)hcd->regs;
> > 
> > +	for (i = 0; i < 3; ++i) {
> > +		char name[6];
> > +
> > +		if (!(inf->flags & (ENABLE_PORT1 << i)))
> > +			continue;
> > +
> > +		sprintf(name, "vbus%u", i + 1);
> > +		pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name);
> > +	}
> > +
> > 
> >  	retval = pxa27x_start_hc(pxa_ohci, &pdev->dev);
> >  	if (retval < 0) {
> >  	
> >  		pr_debug("pxa27x_start_hc failed");
> > 
> > @@ -462,6 +522,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver
> > *driver, struct platform_device> 
> >  void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device
> >  *pdev) {
> >  
> >  	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
> > 
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < 3; ++i)
> > +		pxa27x_ohci_set_vbus_power(pxa_ohci, i, false);
> > 
> >  	usb_remove_hcd(hcd);
> >  	pxa27x_stop_hc(pxa_ohci, &pdev->dev);
> 
> You probably should leave the port power enabled until after
> usb_remove_hcd() returns.  Apart from that,
> 
> Acked-by: Alan Stern <stern@rowland.harvard.edu>

Good point, I'll fix that and submit v4. Thank you.

-- 
Regards,

Laurent Pinchart

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

end of thread, other threads:[~2014-04-16 15:40 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-16 13:16 [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Laurent Pinchart
2014-04-16 13:16 ` [PATCH v3 1/4] USB: OHCI: Export the OHCI hub control and status_data functions Laurent Pinchart
2014-04-16 13:16 ` [PATCH v3 2/4] USB: EHCI: Export the ehci_hub_control function Laurent Pinchart
2014-04-16 13:16 ` [PATCH v3 3/4] USB: ohci-pxa27x: Add support for external vbus regulators Laurent Pinchart
2014-04-16 15:07   ` Alan Stern
2014-04-16 15:40     ` Laurent Pinchart
2014-04-16 13:16 ` [PATCH v3 4/4] ARM: pxa: zeus: Replace OHCI init/exit functions with a regulator Laurent Pinchart
2014-04-16 15:01 ` [PATCH v3 0/4] Allow OHCI/EHCI drivers to override more hub operations Alan Stern

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.