// SPDX-License-Identifier: GPL-2.01/*2* drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks3*4* Copyright (c) 2011 Rafael J. Wysocki <[email protected]>, Renesas Electronics Corp.5*/67#include <linux/kernel.h>8#include <linux/device.h>9#include <linux/io.h>10#include <linux/pm.h>11#include <linux/pm_clock.h>12#include <linux/clk.h>13#include <linux/clkdev.h>14#include <linux/of_clk.h>15#include <linux/slab.h>16#include <linux/err.h>17#include <linux/pm_domain.h>18#include <linux/pm_runtime.h>1920#ifdef CONFIG_PM_CLK2122enum pce_status {23PCE_STATUS_NONE = 0,24PCE_STATUS_ACQUIRED,25PCE_STATUS_PREPARED,26PCE_STATUS_ENABLED,27PCE_STATUS_ERROR,28};2930struct pm_clock_entry {31struct list_head node;32char *con_id;33struct clk *clk;34enum pce_status status;35bool enabled_when_prepared;36};3738/**39* pm_clk_list_lock - ensure exclusive access for modifying the PM clock40* entry list.41* @psd: pm_subsys_data instance corresponding to the PM clock entry list42* and clk_op_might_sleep count to be modified.43*44* Get exclusive access before modifying the PM clock entry list and the45* clock_op_might_sleep count to guard against concurrent modifications.46* This also protects against a concurrent clock_op_might_sleep and PM clock47* entry list usage in pm_clk_suspend()/pm_clk_resume() that may or may not48* happen in atomic context, hence both the mutex and the spinlock must be49* taken here.50*/51static void pm_clk_list_lock(struct pm_subsys_data *psd)52__acquires(&psd->lock)53{54mutex_lock(&psd->clock_mutex);55spin_lock_irq(&psd->lock);56}5758/**59* pm_clk_list_unlock - counterpart to pm_clk_list_lock().60* @psd: the same pm_subsys_data instance previously passed to61* pm_clk_list_lock().62*/63static void pm_clk_list_unlock(struct pm_subsys_data *psd)64__releases(&psd->lock)65{66spin_unlock_irq(&psd->lock);67mutex_unlock(&psd->clock_mutex);68}6970/**71* pm_clk_op_lock - ensure exclusive access for performing clock operations.72* @psd: pm_subsys_data instance corresponding to the PM clock entry list73* and clk_op_might_sleep count being used.74* @flags: stored irq flags.75* @fn: string for the caller function's name.76*77* This is used by pm_clk_suspend() and pm_clk_resume() to guard78* against concurrent modifications to the clock entry list and the79* clock_op_might_sleep count. If clock_op_might_sleep is != 0 then80* only the mutex can be locked and those functions can only be used in81* non atomic context. If clock_op_might_sleep == 0 then these functions82* may be used in any context and only the spinlock can be locked.83* Returns -EINVAL if called in atomic context when clock ops might sleep.84*/85static int pm_clk_op_lock(struct pm_subsys_data *psd, unsigned long *flags,86const char *fn)87/* sparse annotations don't work here as exit state isn't static */88{89bool atomic_context = in_atomic() || irqs_disabled();9091try_again:92spin_lock_irqsave(&psd->lock, *flags);93if (!psd->clock_op_might_sleep) {94/* the __release is there to work around sparse limitations */95__release(&psd->lock);96return 0;97}9899/* bail out if in atomic context */100if (atomic_context) {101pr_err("%s: atomic context with clock_ops_might_sleep = %d",102fn, psd->clock_op_might_sleep);103spin_unlock_irqrestore(&psd->lock, *flags);104might_sleep();105return -EPERM;106}107108/* we must switch to the mutex */109spin_unlock_irqrestore(&psd->lock, *flags);110mutex_lock(&psd->clock_mutex);111112/*113* There was a possibility for psd->clock_op_might_sleep114* to become 0 above. Keep the mutex only if not the case.115*/116if (likely(psd->clock_op_might_sleep))117return 0;118119mutex_unlock(&psd->clock_mutex);120goto try_again;121}122123/**124* pm_clk_op_unlock - counterpart to pm_clk_op_lock().125* @psd: the same pm_subsys_data instance previously passed to126* pm_clk_op_lock().127* @flags: irq flags provided by pm_clk_op_lock().128*/129static void pm_clk_op_unlock(struct pm_subsys_data *psd, unsigned long *flags)130/* sparse annotations don't work here as entry state isn't static */131{132if (psd->clock_op_might_sleep) {133mutex_unlock(&psd->clock_mutex);134} else {135/* the __acquire is there to work around sparse limitations */136__acquire(&psd->lock);137spin_unlock_irqrestore(&psd->lock, *flags);138}139}140141/**142* __pm_clk_enable - Enable a clock, reporting any errors143* @dev: The device for the given clock144* @ce: PM clock entry corresponding to the clock.145*/146static inline void __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)147{148int ret;149150switch (ce->status) {151case PCE_STATUS_ACQUIRED:152ret = clk_prepare_enable(ce->clk);153break;154case PCE_STATUS_PREPARED:155ret = clk_enable(ce->clk);156break;157default:158return;159}160if (!ret)161ce->status = PCE_STATUS_ENABLED;162else163dev_err(dev, "%s: failed to enable clk %p, error %d\n",164__func__, ce->clk, ret);165}166167/**168* pm_clk_acquire - Acquire a device clock.169* @dev: Device whose clock is to be acquired.170* @ce: PM clock entry corresponding to the clock.171*/172static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)173{174if (!ce->clk)175ce->clk = clk_get(dev, ce->con_id);176if (IS_ERR(ce->clk)) {177ce->status = PCE_STATUS_ERROR;178return;179} else if (clk_is_enabled_when_prepared(ce->clk)) {180/* we defer preparing the clock in that case */181ce->status = PCE_STATUS_ACQUIRED;182ce->enabled_when_prepared = true;183} else if (clk_prepare(ce->clk)) {184ce->status = PCE_STATUS_ERROR;185dev_err(dev, "clk_prepare() failed\n");186return;187} else {188ce->status = PCE_STATUS_PREPARED;189}190dev_dbg(dev, "Clock %pC con_id %s managed by runtime PM.\n",191ce->clk, ce->con_id);192}193194static int __pm_clk_add(struct device *dev, const char *con_id,195struct clk *clk)196{197struct pm_subsys_data *psd = dev_to_psd(dev);198struct pm_clock_entry *ce;199200if (!psd)201return -EINVAL;202203ce = kzalloc(sizeof(*ce), GFP_KERNEL);204if (!ce)205return -ENOMEM;206207if (con_id) {208ce->con_id = kstrdup(con_id, GFP_KERNEL);209if (!ce->con_id) {210kfree(ce);211return -ENOMEM;212}213} else {214if (IS_ERR(clk)) {215kfree(ce);216return -ENOENT;217}218ce->clk = clk;219}220221pm_clk_acquire(dev, ce);222223pm_clk_list_lock(psd);224list_add_tail(&ce->node, &psd->clock_list);225if (ce->enabled_when_prepared)226psd->clock_op_might_sleep++;227pm_clk_list_unlock(psd);228return 0;229}230231/**232* pm_clk_add - Start using a device clock for power management.233* @dev: Device whose clock is going to be used for power management.234* @con_id: Connection ID of the clock.235*236* Add the clock represented by @con_id to the list of clocks used for237* the power management of @dev.238*/239int pm_clk_add(struct device *dev, const char *con_id)240{241return __pm_clk_add(dev, con_id, NULL);242}243EXPORT_SYMBOL_GPL(pm_clk_add);244245/**246* pm_clk_add_clk - Start using a device clock for power management.247* @dev: Device whose clock is going to be used for power management.248* @clk: Clock pointer249*250* Add the clock to the list of clocks used for the power management of @dev.251* The power-management code will take control of the clock reference, so252* callers should not call clk_put() on @clk after this function sucessfully253* returned.254*/255int pm_clk_add_clk(struct device *dev, struct clk *clk)256{257return __pm_clk_add(dev, NULL, clk);258}259EXPORT_SYMBOL_GPL(pm_clk_add_clk);260261/**262* of_pm_clk_add_clks - Start using device clock(s) for power management.263* @dev: Device whose clock(s) is going to be used for power management.264*265* Add a series of clocks described in the 'clocks' device-tree node for266* a device to the list of clocks used for the power management of @dev.267* On success, returns the number of clocks added. Returns a negative268* error code if there are no clocks in the device node for the device269* or if adding a clock fails.270*/271int of_pm_clk_add_clks(struct device *dev)272{273struct clk **clks;274int i, count;275int ret;276277if (!dev || !dev->of_node)278return -EINVAL;279280count = of_clk_get_parent_count(dev->of_node);281if (count <= 0)282return -ENODEV;283284clks = kcalloc(count, sizeof(*clks), GFP_KERNEL);285if (!clks)286return -ENOMEM;287288for (i = 0; i < count; i++) {289clks[i] = of_clk_get(dev->of_node, i);290if (IS_ERR(clks[i])) {291ret = PTR_ERR(clks[i]);292goto error;293}294295ret = pm_clk_add_clk(dev, clks[i]);296if (ret) {297clk_put(clks[i]);298goto error;299}300}301302kfree(clks);303304return i;305306error:307while (i--)308pm_clk_remove_clk(dev, clks[i]);309310kfree(clks);311312return ret;313}314EXPORT_SYMBOL_GPL(of_pm_clk_add_clks);315316/**317* __pm_clk_remove - Destroy PM clock entry.318* @ce: PM clock entry to destroy.319*/320static void __pm_clk_remove(struct pm_clock_entry *ce)321{322if (!ce)323return;324325switch (ce->status) {326case PCE_STATUS_ENABLED:327clk_disable(ce->clk);328fallthrough;329case PCE_STATUS_PREPARED:330clk_unprepare(ce->clk);331fallthrough;332case PCE_STATUS_ACQUIRED:333case PCE_STATUS_ERROR:334if (!IS_ERR(ce->clk))335clk_put(ce->clk);336break;337default:338break;339}340341kfree(ce->con_id);342kfree(ce);343}344345/**346* pm_clk_remove_clk - Stop using a device clock for power management.347* @dev: Device whose clock should not be used for PM any more.348* @clk: Clock pointer349*350* Remove the clock pointed to by @clk from the list of clocks used for351* the power management of @dev.352*/353void pm_clk_remove_clk(struct device *dev, struct clk *clk)354{355struct pm_subsys_data *psd = dev_to_psd(dev);356struct pm_clock_entry *ce;357358if (!psd || !clk)359return;360361pm_clk_list_lock(psd);362363list_for_each_entry(ce, &psd->clock_list, node) {364if (clk == ce->clk)365goto remove;366}367368pm_clk_list_unlock(psd);369return;370371remove:372list_del(&ce->node);373if (ce->enabled_when_prepared)374psd->clock_op_might_sleep--;375pm_clk_list_unlock(psd);376377__pm_clk_remove(ce);378}379EXPORT_SYMBOL_GPL(pm_clk_remove_clk);380381/**382* pm_clk_init - Initialize a device's list of power management clocks.383* @dev: Device to initialize the list of PM clocks for.384*385* Initialize the lock and clock_list members of the device's pm_subsys_data386* object, set the count of clocks that might sleep to 0.387*/388void pm_clk_init(struct device *dev)389{390struct pm_subsys_data *psd = dev_to_psd(dev);391if (psd) {392INIT_LIST_HEAD(&psd->clock_list);393mutex_init(&psd->clock_mutex);394psd->clock_op_might_sleep = 0;395}396}397EXPORT_SYMBOL_GPL(pm_clk_init);398399/**400* pm_clk_create - Create and initialize a device's list of PM clocks.401* @dev: Device to create and initialize the list of PM clocks for.402*403* Allocate a struct pm_subsys_data object, initialize its lock and clock_list404* members and make the @dev's power.subsys_data field point to it.405*/406int pm_clk_create(struct device *dev)407{408return dev_pm_get_subsys_data(dev);409}410EXPORT_SYMBOL_GPL(pm_clk_create);411412/**413* pm_clk_destroy - Destroy a device's list of power management clocks.414* @dev: Device to destroy the list of PM clocks for.415*416* Clear the @dev's power.subsys_data field, remove the list of clock entries417* from the struct pm_subsys_data object pointed to by it before and free418* that object.419*/420void pm_clk_destroy(struct device *dev)421{422struct pm_subsys_data *psd = dev_to_psd(dev);423struct pm_clock_entry *ce, *c;424struct list_head list;425426if (!psd)427return;428429INIT_LIST_HEAD(&list);430431pm_clk_list_lock(psd);432433list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)434list_move(&ce->node, &list);435psd->clock_op_might_sleep = 0;436437pm_clk_list_unlock(psd);438439dev_pm_put_subsys_data(dev);440441list_for_each_entry_safe_reverse(ce, c, &list, node) {442list_del(&ce->node);443__pm_clk_remove(ce);444}445}446EXPORT_SYMBOL_GPL(pm_clk_destroy);447448static void pm_clk_destroy_action(void *data)449{450pm_clk_destroy(data);451}452453int devm_pm_clk_create(struct device *dev)454{455int ret;456457ret = pm_clk_create(dev);458if (ret)459return ret;460461return devm_add_action_or_reset(dev, pm_clk_destroy_action, dev);462}463EXPORT_SYMBOL_GPL(devm_pm_clk_create);464465/**466* pm_clk_suspend - Disable clocks in a device's PM clock list.467* @dev: Device to disable the clocks for.468*/469int pm_clk_suspend(struct device *dev)470{471struct pm_subsys_data *psd = dev_to_psd(dev);472struct pm_clock_entry *ce;473unsigned long flags;474int ret;475476dev_dbg(dev, "%s()\n", __func__);477478if (!psd)479return 0;480481ret = pm_clk_op_lock(psd, &flags, __func__);482if (ret)483return ret;484485list_for_each_entry_reverse(ce, &psd->clock_list, node) {486if (ce->status == PCE_STATUS_ENABLED) {487if (ce->enabled_when_prepared) {488clk_disable_unprepare(ce->clk);489ce->status = PCE_STATUS_ACQUIRED;490} else {491clk_disable(ce->clk);492ce->status = PCE_STATUS_PREPARED;493}494}495}496497pm_clk_op_unlock(psd, &flags);498499return 0;500}501EXPORT_SYMBOL_GPL(pm_clk_suspend);502503/**504* pm_clk_resume - Enable clocks in a device's PM clock list.505* @dev: Device to enable the clocks for.506*/507int pm_clk_resume(struct device *dev)508{509struct pm_subsys_data *psd = dev_to_psd(dev);510struct pm_clock_entry *ce;511unsigned long flags;512int ret;513514dev_dbg(dev, "%s()\n", __func__);515516if (!psd)517return 0;518519ret = pm_clk_op_lock(psd, &flags, __func__);520if (ret)521return ret;522523list_for_each_entry(ce, &psd->clock_list, node)524__pm_clk_enable(dev, ce);525526pm_clk_op_unlock(psd, &flags);527528return 0;529}530EXPORT_SYMBOL_GPL(pm_clk_resume);531532/**533* pm_clk_notify - Notify routine for device addition and removal.534* @nb: Notifier block object this function is a member of.535* @action: Operation being carried out by the caller.536* @data: Device the routine is being run for.537*538* For this function to work, @nb must be a member of an object of type539* struct pm_clk_notifier_block containing all of the requisite data.540* Specifically, the pm_domain member of that object is copied to the device's541* pm_domain field and its con_ids member is used to populate the device's list542* of PM clocks, depending on @action.543*544* If the device's pm_domain field is already populated with a value different545* from the one stored in the struct pm_clk_notifier_block object, the function546* does nothing.547*/548static int pm_clk_notify(struct notifier_block *nb,549unsigned long action, void *data)550{551struct pm_clk_notifier_block *clknb;552struct device *dev = data;553char **con_id;554int error;555556dev_dbg(dev, "%s() %ld\n", __func__, action);557558clknb = container_of(nb, struct pm_clk_notifier_block, nb);559560switch (action) {561case BUS_NOTIFY_ADD_DEVICE:562if (dev->pm_domain)563break;564565error = pm_clk_create(dev);566if (error)567break;568569dev_pm_domain_set(dev, clknb->pm_domain);570if (clknb->con_ids[0]) {571for (con_id = clknb->con_ids; *con_id; con_id++)572pm_clk_add(dev, *con_id);573} else {574pm_clk_add(dev, NULL);575}576577break;578case BUS_NOTIFY_DEL_DEVICE:579if (dev->pm_domain != clknb->pm_domain)580break;581582dev_pm_domain_set(dev, NULL);583pm_clk_destroy(dev);584break;585}586587return 0;588}589590int pm_clk_runtime_suspend(struct device *dev)591{592int ret;593594dev_dbg(dev, "%s\n", __func__);595596ret = pm_generic_runtime_suspend(dev);597if (ret) {598dev_err(dev, "failed to suspend device\n");599return ret;600}601602ret = pm_clk_suspend(dev);603if (ret) {604dev_err(dev, "failed to suspend clock\n");605pm_generic_runtime_resume(dev);606return ret;607}608609return 0;610}611EXPORT_SYMBOL_GPL(pm_clk_runtime_suspend);612613int pm_clk_runtime_resume(struct device *dev)614{615int ret;616617dev_dbg(dev, "%s\n", __func__);618619ret = pm_clk_resume(dev);620if (ret) {621dev_err(dev, "failed to resume clock\n");622return ret;623}624625return pm_generic_runtime_resume(dev);626}627EXPORT_SYMBOL_GPL(pm_clk_runtime_resume);628629#else /* !CONFIG_PM_CLK */630631/**632* enable_clock - Enable a device clock.633* @dev: Device whose clock is to be enabled.634* @con_id: Connection ID of the clock.635*/636static void enable_clock(struct device *dev, const char *con_id)637{638struct clk *clk;639640clk = clk_get(dev, con_id);641if (!IS_ERR(clk)) {642clk_prepare_enable(clk);643clk_put(clk);644dev_info(dev, "Runtime PM disabled, clock forced on.\n");645}646}647648/**649* disable_clock - Disable a device clock.650* @dev: Device whose clock is to be disabled.651* @con_id: Connection ID of the clock.652*/653static void disable_clock(struct device *dev, const char *con_id)654{655struct clk *clk;656657clk = clk_get(dev, con_id);658if (!IS_ERR(clk)) {659clk_disable_unprepare(clk);660clk_put(clk);661dev_info(dev, "Runtime PM disabled, clock forced off.\n");662}663}664665/**666* pm_clk_notify - Notify routine for device addition and removal.667* @nb: Notifier block object this function is a member of.668* @action: Operation being carried out by the caller.669* @data: Device the routine is being run for.670*671* For this function to work, @nb must be a member of an object of type672* struct pm_clk_notifier_block containing all of the requisite data.673* Specifically, the con_ids member of that object is used to enable or disable674* the device's clocks, depending on @action.675*/676static int pm_clk_notify(struct notifier_block *nb,677unsigned long action, void *data)678{679struct pm_clk_notifier_block *clknb;680struct device *dev = data;681char **con_id;682683dev_dbg(dev, "%s() %ld\n", __func__, action);684685clknb = container_of(nb, struct pm_clk_notifier_block, nb);686687switch (action) {688case BUS_NOTIFY_BIND_DRIVER:689if (clknb->con_ids[0]) {690for (con_id = clknb->con_ids; *con_id; con_id++)691enable_clock(dev, *con_id);692} else {693enable_clock(dev, NULL);694}695break;696case BUS_NOTIFY_DRIVER_NOT_BOUND:697case BUS_NOTIFY_UNBOUND_DRIVER:698if (clknb->con_ids[0]) {699for (con_id = clknb->con_ids; *con_id; con_id++)700disable_clock(dev, *con_id);701} else {702disable_clock(dev, NULL);703}704break;705}706707return 0;708}709710#endif /* !CONFIG_PM_CLK */711712/**713* pm_clk_add_notifier - Add bus type notifier for power management clocks.714* @bus: Bus type to add the notifier to.715* @clknb: Notifier to be added to the given bus type.716*717* The nb member of @clknb is not expected to be initialized and its718* notifier_call member will be replaced with pm_clk_notify(). However,719* the remaining members of @clknb should be populated prior to calling this720* routine.721*/722void pm_clk_add_notifier(const struct bus_type *bus,723struct pm_clk_notifier_block *clknb)724{725if (!bus || !clknb)726return;727728clknb->nb.notifier_call = pm_clk_notify;729bus_register_notifier(bus, &clknb->nb);730}731EXPORT_SYMBOL_GPL(pm_clk_add_notifier);732733734