diff options
Diffstat (limited to 'drivers/usb/phy/phy-mxs-usb.c')
-rw-r--r-- | drivers/usb/phy/phy-mxs-usb.c | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index eb746051eda4..c3177a1757ee 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c | |||
@@ -70,6 +70,9 @@ | |||
70 | #define ANADIG_USB2_LOOPBACK_SET 0x244 | 70 | #define ANADIG_USB2_LOOPBACK_SET 0x244 |
71 | #define ANADIG_USB2_LOOPBACK_CLR 0x248 | 71 | #define ANADIG_USB2_LOOPBACK_CLR 0x248 |
72 | 72 | ||
73 | #define ANADIG_USB1_MISC 0x1f0 | ||
74 | #define ANADIG_USB2_MISC 0x250 | ||
75 | |||
73 | #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12) | 76 | #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12) |
74 | #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) | 77 | #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) |
75 | 78 | ||
@@ -81,6 +84,11 @@ | |||
81 | #define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2) | 84 | #define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2) |
82 | #define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5) | 85 | #define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5) |
83 | 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 | |||
84 | #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) |
85 | 93 | ||
86 | /* Do disconnection between PHY and controller without vbus */ | 94 | /* Do disconnection between PHY and controller without vbus */ |
@@ -323,13 +331,50 @@ static void mxs_phy_shutdown(struct usb_phy *phy) | |||
323 | clk_disable_unprepare(mxs_phy->clk); | 331 | clk_disable_unprepare(mxs_phy->clk); |
324 | } | 332 | } |
325 | 333 | ||
334 | static 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 | |||
326 | static int mxs_phy_suspend(struct usb_phy *x, int suspend) | 359 | static int mxs_phy_suspend(struct usb_phy *x, int suspend) |
327 | { | 360 | { |
328 | int ret; | 361 | int ret; |
329 | 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); | ||
330 | 367 | ||
331 | if (suspend) { | 368 | if (suspend) { |
332 | 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 | writel(0xfffbffff, x->io_priv + HW_USBPHY_PWD); | ||
376 | else | ||
377 | writel(0xffffffff, x->io_priv + HW_USBPHY_PWD); | ||
333 | writel(BM_USBPHY_CTRL_CLKGATE, | 378 | writel(BM_USBPHY_CTRL_CLKGATE, |
334 | x->io_priv + HW_USBPHY_CTRL_SET); | 379 | x->io_priv + HW_USBPHY_CTRL_SET); |
335 | clk_disable_unprepare(mxs_phy->clk); | 380 | clk_disable_unprepare(mxs_phy->clk); |