--- zzzz-none-000/linux-3.10.107/drivers/base/power/clock_ops.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/base/power/clock_ops.c 2021-02-04 17:41:59.000000000 +0000 @@ -6,17 +6,18 @@ * This file is released under the GPLv2. */ -#include #include #include #include #include #include #include +#include #include #include +#include -#ifdef CONFIG_PM +#ifdef CONFIG_PM_CLK enum pce_status { PCE_STATUS_NONE = 0, @@ -33,30 +34,45 @@ }; /** + * pm_clk_enable - Enable a clock, reporting any errors + * @dev: The device for the given clock + * @ce: PM clock entry corresponding to the clock. + */ +static inline void __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) +{ + int ret; + + if (ce->status < PCE_STATUS_ERROR) { + ret = clk_enable(ce->clk); + if (!ret) + ce->status = PCE_STATUS_ENABLED; + else + dev_err(dev, "%s: failed to enable clk %p, error %d\n", + __func__, ce->clk, ret); + } +} + +/** * pm_clk_acquire - Acquire a device clock. * @dev: Device whose clock is to be acquired. * @ce: PM clock entry corresponding to the clock. */ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) { - ce->clk = clk_get(dev, ce->con_id); + if (!ce->clk) + ce->clk = clk_get(dev, ce->con_id); if (IS_ERR(ce->clk)) { ce->status = PCE_STATUS_ERROR; } else { + clk_prepare(ce->clk); ce->status = PCE_STATUS_ACQUIRED; - dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); + dev_dbg(dev, "Clock %pC con_id %s managed by runtime PM.\n", + ce->clk, ce->con_id); } } -/** - * pm_clk_add - Start using a device clock for power management. - * @dev: Device whose clock is going to be used for power management. - * @con_id: Connection ID of the clock. - * - * Add the clock represented by @con_id to the list of clocks used for - * the power management of @dev. - */ -int pm_clk_add(struct device *dev, const char *con_id) +static int __pm_clk_add(struct device *dev, const char *con_id, + struct clk *clk) { struct pm_subsys_data *psd = dev_to_psd(dev); struct pm_clock_entry *ce; @@ -65,10 +81,8 @@ return -EINVAL; ce = kzalloc(sizeof(*ce), GFP_KERNEL); - if (!ce) { - dev_err(dev, "Not enough memory for clock entry.\n"); + if (!ce) return -ENOMEM; - } if (con_id) { ce->con_id = kstrdup(con_id, GFP_KERNEL); @@ -78,6 +92,12 @@ kfree(ce); return -ENOMEM; } + } else { + if (IS_ERR(clk)) { + kfree(ce); + return -ENOENT; + } + ce->clk = clk; } pm_clk_acquire(dev, ce); @@ -89,6 +109,34 @@ } /** + * pm_clk_add - Start using a device clock for power management. + * @dev: Device whose clock is going to be used for power management. + * @con_id: Connection ID of the clock. + * + * Add the clock represented by @con_id to the list of clocks used for + * the power management of @dev. + */ +int pm_clk_add(struct device *dev, const char *con_id) +{ + return __pm_clk_add(dev, con_id, NULL); +} + +/** + * pm_clk_add_clk - Start using a device clock for power management. + * @dev: Device whose clock is going to be used for power management. + * @clk: Clock pointer + * + * Add the clock to the list of clocks used for the power management of @dev. + * The power-management code will take control of the clock reference, so + * callers should not call clk_put() on @clk after this function sucessfully + * returned. + */ +int pm_clk_add_clk(struct device *dev, struct clk *clk) +{ + return __pm_clk_add(dev, NULL, clk); +} + +/** * __pm_clk_remove - Destroy PM clock entry. * @ce: PM clock entry to destroy. */ @@ -99,10 +147,12 @@ if (ce->status < PCE_STATUS_ERROR) { if (ce->status == PCE_STATUS_ENABLED) - clk_disable_unprepare(ce->clk); + clk_disable(ce->clk); - if (ce->status >= PCE_STATUS_ACQUIRED) + if (ce->status >= PCE_STATUS_ACQUIRED) { + clk_unprepare(ce->clk); clk_put(ce->clk); + } } kfree(ce->con_id); @@ -206,10 +256,6 @@ } } -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_RUNTIME - /** * pm_clk_suspend - Disable clocks in a device's PM clock list. * @dev: Device to disable the clocks for. @@ -257,12 +303,8 @@ spin_lock_irqsave(&psd->lock, flags); - list_for_each_entry(ce, &psd->clock_list, node) { - if (ce->status < PCE_STATUS_ERROR) { - clk_enable(ce->clk); - ce->status = PCE_STATUS_ENABLED; - } - } + list_for_each_entry(ce, &psd->clock_list, node) + __pm_clk_enable(dev, ce); spin_unlock_irqrestore(&psd->lock, flags); @@ -327,63 +369,44 @@ return 0; } -#else /* !CONFIG_PM_RUNTIME */ - -#ifdef CONFIG_PM - -/** - * pm_clk_suspend - Disable clocks in a device's PM clock list. - * @dev: Device to disable the clocks for. - */ -int pm_clk_suspend(struct device *dev) +int pm_clk_runtime_suspend(struct device *dev) { - struct pm_subsys_data *psd = dev_to_psd(dev); - struct pm_clock_entry *ce; - unsigned long flags; - - dev_dbg(dev, "%s()\n", __func__); - - /* If there is no driver, the clocks are already disabled. */ - if (!psd || !dev->driver) - return 0; + int ret; - spin_lock_irqsave(&psd->lock, flags); + dev_dbg(dev, "%s\n", __func__); - list_for_each_entry_reverse(ce, &psd->clock_list, node) - clk_disable(ce->clk); + ret = pm_generic_runtime_suspend(dev); + if (ret) { + dev_err(dev, "failed to suspend device\n"); + return ret; + } - spin_unlock_irqrestore(&psd->lock, flags); + ret = pm_clk_suspend(dev); + if (ret) { + dev_err(dev, "failed to suspend clock\n"); + pm_generic_runtime_resume(dev); + return ret; + } return 0; } -/** - * pm_clk_resume - Enable clocks in a device's PM clock list. - * @dev: Device to enable the clocks for. - */ -int pm_clk_resume(struct device *dev) +int pm_clk_runtime_resume(struct device *dev) { - struct pm_subsys_data *psd = dev_to_psd(dev); - struct pm_clock_entry *ce; - unsigned long flags; - - dev_dbg(dev, "%s()\n", __func__); + int ret; - /* If there is no driver, the clocks should remain disabled. */ - if (!psd || !dev->driver) - return 0; - - spin_lock_irqsave(&psd->lock, flags); + dev_dbg(dev, "%s\n", __func__); - list_for_each_entry(ce, &psd->clock_list, node) - clk_enable(ce->clk); - - spin_unlock_irqrestore(&psd->lock, flags); + ret = pm_clk_resume(dev); + if (ret) { + dev_err(dev, "failed to resume clock\n"); + return ret; + } - return 0; + return pm_generic_runtime_resume(dev); } -#endif /* CONFIG_PM */ +#else /* !CONFIG_PM_CLK */ /** * enable_clock - Enable a device clock. @@ -463,7 +486,7 @@ return 0; } -#endif /* !CONFIG_PM_RUNTIME */ +#endif /* !CONFIG_PM_CLK */ /** * pm_clk_add_notifier - Add bus type notifier for power management clocks.