Browse Source

usb: phy: phy-am335x: bypass first VBUS sensing for host-only mode

To prevent VBUS contention, the am335x MUSB phy senses VBUS first before
transitioning to host mode. However, for host-only mode, VBUS could be
directly tied to 5V power rail which could prevent MUSB transitions to
host mode.

This change receives dr_mode of the controller then bypass the first
VBUS sensing for host-only mode, so that MUSB can work in host mode
event if VBUS is tied to 5V.

Signed-off-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Bin Liu 9 years ago
parent
commit
59f042f644

+ 1 - 0
drivers/usb/phy/Kconfig

@@ -66,6 +66,7 @@ config AM335X_PHY_USB
 	select USB_PHY
 	select USB_PHY
 	select AM335X_CONTROL_USB
 	select AM335X_CONTROL_USB
 	select NOP_USB_XCEIV
 	select NOP_USB_XCEIV
+	select USB_COMMON
 	help
 	help
 	  This driver provides PHY support for that phy which part for the
 	  This driver provides PHY support for that phy which part for the
 	  AM335x SoC.
 	  AM335x SoC.

+ 11 - 3
drivers/usb/phy/phy-am335x-control.c

@@ -4,6 +4,7 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
+#include <linux/usb/otg.h>
 #include "phy-am335x-control.h"
 #include "phy-am335x-control.h"
 
 
 struct am335x_control_usb {
 struct am335x_control_usb {
@@ -58,7 +59,8 @@ static void am335x_phy_wkup(struct  phy_control *phy_ctrl, u32 id, bool on)
 	spin_unlock(&usb_ctrl->lock);
 	spin_unlock(&usb_ctrl->lock);
 }
 }
 
 
-static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
+static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id,
+				enum usb_dr_mode dr_mode, bool on)
 {
 {
 	struct am335x_control_usb *usb_ctrl;
 	struct am335x_control_usb *usb_ctrl;
 	u32 val;
 	u32 val;
@@ -80,8 +82,14 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)
 
 
 	val = readl(usb_ctrl->phy_reg + reg);
 	val = readl(usb_ctrl->phy_reg + reg);
 	if (on) {
 	if (on) {
-		val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
-		val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+		if (dr_mode == USB_DR_MODE_HOST) {
+			val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN |
+					USBPHY_OTGVDET_EN);
+			val |= USBPHY_OTGSESSEND_EN;
+		} else {
+			val &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN);
+			val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
+		}
 	} else {
 	} else {
 		val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
 		val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
 	}
 	}

+ 5 - 3
drivers/usb/phy/phy-am335x-control.h

@@ -2,13 +2,15 @@
 #define _AM335x_PHY_CONTROL_H_
 #define _AM335x_PHY_CONTROL_H_
 
 
 struct phy_control {
 struct phy_control {
-	void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on);
+	void (*phy_power)(struct phy_control *phy_ctrl, u32 id,
+			enum usb_dr_mode dr_mode, bool on);
 	void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
 	void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on);
 };
 };
 
 
-static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id, bool on)
+static inline void phy_ctrl_power(struct phy_control *phy_ctrl, u32 id,
+				enum usb_dr_mode dr_mode, bool on)
 {
 {
-	phy_ctrl->phy_power(phy_ctrl, id, on);
+	phy_ctrl->phy_power(phy_ctrl, id, dr_mode, on);
 }
 }
 
 
 static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)
 static inline void phy_ctrl_wkup(struct phy_control *phy_ctrl, u32 id, bool on)

+ 10 - 5
drivers/usb/phy/phy-am335x.c

@@ -8,6 +8,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_address.h>
+#include <linux/usb/of.h>
 
 
 #include "phy-am335x-control.h"
 #include "phy-am335x-control.h"
 #include "phy-generic.h"
 #include "phy-generic.h"
@@ -16,13 +17,14 @@ struct am335x_phy {
 	struct usb_phy_generic usb_phy_gen;
 	struct usb_phy_generic usb_phy_gen;
 	struct phy_control *phy_ctrl;
 	struct phy_control *phy_ctrl;
 	int id;
 	int id;
+	enum usb_dr_mode dr_mode;
 };
 };
 
 
 static int am335x_init(struct usb_phy *phy)
 static int am335x_init(struct usb_phy *phy)
 {
 {
 	struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
 	struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
 
 
-	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -30,7 +32,7 @@ static void am335x_shutdown(struct usb_phy *phy)
 {
 {
 	struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
 	struct am335x_phy *am_phy = dev_get_drvdata(phy->dev);
 
 
-	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
 }
 }
 
 
 static int am335x_phy_probe(struct platform_device *pdev)
 static int am335x_phy_probe(struct platform_device *pdev)
@@ -46,12 +48,15 @@ static int am335x_phy_probe(struct platform_device *pdev)
 	am_phy->phy_ctrl = am335x_get_phy_control(dev);
 	am_phy->phy_ctrl = am335x_get_phy_control(dev);
 	if (!am_phy->phy_ctrl)
 	if (!am_phy->phy_ctrl)
 		return -EPROBE_DEFER;
 		return -EPROBE_DEFER;
+
 	am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
 	am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
 	if (am_phy->id < 0) {
 	if (am_phy->id < 0) {
 		dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
 		dev_err(&pdev->dev, "Missing PHY id: %d\n", am_phy->id);
 		return am_phy->id;
 		return am_phy->id;
 	}
 	}
 
 
+	am_phy->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node);
+
 	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
 	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
@@ -75,7 +80,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
 	 */
 	 */
 
 
 	device_set_wakeup_enable(dev, false);
 	device_set_wakeup_enable(dev, false);
-	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -105,7 +110,7 @@ static int am335x_phy_suspend(struct device *dev)
 	if (device_may_wakeup(dev))
 	if (device_may_wakeup(dev))
 		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true);
 		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true);
 
 
-	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false);
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, false);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -115,7 +120,7 @@ static int am335x_phy_resume(struct device *dev)
 	struct platform_device	*pdev = to_platform_device(dev);
 	struct platform_device	*pdev = to_platform_device(dev);
 	struct am335x_phy	*am_phy = platform_get_drvdata(pdev);
 	struct am335x_phy	*am_phy = platform_get_drvdata(pdev);
 
 
-	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true);
+	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, am_phy->dr_mode, true);
 
 
 	if (device_may_wakeup(dev))
 	if (device_may_wakeup(dev))
 		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false);
 		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false);