phy: rcar-gen3-usb2: Add vbus-supply to handle VBUS on/off
authorYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Thu, 3 Mar 2016 10:09:05 +0000 (19:09 +0900)
committerKishon Vijay Abraham I <kishon@ti.com>
Sat, 30 Apr 2016 14:42:25 +0000 (20:12 +0530)
To handle the VBUS on/off by a regulator driver, this patch adds
regulator APIs calling in the driver and description about vbus-supply
in the rcar-gen3-phy-usb2.txt.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
drivers/phy/phy-rcar-gen3-usb2.c

index f9511ad95b9429f69515ab3ad19cde27c74882cd..2281d6cdecb13cfec3c7c6c9ad6ab4a641524fa4 100644 (file)
@@ -21,6 +21,8 @@ To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are
 combined, the device tree node should set interrupt properties to use the
 channel as USB OTG:
 - interrupts: interrupt specifier for the PHY.
+- vbus-supply: Phandle to a regulator that provides power to the VBUS. This
+              regulator will be managed during the PHY power on/off sequence.
 
 Example (R-Car H3):
 
index 3c647cd9c432af150401c1200ff5e461cab8aa63..7b14244be285731d161423226d28616abeee90d8 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of_address.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 
 /******* USB2.0 Host registers (original offset is +0x200) *******/
 #define USB2_INT_ENABLE                0x000
@@ -77,6 +78,7 @@
 struct rcar_gen3_chan {
        void __iomem *base;
        struct phy *phy;
+       struct regulator *vbus;
        bool has_otg;
 };
 
@@ -210,6 +212,13 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
        struct rcar_gen3_chan *channel = phy_get_drvdata(p);
        void __iomem *usb2_base = channel->base;
        u32 val;
+       int ret;
+
+       if (channel->vbus) {
+               ret = regulator_enable(channel->vbus);
+               if (ret)
+                       return ret;
+       }
 
        val = readl(usb2_base + USB2_USBCTR);
        val |= USB2_USBCTR_PLL_RST;
@@ -220,10 +229,22 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
        return 0;
 }
 
+static int rcar_gen3_phy_usb2_power_off(struct phy *p)
+{
+       struct rcar_gen3_chan *channel = phy_get_drvdata(p);
+       int ret = 0;
+
+       if (channel->vbus)
+               ret = regulator_disable(channel->vbus);
+
+       return ret;
+}
+
 static struct phy_ops rcar_gen3_phy_usb2_ops = {
        .init           = rcar_gen3_phy_usb2_init,
        .exit           = rcar_gen3_phy_usb2_exit,
        .power_on       = rcar_gen3_phy_usb2_power_on,
+       .power_off      = rcar_gen3_phy_usb2_power_off,
        .owner          = THIS_MODULE,
 };
 
@@ -290,6 +311,13 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
                return PTR_ERR(channel->phy);
        }
 
+       channel->vbus = devm_regulator_get_optional(dev, "vbus");
+       if (IS_ERR(channel->vbus)) {
+               if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
+                       return PTR_ERR(channel->vbus);
+               channel->vbus = NULL;
+       }
+
        phy_set_drvdata(channel->phy, channel);
 
        provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);