aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/phy/phy-mxs-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/phy/phy-mxs-usb.c')
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c86
1 files changed, 81 insertions, 5 deletions
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index b9589f663683..8f7cb068d29b 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -40,6 +40,7 @@
40 40
41#define BM_USBPHY_CTRL_SFTRST BIT(31) 41#define BM_USBPHY_CTRL_SFTRST BIT(31)
42#define BM_USBPHY_CTRL_CLKGATE BIT(30) 42#define BM_USBPHY_CTRL_CLKGATE BIT(30)
43#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
43#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26) 44#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
44#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25) 45#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
45#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23) 46#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
@@ -69,6 +70,9 @@
69#define ANADIG_USB2_LOOPBACK_SET 0x244 70#define ANADIG_USB2_LOOPBACK_SET 0x244
70#define ANADIG_USB2_LOOPBACK_CLR 0x248 71#define ANADIG_USB2_LOOPBACK_CLR 0x248
71 72
73#define ANADIG_USB1_MISC 0x1f0
74#define ANADIG_USB2_MISC 0x250
75
72#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12) 76#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
73#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) 77#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
74 78
@@ -80,6 +84,11 @@
80#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2) 84#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
81#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5) 85#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
82 86
87#define BM_ANADIG_USB1_MISC_RX_VPIN_FS BIT(29)
88#define BM_ANADIG_USB1_MISC_RX_VMIN_FS BIT(28)
89#define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
90#define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
91
83#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) 92#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
84 93
85/* Do disconnection between PHY and controller without vbus */ 94/* Do disconnection between PHY and controller without vbus */
@@ -131,8 +140,7 @@ static const struct mxs_phy_data vf610_phy_data = {
131}; 140};
132 141
133static const struct mxs_phy_data imx6sx_phy_data = { 142static const struct mxs_phy_data imx6sx_phy_data = {
134 .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | 143 .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
135 MXS_PHY_NEED_IP_FIX,
136}; 144};
137 145
138static const struct of_device_id mxs_phy_dt_ids[] = { 146static const struct of_device_id mxs_phy_dt_ids[] = {
@@ -256,6 +264,18 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
256 usleep_range(500, 1000); 264 usleep_range(500, 1000);
257} 265}
258 266
267static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
268{
269 void __iomem *base = mxs_phy->phy.io_priv;
270 u32 phyctrl = readl(base + HW_USBPHY_CTRL);
271
272 if (IS_ENABLED(CONFIG_USB_OTG) &&
273 !(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
274 return true;
275
276 return false;
277}
278
259static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) 279static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
260{ 280{
261 bool vbus_is_on = false; 281 bool vbus_is_on = false;
@@ -270,7 +290,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
270 290
271 vbus_is_on = mxs_phy_get_vbus_status(mxs_phy); 291 vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
272 292
273 if (on && !vbus_is_on) 293 if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
274 __mxs_phy_disconnect_line(mxs_phy, true); 294 __mxs_phy_disconnect_line(mxs_phy, true);
275 else 295 else
276 __mxs_phy_disconnect_line(mxs_phy, false); 296 __mxs_phy_disconnect_line(mxs_phy, false);
@@ -293,6 +313,17 @@ static int mxs_phy_init(struct usb_phy *phy)
293static void mxs_phy_shutdown(struct usb_phy *phy) 313static void mxs_phy_shutdown(struct usb_phy *phy)
294{ 314{
295 struct mxs_phy *mxs_phy = to_mxs_phy(phy); 315 struct mxs_phy *mxs_phy = to_mxs_phy(phy);
316 u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
317 BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
318 BM_USBPHY_CTRL_ENIDCHG_WKUP |
319 BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
320 BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
321 BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
322 BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
323 BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
324
325 writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
326 writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
296 327
297 writel(BM_USBPHY_CTRL_CLKGATE, 328 writel(BM_USBPHY_CTRL_CLKGATE,
298 phy->io_priv + HW_USBPHY_CTRL_SET); 329 phy->io_priv + HW_USBPHY_CTRL_SET);
@@ -300,13 +331,56 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
300 clk_disable_unprepare(mxs_phy->clk); 331 clk_disable_unprepare(mxs_phy->clk);
301} 332}
302 333
334static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
335{
336 unsigned int line_state;
337 /* bit definition is the same for all controllers */
338 unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
339 dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
340 unsigned int reg = ANADIG_USB1_MISC;
341
342 /* If the SoCs don't have anatop, quit */
343 if (!mxs_phy->regmap_anatop)
344 return false;
345
346 if (mxs_phy->port_id == 0)
347 reg = ANADIG_USB1_MISC;
348 else if (mxs_phy->port_id == 1)
349 reg = ANADIG_USB2_MISC;
350
351 regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
352
353 if ((line_state & (dp_bit | dm_bit)) == dm_bit)
354 return true;
355 else
356 return false;
357}
358
303static int mxs_phy_suspend(struct usb_phy *x, int suspend) 359static int mxs_phy_suspend(struct usb_phy *x, int suspend)
304{ 360{
305 int ret; 361 int ret;
306 struct mxs_phy *mxs_phy = to_mxs_phy(x); 362 struct mxs_phy *mxs_phy = to_mxs_phy(x);
363 bool low_speed_connection, vbus_is_on;
364
365 low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
366 vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
307 367
308 if (suspend) { 368 if (suspend) {
309 writel(0xffffffff, x->io_priv + HW_USBPHY_PWD); 369 /*
370 * FIXME: Do not power down RXPWD1PT1 bit for low speed
371 * connect. The low speed connection will have problem at
372 * very rare cases during usb suspend and resume process.
373 */
374 if (low_speed_connection & vbus_is_on) {
375 /*
376 * If value to be set as pwd value is not 0xffffffff,
377 * several 32Khz cycles are needed.
378 */
379 mxs_phy_clock_switch_delay();
380 writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
381 } else {
382 writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
383 }
310 writel(BM_USBPHY_CTRL_CLKGATE, 384 writel(BM_USBPHY_CTRL_CLKGATE,
311 x->io_priv + HW_USBPHY_CTRL_SET); 385 x->io_priv + HW_USBPHY_CTRL_SET);
312 clk_disable_unprepare(mxs_phy->clk); 386 clk_disable_unprepare(mxs_phy->clk);
@@ -359,7 +433,9 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
359 dev_dbg(phy->dev, "%s device has disconnected\n", 433 dev_dbg(phy->dev, "%s device has disconnected\n",
360 (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS"); 434 (speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
361 435
362 if (speed == USB_SPEED_HIGH) 436 /* Sometimes, the speed is not high speed when the error occurs */
437 if (readl(phy->io_priv + HW_USBPHY_CTRL) &
438 BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
363 writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, 439 writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
364 phy->io_priv + HW_USBPHY_CTRL_CLR); 440 phy->io_priv + HW_USBPHY_CTRL_CLR);
365 441