diff options
| -rw-r--r-- | drivers/usb/phy/phy-mxs-usb.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index da2eb6c968ca..31ef59f88901 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c | |||
| @@ -57,6 +57,10 @@ | |||
| 57 | #define BM_USBPHY_DEBUG_CLKGATE BIT(30) | 57 | #define BM_USBPHY_DEBUG_CLKGATE BIT(30) |
| 58 | 58 | ||
| 59 | /* Anatop Registers */ | 59 | /* Anatop Registers */ |
| 60 | #define ANADIG_ANA_MISC0 0x150 | ||
| 61 | #define ANADIG_ANA_MISC0_SET 0x154 | ||
| 62 | #define ANADIG_ANA_MISC0_CLR 0x158 | ||
| 63 | |||
| 60 | #define ANADIG_USB1_VBUS_DET_STAT 0x1c0 | 64 | #define ANADIG_USB1_VBUS_DET_STAT 0x1c0 |
| 61 | #define ANADIG_USB2_VBUS_DET_STAT 0x220 | 65 | #define ANADIG_USB2_VBUS_DET_STAT 0x220 |
| 62 | 66 | ||
| @@ -65,6 +69,9 @@ | |||
| 65 | #define ANADIG_USB2_LOOPBACK_SET 0x244 | 69 | #define ANADIG_USB2_LOOPBACK_SET 0x244 |
| 66 | #define ANADIG_USB2_LOOPBACK_CLR 0x248 | 70 | #define ANADIG_USB2_LOOPBACK_CLR 0x248 |
| 67 | 71 | ||
| 72 | #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12) | ||
| 73 | #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) | ||
| 74 | |||
| 68 | #define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3) | 75 | #define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3) |
| 69 | #define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3) | 76 | #define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3) |
| 70 | 77 | ||
| @@ -134,6 +141,16 @@ struct mxs_phy { | |||
| 134 | int port_id; | 141 | int port_id; |
| 135 | }; | 142 | }; |
| 136 | 143 | ||
| 144 | static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy) | ||
| 145 | { | ||
| 146 | return mxs_phy->data == &imx6q_phy_data; | ||
| 147 | } | ||
| 148 | |||
| 149 | static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy) | ||
| 150 | { | ||
| 151 | return mxs_phy->data == &imx6sl_phy_data; | ||
| 152 | } | ||
| 153 | |||
| 137 | static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) | 154 | static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) |
| 138 | { | 155 | { |
| 139 | int ret; | 156 | int ret; |
| @@ -387,6 +404,8 @@ static int mxs_phy_probe(struct platform_device *pdev) | |||
| 387 | 404 | ||
| 388 | platform_set_drvdata(pdev, mxs_phy); | 405 | platform_set_drvdata(pdev, mxs_phy); |
| 389 | 406 | ||
| 407 | device_set_wakeup_capable(&pdev->dev, true); | ||
| 408 | |||
| 390 | ret = usb_add_phy_dev(&mxs_phy->phy); | 409 | ret = usb_add_phy_dev(&mxs_phy->phy); |
| 391 | if (ret) | 410 | if (ret) |
| 392 | return ret; | 411 | return ret; |
| @@ -403,6 +422,47 @@ static int mxs_phy_remove(struct platform_device *pdev) | |||
| 403 | return 0; | 422 | return 0; |
| 404 | } | 423 | } |
| 405 | 424 | ||
| 425 | #ifdef CONFIG_PM_SLEEP | ||
| 426 | static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on) | ||
| 427 | { | ||
| 428 | unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR; | ||
| 429 | |||
| 430 | /* If the SoCs don't have anatop, quit */ | ||
| 431 | if (!mxs_phy->regmap_anatop) | ||
| 432 | return; | ||
| 433 | |||
| 434 | if (is_imx6q_phy(mxs_phy)) | ||
| 435 | regmap_write(mxs_phy->regmap_anatop, reg, | ||
| 436 | BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG); | ||
| 437 | else if (is_imx6sl_phy(mxs_phy)) | ||
| 438 | regmap_write(mxs_phy->regmap_anatop, | ||
| 439 | reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL); | ||
| 440 | } | ||
| 441 | |||
| 442 | static int mxs_phy_system_suspend(struct device *dev) | ||
| 443 | { | ||
| 444 | struct mxs_phy *mxs_phy = dev_get_drvdata(dev); | ||
| 445 | |||
| 446 | if (device_may_wakeup(dev)) | ||
| 447 | mxs_phy_enable_ldo_in_suspend(mxs_phy, true); | ||
| 448 | |||
| 449 | return 0; | ||
| 450 | } | ||
| 451 | |||
| 452 | static int mxs_phy_system_resume(struct device *dev) | ||
| 453 | { | ||
| 454 | struct mxs_phy *mxs_phy = dev_get_drvdata(dev); | ||
| 455 | |||
| 456 | if (device_may_wakeup(dev)) | ||
| 457 | mxs_phy_enable_ldo_in_suspend(mxs_phy, false); | ||
| 458 | |||
| 459 | return 0; | ||
| 460 | } | ||
| 461 | #endif /* CONFIG_PM_SLEEP */ | ||
| 462 | |||
| 463 | static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend, | ||
| 464 | mxs_phy_system_resume); | ||
| 465 | |||
| 406 | static struct platform_driver mxs_phy_driver = { | 466 | static struct platform_driver mxs_phy_driver = { |
| 407 | .probe = mxs_phy_probe, | 467 | .probe = mxs_phy_probe, |
| 408 | .remove = mxs_phy_remove, | 468 | .remove = mxs_phy_remove, |
| @@ -410,6 +470,7 @@ static struct platform_driver mxs_phy_driver = { | |||
| 410 | .name = DRIVER_NAME, | 470 | .name = DRIVER_NAME, |
| 411 | .owner = THIS_MODULE, | 471 | .owner = THIS_MODULE, |
| 412 | .of_match_table = mxs_phy_dt_ids, | 472 | .of_match_table = mxs_phy_dt_ids, |
| 473 | .pm = &mxs_phy_pm, | ||
| 413 | }, | 474 | }, |
| 414 | }; | 475 | }; |
| 415 | 476 | ||
