This source file includes following definitions.
- clock_cooling_get_property
- clock_cooling_get_level
- clock_cooling_get_frequency
- clock_cooling_apply
- clock_cooling_clock_notifier
- clock_cooling_get_max_state
- clock_cooling_get_cur_state
- clock_cooling_set_cur_state
- clock_cooling_register
- clock_cooling_unregister
1
2
3
4
5
6
7
8
9
10
11
12
13
14 #include <linux/clk.h>
15 #include <linux/cpufreq.h>
16 #include <linux/device.h>
17 #include <linux/err.h>
18 #include <linux/idr.h>
19 #include <linux/mutex.h>
20 #include <linux/pm_opp.h>
21 #include <linux/slab.h>
22 #include <linux/thermal.h>
23 #include <linux/clock_cooling.h>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 struct clock_cooling_device {
48 int id;
49 struct device *dev;
50 struct thermal_cooling_device *cdev;
51 struct notifier_block clk_rate_change_nb;
52 struct cpufreq_frequency_table *freq_table;
53 unsigned long clock_state;
54 unsigned long clock_val;
55 struct clk *clk;
56 struct mutex lock;
57 };
58 #define to_clock_cooling_device(x) \
59 container_of(x, struct clock_cooling_device, clk_rate_change_nb)
60 static DEFINE_IDA(clock_ida);
61
62
63
64 enum clock_cooling_property {
65 GET_LEVEL,
66 GET_FREQ,
67 GET_MAXL,
68 };
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 static int clock_cooling_get_property(struct clock_cooling_device *ccdev,
90 unsigned long input,
91 unsigned long *output,
92 enum clock_cooling_property property)
93 {
94 int i;
95 unsigned long max_level = 0, level = 0;
96 unsigned int freq = CPUFREQ_ENTRY_INVALID;
97 int descend = -1;
98 struct cpufreq_frequency_table *pos, *table = ccdev->freq_table;
99
100 if (!output)
101 return -EINVAL;
102
103 if (!table)
104 return -EINVAL;
105
106 cpufreq_for_each_valid_entry(pos, table) {
107
108 if (freq == pos->frequency)
109 continue;
110
111
112 if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
113 descend = freq > pos->frequency;
114
115 freq = pos->frequency;
116 max_level++;
117 }
118
119
120 if (max_level == 0)
121 return -EINVAL;
122
123
124 max_level--;
125
126
127 if (property == GET_MAXL) {
128 *output = max_level;
129 return 0;
130 }
131
132 if (property == GET_FREQ)
133 level = descend ? input : (max_level - input);
134
135 i = 0;
136 cpufreq_for_each_valid_entry(pos, table) {
137
138 if (freq == pos->frequency)
139 continue;
140
141
142 freq = pos->frequency;
143
144 if (property == GET_LEVEL && (unsigned int)input == freq) {
145
146 *output = descend ? i : (max_level - i);
147 return 0;
148 }
149 if (property == GET_FREQ && level == i) {
150
151 *output = freq;
152 return 0;
153 }
154 i++;
155 }
156
157 return -EINVAL;
158 }
159
160
161
162
163
164
165
166
167
168
169
170
171 unsigned long clock_cooling_get_level(struct thermal_cooling_device *cdev,
172 unsigned long freq)
173 {
174 struct clock_cooling_device *ccdev = cdev->devdata;
175 unsigned long val;
176
177 if (clock_cooling_get_property(ccdev, (unsigned long)freq, &val,
178 GET_LEVEL))
179 return THERMAL_CSTATE_INVALID;
180
181 return val;
182 }
183 EXPORT_SYMBOL_GPL(clock_cooling_get_level);
184
185
186
187
188
189
190
191
192
193
194
195
196
197 static unsigned long
198 clock_cooling_get_frequency(struct clock_cooling_device *ccdev,
199 unsigned long level)
200 {
201 int ret = 0;
202 unsigned long freq;
203
204 ret = clock_cooling_get_property(ccdev, level, &freq, GET_FREQ);
205 if (ret)
206 return 0;
207
208 return freq;
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223 static int clock_cooling_apply(struct clock_cooling_device *ccdev,
224 unsigned long cooling_state)
225 {
226 unsigned long clip_freq, cur_freq;
227 int ret = 0;
228
229
230
231 if (ccdev->clock_state == cooling_state)
232 return 0;
233
234 clip_freq = clock_cooling_get_frequency(ccdev, cooling_state);
235 if (!clip_freq)
236 return -EINVAL;
237
238 cur_freq = clk_get_rate(ccdev->clk);
239
240 mutex_lock(&ccdev->lock);
241 ccdev->clock_state = cooling_state;
242 ccdev->clock_val = clip_freq;
243
244 if (cur_freq > clip_freq)
245 ret = clk_set_rate(ccdev->clk, clip_freq);
246 mutex_unlock(&ccdev->lock);
247
248 return ret;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263 static int clock_cooling_clock_notifier(struct notifier_block *nb,
264 unsigned long event, void *data)
265 {
266 struct clk_notifier_data *ndata = data;
267 struct clock_cooling_device *ccdev = to_clock_cooling_device(nb);
268
269 switch (event) {
270 case PRE_RATE_CHANGE:
271
272
273
274
275
276
277 if (ndata->new_rate > ccdev->clock_val)
278 return NOTIFY_BAD;
279
280 case POST_RATE_CHANGE:
281 case ABORT_RATE_CHANGE:
282 default:
283 return NOTIFY_DONE;
284 }
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299 static int clock_cooling_get_max_state(struct thermal_cooling_device *cdev,
300 unsigned long *state)
301 {
302 struct clock_cooling_device *ccdev = cdev->devdata;
303 unsigned long count = 0;
304 int ret;
305
306 ret = clock_cooling_get_property(ccdev, 0, &count, GET_MAXL);
307 if (!ret)
308 *state = count;
309
310 return ret;
311 }
312
313
314
315
316
317
318
319
320
321
322
323 static int clock_cooling_get_cur_state(struct thermal_cooling_device *cdev,
324 unsigned long *state)
325 {
326 struct clock_cooling_device *ccdev = cdev->devdata;
327
328 *state = ccdev->clock_state;
329
330 return 0;
331 }
332
333
334
335
336
337
338
339
340
341
342
343 static int clock_cooling_set_cur_state(struct thermal_cooling_device *cdev,
344 unsigned long state)
345 {
346 struct clock_cooling_device *clock_device = cdev->devdata;
347
348 return clock_cooling_apply(clock_device, state);
349 }
350
351
352 static struct thermal_cooling_device_ops const clock_cooling_ops = {
353 .get_max_state = clock_cooling_get_max_state,
354 .get_cur_state = clock_cooling_get_cur_state,
355 .set_cur_state = clock_cooling_set_cur_state,
356 };
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374 struct thermal_cooling_device *
375 clock_cooling_register(struct device *dev, const char *clock_name)
376 {
377 struct thermal_cooling_device *cdev;
378 struct clock_cooling_device *ccdev = NULL;
379 char dev_name[THERMAL_NAME_LENGTH];
380 int ret = 0;
381
382 ccdev = devm_kzalloc(dev, sizeof(*ccdev), GFP_KERNEL);
383 if (!ccdev)
384 return ERR_PTR(-ENOMEM);
385
386 mutex_init(&ccdev->lock);
387 ccdev->dev = dev;
388 ccdev->clk = devm_clk_get(dev, clock_name);
389 if (IS_ERR(ccdev->clk))
390 return ERR_CAST(ccdev->clk);
391
392 ret = ida_simple_get(&clock_ida, 0, 0, GFP_KERNEL);
393 if (ret < 0)
394 return ERR_PTR(ret);
395 ccdev->id = ret;
396
397 snprintf(dev_name, sizeof(dev_name), "thermal-clock-%d", ccdev->id);
398
399 cdev = thermal_cooling_device_register(dev_name, ccdev,
400 &clock_cooling_ops);
401 if (IS_ERR(cdev)) {
402 ida_simple_remove(&clock_ida, ccdev->id);
403 return ERR_PTR(-EINVAL);
404 }
405 ccdev->cdev = cdev;
406 ccdev->clk_rate_change_nb.notifier_call = clock_cooling_clock_notifier;
407
408
409 ret = dev_pm_opp_init_cpufreq_table(dev, &ccdev->freq_table);
410 if (ret) {
411 ida_simple_remove(&clock_ida, ccdev->id);
412 return ERR_PTR(ret);
413 }
414 ccdev->clock_state = 0;
415 ccdev->clock_val = clock_cooling_get_frequency(ccdev, 0);
416
417 clk_notifier_register(ccdev->clk, &ccdev->clk_rate_change_nb);
418
419 return cdev;
420 }
421 EXPORT_SYMBOL_GPL(clock_cooling_register);
422
423
424
425
426
427
428
429 void clock_cooling_unregister(struct thermal_cooling_device *cdev)
430 {
431 struct clock_cooling_device *ccdev;
432
433 if (!cdev)
434 return;
435
436 ccdev = cdev->devdata;
437
438 clk_notifier_unregister(ccdev->clk, &ccdev->clk_rate_change_nb);
439 dev_pm_opp_free_cpufreq_table(ccdev->dev, &ccdev->freq_table);
440
441 thermal_cooling_device_unregister(ccdev->cdev);
442 ida_simple_remove(&clock_ida, ccdev->id);
443 }
444 EXPORT_SYMBOL_GPL(clock_cooling_unregister);