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