Branch data Line data Source code
1 : : /*
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>
11 : : #include <linux/device.h>
12 : : #include <linux/io.h>
13 : : #include <linux/pm.h>
14 : : #include <linux/pm_clock.h>
15 : : #include <linux/clk.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/err.h>
18 : :
19 : : #ifdef CONFIG_PM
20 : :
21 : : enum pce_status {
22 : : PCE_STATUS_NONE = 0,
23 : : PCE_STATUS_ACQUIRED,
24 : : PCE_STATUS_ENABLED,
25 : : PCE_STATUS_ERROR,
26 : : };
27 : :
28 : : struct pm_clock_entry {
29 : : struct list_head node;
30 : : char *con_id;
31 : : struct clk *clk;
32 : : enum pce_status status;
33 : : };
34 : :
35 : : /**
36 : : * pm_clk_enable - Enable a clock, reporting any errors
37 : : * @dev: The device for the given clock
38 : : * @clk: The clock being enabled.
39 : : */
40 : : static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
41 : : {
42 : 0 : int ret = clk_enable(clk);
43 [ # # ]: 0 : if (ret)
44 : 0 : dev_err(dev, "%s: failed to enable clk %p, error %d\n",
45 : : __func__, clk, ret);
46 : :
47 : : return ret;
48 : : }
49 : :
50 : : /**
51 : : * 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 : : */
55 : 0 : static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
56 : : {
57 : 0 : ce->clk = clk_get(dev, ce->con_id);
58 [ # # ]: 0 : if (IS_ERR(ce->clk)) {
59 : 0 : ce->status = PCE_STATUS_ERROR;
60 : : } else {
61 : 0 : clk_prepare(ce->clk);
62 : 0 : ce->status = PCE_STATUS_ACQUIRED;
63 : : dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
64 : : }
65 : 0 : }
66 : :
67 : : /**
68 : : * pm_clk_add - Start using a device clock for power management.
69 : : * @dev: Device whose clock is going to be used for power management.
70 : : * @con_id: Connection ID of the clock.
71 : : *
72 : : * Add the clock represented by @con_id to the list of clocks used for
73 : : * the power management of @dev.
74 : : */
75 : 0 : int pm_clk_add(struct device *dev, const char *con_id)
76 : : {
77 : : struct pm_subsys_data *psd = dev_to_psd(dev);
78 : : struct pm_clock_entry *ce;
79 : :
80 [ # # ]: 0 : if (!psd)
81 : : return -EINVAL;
82 : :
83 : : ce = kzalloc(sizeof(*ce), GFP_KERNEL);
84 [ # # ]: 0 : if (!ce) {
85 : 0 : dev_err(dev, "Not enough memory for clock entry.\n");
86 : 0 : return -ENOMEM;
87 : : }
88 : :
89 [ # # ]: 0 : if (con_id) {
90 : 0 : ce->con_id = kstrdup(con_id, GFP_KERNEL);
91 [ # # ]: 0 : if (!ce->con_id) {
92 : 0 : dev_err(dev,
93 : : "Not enough memory for clock connection ID.\n");
94 : 0 : kfree(ce);
95 : 0 : return -ENOMEM;
96 : : }
97 : : }
98 : :
99 : 0 : pm_clk_acquire(dev, ce);
100 : :
101 : : spin_lock_irq(&psd->lock);
102 : 0 : list_add_tail(&ce->node, &psd->clock_list);
103 : : spin_unlock_irq(&psd->lock);
104 : 0 : return 0;
105 : : }
106 : :
107 : : /**
108 : : * __pm_clk_remove - Destroy PM clock entry.
109 : : * @ce: PM clock entry to destroy.
110 : : */
111 : 0 : static void __pm_clk_remove(struct pm_clock_entry *ce)
112 : : {
113 [ # # ]: 0 : if (!ce)
114 : 0 : return;
115 : :
116 [ # # ]: 0 : if (ce->status < PCE_STATUS_ERROR) {
117 [ # # ]: 0 : if (ce->status == PCE_STATUS_ENABLED)
118 : 0 : clk_disable(ce->clk);
119 : :
120 [ # # ]: 0 : if (ce->status >= PCE_STATUS_ACQUIRED) {
121 : 0 : clk_unprepare(ce->clk);
122 : 0 : clk_put(ce->clk);
123 : : }
124 : : }
125 : :
126 : 0 : kfree(ce->con_id);
127 : 0 : kfree(ce);
128 : : }
129 : :
130 : : /**
131 : : * pm_clk_remove - Stop using a device clock for power management.
132 : : * @dev: Device whose clock should not be used for PM any more.
133 : : * @con_id: Connection ID of the clock.
134 : : *
135 : : * Remove the clock represented by @con_id from the list of clocks used for
136 : : * the power management of @dev.
137 : : */
138 : 0 : void pm_clk_remove(struct device *dev, const char *con_id)
139 : : {
140 : : struct pm_subsys_data *psd = dev_to_psd(dev);
141 : : struct pm_clock_entry *ce;
142 : :
143 [ # # ]: 0 : if (!psd)
144 : : return;
145 : :
146 : : spin_lock_irq(&psd->lock);
147 : :
148 [ # # ]: 0 : list_for_each_entry(ce, &psd->clock_list, node) {
149 [ # # ][ # # ]: 0 : if (!con_id && !ce->con_id)
150 : : goto remove;
151 [ # # ][ # # ]: 0 : else if (!con_id || !ce->con_id)
152 : 0 : continue;
153 [ # # ]: 0 : else if (!strcmp(con_id, ce->con_id))
154 : : goto remove;
155 : : }
156 : :
157 : : spin_unlock_irq(&psd->lock);
158 : : return;
159 : :
160 : : remove:
161 : : list_del(&ce->node);
162 : : spin_unlock_irq(&psd->lock);
163 : :
164 : 0 : __pm_clk_remove(ce);
165 : : }
166 : :
167 : : /**
168 : : * pm_clk_init - Initialize a device's list of power management clocks.
169 : : * @dev: Device to initialize the list of PM clocks for.
170 : : *
171 : : * Initialize the lock and clock_list members of the device's pm_subsys_data
172 : : * object.
173 : : */
174 : 0 : void pm_clk_init(struct device *dev)
175 : : {
176 : : struct pm_subsys_data *psd = dev_to_psd(dev);
177 [ # # ]: 0 : if (psd)
178 : 0 : INIT_LIST_HEAD(&psd->clock_list);
179 : 0 : }
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 : : */
188 : 0 : int pm_clk_create(struct device *dev)
189 : : {
190 : 0 : return dev_pm_get_subsys_data(dev);
191 : : }
192 : :
193 : : /**
194 : : * pm_clk_destroy - Destroy a device's list of power management clocks.
195 : : * @dev: Device to destroy the list of PM clocks for.
196 : : *
197 : : * Clear the @dev's power.subsys_data field, remove the list of clock entries
198 : : * from the struct pm_subsys_data object pointed to by it before and free
199 : : * that object.
200 : : */
201 : 0 : void pm_clk_destroy(struct device *dev)
202 : : {
203 : : struct pm_subsys_data *psd = dev_to_psd(dev);
204 : : struct pm_clock_entry *ce, *c;
205 : : struct list_head list;
206 : :
207 [ # # ]: 0 : if (!psd)
208 : 0 : return;
209 : :
210 : : INIT_LIST_HEAD(&list);
211 : :
212 : : spin_lock_irq(&psd->lock);
213 : :
214 [ # # ]: 0 : list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
215 : : list_move(&ce->node, &list);
216 : :
217 : : spin_unlock_irq(&psd->lock);
218 : :
219 : 0 : dev_pm_put_subsys_data(dev);
220 : :
221 [ # # ]: 0 : list_for_each_entry_safe_reverse(ce, c, &list, node) {
222 : : list_del(&ce->node);
223 : 0 : __pm_clk_remove(ce);
224 : : }
225 : : }
226 : :
227 : : #endif /* CONFIG_PM */
228 : :
229 : : #ifdef CONFIG_PM_RUNTIME
230 : :
231 : : /**
232 : : * pm_clk_suspend - Disable clocks in a device's PM clock list.
233 : : * @dev: Device to disable the clocks for.
234 : : */
235 : : int pm_clk_suspend(struct device *dev)
236 : : {
237 : : struct pm_subsys_data *psd = dev_to_psd(dev);
238 : : struct pm_clock_entry *ce;
239 : : unsigned long flags;
240 : :
241 : : dev_dbg(dev, "%s()\n", __func__);
242 : :
243 : : if (!psd)
244 : : return 0;
245 : :
246 : : spin_lock_irqsave(&psd->lock, flags);
247 : :
248 : : list_for_each_entry_reverse(ce, &psd->clock_list, node) {
249 : : if (ce->status < PCE_STATUS_ERROR) {
250 : : if (ce->status == PCE_STATUS_ENABLED)
251 : : clk_disable(ce->clk);
252 : : ce->status = PCE_STATUS_ACQUIRED;
253 : : }
254 : : }
255 : :
256 : : spin_unlock_irqrestore(&psd->lock, flags);
257 : :
258 : : return 0;
259 : : }
260 : :
261 : : /**
262 : : * pm_clk_resume - Enable clocks in a device's PM clock list.
263 : : * @dev: Device to enable the clocks for.
264 : : */
265 : : int pm_clk_resume(struct device *dev)
266 : : {
267 : : struct pm_subsys_data *psd = dev_to_psd(dev);
268 : : struct pm_clock_entry *ce;
269 : : unsigned long flags;
270 : : int ret;
271 : :
272 : : dev_dbg(dev, "%s()\n", __func__);
273 : :
274 : : if (!psd)
275 : : return 0;
276 : :
277 : : spin_lock_irqsave(&psd->lock, flags);
278 : :
279 : : list_for_each_entry(ce, &psd->clock_list, node) {
280 : : if (ce->status < PCE_STATUS_ERROR) {
281 : : ret = __pm_clk_enable(dev, ce->clk);
282 : : if (!ret)
283 : : ce->status = PCE_STATUS_ENABLED;
284 : : }
285 : : }
286 : :
287 : : spin_unlock_irqrestore(&psd->lock, flags);
288 : :
289 : : return 0;
290 : : }
291 : :
292 : : /**
293 : : * pm_clk_notify - Notify routine for device addition and removal.
294 : : * @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.
300 : : * 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
302 : : * of PM clocks, depending on @action.
303 : : *
304 : : * If the device's pm_domain field is already populated with a value different
305 : : * from the one stored in the struct pm_clk_notifier_block object, the function
306 : : * does nothing.
307 : : */
308 : : static int pm_clk_notify(struct notifier_block *nb,
309 : : unsigned long action, void *data)
310 : : {
311 : : struct pm_clk_notifier_block *clknb;
312 : : struct device *dev = data;
313 : : char **con_id;
314 : : 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:
322 : : if (dev->pm_domain)
323 : : break;
324 : :
325 : : error = pm_clk_create(dev);
326 : : if (error)
327 : : break;
328 : :
329 : : dev->pm_domain = clknb->pm_domain;
330 : : if (clknb->con_ids[0]) {
331 : : for (con_id = clknb->con_ids; *con_id; con_id++)
332 : : pm_clk_add(dev, *con_id);
333 : : } else {
334 : : pm_clk_add(dev, NULL);
335 : : }
336 : :
337 : : break;
338 : : case BUS_NOTIFY_DEL_DEVICE:
339 : : if (dev->pm_domain != clknb->pm_domain)
340 : : break;
341 : :
342 : : dev->pm_domain = NULL;
343 : : pm_clk_destroy(dev);
344 : : break;
345 : : }
346 : :
347 : : return 0;
348 : : }
349 : :
350 : : #else /* !CONFIG_PM_RUNTIME */
351 : :
352 : : #ifdef CONFIG_PM
353 : :
354 : : /**
355 : : * pm_clk_suspend - Disable clocks in a device's PM clock list.
356 : : * @dev: Device to disable the clocks for.
357 : : */
358 : 0 : int pm_clk_suspend(struct device *dev)
359 : : {
360 : : struct pm_subsys_data *psd = dev_to_psd(dev);
361 : : struct pm_clock_entry *ce;
362 : : unsigned long flags;
363 : :
364 : : dev_dbg(dev, "%s()\n", __func__);
365 : :
366 : : /* If there is no driver, the clocks are already disabled. */
367 [ # # ][ # # ]: 0 : if (!psd || !dev->driver)
368 : : return 0;
369 : :
370 : 0 : spin_lock_irqsave(&psd->lock, flags);
371 : :
372 [ # # ]: 0 : list_for_each_entry_reverse(ce, &psd->clock_list, node)
373 : 0 : clk_disable(ce->clk);
374 : :
375 : : spin_unlock_irqrestore(&psd->lock, flags);
376 : :
377 : 0 : return 0;
378 : : }
379 : :
380 : : /**
381 : : * pm_clk_resume - Enable clocks in a device's PM clock list.
382 : : * @dev: Device to enable the clocks for.
383 : : */
384 : 0 : int pm_clk_resume(struct device *dev)
385 : : {
386 : : struct pm_subsys_data *psd = dev_to_psd(dev);
387 : : struct pm_clock_entry *ce;
388 : : unsigned long flags;
389 : :
390 : : dev_dbg(dev, "%s()\n", __func__);
391 : :
392 : : /* If there is no driver, the clocks should remain disabled. */
393 [ # # ][ # # ]: 0 : if (!psd || !dev->driver)
394 : : return 0;
395 : :
396 : 0 : spin_lock_irqsave(&psd->lock, flags);
397 : :
398 [ # # ]: 0 : list_for_each_entry(ce, &psd->clock_list, node)
399 : 0 : __pm_clk_enable(dev, ce->clk);
400 : :
401 : : spin_unlock_irqrestore(&psd->lock, flags);
402 : :
403 : 0 : return 0;
404 : : }
405 : :
406 : : #endif /* CONFIG_PM */
407 : :
408 : : /**
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 : : */
413 : 0 : static void enable_clock(struct device *dev, const char *con_id)
414 : : {
415 : : struct clk *clk;
416 : :
417 : 0 : clk = clk_get(dev, con_id);
418 [ # # ]: 0 : if (!IS_ERR(clk)) {
419 : : clk_prepare_enable(clk);
420 : 0 : clk_put(clk);
421 : 0 : dev_info(dev, "Runtime PM disabled, clock forced on.\n");
422 : : }
423 : 0 : }
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 : : */
430 : 0 : static void disable_clock(struct device *dev, const char *con_id)
431 : : {
432 : : struct clk *clk;
433 : :
434 : 0 : clk = clk_get(dev, con_id);
435 [ # # ]: 0 : if (!IS_ERR(clk)) {
436 : : clk_disable_unprepare(clk);
437 : 0 : clk_put(clk);
438 : 0 : dev_info(dev, "Runtime PM disabled, clock forced off.\n");
439 : : }
440 : 0 : }
441 : :
442 : : /**
443 : : * pm_clk_notify - Notify routine for device addition and removal.
444 : : * @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 : : */
453 : 0 : static int pm_clk_notify(struct notifier_block *nb,
454 : : unsigned long action, void *data)
455 : : {
456 : : struct pm_clk_notifier_block *clknb;
457 : : struct device *dev = data;
458 : : char **con_id;
459 : :
460 : : dev_dbg(dev, "%s() %ld\n", __func__, action);
461 : :
462 : : clknb = container_of(nb, struct pm_clk_notifier_block, nb);
463 : :
464 [ # # # ]: 0 : switch (action) {
465 : : case BUS_NOTIFY_BIND_DRIVER:
466 [ # # ]: 0 : if (clknb->con_ids[0]) {
467 [ # # ]: 0 : for (con_id = clknb->con_ids; *con_id; con_id++)
468 : 0 : enable_clock(dev, *con_id);
469 : : } else {
470 : 0 : enable_clock(dev, NULL);
471 : : }
472 : : break;
473 : : case BUS_NOTIFY_UNBOUND_DRIVER:
474 [ # # ]: 0 : if (clknb->con_ids[0]) {
475 [ # # ]: 0 : for (con_id = clknb->con_ids; *con_id; con_id++)
476 : 0 : disable_clock(dev, *con_id);
477 : : } else {
478 : 0 : disable_clock(dev, NULL);
479 : : }
480 : : break;
481 : : }
482 : :
483 : 0 : return 0;
484 : : }
485 : :
486 : : #endif /* !CONFIG_PM_RUNTIME */
487 : :
488 : : /**
489 : : * pm_clk_add_notifier - Add bus type notifier for power management clocks.
490 : : * @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
494 : : * notifier_call member will be replaced with pm_clk_notify(). However,
495 : : * the remaining members of @clknb should be populated prior to calling this
496 : : * routine.
497 : : */
498 : 0 : void pm_clk_add_notifier(struct bus_type *bus,
499 : : struct pm_clk_notifier_block *clknb)
500 : : {
501 [ # # ]: 0 : if (!bus || !clknb)
502 : 0 : return;
503 : :
504 : 0 : clknb->nb.notifier_call = pm_clk_notify;
505 : 0 : bus_register_notifier(bus, &clknb->nb);
506 : : }
|