phy: meson-g12a-usb3-pcie: add support for PCIe ops

Add the PCIe part of the G12A USB3 PCIe Combo PHY driver.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
diff --git a/drivers/phy/meson-g12a-usb3-pcie.c b/drivers/phy/meson-g12a-usb3-pcie.c
index 0433d93..8f72b5a 100644
--- a/drivers/phy/meson-g12a-usb3-pcie.c
+++ b/drivers/phy/meson-g12a-usb3-pcie.c
@@ -23,6 +23,9 @@
 #include <linux/compat.h>
 #include <linux/bitfield.h>
 
+#define PHY_TYPE_PCIE           2
+#define PHY_TYPE_USB3           4
+
 #define PHY_R0							0x00
 	#define PHY_R0_PCIE_POWER_STATE				GENMASK(4, 0)
 	#define PHY_R0_PCIE_USB3_SWITCH				GENMASK(6, 5)
@@ -55,6 +58,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;
 #if CONFIG_IS_ENABLED(CLK)
@@ -202,8 +207,6 @@
 	unsigned int data;
 	int ret;
 
-	/* TOFIX Handle PCIE mode */
-
 	ret = reset_assert_bulk(&priv->resets);
 	udelay(1);
 	ret |= reset_deassert_bulk(&priv->resets);
@@ -296,9 +299,79 @@
 	return reset_assert_bulk(&priv->resets);
 }
 
+static int phy_meson_g12a_usb3_pcie_init(struct phy *phy)
+{
+	if (phy->id == PHY_TYPE_USB3)
+		return phy_meson_g12a_usb3_init(phy);
+
+	return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_exit(struct phy *phy)
+{
+	if (phy->id == PHY_TYPE_USB3)
+		return phy_meson_g12a_usb3_exit(phy);
+
+	return 0;
+}
+
+static int phy_meson_g12a_usb3_pcie_power_on(struct phy *phy)
+{
+	struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+	if (phy->id == 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_meson_g12a_usb3_pcie_power_off(struct phy *phy)
+{
+	struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+
+	if (phy->id == 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_meson_g12a_usb3_pcie_reset(struct phy *phy)
+{
+	struct phy_g12a_usb3_pcie_priv *priv = dev_get_priv(phy->dev);
+	int ret;
+
+	if (phy->id == PHY_TYPE_USB3)
+		return 0;
+
+	ret = reset_assert_bulk(&priv->resets);
+	if (ret)
+		return ret;
+
+	udelay(PCIE_RESET_DELAY);
+
+	ret = reset_deassert_bulk(&priv->resets);
+	if (ret)
+		return ret;
+
+	udelay(PCIE_RESET_DELAY);
+
+	return 0;
+}
+
 struct phy_ops meson_g12a_usb3_pcie_phy_ops = {
-	.init = phy_meson_g12a_usb3_init,
-	.exit = phy_meson_g12a_usb3_exit,
+	.init = phy_meson_g12a_usb3_pcie_init,
+	.exit = phy_meson_g12a_usb3_pcie_exit,
+	.power_on = phy_meson_g12a_usb3_pcie_power_on,
+	.power_off = phy_meson_g12a_usb3_pcie_power_off,
+	.reset = phy_meson_g12a_usb3_pcie_reset,
 };
 
 int meson_g12a_usb3_pcie_phy_probe(struct udevice *dev)