diff mbox series

[02/10] phy: meson-gxl-usb: add set_mode call to force switch to peripheral mode

Message ID 20200330092732.7198-3-narmstrong@baylibre.com
State Accepted
Commit 838c0af9d25daa6f783acf0091deca0512baf0df
Headers show
Series meson: enable USB Gadget support fot GXL/GXM SoCs | expand

Commit Message

Neil Armstrong March 30, 2020, 9:27 a.m. UTC
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 at baylibre.com>
---
 arch/arm/include/asm/arch-meson/usb-gx.h | 16 +++++++++
 drivers/phy/meson-gxl-usb2.c             | 30 ++++++++++++----
 drivers/phy/meson-gxl-usb3.c             | 44 +++++++++++++++++-------
 3 files changed, 72 insertions(+), 18 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-meson/usb-gx.h
diff mbox series

Patch

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
index 0000000000..aeb8e0c673
--- /dev/null
+++ b/arch/arm/include/asm/arch-meson/usb-gx.h
@@ -0,0 +1,16 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 BayLibre SAS
+ * Author: Neil Armstrong <narmstrong at 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
diff --git a/drivers/phy/meson-gxl-usb2.c b/drivers/phy/meson-gxl-usb2.c
index c98d12b627..b4f4c3c76b 100644
--- a/drivers/phy/meson-gxl-usb2.c
+++ b/drivers/phy/meson-gxl-usb2.c
@@ -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) {
diff --git a/drivers/phy/meson-gxl-usb3.c b/drivers/phy/meson-gxl-usb3.c
index c2a8593b39..227efa7a17 100644
--- a/drivers/phy/meson-gxl-usb3.c
+++ b/drivers/phy/meson-gxl-usb3.c
@@ -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)