diff options
author | Sekhar Nori <nsekhar@ti.com> | 2016-08-23 04:57:39 -0400 |
---|---|---|
committer | Kishon Vijay Abraham I <kishon@ti.com> | 2016-09-10 07:18:39 -0400 |
commit | 80fc6660caa64ebc7df7c78d886d2023fd652904 (patch) | |
tree | 2fc762720e5364a5ed3f04fa30a57da084ce364b | |
parent | 800dcc307dfeea7c3d7ff46f3d7d592a8dac3ea1 (diff) |
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>
-rw-r--r-- | drivers/phy/phy-omap-usb2.c | 100 |
1 files changed, 46 insertions, 54 deletions
diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index c134989052f5..fe909fd8144f 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c | |||
@@ -133,11 +133,49 @@ static int omap_usb_power_on(struct phy *x) | |||
133 | return omap_usb_phy_power(phy, true); | 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 | static int omap_usb_init(struct phy *x) | 172 | static int omap_usb_init(struct phy *x) |
137 | { | 173 | { |
138 | struct omap_usb *phy = phy_get_drvdata(x); | 174 | struct omap_usb *phy = phy_get_drvdata(x); |
139 | u32 val; | 175 | u32 val; |
140 | 176 | ||
177 | omap_usb2_enable_clocks(phy); | ||
178 | |||
141 | if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { | 179 | if (phy->flags & OMAP_USB2_CALIBRATE_FALSE_DISCONNECT) { |
142 | /* | 180 | /* |
143 | * | 181 | * |
@@ -155,8 +193,16 @@ static int omap_usb_init(struct phy *x) | |||
155 | return 0; | 193 | return 0; |
156 | } | 194 | } |
157 | 195 | ||
196 | static int omap_usb_exit(struct phy *x) | ||
197 | { | ||
198 | struct omap_usb *phy = phy_get_drvdata(x); | ||
199 | |||
200 | return omap_usb2_disable_clocks(phy); | ||
201 | } | ||
202 | |||
158 | static const struct phy_ops ops = { | 203 | static const struct phy_ops ops = { |
159 | .init = omap_usb_init, | 204 | .init = omap_usb_init, |
205 | .exit = omap_usb_exit, | ||
160 | .power_on = omap_usb_power_on, | 206 | .power_on = omap_usb_power_on, |
161 | .power_off = omap_usb_power_off, | 207 | .power_off = omap_usb_power_off, |
162 | .owner = THIS_MODULE, | 208 | .owner = THIS_MODULE, |
@@ -376,65 +422,11 @@ static int omap_usb2_remove(struct platform_device *pdev) | |||
376 | return 0; | 422 | return 0; |
377 | } | 423 | } |
378 | 424 | ||
379 | #ifdef CONFIG_PM | ||
380 | |||
381 | static int omap_usb2_runtime_suspend(struct device *dev) | ||
382 | { | ||
383 | struct platform_device *pdev = to_platform_device(dev); | ||
384 | struct omap_usb *phy = platform_get_drvdata(pdev); | ||
385 | |||
386 | clk_disable(phy->wkupclk); | ||
387 | if (!IS_ERR(phy->optclk)) | ||
388 | clk_disable(phy->optclk); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int omap_usb2_runtime_resume(struct device *dev) | ||
394 | { | ||
395 | struct platform_device *pdev = to_platform_device(dev); | ||
396 | struct omap_usb *phy = platform_get_drvdata(pdev); | ||
397 | int ret; | ||
398 | |||
399 | ret = clk_enable(phy->wkupclk); | ||
400 | if (ret < 0) { | ||
401 | dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); | ||
402 | goto err0; | ||
403 | } | ||
404 | |||
405 | if (!IS_ERR(phy->optclk)) { | ||
406 | ret = clk_enable(phy->optclk); | ||
407 | if (ret < 0) { | ||
408 | dev_err(phy->dev, "Failed to enable optclk %d\n", ret); | ||
409 | goto err1; | ||
410 | } | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | |||
415 | err1: | ||
416 | clk_disable(phy->wkupclk); | ||
417 | |||
418 | err0: | ||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | static const struct dev_pm_ops omap_usb2_pm_ops = { | ||
423 | SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, | ||
424 | NULL) | ||
425 | }; | ||
426 | |||
427 | #define DEV_PM_OPS (&omap_usb2_pm_ops) | ||
428 | #else | ||
429 | #define DEV_PM_OPS NULL | ||
430 | #endif | ||
431 | |||
432 | static struct platform_driver omap_usb2_driver = { | 425 | static struct platform_driver omap_usb2_driver = { |
433 | .probe = omap_usb2_probe, | 426 | .probe = omap_usb2_probe, |
434 | .remove = omap_usb2_remove, | 427 | .remove = omap_usb2_remove, |
435 | .driver = { | 428 | .driver = { |
436 | .name = "omap-usb2", | 429 | .name = "omap-usb2", |
437 | .pm = DEV_PM_OPS, | ||
438 | .of_match_table = omap_usb2_id_table, | 430 | .of_match_table = omap_usb2_id_table, |
439 | }, | 431 | }, |
440 | }; | 432 | }; |