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:
parent
5306661eff
commit
59f042f644
@ -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 @@
|
|||||||
#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;
|
||||||
}
|
}
|
||||||
|
@ -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 @@
|
|||||||
#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);
|
||||||
|
Loading…
Reference in New Issue
Block a user