Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: phy: mxs: Add system suspend/resume API

We need this to keep PHY's power on or off during the system
suspend mode. If we need to enable USB wakeup, then we
must keep PHY's power being on during the system suspend mode.
Otherwise, we need to keep PHY's power being off to save power.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Peter Chen and committed by
Felipe Balbi
bf783438 3f126505

+61
+61
drivers/usb/phy/phy-mxs-usb.c
··· 57 57 #define BM_USBPHY_DEBUG_CLKGATE BIT(30) 58 58 59 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 64 #define ANADIG_USB1_VBUS_DET_STAT 0x1c0 61 65 #define ANADIG_USB2_VBUS_DET_STAT 0x220 62 66 ··· 68 64 #define ANADIG_USB1_LOOPBACK_CLR 0x1e8 69 65 #define ANADIG_USB2_LOOPBACK_SET 0x244 70 66 #define ANADIG_USB2_LOOPBACK_CLR 0x248 67 + 68 + #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12) 69 + #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) 71 70 72 71 #define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3) 73 72 #define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID BIT(3) ··· 140 133 struct regmap *regmap_anatop; 141 134 int port_id; 142 135 }; 136 + 137 + static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy) 138 + { 139 + return mxs_phy->data == &imx6q_phy_data; 140 + } 141 + 142 + static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy) 143 + { 144 + return mxs_phy->data == &imx6sl_phy_data; 145 + } 143 146 144 147 static int mxs_phy_hw_init(struct mxs_phy *mxs_phy) 145 148 { ··· 404 387 405 388 platform_set_drvdata(pdev, mxs_phy); 406 389 390 + device_set_wakeup_capable(&pdev->dev, true); 391 + 407 392 ret = usb_add_phy_dev(&mxs_phy->phy); 408 393 if (ret) 409 394 return ret; ··· 422 403 return 0; 423 404 } 424 405 406 + #ifdef CONFIG_PM_SLEEP 407 + static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on) 408 + { 409 + unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR; 410 + 411 + /* If the SoCs don't have anatop, quit */ 412 + if (!mxs_phy->regmap_anatop) 413 + return; 414 + 415 + if (is_imx6q_phy(mxs_phy)) 416 + regmap_write(mxs_phy->regmap_anatop, reg, 417 + BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG); 418 + else if (is_imx6sl_phy(mxs_phy)) 419 + regmap_write(mxs_phy->regmap_anatop, 420 + reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL); 421 + } 422 + 423 + static int mxs_phy_system_suspend(struct device *dev) 424 + { 425 + struct mxs_phy *mxs_phy = dev_get_drvdata(dev); 426 + 427 + if (device_may_wakeup(dev)) 428 + mxs_phy_enable_ldo_in_suspend(mxs_phy, true); 429 + 430 + return 0; 431 + } 432 + 433 + static int mxs_phy_system_resume(struct device *dev) 434 + { 435 + struct mxs_phy *mxs_phy = dev_get_drvdata(dev); 436 + 437 + if (device_may_wakeup(dev)) 438 + mxs_phy_enable_ldo_in_suspend(mxs_phy, false); 439 + 440 + return 0; 441 + } 442 + #endif /* CONFIG_PM_SLEEP */ 443 + 444 + static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend, 445 + mxs_phy_system_resume); 446 + 425 447 static struct platform_driver mxs_phy_driver = { 426 448 .probe = mxs_phy_probe, 427 449 .remove = mxs_phy_remove, ··· 470 410 .name = DRIVER_NAME, 471 411 .owner = THIS_MODULE, 472 412 .of_match_table = mxs_phy_dt_ids, 413 + .pm = &mxs_phy_pm, 473 414 }, 474 415 }; 475 416