Skip to content

Commit

Permalink
usb: phy: phy-am335x: bypass first VBUS sensing for host-only mode
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Felipe Balbi <[email protected]>
  • Loading branch information
liubiin authored and Felipe Balbi committed Dec 16, 2015
1 parent 5306661 commit 59f042f
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 11 deletions.
1 change: 1 addition & 0 deletions drivers/usb/phy/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ config AM335X_PHY_USB
select USB_PHY
select AM335X_CONTROL_USB
select NOP_USB_XCEIV
select USB_COMMON
help
This driver provides PHY support for that phy which part for the
AM335x SoC.
Expand Down
14 changes: 11 additions & 3 deletions drivers/usb/phy/phy-am335x-control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
8 changes: 5 additions & 3 deletions drivers/usb/phy/phy-am335x-control.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 10 additions & 5 deletions drivers/usb/phy/phy-am335x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -16,21 +17,22 @@ 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;
}

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)
Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down

0 comments on commit 59f042f

Please sign in to comment.