diff options
author | Peter Chen <peter.chen@freescale.com> | 2013-11-21 19:14:42 +0800 |
---|---|---|
committer | Peter Chen <peter.chen@freescale.com> | 2013-11-22 14:31:33 +0800 |
commit | 3df2a631297a24f98a1f78d80c4fb563f8d118a5 (patch) | |
tree | c94a805c877b711fb2b8f77e8e9d4f5a7d1cb863 /drivers | |
parent | 49782afd20342bd21bdc8110dc8dcf844442a85f (diff) |
ENGR00288578-7 usb: phy-mxs: add controller id
Meanwhile, we fix the problem that we only use controller-1's related
registers at mxs_phy_disconnect_line.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
(cherry picked from commit 36d81e91fb7cd7fca74daf41ca70e4826e2ae8a1)
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/phy/phy-mxs-usb.c | 97 |
1 files changed, 71 insertions, 26 deletions
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index d4466a78572c..884ed7d27c7d 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -62,17 +62,23 @@ #define ANADIG_ANA_MISC0_CLR 0x158 #define ANADIG_USB1_VBUS_DET_STAT 0x1c0 +#define ANADIG_USB2_VBUS_DET_STAT 0x220 #define ANADIG_USB1_LOOPBACK_SET 0x1e4 #define ANADIG_USB1_LOOPBACK_CLR 0x1e8 +#define ANADIG_USB2_LOOPBACK_SET 0x244 +#define ANADIG_USB2_LOOPBACK_CLR 0x248 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12) #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) #define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3) +#define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3) #define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 BIT(2) #define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN BIT(5) +#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2) +#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5) #define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) @@ -127,6 +133,7 @@ struct mxs_phy { struct clk *clk; const struct mxs_phy_data *data; struct regmap *regmap_anatop; + int port_id; }; static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy) @@ -181,12 +188,61 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) return 0; } -static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) +/* Return true if the vbus is there */ +static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy) +{ + unsigned int vbus_value; + + if (mxs_phy->port_id == 0) + regmap_read(mxs_phy->regmap_anatop, + ANADIG_USB1_VBUS_DET_STAT, + &vbus_value); + else if (mxs_phy->port_id == 1) + regmap_read(mxs_phy->regmap_anatop, + ANADIG_USB2_VBUS_DET_STAT, + &vbus_value); + + if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID) + return true; + else + return false; +} + +static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect) { void __iomem *base = mxs_phy->phy.io_priv; + u32 reg; + + if (disconnect) + writel_relaxed(BM_USBPHY_DEBUG_CLKGATE, + base + HW_USBPHY_DEBUG_CLR); + + if (mxs_phy->port_id == 0) { + reg = disconnect ? ANADIG_USB1_LOOPBACK_SET + : ANADIG_USB1_LOOPBACK_CLR; + regmap_write(mxs_phy->regmap_anatop, reg, + BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 | + BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN); + } else if (mxs_phy->port_id == 1) { + reg = disconnect ? ANADIG_USB2_LOOPBACK_SET + : ANADIG_USB2_LOOPBACK_CLR; + regmap_write(mxs_phy->regmap_anatop, reg, + BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 | + BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN); + } + + if (!disconnect) + writel_relaxed(BM_USBPHY_DEBUG_CLKGATE, + base + HW_USBPHY_DEBUG_SET); + + /* Delay some time, and let Linestate be SE0 for controller */ + if (disconnect) + usleep_range(500, 1000); +} + +static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) +{ bool vbus_is_on = false; - static bool line_is_disconnected; - unsigned int vbus_value = 0; /* If the SoCs don't need to disconnect line without vbus, quit */ if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS)) @@ -196,31 +252,13 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) if (!mxs_phy->regmap_anatop) return; - regmap_read(mxs_phy->regmap_anatop, ANADIG_USB1_VBUS_DET_STAT, - &vbus_value); - if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID) - vbus_is_on = true; + vbus_is_on = mxs_phy_get_vbus_status(mxs_phy); - if (on && !vbus_is_on) { - writel_relaxed(BM_USBPHY_DEBUG_CLKGATE, - base + HW_USBPHY_DEBUG_CLR); - regmap_write(mxs_phy->regmap_anatop, ANADIG_USB1_LOOPBACK_SET, - BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 | - BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN); - /* Delay some time, and let Linestate be SE0 for controller */ - usleep_range(500, 1000); - line_is_disconnected = true; - } else if (line_is_disconnected) { - regmap_write(mxs_phy->regmap_anatop, ANADIG_USB1_LOOPBACK_CLR, - BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 | - BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN); - writel_relaxed(BM_USBPHY_DEBUG_CLKGATE, - base + HW_USBPHY_DEBUG_SET); - line_is_disconnected = false; - } + if (on && !vbus_is_on) + __mxs_phy_disconnect_line(mxs_phy, true); + else + __mxs_phy_disconnect_line(mxs_phy, false); - dev_dbg(mxs_phy->phy.dev, "line is %s\n", line_is_disconnected - ? "disconnected" : "connected"); } static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on) @@ -392,6 +430,13 @@ static int mxs_phy_probe(struct platform_device *pdev) return -ENOMEM; } + ret = of_alias_get_id(np, "usbphy"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + mxs_phy->port_id = ret; + mxs_phy->phy.io_priv = base; mxs_phy->phy.dev = &pdev->dev; mxs_phy->phy.label = DRIVER_NAME; |