summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2013-11-21 19:14:42 +0800
committerPeter Chen <peter.chen@freescale.com>2013-11-22 14:31:33 +0800
commit3df2a631297a24f98a1f78d80c4fb563f8d118a5 (patch)
treec94a805c877b711fb2b8f77e8e9d4f5a7d1cb863 /drivers
parent49782afd20342bd21bdc8110dc8dcf844442a85f (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.c97
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;