phy: meson-g12a-usb3-pcie: Add support for PCIe mode
[linux-2.6-microblaze.git] / drivers / phy / amlogic / phy-meson-g12a-usb3-pcie.c
index ac322d6..08e3227 100644 (file)
@@ -50,6 +50,8 @@
        #define PHY_R5_PHY_CR_ACK                               BIT(16)
        #define PHY_R5_PHY_BS_OUT                               BIT(17)
 
+#define PCIE_RESET_DELAY                                       500
+
 struct phy_g12a_usb3_pcie_priv {
        struct regmap           *regmap;
        struct regmap           *regmap_cr;
@@ -196,6 +198,10 @@ static int phy_g12a_usb3_init(struct phy *phy)
        struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
        int data, ret;
 
+       ret = reset_control_reset(priv->reset);
+       if (ret)
+               return ret;
+
        /* Switch PHY to USB3 */
        /* TODO figure out how to handle when PCIe was set in the bootloader */
        regmap_update_bits(priv->regmap, PHY_R0,
@@ -272,24 +278,64 @@ static int phy_g12a_usb3_init(struct phy *phy)
        return 0;
 }
 
-static int phy_g12a_usb3_pcie_init(struct phy *phy)
+static int phy_g12a_usb3_pcie_power_on(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
+
+       if (priv->mode == PHY_TYPE_USB3)
+               return 0;
+
+       regmap_update_bits(priv->regmap, PHY_R0,
+                          PHY_R0_PCIE_POWER_STATE,
+                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c));
+
+       return 0;
+}
+
+static int phy_g12a_usb3_pcie_power_off(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
+
+       if (priv->mode == PHY_TYPE_USB3)
+               return 0;
+
+       regmap_update_bits(priv->regmap, PHY_R0,
+                          PHY_R0_PCIE_POWER_STATE,
+                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1d));
+
+       return 0;
+}
+
+static int phy_g12a_usb3_pcie_reset(struct phy *phy)
 {
        struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
        int ret;
 
-       ret = reset_control_reset(priv->reset);
+       if (priv->mode == PHY_TYPE_USB3)
+               return 0;
+
+       ret = reset_control_assert(priv->reset);
        if (ret)
                return ret;
 
+       udelay(PCIE_RESET_DELAY);
+
+       ret = reset_control_deassert(priv->reset);
+       if (ret)
+               return ret;
+
+       udelay(PCIE_RESET_DELAY);
+
+       return 0;
+}
+
+static int phy_g12a_usb3_pcie_init(struct phy *phy)
+{
+       struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
+
        if (priv->mode == PHY_TYPE_USB3)
                return phy_g12a_usb3_init(phy);
 
-       /* Power UP PCIE */
-       /* TODO figure out when the bootloader has set USB3 mode before */
-       regmap_update_bits(priv->regmap, PHY_R0,
-                          PHY_R0_PCIE_POWER_STATE,
-                          FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c));
-
        return 0;
 }
 
@@ -297,7 +343,10 @@ static int phy_g12a_usb3_pcie_exit(struct phy *phy)
 {
        struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy);
 
-       return reset_control_reset(priv->reset);
+       if (priv->mode == PHY_TYPE_USB3)
+               return reset_control_reset(priv->reset);
+
+       return 0;
 }
 
 static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev,
@@ -326,6 +375,9 @@ static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev,
 static const struct phy_ops phy_g12a_usb3_pcie_ops = {
        .init           = phy_g12a_usb3_pcie_init,
        .exit           = phy_g12a_usb3_pcie_exit,
+       .power_on       = phy_g12a_usb3_pcie_power_on,
+       .power_off      = phy_g12a_usb3_pcie_power_off,
+       .reset          = phy_g12a_usb3_pcie_reset,
        .owner          = THIS_MODULE,
 };