phy: meson-gxl-usb: add set_mode call to force switch to peripheral mode
authorNeil Armstrong <narmstrong@baylibre.com>
Mon, 30 Mar 2020 09:27:24 +0000 (11:27 +0200)
committerNeil Armstrong <narmstrong@baylibre.com>
Mon, 20 Apr 2020 12:19:10 +0000 (14:19 +0200)
Add set_mode function in the Amlogic GXL PHYs that will be called by
the arch code to switch PHYs from/to gadget mode.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
arch/arm/include/asm/arch-meson/usb-gx.h [new file with mode: 0644]
drivers/phy/meson-gxl-usb2.c
drivers/phy/meson-gxl-usb3.c

diff --git a/arch/arm/include/asm/arch-meson/usb-gx.h b/arch/arm/include/asm/arch-meson/usb-gx.h
new file mode 100644 (file)
index 0000000..aeb8e0c
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 BayLibre SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+#ifndef _ARCH_MESON_USB_GX_H_
+#define _ARCH_MESON_USB_GX_H_
+
+#include <generic-phy.h>
+#include <linux/usb/otg.h>
+
+/* TOFIX add set_mode to struct phy_ops */
+void phy_meson_gxl_usb2_set_mode(struct phy *phy, enum usb_dr_mode mode);
+void phy_meson_gxl_usb3_set_mode(struct phy *phy, enum usb_dr_mode mode);
+
+#endif
index c98d12b627da3da9910086d083d66d40e8eba9bc..b4f4c3c76b97d7b9b764406fc5ae843cc4a0e2ec 100644 (file)
@@ -17,6 +17,9 @@
 #include <regmap.h>
 #include <power/regulator.h>
 #include <clk.h>
+#include <linux/usb/otg.h>
+
+#include <asm/arch/usb-gx.h>
 
 #include <linux/bitops.h>
 #include <linux/compat.h>
@@ -121,15 +124,30 @@ static void phy_meson_gxl_usb2_reset(struct phy_meson_gxl_usb2_priv *priv)
        udelay(RESET_COMPLETE_TIME);
 }
 
-static void
-phy_meson_gxl_usb2_set_host_mode(struct phy_meson_gxl_usb2_priv *priv)
+void phy_meson_gxl_usb2_set_mode(struct phy *phy, enum usb_dr_mode mode)
 {
+       struct udevice *dev = phy->dev;
+       struct phy_meson_gxl_usb2_priv *priv = dev_get_priv(dev);
        uint val;
 
        regmap_read(priv->regmap, U2P_R0, &val);
-       val |= U2P_R0_DM_PULLDOWN;
-       val |= U2P_R0_DP_PULLDOWN;
-       val &= ~U2P_R0_ID_PULLUP;
+
+       switch (mode) {
+       case USB_DR_MODE_UNKNOWN:
+       case USB_DR_MODE_HOST:
+       case USB_DR_MODE_OTG:
+               val |= U2P_R0_DM_PULLDOWN;
+               val |= U2P_R0_DP_PULLDOWN;
+               val &= ~U2P_R0_ID_PULLUP;
+               break;
+
+       case USB_DR_MODE_PERIPHERAL:
+               val &= ~U2P_R0_DM_PULLDOWN;
+               val &= ~U2P_R0_DP_PULLDOWN;
+               val |= U2P_R0_ID_PULLUP;
+               break;
+       }
+
        regmap_write(priv->regmap, U2P_R0, val);
 
        phy_meson_gxl_usb2_reset(priv);
@@ -146,7 +164,7 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy)
        val &= ~U2P_R0_POWER_ON_RESET;
        regmap_write(priv->regmap, U2P_R0, val);
 
-       phy_meson_gxl_usb2_set_host_mode(priv);
+       phy_meson_gxl_usb2_set_mode(phy, USB_DR_MODE_HOST);
 
 #if CONFIG_IS_ENABLED(DM_REGULATOR)
        if (priv->phy_supply) {
index c2a8593b39f51518a3f7da8f7ee0ed741be6a134..9de55bb5df0cbd0c0eff88b55e665f2813813f4b 100644 (file)
@@ -16,6 +16,9 @@
 #include <generic-phy.h>
 #include <regmap.h>
 #include <clk.h>
+#include <linux/usb/otg.h>
+
+#include <asm/arch/usb-gx.h>
 
 #include <linux/bitops.h>
 #include <linux/compat.h>
@@ -93,20 +96,35 @@ struct phy_meson_gxl_usb3_priv {
 #endif
 };
 
-static int
-phy_meson_gxl_usb3_set_host_mode(struct phy_meson_gxl_usb3_priv *priv)
+void phy_meson_gxl_usb3_set_mode(struct phy *phy, enum usb_dr_mode mode)
 {
+       struct udevice *dev = phy->dev;
+       struct phy_meson_gxl_usb3_priv *priv = dev_get_priv(dev);
        uint val;
 
-       regmap_read(priv->regmap, USB_R0, &val);
-       val &= ~USB_R0_U2D_ACT;
-       regmap_write(priv->regmap, USB_R0, val);
-
-       regmap_read(priv->regmap, USB_R4, &val);
-       val &= ~USB_R4_P21_SLEEP_M0;
-       regmap_write(priv->regmap, USB_R4, val);
-
-       return 0;
+       switch (mode) {
+       case USB_DR_MODE_UNKNOWN:
+       case USB_DR_MODE_HOST:
+       case USB_DR_MODE_OTG:
+               regmap_read(priv->regmap, USB_R0, &val);
+               val &= ~USB_R0_U2D_ACT;
+               regmap_write(priv->regmap, USB_R0, val);
+
+               regmap_read(priv->regmap, USB_R4, &val);
+               val &= ~USB_R4_P21_SLEEP_M0;
+               regmap_write(priv->regmap, USB_R4, val);
+               break;
+
+       case USB_DR_MODE_PERIPHERAL:
+               regmap_read(priv->regmap, USB_R0, &val);
+               val |= USB_R0_U2D_ACT;
+               regmap_write(priv->regmap, USB_R0, val);
+
+               regmap_read(priv->regmap, USB_R4, &val);
+               val |= USB_R4_P21_SLEEP_M0;
+               regmap_write(priv->regmap, USB_R4, val);
+               break;
+       }
 }
 
 static int phy_meson_gxl_usb3_power_on(struct phy *phy)
@@ -122,7 +140,9 @@ static int phy_meson_gxl_usb3_power_on(struct phy *phy)
        val |= FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff);
        regmap_write(priv->regmap, USB_R5, val);
 
-       return phy_meson_gxl_usb3_set_host_mode(priv);
+       phy_meson_gxl_usb3_set_mode(phy, USB_DR_MODE_HOST);
+
+       return 0;
 }
 
 static int phy_meson_gxl_usb3_power_off(struct phy *phy)