summaryrefslogtreecommitdiff
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.c61
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 @@
#define BM_USBPHY_DEBUG_CLKGATE BIT(30)
/* Anatop Registers */
+#define ANADIG_ANA_MISC0 0x150
+#define ANADIG_ANA_MISC0_SET 0x154
+#define ANADIG_ANA_MISC0_CLR 0x158
+
#define ANADIG_USB1_VBUS_DET_STAT 0x1c0
#define ANADIG_USB2_VBUS_DET_STAT 0x220
@@ -65,6 +69,9 @@
#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)
@@ -134,6 +141,16 @@ struct mxs_phy {
int port_id;
};
+static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx6q_phy_data;
+}
+
+static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy)
+{
+ return mxs_phy->data == &imx6sl_phy_data;
+}
+
static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)
{
int ret;
@@ -387,6 +404,8 @@ static int mxs_phy_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mxs_phy);
+ device_set_wakeup_capable(&pdev->dev, true);
+
ret = usb_add_phy_dev(&mxs_phy->phy);
if (ret)
return ret;
@@ -403,6 +422,47 @@ static int mxs_phy_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
+{
+ unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR;
+
+ /* If the SoCs don't have anatop, quit */
+ if (!mxs_phy->regmap_anatop)
+ return;
+
+ if (is_imx6q_phy(mxs_phy))
+ regmap_write(mxs_phy->regmap_anatop, reg,
+ BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG);
+ else if (is_imx6sl_phy(mxs_phy))
+ regmap_write(mxs_phy->regmap_anatop,
+ reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL);
+}
+
+static int mxs_phy_system_suspend(struct device *dev)
+{
+ struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ mxs_phy_enable_ldo_in_suspend(mxs_phy, true);
+
+ return 0;
+}
+
+static int mxs_phy_system_resume(struct device *dev)
+{
+ struct mxs_phy *mxs_phy = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ mxs_phy_enable_ldo_in_suspend(mxs_phy, false);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend,
+ mxs_phy_system_resume);
+
static struct platform_driver mxs_phy_driver = {
.probe = mxs_phy_probe,
.remove = mxs_phy_remove,
@@ -410,6 +470,7 @@ static struct platform_driver mxs_phy_driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = mxs_phy_dt_ids,
+ .pm = &mxs_phy_pm,
},
};