Add regulator support for devices that sit on USB ports,
thus allowing usb devices power management for suspend/resume.

Cc: Alan Stern <st...@rowland.harvard.edu>
Cc: Greg Kroah-Hartman <gre...@linuxfoundation.org>
Signed-off-by: Nikita Kiryanov <nik...@compulab.co.il>
Signed-off-by: Igor Grinberg <grinb...@compulab.co.il>
---
 drivers/usb/host/ohci-pxa27x.c | 47 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 43 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 35e739e..ae4c64f 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -109,6 +109,7 @@ struct pxa27x_ohci {
        struct device   *dev;
        struct clk      *clk;
        struct regulator *usb_regulator;
+       struct regulator *ext_regulator[PXA_UHC_MAX_PORTNUM];
        void __iomem    *mmio_base;
 };
 
@@ -217,7 +218,7 @@ extern void pxa27x_clear_otgph(void);
 
 static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
 {
-       int retval = 0;
+       int i, retval = 0;
        struct pxaohci_platform_data *inf;
        uint32_t uhchr;
 
@@ -227,6 +228,16 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, 
struct device *dev)
        if (retval)
                return retval;
 
+       for (i = 0; i < PXA_UHC_MAX_PORTNUM; i++) {
+               retval = 0;
+               if (ohci->ext_regulator[i])
+                       retval = regulator_enable(ohci->ext_regulator[i]);
+
+               if (retval)
+                       pr_err("%s: regulator enable failed: port%d, err=%d\n",
+                              __func__, i, retval);
+       }
+
        clk_prepare_enable(ohci->clk);
 
        pxa27x_reset_hc(ohci);
@@ -257,8 +268,22 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, 
struct device *dev)
        return 0;
 }
 
+static void ohci_regulator_put_all(struct pxa27x_ohci *ohci)
+{
+       int i;
+
+       for (i = 0; i < PXA_UHC_MAX_PORTNUM; i++) {
+               if (ohci->ext_regulator[i])
+                       regulator_put(ohci->ext_regulator[i]);
+       }
+
+       /* usb regulator should be present if we get here */
+       regulator_put(ohci->usb_regulator);
+}
+
 static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
 {
+       int i;
        struct pxaohci_platform_data *inf;
        uint32_t uhccoms;
 
@@ -278,6 +303,12 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, 
struct device *dev)
        udelay(10);
 
        clk_disable_unprepare(ohci->clk);
+
+       for (i = 0; i < PXA_UHC_MAX_PORTNUM; i++) {
+               if (ohci->ext_regulator[i])
+                       regulator_disable(ohci->ext_regulator[i]);
+       }
+
        regulator_disable(ohci->usb_regulator);
 }
 
@@ -360,12 +391,13 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
  */
 int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct 
platform_device *pdev)
 {
-       int retval, irq;
+       int retval, irq, i;
        struct usb_hcd *hcd;
        struct pxaohci_platform_data *inf;
        struct pxa27x_ohci *ohci;
        struct resource *r;
        struct clk *usb_clk;
+       char supply[7];
 
        retval = ohci_pxa_of_init(pdev);
        if (retval)
@@ -427,6 +459,13 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, 
struct platform_device
                goto err3;
        }
 
+       for (i = 0; i < PXA_UHC_MAX_PORTNUM; i++) {
+               snprintf(supply, sizeof(supply), "fsusb%d", i);
+               ohci->ext_regulator[i] = regulator_get(&pdev->dev, supply);
+               if (IS_ERR(ohci->ext_regulator[i]))
+                       ohci->ext_regulator[i] = NULL;
+       }
+
        if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) {
                pr_debug("pxa27x_start_hc failed");
                goto err4;
@@ -447,7 +486,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, 
struct platform_device
        pxa27x_stop_hc(ohci, &pdev->dev);
 
 err4:
-       regulator_put(ohci->usb_regulator);
+       ohci_regulator_put_all(ohci);
  err3:
        iounmap(hcd->regs);
  err2:
@@ -483,7 +522,7 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct 
platform_device *pdev)
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        clk_put(ohci->clk);
-       regulator_put(ohci->usb_regulator);
+       ohci_regulator_put_all(ohci);
 }
 
 /*-------------------------------------------------------------------------*/
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to