Commit 59f042f6 authored by Bin Liu's avatar Bin Liu Committed by Felipe Balbi

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: default avatarBin Liu <b-liu@ti.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 5306661e
...@@ -66,6 +66,7 @@ config AM335X_PHY_USB ...@@ -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.
......
...@@ -4,6 +4,7 @@ ...@@ -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) ...@@ -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) ...@@ -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) {
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_CM_PWRDN | USBPHY_OTG_PWRDN);
val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN;
}
} else { } else {
val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; val |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN;
} }
......
...@@ -2,13 +2,15 @@ ...@@ -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)
......
...@@ -8,6 +8,7 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment