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