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

phy: omap-usb2: support suspend/resume

Relying on PM-ops for shutting down PHY clocks was a
bad idea since the users (e.g. USB DWC3) might not
have been suspended by then.

Get rid of all PM-ops. It is the sole responsibility
of the PHY user to properly turn OFF and de-initialize
the PHY as part of its suspend routine.

Enable/disable PHY clock as part of ->init()/->exit()
call respectively. With this phy_init() and phy_exit()
can be called by PHY user during suspend/resume.

This is similar to what is done for ti-pipe3 driver.
See 31c8954efb1b ("phy: ti-pipe3: fix suspend")

The pm_runtime_enable() call in omap_usb2_probe()
is still required because without it, phy_create()
will not enable runtime PM on the phy device it
creates and phy_init() will not call
pm_runtime_get_sync().

Without pm_runtime_get_sync(), ocp2scp hwmod will
_not_ enable the IP and, thus, we will have abort
exceptions.

Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>

authored by

Sekhar Nori and committed by
Kishon Vijay Abraham I
80fc6660 800dcc30

+46 -54
+46 -54
drivers/phy/phy-omap-usb2.c
··· 133 133 return omap_usb_phy_power(phy, true); 134 134 } 135 135 136 + static int omap_usb2_disable_clocks(struct omap_usb *phy) 137 + { 138 + clk_disable(phy->wkupclk); 139 + if (!IS_ERR(phy->optclk)) 140 + clk_disable(phy->optclk); 141 + 142 + return 0; 143 + } 144 + 145 + static int omap_usb2_enable_clocks(struct omap_usb *phy) 146 + { 147 + int ret; 148 + 149 + ret = clk_enable(phy->wkupclk); 150 + if (ret < 0) { 151 + dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); 152 + goto err0; 153 + } 154 + 155 + if (!IS_ERR(phy->optclk)) { 156 + ret = clk_enable(phy->optclk); 157 + if (ret < 0) { 158 + dev_err(phy->dev, "Failed to enable optclk %d\n", ret); 159 + goto err1; 160 + } 161 + } 162 + 163 + return 0; 164 + 165 + err1: 166 + clk_disable(phy->wkupclk); 167 + 168 + err0: 169 + return ret; 170 + } 171 + 136 172 static int omap_usb_init(struct phy *x) 137 173 { 138 174 struct omap_usb *phy = phy_get_drvdata(x); 139 175 u32 val; 176 + 177 + omap_usb2_enable_clocks(phy); 140 178 141 179 if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { 142 180 /* ··· 193 155 return 0; 194 156 } 195 157 158 + static int omap_usb_exit(struct phy *x) 159 + { 160 + struct omap_usb *phy = phy_get_drvdata(x); 161 + 162 + return omap_usb2_disable_clocks(phy); 163 + } 164 + 196 165 static const struct phy_ops ops = { 197 166 .init = omap_usb_init, 167 + .exit = omap_usb_exit, 198 168 .power_on = omap_usb_power_on, 199 169 .power_off = omap_usb_power_off, 200 170 .owner = THIS_MODULE, ··· 422 376 return 0; 423 377 } 424 378 425 - #ifdef CONFIG_PM 426 - 427 - static int omap_usb2_runtime_suspend(struct device *dev) 428 - { 429 - struct platform_device *pdev = to_platform_device(dev); 430 - struct omap_usb *phy = platform_get_drvdata(pdev); 431 - 432 - clk_disable(phy->wkupclk); 433 - if (!IS_ERR(phy->optclk)) 434 - clk_disable(phy->optclk); 435 - 436 - return 0; 437 - } 438 - 439 - static int omap_usb2_runtime_resume(struct device *dev) 440 - { 441 - struct platform_device *pdev = to_platform_device(dev); 442 - struct omap_usb *phy = platform_get_drvdata(pdev); 443 - int ret; 444 - 445 - ret = clk_enable(phy->wkupclk); 446 - if (ret < 0) { 447 - dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); 448 - goto err0; 449 - } 450 - 451 - if (!IS_ERR(phy->optclk)) { 452 - ret = clk_enable(phy->optclk); 453 - if (ret < 0) { 454 - dev_err(phy->dev, "Failed to enable optclk %d\n", ret); 455 - goto err1; 456 - } 457 - } 458 - 459 - return 0; 460 - 461 - err1: 462 - clk_disable(phy->wkupclk); 463 - 464 - err0: 465 - return ret; 466 - } 467 - 468 - static const struct dev_pm_ops omap_usb2_pm_ops = { 469 - SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, 470 - NULL) 471 - }; 472 - 473 - #define DEV_PM_OPS (&omap_usb2_pm_ops) 474 - #else 475 - #define DEV_PM_OPS NULL 476 - #endif 477 - 478 379 static struct platform_driver omap_usb2_driver = { 479 380 .probe = omap_usb2_probe, 480 381 .remove = omap_usb2_remove, 481 382 .driver = { 482 383 .name = "omap-usb2", 483 - .pm = DEV_PM_OPS, 484 384 .of_match_table = omap_usb2_id_table, 485 385 }, 486 386 };