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>
This commit is contained in:
Bin Liu 2015-12-08 10:31:50 -06:00 committed by Felipe Balbi
parent 5306661eff
commit 59f042f644
4 changed files with 27 additions and 11 deletions

View File

@ -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.

View File

@ -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); if (dr_mode == USB_DR_MODE_HOST) {
val |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; 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;
} }

View File

@ -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)

View File

@ -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);