Add regulator support for devices that sit on USB ports, thus allowing usb devices power management for suspend/resume. Cc: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Cc: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Nikita Kiryanov <nikita@xxxxxxxxxxxxxx> Signed-off-by: Igor Grinberg <grinberg@xxxxxxxxxxxxxx> --- 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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html