blob: e870bbe9ec4e674d91fb3bede6e4105fd25ccd6a [file] [log] [blame]
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +02001/*
2 * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
3 *
4 * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
5 *
6 * This file is released under the GPLv2.
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
Paul Gortmaker51990e82012-01-22 11:23:42 -050011#include <linux/device.h>
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020012#include <linux/io.h>
13#include <linux/pm.h>
Rafael J. Wysockib5e8d262011-08-25 15:34:19 +020014#include <linux/pm_clock.h>
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020015#include <linux/clk.h>
16#include <linux/slab.h>
17#include <linux/err.h>
18
Rafael J. Wysockib7b95922011-07-01 22:13:37 +020019#ifdef CONFIG_PM
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020020
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020021enum pce_status {
22 PCE_STATUS_NONE = 0,
23 PCE_STATUS_ACQUIRED,
24 PCE_STATUS_ENABLED,
25 PCE_STATUS_ERROR,
26};
27
28struct pm_clock_entry {
29 struct list_head node;
30 char *con_id;
31 struct clk *clk;
32 enum pce_status status;
33};
34
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020035/**
Ben Dooks5cda3fb2014-01-14 12:23:42 +000036 * pm_clk_enable - Enable a clock, reporting any errors
37 * @dev: The device for the given clock
38 * @clk: The clock being enabled.
39 */
40static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
41{
42 int ret = clk_enable(clk);
43 if (ret)
44 dev_err(dev, "%s: failed to enable clk %p, error %d\n",
45 __func__, clk, ret);
46
47 return ret;
48}
49
50/**
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020051 * pm_clk_acquire - Acquire a device clock.
52 * @dev: Device whose clock is to be acquired.
53 * @ce: PM clock entry corresponding to the clock.
54 */
55static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
56{
57 ce->clk = clk_get(dev, ce->con_id);
58 if (IS_ERR(ce->clk)) {
59 ce->status = PCE_STATUS_ERROR;
60 } else {
Ben Dooks8a6720e2014-01-14 12:23:40 +000061 clk_prepare(ce->clk);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020062 ce->status = PCE_STATUS_ACQUIRED;
63 dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
64 }
65}
66
67/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +020068 * pm_clk_add - Start using a device clock for power management.
69 * @dev: Device whose clock is going to be used for power management.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020070 * @con_id: Connection ID of the clock.
71 *
72 * Add the clock represented by @con_id to the list of clocks used for
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +020073 * the power management of @dev.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020074 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +020075int pm_clk_add(struct device *dev, const char *con_id)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020076{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +020077 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020078 struct pm_clock_entry *ce;
79
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +020080 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020081 return -EINVAL;
82
83 ce = kzalloc(sizeof(*ce), GFP_KERNEL);
84 if (!ce) {
85 dev_err(dev, "Not enough memory for clock entry.\n");
86 return -ENOMEM;
87 }
88
89 if (con_id) {
90 ce->con_id = kstrdup(con_id, GFP_KERNEL);
91 if (!ce->con_id) {
92 dev_err(dev,
93 "Not enough memory for clock connection ID.\n");
94 kfree(ce);
95 return -ENOMEM;
96 }
97 }
98
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020099 pm_clk_acquire(dev, ce);
100
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200101 spin_lock_irq(&psd->lock);
102 list_add_tail(&ce->node, &psd->clock_list);
103 spin_unlock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200104 return 0;
105}
106
107/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200108 * __pm_clk_remove - Destroy PM clock entry.
109 * @ce: PM clock entry to destroy.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200110 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200111static void __pm_clk_remove(struct pm_clock_entry *ce)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200112{
113 if (!ce)
114 return;
115
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200116 if (ce->status < PCE_STATUS_ERROR) {
117 if (ce->status == PCE_STATUS_ENABLED)
Ben Dooks8a6720e2014-01-14 12:23:40 +0000118 clk_disable(ce->clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200119
Ben Dooks8a6720e2014-01-14 12:23:40 +0000120 if (ce->status >= PCE_STATUS_ACQUIRED) {
121 clk_unprepare(ce->clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200122 clk_put(ce->clk);
Ben Dooks8a6720e2014-01-14 12:23:40 +0000123 }
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200124 }
125
Jonghwan Choi0ab1e792011-10-22 00:22:54 +0200126 kfree(ce->con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200127 kfree(ce);
128}
129
130/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200131 * pm_clk_remove - Stop using a device clock for power management.
132 * @dev: Device whose clock should not be used for PM any more.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200133 * @con_id: Connection ID of the clock.
134 *
135 * Remove the clock represented by @con_id from the list of clocks used for
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200136 * the power management of @dev.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200137 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200138void pm_clk_remove(struct device *dev, const char *con_id)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200139{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200140 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200141 struct pm_clock_entry *ce;
142
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200143 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200144 return;
145
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200146 spin_lock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200147
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200148 list_for_each_entry(ce, &psd->clock_list, node) {
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200149 if (!con_id && !ce->con_id)
150 goto remove;
151 else if (!con_id || !ce->con_id)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200152 continue;
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200153 else if (!strcmp(con_id, ce->con_id))
154 goto remove;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200155 }
156
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200157 spin_unlock_irq(&psd->lock);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200158 return;
159
160 remove:
161 list_del(&ce->node);
Rafael J. Wysocki0d41da22011-09-26 20:12:45 +0200162 spin_unlock_irq(&psd->lock);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200163
164 __pm_clk_remove(ce);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200165}
166
167/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200168 * pm_clk_init - Initialize a device's list of power management clocks.
169 * @dev: Device to initialize the list of PM clocks for.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200170 *
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200171 * Initialize the lock and clock_list members of the device's pm_subsys_data
172 * object.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200173 */
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200174void pm_clk_init(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200175{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200176 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysockief27bed12011-08-25 15:34:01 +0200177 if (psd)
178 INIT_LIST_HEAD(&psd->clock_list);
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200179}
180
181/**
182 * pm_clk_create - Create and initialize a device's list of PM clocks.
183 * @dev: Device to create and initialize the list of PM clocks for.
184 *
185 * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
186 * members and make the @dev's power.subsys_data field point to it.
187 */
188int pm_clk_create(struct device *dev)
189{
Rafael J. Wysocki77254952012-08-07 13:50:14 +0200190 return dev_pm_get_subsys_data(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200191}
192
193/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200194 * pm_clk_destroy - Destroy a device's list of power management clocks.
195 * @dev: Device to destroy the list of PM clocks for.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200196 *
197 * Clear the @dev's power.subsys_data field, remove the list of clock entries
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200198 * from the struct pm_subsys_data object pointed to by it before and free
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200199 * that object.
200 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200201void pm_clk_destroy(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200202{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200203 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200204 struct pm_clock_entry *ce, *c;
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200205 struct list_head list;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200206
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200207 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200208 return;
209
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200210 INIT_LIST_HEAD(&list);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200211
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200212 spin_lock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200213
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200214 list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200215 list_move(&ce->node, &list);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200216
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200217 spin_unlock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200218
Rafael J. Wysockief27bed12011-08-25 15:34:01 +0200219 dev_pm_put_subsys_data(dev);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200220
221 list_for_each_entry_safe_reverse(ce, c, &list, node) {
222 list_del(&ce->node);
223 __pm_clk_remove(ce);
224 }
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200225}
226
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200227#endif /* CONFIG_PM */
228
229#ifdef CONFIG_PM_RUNTIME
230
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200231/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200232 * pm_clk_suspend - Disable clocks in a device's PM clock list.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200233 * @dev: Device to disable the clocks for.
234 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200235int pm_clk_suspend(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200236{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200237 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200238 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200239 unsigned long flags;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200240
241 dev_dbg(dev, "%s()\n", __func__);
242
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200243 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200244 return 0;
245
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200246 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200247
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200248 list_for_each_entry_reverse(ce, &psd->clock_list, node) {
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200249 if (ce->status < PCE_STATUS_ERROR) {
Magnus Damm24050952011-11-10 00:44:10 +0100250 if (ce->status == PCE_STATUS_ENABLED)
251 clk_disable(ce->clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200252 ce->status = PCE_STATUS_ACQUIRED;
253 }
254 }
255
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200256 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200257
258 return 0;
259}
260
261/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200262 * pm_clk_resume - Enable clocks in a device's PM clock list.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200263 * @dev: Device to enable the clocks for.
264 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200265int pm_clk_resume(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200266{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200267 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200268 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200269 unsigned long flags;
Ben Dooksafdd3ab2014-01-14 12:23:41 +0000270 int ret;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200271
272 dev_dbg(dev, "%s()\n", __func__);
273
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200274 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200275 return 0;
276
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200277 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200278
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200279 list_for_each_entry(ce, &psd->clock_list, node) {
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200280 if (ce->status < PCE_STATUS_ERROR) {
Ben Dooks5cda3fb2014-01-14 12:23:42 +0000281 ret = __pm_clk_enable(dev, ce->clk);
Ben Dooksafdd3ab2014-01-14 12:23:41 +0000282 if (!ret)
283 ce->status = PCE_STATUS_ENABLED;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200284 }
285 }
286
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200287 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200288
289 return 0;
290}
291
292/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200293 * pm_clk_notify - Notify routine for device addition and removal.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200294 * @nb: Notifier block object this function is a member of.
295 * @action: Operation being carried out by the caller.
296 * @data: Device the routine is being run for.
297 *
298 * For this function to work, @nb must be a member of an object of type
299 * struct pm_clk_notifier_block containing all of the requisite data.
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200300 * Specifically, the pm_domain member of that object is copied to the device's
301 * pm_domain field and its con_ids member is used to populate the device's list
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200302 * of PM clocks, depending on @action.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200303 *
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200304 * If the device's pm_domain field is already populated with a value different
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200305 * from the one stored in the struct pm_clk_notifier_block object, the function
306 * does nothing.
307 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200308static int pm_clk_notify(struct notifier_block *nb,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200309 unsigned long action, void *data)
310{
311 struct pm_clk_notifier_block *clknb;
312 struct device *dev = data;
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200313 char **con_id;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200314 int error;
315
316 dev_dbg(dev, "%s() %ld\n", __func__, action);
317
318 clknb = container_of(nb, struct pm_clk_notifier_block, nb);
319
320 switch (action) {
321 case BUS_NOTIFY_ADD_DEVICE:
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200322 if (dev->pm_domain)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200323 break;
324
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200325 error = pm_clk_create(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200326 if (error)
327 break;
328
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200329 dev->pm_domain = clknb->pm_domain;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200330 if (clknb->con_ids[0]) {
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200331 for (con_id = clknb->con_ids; *con_id; con_id++)
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200332 pm_clk_add(dev, *con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200333 } else {
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200334 pm_clk_add(dev, NULL);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200335 }
336
337 break;
338 case BUS_NOTIFY_DEL_DEVICE:
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200339 if (dev->pm_domain != clknb->pm_domain)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200340 break;
341
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200342 dev->pm_domain = NULL;
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200343 pm_clk_destroy(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200344 break;
345 }
346
347 return 0;
348}
349
350#else /* !CONFIG_PM_RUNTIME */
351
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200352#ifdef CONFIG_PM
353
354/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200355 * pm_clk_suspend - Disable clocks in a device's PM clock list.
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200356 * @dev: Device to disable the clocks for.
357 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200358int pm_clk_suspend(struct device *dev)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200359{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200360 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200361 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200362 unsigned long flags;
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200363
364 dev_dbg(dev, "%s()\n", __func__);
365
366 /* If there is no driver, the clocks are already disabled. */
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200367 if (!psd || !dev->driver)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200368 return 0;
369
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200370 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200371
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200372 list_for_each_entry_reverse(ce, &psd->clock_list, node)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200373 clk_disable(ce->clk);
374
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200375 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200376
377 return 0;
378}
379
380/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200381 * pm_clk_resume - Enable clocks in a device's PM clock list.
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200382 * @dev: Device to enable the clocks for.
383 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200384int pm_clk_resume(struct device *dev)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200385{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200386 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200387 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200388 unsigned long flags;
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200389
390 dev_dbg(dev, "%s()\n", __func__);
391
392 /* If there is no driver, the clocks should remain disabled. */
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200393 if (!psd || !dev->driver)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200394 return 0;
395
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200396 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200397
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200398 list_for_each_entry(ce, &psd->clock_list, node)
Ben Dooks5cda3fb2014-01-14 12:23:42 +0000399 __pm_clk_enable(dev, ce->clk);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200400
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200401 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200402
403 return 0;
404}
405
406#endif /* CONFIG_PM */
407
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200408/**
409 * enable_clock - Enable a device clock.
410 * @dev: Device whose clock is to be enabled.
411 * @con_id: Connection ID of the clock.
412 */
413static void enable_clock(struct device *dev, const char *con_id)
414{
415 struct clk *clk;
416
417 clk = clk_get(dev, con_id);
418 if (!IS_ERR(clk)) {
Murali Karicheric122f272012-10-23 01:18:40 +0200419 clk_prepare_enable(clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200420 clk_put(clk);
421 dev_info(dev, "Runtime PM disabled, clock forced on.\n");
422 }
423}
424
425/**
426 * disable_clock - Disable a device clock.
427 * @dev: Device whose clock is to be disabled.
428 * @con_id: Connection ID of the clock.
429 */
430static void disable_clock(struct device *dev, const char *con_id)
431{
432 struct clk *clk;
433
434 clk = clk_get(dev, con_id);
435 if (!IS_ERR(clk)) {
Murali Karicheric122f272012-10-23 01:18:40 +0200436 clk_disable_unprepare(clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200437 clk_put(clk);
438 dev_info(dev, "Runtime PM disabled, clock forced off.\n");
439 }
440}
441
442/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200443 * pm_clk_notify - Notify routine for device addition and removal.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200444 * @nb: Notifier block object this function is a member of.
445 * @action: Operation being carried out by the caller.
446 * @data: Device the routine is being run for.
447 *
448 * For this function to work, @nb must be a member of an object of type
449 * struct pm_clk_notifier_block containing all of the requisite data.
450 * Specifically, the con_ids member of that object is used to enable or disable
451 * the device's clocks, depending on @action.
452 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200453static int pm_clk_notify(struct notifier_block *nb,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200454 unsigned long action, void *data)
455{
456 struct pm_clk_notifier_block *clknb;
457 struct device *dev = data;
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200458 char **con_id;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200459
460 dev_dbg(dev, "%s() %ld\n", __func__, action);
461
462 clknb = container_of(nb, struct pm_clk_notifier_block, nb);
463
464 switch (action) {
Rafael J. Wysocki4d1518f2011-06-21 23:24:33 +0200465 case BUS_NOTIFY_BIND_DRIVER:
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200466 if (clknb->con_ids[0]) {
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200467 for (con_id = clknb->con_ids; *con_id; con_id++)
468 enable_clock(dev, *con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200469 } else {
470 enable_clock(dev, NULL);
471 }
472 break;
Rafael J. Wysocki4d1518f2011-06-21 23:24:33 +0200473 case BUS_NOTIFY_UNBOUND_DRIVER:
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200474 if (clknb->con_ids[0]) {
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200475 for (con_id = clknb->con_ids; *con_id; con_id++)
476 disable_clock(dev, *con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200477 } else {
478 disable_clock(dev, NULL);
479 }
480 break;
481 }
482
483 return 0;
484}
485
486#endif /* !CONFIG_PM_RUNTIME */
487
488/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200489 * pm_clk_add_notifier - Add bus type notifier for power management clocks.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200490 * @bus: Bus type to add the notifier to.
491 * @clknb: Notifier to be added to the given bus type.
492 *
493 * The nb member of @clknb is not expected to be initialized and its
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200494 * notifier_call member will be replaced with pm_clk_notify(). However,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200495 * the remaining members of @clknb should be populated prior to calling this
496 * routine.
497 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200498void pm_clk_add_notifier(struct bus_type *bus,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200499 struct pm_clk_notifier_block *clknb)
500{
501 if (!bus || !clknb)
502 return;
503
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200504 clknb->nb.notifier_call = pm_clk_notify;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200505 bus_register_notifier(bus, &clknb->nb);
506}