aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@freescale.com>2014-02-23 21:21:02 -0500
committerFelipe Balbi <balbi@ti.com>2014-03-05 15:40:09 -0500
commit3f1265056be0a3a569a0409410d4b11048688216 (patch)
treee34e2a9526a127a5c633bfb0bfdf6d6887f11d1f
parent57bf9b09a6ad517b0c790b786845660ec5604774 (diff)
usb: phy: mxs: Add implementation of set_wakeup
When we need the PHY can be waken up by external signals, we can call this API. Besides, we call mxs_phy_disconnect_line at this API to close the connection between USB PHY and controller, after that, the line state from controller is SE0. Once the PHY is out of power, without calling mxs_phy_disconnect_line, there are unknown wakeups due to dp/dm floating at device mode. Signed-off-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 3009ab57614e..da2eb6c968ca 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -31,6 +31,9 @@
31#define HW_USBPHY_CTRL_SET 0x34 31#define HW_USBPHY_CTRL_SET 0x34
32#define HW_USBPHY_CTRL_CLR 0x38 32#define HW_USBPHY_CTRL_CLR 0x38
33 33
34#define HW_USBPHY_DEBUG_SET 0x54
35#define HW_USBPHY_DEBUG_CLR 0x58
36
34#define HW_USBPHY_IP 0x90 37#define HW_USBPHY_IP 0x90
35#define HW_USBPHY_IP_SET 0x94 38#define HW_USBPHY_IP_SET 0x94
36#define HW_USBPHY_IP_CLR 0x98 39#define HW_USBPHY_IP_CLR 0x98
@@ -39,6 +42,9 @@
39#define BM_USBPHY_CTRL_CLKGATE BIT(30) 42#define BM_USBPHY_CTRL_CLKGATE BIT(30)
40#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26) 43#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
41#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25) 44#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
45#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
46#define BM_USBPHY_CTRL_ENIDCHG_WKUP BIT(22)
47#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP BIT(21)
42#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD BIT(20) 48#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD BIT(20)
43#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE BIT(19) 49#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE BIT(19)
44#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL BIT(18) 50#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL BIT(18)
@@ -48,6 +54,25 @@
48 54
49#define BM_USBPHY_IP_FIX (BIT(17) | BIT(18)) 55#define BM_USBPHY_IP_FIX (BIT(17) | BIT(18))
50 56
57#define BM_USBPHY_DEBUG_CLKGATE BIT(30)
58
59/* Anatop Registers */
60#define ANADIG_USB1_VBUS_DET_STAT 0x1c0
61#define ANADIG_USB2_VBUS_DET_STAT 0x220
62
63#define ANADIG_USB1_LOOPBACK_SET 0x1e4
64#define ANADIG_USB1_LOOPBACK_CLR 0x1e8
65#define ANADIG_USB2_LOOPBACK_SET 0x244
66#define ANADIG_USB2_LOOPBACK_CLR 0x248
67
68#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
69#define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3)
70
71#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 BIT(2)
72#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN BIT(5)
73#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
74#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
75
51#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) 76#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
52 77
53/* Do disconnection between PHY and controller without vbus */ 78/* Do disconnection between PHY and controller without vbus */
@@ -141,6 +166,79 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
141 return 0; 166 return 0;
142} 167}
143 168
169/* Return true if the vbus is there */
170static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
171{
172 unsigned int vbus_value;
173
174 if (mxs_phy->port_id == 0)
175 regmap_read(mxs_phy->regmap_anatop,
176 ANADIG_USB1_VBUS_DET_STAT,
177 &vbus_value);
178 else if (mxs_phy->port_id == 1)
179 regmap_read(mxs_phy->regmap_anatop,
180 ANADIG_USB2_VBUS_DET_STAT,
181 &vbus_value);
182
183 if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)
184 return true;
185 else
186 return false;
187}
188
189static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
190{
191 void __iomem *base = mxs_phy->phy.io_priv;
192 u32 reg;
193
194 if (disconnect)
195 writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
196 base + HW_USBPHY_DEBUG_CLR);
197
198 if (mxs_phy->port_id == 0) {
199 reg = disconnect ? ANADIG_USB1_LOOPBACK_SET
200 : ANADIG_USB1_LOOPBACK_CLR;
201 regmap_write(mxs_phy->regmap_anatop, reg,
202 BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 |
203 BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN);
204 } else if (mxs_phy->port_id == 1) {
205 reg = disconnect ? ANADIG_USB2_LOOPBACK_SET
206 : ANADIG_USB2_LOOPBACK_CLR;
207 regmap_write(mxs_phy->regmap_anatop, reg,
208 BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 |
209 BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN);
210 }
211
212 if (!disconnect)
213 writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
214 base + HW_USBPHY_DEBUG_SET);
215
216 /* Delay some time, and let Linestate be SE0 for controller */
217 if (disconnect)
218 usleep_range(500, 1000);
219}
220
221static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
222{
223 bool vbus_is_on = false;
224
225 /* If the SoCs don't need to disconnect line without vbus, quit */
226 if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS))
227 return;
228
229 /* If the SoCs don't have anatop, quit */
230 if (!mxs_phy->regmap_anatop)
231 return;
232
233 vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
234
235 if (on && !vbus_is_on)
236 __mxs_phy_disconnect_line(mxs_phy, true);
237 else
238 __mxs_phy_disconnect_line(mxs_phy, false);
239
240}
241
144static int mxs_phy_init(struct usb_phy *phy) 242static int mxs_phy_init(struct usb_phy *phy)
145{ 243{
146 int ret; 244 int ret;
@@ -185,6 +283,23 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)
185 return 0; 283 return 0;
186} 284}
187 285
286static int mxs_phy_set_wakeup(struct usb_phy *x, bool enabled)
287{
288 struct mxs_phy *mxs_phy = to_mxs_phy(x);
289 u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
290 BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
291 BM_USBPHY_CTRL_ENIDCHG_WKUP;
292 if (enabled) {
293 mxs_phy_disconnect_line(mxs_phy, true);
294 writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_SET);
295 } else {
296 writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_CLR);
297 mxs_phy_disconnect_line(mxs_phy, false);
298 }
299
300 return 0;
301}
302
188static int mxs_phy_on_connect(struct usb_phy *phy, 303static int mxs_phy_on_connect(struct usb_phy *phy,
189 enum usb_device_speed speed) 304 enum usb_device_speed speed)
190{ 305{
@@ -265,6 +380,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
265 mxs_phy->phy.notify_connect = mxs_phy_on_connect; 380 mxs_phy->phy.notify_connect = mxs_phy_on_connect;
266 mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; 381 mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
267 mxs_phy->phy.type = USB_PHY_TYPE_USB2; 382 mxs_phy->phy.type = USB_PHY_TYPE_USB2;
383 mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
268 384
269 mxs_phy->clk = clk; 385 mxs_phy->clk = clk;
270 mxs_phy->data = of_id->data; 386 mxs_phy->data = of_id->data;