[PATCH 1/2] phy: ti-pipe3: Disable clocks on system suspend
On system suspend, the runtime_suspend() driver hook doesn't get called and so the clocks are not disabled in the driver. This causes the L3INIT_960M_GFCLK and L3INIT_480M_GFCLK to remain active on the DRA7 platform while in system suspend. Add suspend/resume hooks to the driver. In case of pcie-phy, the runtime_suspend hook gets called after the suspend hook so we introduce a flag phy->enabled to keep track if our clocks are enabled or not to prevent multiple enable/disables. Move enabling/disabling clock code into helper functions. Reported-by: Nishant Menon Signed-off-by: Roger Quadros --- drivers/phy/phy-ti-pipe3.c | 99 +++--- 1 file changed, 77 insertions(+), 22 deletions(-) diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c index 1387b4d..e60ff14 100644 --- a/drivers/phy/phy-ti-pipe3.c +++ b/drivers/phy/phy-ti-pipe3.c @@ -28,6 +28,7 @@ #include #include #include +#include #definePLL_STATUS 0x0004 #definePLL_GO 0x0008 @@ -83,6 +84,8 @@ struct ti_pipe3 { struct clk *div_clk; struct pipe3_dpll_map *dpll_map; u8 id; + bool enabled; + spinlock_t lock;/* serialize clock enable/disable */ }; static struct pipe3_dpll_map dpll_map_usb[] = { @@ -303,6 +306,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) return -ENOMEM; phy->dev= &pdev->dev; + spin_lock_init(&phy->lock); if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { match = of_match_device(of_match_ptr(ti_pipe3_id_table), @@ -425,24 +429,14 @@ static int ti_pipe3_remove(struct platform_device *pdev) #ifdef CONFIG_PM -static int ti_pipe3_runtime_suspend(struct device *dev) +static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) { - struct ti_pipe3 *phy = dev_get_drvdata(dev); - - if (!IS_ERR(phy->wkupclk)) - clk_disable_unprepare(phy->wkupclk); - if (!IS_ERR(phy->refclk)) - clk_disable_unprepare(phy->refclk); - if (!IS_ERR(phy->div_clk)) - clk_disable_unprepare(phy->div_clk); - - return 0; -} + int ret = 0; + unsigned long flags; -static int ti_pipe3_runtime_resume(struct device *dev) -{ - u32 ret = 0; - struct ti_pipe3 *phy = dev_get_drvdata(dev); + spin_lock_irqsave(&phy->lock, flags); + if (phy->enabled) + goto err1; if (!IS_ERR(phy->refclk)) { ret = clk_prepare_enable(phy->refclk); @@ -467,6 +461,9 @@ static int ti_pipe3_runtime_resume(struct device *dev) goto err3; } } + + phy->enabled = true; + spin_unlock_irqrestore(&phy->lock, flags); return 0; err3: @@ -478,19 +475,77 @@ err2: clk_disable_unprepare(phy->refclk); err1: + spin_unlock_irqrestore(&phy->lock, flags); + return ret; +} + +static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) +{ + unsigned long flags; + + spin_lock_irqsave(&phy->lock, flags); + if (!phy->enabled) { + spin_unlock_irqrestore(&phy->lock, flags); + return; + } + + if (!IS_ERR(phy->wkupclk)) + clk_disable_unprepare(phy->wkupclk); + if (!IS_ERR(phy->refclk)) + clk_disable_unprepare(phy->refclk); + if (!IS_ERR(phy->div_clk)) + clk_disable_unprepare(phy->div_clk); + phy->enabled = false; + spin_unlock_irqrestore(&phy->lock, flags); +} + +static int ti_pipe3_runtime_suspend(struct device *dev) +{ + struct ti_pipe3 *phy = dev_get_drvdata(dev); + + ti_pipe3_disable_clocks(phy); + return 0; +} + +static int ti_pipe3_runtime_resume(struct device *dev) +{ + struct ti_pipe3 *phy = dev_get_drvdata(dev); + int ret = 0; + + ret = ti_pipe3_enable_clocks(phy); return ret; } +static int ti_pipe3_suspend(struct device *dev) +{ + struct ti_pipe3 *phy = dev_get_drvdata(dev); + + ti_pipe3_disable_clocks(phy); + return 0; +} + +static int ti_pipe3_resume(struct device *dev) +{ + struct ti_pipe3 *phy = dev_get_drvdata(dev); + int ret; + + ret = ti_pipe3_enable_clocks(phy); + if (ret) + return ret; + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; +} +#endif + static const struct dev_pm_ops ti_pipe3_pm_ops = { SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend, ti_pipe3_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume) }; -#define DEV_PM_OPS (&ti_pipe3_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - #ifdef CONFIG_OF static const struct of_device_id ti_pipe3_id_table[] = { { @@ -518,7 +573,7 @@ static struct
Re: [PATCH 1/2] phy: ti-pipe3: Disable clocks on system suspend
Hi Roger, On Friday 19 December 2014 05:35 PM, Roger Quadros wrote: > On system suspend, the runtime_suspend() driver hook doesn't get > called and so the clocks are not disabled in the driver. > This causes the L3INIT_960M_GFCLK and L3INIT_480M_GFCLK to remain > active on the DRA7 platform while in system suspend. > > Add suspend/resume hooks to the driver. > In case of pcie-phy, the runtime_suspend hook gets called after This contradicts with the first line of your commit message. Is pcie-phy driver is an exception? Thanks Kishon > the suspend hook so we introduce a flag phy->enabled to keep > track if our clocks are enabled or not to prevent multiple > enable/disables. > > Move enabling/disabling clock code into helper functions. > > Reported-by: Nishant Menon > Signed-off-by: Roger Quadros > --- > drivers/phy/phy-ti-pipe3.c | 99 > +++--- > 1 file changed, 77 insertions(+), 22 deletions(-) > > diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c > index 1387b4d..e60ff14 100644 > --- a/drivers/phy/phy-ti-pipe3.c > +++ b/drivers/phy/phy-ti-pipe3.c > @@ -28,6 +28,7 @@ > #include > #include > #include > +#include > > #define PLL_STATUS 0x0004 > #define PLL_GO 0x0008 > @@ -83,6 +84,8 @@ struct ti_pipe3 { > struct clk *div_clk; > struct pipe3_dpll_map *dpll_map; > u8 id; > + bool enabled; > + spinlock_t lock;/* serialize clock enable/disable */ > }; > > static struct pipe3_dpll_map dpll_map_usb[] = { > @@ -303,6 +306,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) > return -ENOMEM; > > phy->dev= &pdev->dev; > + spin_lock_init(&phy->lock); > > if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { > match = of_match_device(of_match_ptr(ti_pipe3_id_table), > @@ -425,24 +429,14 @@ static int ti_pipe3_remove(struct platform_device *pdev) > > #ifdef CONFIG_PM > > -static int ti_pipe3_runtime_suspend(struct device *dev) > +static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy) > { > - struct ti_pipe3 *phy = dev_get_drvdata(dev); > - > - if (!IS_ERR(phy->wkupclk)) > - clk_disable_unprepare(phy->wkupclk); > - if (!IS_ERR(phy->refclk)) > - clk_disable_unprepare(phy->refclk); > - if (!IS_ERR(phy->div_clk)) > - clk_disable_unprepare(phy->div_clk); > - > - return 0; > -} > + int ret = 0; > + unsigned long flags; > > -static int ti_pipe3_runtime_resume(struct device *dev) > -{ > - u32 ret = 0; > - struct ti_pipe3 *phy = dev_get_drvdata(dev); > + spin_lock_irqsave(&phy->lock, flags); > + if (phy->enabled) > + goto err1; > > if (!IS_ERR(phy->refclk)) { > ret = clk_prepare_enable(phy->refclk); > @@ -467,6 +461,9 @@ static int ti_pipe3_runtime_resume(struct device *dev) > goto err3; > } > } > + > + phy->enabled = true; > + spin_unlock_irqrestore(&phy->lock, flags); > return 0; > > err3: > @@ -478,19 +475,77 @@ err2: > clk_disable_unprepare(phy->refclk); > > err1: > + spin_unlock_irqrestore(&phy->lock, flags); > + return ret; > +} > + > +static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&phy->lock, flags); > + if (!phy->enabled) { > + spin_unlock_irqrestore(&phy->lock, flags); > + return; > + } > + > + if (!IS_ERR(phy->wkupclk)) > + clk_disable_unprepare(phy->wkupclk); > + if (!IS_ERR(phy->refclk)) > + clk_disable_unprepare(phy->refclk); > + if (!IS_ERR(phy->div_clk)) > + clk_disable_unprepare(phy->div_clk); > + phy->enabled = false; > + spin_unlock_irqrestore(&phy->lock, flags); > +} > + > +static int ti_pipe3_runtime_suspend(struct device *dev) > +{ > + struct ti_pipe3 *phy = dev_get_drvdata(dev); > + > + ti_pipe3_disable_clocks(phy); > + return 0; > +} > + > +static int ti_pipe3_runtime_resume(struct device *dev) > +{ > + struct ti_pipe3 *phy = dev_get_drvdata(dev); > + int ret = 0; > + > + ret = ti_pipe3_enable_clocks(phy); > return ret; > } > > +static int ti_pipe3_suspend(struct device *dev) > +{ > + struct ti_pipe3 *phy = dev_get_drvdata(dev); > + > + ti_pipe3_disable_clocks(phy); > + return 0; > +} > + > +static int ti_pipe3_resume(struct device *dev) > +{ > + struct ti_pipe3 *phy = dev_get_drvdata(dev); > + int ret; > + > + ret = ti_pipe3_enable_clocks(phy); > + if (ret) > + return ret; > + > + pm_runtime_disable(dev); > + pm_runtime_set_active(dev); > + pm_runtime_enable(dev); > + return 0; > +} > +#endif > + > static const struct dev_pm_ops ti_pipe3_pm_ops = { > SET_RUNTIME_PM_OPS(ti_
Re: [PATCH 1/2] phy: ti-pipe3: Disable clocks on system suspend
Kishon, On 09/01/15 15:57, Kishon Vijay Abraham I wrote: > Hi Roger, > > On Friday 19 December 2014 05:35 PM, Roger Quadros wrote: >> On system suspend, the runtime_suspend() driver hook doesn't get >> called and so the clocks are not disabled in the driver. >> This causes the L3INIT_960M_GFCLK and L3INIT_480M_GFCLK to remain >> active on the DRA7 platform while in system suspend. >> >> Add suspend/resume hooks to the driver. >> In case of pcie-phy, the runtime_suspend hook gets called after > > This contradicts with the first line of your commit message. Is pcie-phy > driver > is an exception? Yes in the pcie-phy case it behaves differently. I'll rewrite the message. cheers, -roger > > Thanks > Kishon > >> the suspend hook so we introduce a flag phy->enabled to keep >> track if our clocks are enabled or not to prevent multiple >> enable/disables. >> >> Move enabling/disabling clock code into helper functions. >> >> Reported-by: Nishant Menon >> Signed-off-by: Roger Quadros -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html