usb: gadget: s3c-hsudc: Add regulator handling
authorHeiko Stübner <heiko@sntech.de>
Mon, 19 Dec 2011 18:42:19 +0000 (19:42 +0100)
committerFelipe Balbi <balbi@ti.com>
Wed, 21 Dec 2011 11:24:40 +0000 (13:24 +0200)
The udc has three supplies: vdda (3.3V), vddi (1.2V) and vddosc (1.8-3.3V).
Turn these on and off on start and stop calls.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/gadget/s3c-hsudc.c

index 1de955082abcd8f8f732fe6a3d1553ffaf249e51..94f48f66f59048ffc5f83fd140e618c7d0382055 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/usb/otg.h>
 #include <linux/prefetch.h>
 #include <linux/platform_data/s3c-hsudc.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/regs-s3c2443-clock.h>
 
 #define DATA_STATE_XMIT                        (1)
 #define DATA_STATE_RECV                        (2)
 
+static const char * const s3c_hsudc_supply_names[] = {
+       "vdda",         /* analog phy supply, 3.3V */
+       "vddi",         /* digital phy supply, 1.2V */
+       "vddosc",       /* oscillator supply, 1.8V - 3.3V */
+};
+
 /**
  * struct s3c_hsudc_ep - Endpoint representation used by driver.
  * @ep: USB gadget layer representation of device endpoint.
@@ -139,6 +146,7 @@ struct s3c_hsudc {
        struct device *dev;
        struct s3c24xx_hsudc_platdata *pd;
        struct otg_transceiver *transceiver;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
        spinlock_t lock;
        void __iomem *regs;
        struct resource *mem_rsrc;
@@ -1150,15 +1158,20 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
        hsudc->driver = driver;
        hsudc->gadget.dev.driver = &driver->driver;
 
+       ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
+                                   hsudc->supplies);
+       if (ret != 0) {
+               dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret);
+               goto err_supplies;
+       }
+
        /* connect to bus through transceiver */
        if (hsudc->transceiver) {
                ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
                if (ret) {
                        dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
                                        hsudc->gadget.name);
-                       hsudc->driver = NULL;
-                       hsudc->gadget.dev.driver = NULL;
-                       return ret;
+                       goto err_otg;
                }
        }
 
@@ -1171,6 +1184,12 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
                hsudc->pd->gpio_init();
 
        return 0;
+err_otg:
+       regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
+       hsudc->driver = NULL;
+       hsudc->gadget.dev.driver = NULL;
+       return ret;
 }
 
 static int s3c_hsudc_stop(struct usb_gadget *gadget,
@@ -1200,6 +1219,8 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
 
        disable_irq(hsudc->irq);
 
+       regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+
        dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
                        driver->driver.name);
        return 0;
@@ -1241,7 +1262,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
        struct resource *res;
        struct s3c_hsudc *hsudc;
        struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
-       int ret;
+       int ret, i;
 
        hsudc = kzalloc(sizeof(struct s3c_hsudc) +
                        sizeof(struct s3c_hsudc_ep) * pd->epnum,
@@ -1258,6 +1279,16 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 
        hsudc->transceiver = otg_get_transceiver();
 
+       for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
+               hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
+
+       ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
+                                hsudc->supplies);
+       if (ret != 0) {
+               dev_err(dev, "failed to request supplies: %d\n", ret);
+               goto err_supplies;
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "unable to obtain driver resource data\n");
@@ -1352,6 +1383,8 @@ err_res:
        if (hsudc->transceiver)
                otg_put_transceiver(hsudc->transceiver);
 
+       regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
        kfree(hsudc);
        return ret;
 }