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