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-...@ti.com>
---
v2: move in drivers/usb/phy/phy-am335x.c change from patch 1/3.
    fix module dependency, had compile error when CONFIG_USB_OTG undefined.

 drivers/usb/Kconfig                  |  2 +-
 drivers/usb/phy/phy-am335x-control.c | 14 +++++++++++---
 drivers/usb/phy/phy-am335x-control.h |  8 +++++---
 drivers/usb/phy/phy-am335x.c         | 15 ++++++++++-----
 4 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 5b625e2..b33e00b 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -32,7 +32,7 @@ if USB_SUPPORT
 config USB_COMMON
        tristate
        default y
-       depends on USB || USB_GADGET || USB_OTG
+       depends on USB || USB_GADGET || USB_OTG || AM335X_PHY_USB
 
 config USB_ARCH_HAS_HCD
        def_bool y
diff --git a/drivers/usb/phy/phy-am335x-control.c 
b/drivers/usb/phy/phy-am335x-control.c
index 23fca51..42a1afe 100644
--- a/drivers/usb/phy/phy-am335x-control.c
+++ b/drivers/usb/phy/phy-am335x-control.c
@@ -4,6 +4,7 @@
 #include <linux/of.h>
 #include <linux/io.h>
 #include <linux/delay.h>
+#include <linux/usb/otg.h>
 #include "phy-am335x-control.h"
 
 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);
 }
 
-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;
        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);
        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 {
                val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
        }
diff --git a/drivers/usb/phy/phy-am335x-control.h 
b/drivers/usb/phy/phy-am335x-control.h
index b96594d..e86b316 100644
--- a/drivers/usb/phy/phy-am335x-control.h
+++ b/drivers/usb/phy/phy-am335x-control.h
@@ -2,13 +2,15 @@
 #define _AM335x_PHY_CONTROL_H_
 
 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);
 };
 
-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)
diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c
index 8b6139d..39b424f 100644
--- a/drivers/usb/phy/phy-am335x.c
+++ b/drivers/usb/phy/phy-am335x.c
@@ -8,6 +8,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/usb/of.h>
 
 #include "phy-am335x-control.h"
 #include "phy-generic.h"
@@ -16,13 +17,14 @@ struct am335x_phy {
        struct usb_phy_generic usb_phy_gen;
        struct phy_control *phy_ctrl;
        int id;
+       enum usb_dr_mode dr_mode;
 };
 
 static int am335x_init(struct usb_phy *phy)
 {
        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;
 }
 
@@ -30,7 +32,7 @@ static void am335x_shutdown(struct usb_phy *phy)
 {
        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)
@@ -46,12 +48,15 @@ static int am335x_phy_probe(struct platform_device *pdev)
        am_phy->phy_ctrl = am335x_get_phy_control(dev);
        if (!am_phy->phy_ctrl)
                return -EPROBE_DEFER;
+
        am_phy->id = of_alias_get_id(pdev->dev.of_node, "phy");
        if (am_phy->id < 0) {
                dev_err(&pdev->dev, "Missing PHY id: %d\n", 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);
        if (ret)
                return ret;
@@ -75,7 +80,7 @@ static int am335x_phy_probe(struct platform_device *pdev)
         */
 
        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;
 }
@@ -105,7 +110,7 @@ static int am335x_phy_suspend(struct device *dev)
        if (device_may_wakeup(dev))
                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;
 }
@@ -115,7 +120,7 @@ static int am335x_phy_resume(struct device *dev)
        struct platform_device  *pdev = to_platform_device(dev);
        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))
                phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false);
-- 
1.8.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to