PM / devfreq: documentation cleanups for devfreq header
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / devfreq / devfreq.c
CommitLineData
a3c98b8b
MH
1/*
2 * devfreq: Generic Dynamic Voltage and Frequency Scaling (DVFS) Framework
3 * for Non-CPU Devices.
4 *
5 * Copyright (C) 2011 Samsung Electronics
6 * MyungJoo Ham <myungjoo.ham@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/errno.h>
16#include <linux/err.h>
17#include <linux/init.h>
952f6d13 18#include <linux/module.h>
a3c98b8b 19#include <linux/slab.h>
952f6d13 20#include <linux/stat.h>
a3c98b8b
MH
21#include <linux/opp.h>
22#include <linux/devfreq.h>
23#include <linux/workqueue.h>
24#include <linux/platform_device.h>
25#include <linux/list.h>
26#include <linux/printk.h>
27#include <linux/hrtimer.h>
28#include "governor.h"
29
1a1357ea 30static struct class *devfreq_class;
a3c98b8b
MH
31
32/*
7e6fdd4b
RV
33 * devfreq core provides delayed work based load monitoring helper
34 * functions. Governors can use these or can implement their own
35 * monitoring mechanism.
a3c98b8b 36 */
a3c98b8b 37static struct workqueue_struct *devfreq_wq;
a3c98b8b
MH
38
39/* The list of all device-devfreq */
40static LIST_HEAD(devfreq_list);
41static DEFINE_MUTEX(devfreq_list_lock);
42
43/**
44 * find_device_devfreq() - find devfreq struct using device pointer
45 * @dev: device pointer used to lookup device devfreq.
46 *
47 * Search the list of device devfreqs and return the matched device's
48 * devfreq info. devfreq_list_lock should be held by the caller.
49 */
50static struct devfreq *find_device_devfreq(struct device *dev)
51{
52 struct devfreq *tmp_devfreq;
53
54 if (unlikely(IS_ERR_OR_NULL(dev))) {
55 pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
56 return ERR_PTR(-EINVAL);
57 }
58 WARN(!mutex_is_locked(&devfreq_list_lock),
59 "devfreq_list_lock must be locked.");
60
61 list_for_each_entry(tmp_devfreq, &devfreq_list, node) {
62 if (tmp_devfreq->dev.parent == dev)
63 return tmp_devfreq;
64 }
65
66 return ERR_PTR(-ENODEV);
67}
68
7e6fdd4b
RV
69/* Load monitoring helper functions for governors use */
70
a3c98b8b
MH
71/**
72 * update_devfreq() - Reevaluate the device and configure frequency.
73 * @devfreq: the devfreq instance.
74 *
75 * Note: Lock devfreq->lock before calling update_devfreq
76 * This function is exported for governors.
77 */
78int update_devfreq(struct devfreq *devfreq)
79{
80 unsigned long freq;
81 int err = 0;
ab5f299f 82 u32 flags = 0;
a3c98b8b
MH
83
84 if (!mutex_is_locked(&devfreq->lock)) {
85 WARN(true, "devfreq->lock must be locked by the caller.\n");
86 return -EINVAL;
87 }
88
89 /* Reevaluate the proper frequency */
90 err = devfreq->governor->get_target_freq(devfreq, &freq);
91 if (err)
92 return err;
93
ab5f299f
MH
94 /*
95 * Adjust the freuqency with user freq and QoS.
96 *
97 * List from the highest proiority
98 * max_freq (probably called by thermal when it's too hot)
99 * min_freq
100 */
101
102 if (devfreq->min_freq && freq < devfreq->min_freq) {
103 freq = devfreq->min_freq;
104 flags &= ~DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use GLB */
105 }
106 if (devfreq->max_freq && freq > devfreq->max_freq) {
107 freq = devfreq->max_freq;
108 flags |= DEVFREQ_FLAG_LEAST_UPPER_BOUND; /* Use LUB */
109 }
110
111 err = devfreq->profile->target(devfreq->dev.parent, &freq, flags);
a3c98b8b
MH
112 if (err)
113 return err;
114
115 devfreq->previous_freq = freq;
116 return err;
117}
118
7e6fdd4b
RV
119/**
120 * devfreq_monitor() - Periodically poll devfreq objects.
121 * @work: the work struct used to run devfreq_monitor periodically.
122 *
123 */
124static void devfreq_monitor(struct work_struct *work)
125{
126 int err;
127 struct devfreq *devfreq = container_of(work,
128 struct devfreq, work.work);
129
130 mutex_lock(&devfreq->lock);
131 err = update_devfreq(devfreq);
132 if (err)
133 dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
134
135 queue_delayed_work(devfreq_wq, &devfreq->work,
136 msecs_to_jiffies(devfreq->profile->polling_ms));
137 mutex_unlock(&devfreq->lock);
138}
139
140/**
141 * devfreq_monitor_start() - Start load monitoring of devfreq instance
142 * @devfreq: the devfreq instance.
143 *
144 * Helper function for starting devfreq device load monitoing. By
145 * default delayed work based monitoring is supported. Function
146 * to be called from governor in response to DEVFREQ_GOV_START
147 * event when device is added to devfreq framework.
148 */
149void devfreq_monitor_start(struct devfreq *devfreq)
150{
151 INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
152 if (devfreq->profile->polling_ms)
153 queue_delayed_work(devfreq_wq, &devfreq->work,
154 msecs_to_jiffies(devfreq->profile->polling_ms));
155}
156
157/**
158 * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance
159 * @devfreq: the devfreq instance.
160 *
161 * Helper function to stop devfreq device load monitoing. Function
162 * to be called from governor in response to DEVFREQ_GOV_STOP
163 * event when device is removed from devfreq framework.
164 */
165void devfreq_monitor_stop(struct devfreq *devfreq)
166{
167 cancel_delayed_work_sync(&devfreq->work);
168}
169
170/**
171 * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance
172 * @devfreq: the devfreq instance.
173 *
174 * Helper function to suspend devfreq device load monitoing. Function
175 * to be called from governor in response to DEVFREQ_GOV_SUSPEND
176 * event or when polling interval is set to zero.
177 *
178 * Note: Though this function is same as devfreq_monitor_stop(),
179 * intentionally kept separate to provide hooks for collecting
180 * transition statistics.
181 */
182void devfreq_monitor_suspend(struct devfreq *devfreq)
183{
184 mutex_lock(&devfreq->lock);
185 if (devfreq->stop_polling) {
186 mutex_unlock(&devfreq->lock);
187 return;
188 }
189
190 devfreq->stop_polling = true;
191 mutex_unlock(&devfreq->lock);
192 cancel_delayed_work_sync(&devfreq->work);
193}
194
195/**
196 * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance
197 * @devfreq: the devfreq instance.
198 *
199 * Helper function to resume devfreq device load monitoing. Function
200 * to be called from governor in response to DEVFREQ_GOV_RESUME
201 * event or when polling interval is set to non-zero.
202 */
203void devfreq_monitor_resume(struct devfreq *devfreq)
204{
205 mutex_lock(&devfreq->lock);
206 if (!devfreq->stop_polling)
207 goto out;
208
209 if (!delayed_work_pending(&devfreq->work) &&
210 devfreq->profile->polling_ms)
211 queue_delayed_work(devfreq_wq, &devfreq->work,
212 msecs_to_jiffies(devfreq->profile->polling_ms));
213 devfreq->stop_polling = false;
214
215out:
216 mutex_unlock(&devfreq->lock);
217}
218
219/**
220 * devfreq_interval_update() - Update device devfreq monitoring interval
221 * @devfreq: the devfreq instance.
222 * @delay: new polling interval to be set.
223 *
224 * Helper function to set new load monitoring polling interval. Function
225 * to be called from governor in response to DEVFREQ_GOV_INTERVAL event.
226 */
227void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay)
228{
229 unsigned int cur_delay = devfreq->profile->polling_ms;
230 unsigned int new_delay = *delay;
231
232 mutex_lock(&devfreq->lock);
233 devfreq->profile->polling_ms = new_delay;
234
235 if (devfreq->stop_polling)
236 goto out;
237
238 /* if new delay is zero, stop polling */
239 if (!new_delay) {
240 mutex_unlock(&devfreq->lock);
241 cancel_delayed_work_sync(&devfreq->work);
242 return;
243 }
244
245 /* if current delay is zero, start polling with new delay */
246 if (!cur_delay) {
247 queue_delayed_work(devfreq_wq, &devfreq->work,
248 msecs_to_jiffies(devfreq->profile->polling_ms));
249 goto out;
250 }
251
252 /* if current delay is greater than new delay, restart polling */
253 if (cur_delay > new_delay) {
254 mutex_unlock(&devfreq->lock);
255 cancel_delayed_work_sync(&devfreq->work);
256 mutex_lock(&devfreq->lock);
257 if (!devfreq->stop_polling)
258 queue_delayed_work(devfreq_wq, &devfreq->work,
259 msecs_to_jiffies(devfreq->profile->polling_ms));
260 }
261out:
262 mutex_unlock(&devfreq->lock);
263}
264
a3c98b8b
MH
265/**
266 * devfreq_notifier_call() - Notify that the device frequency requirements
267 * has been changed out of devfreq framework.
c5b4a1c1
NM
268 * @nb: the notifier_block (supposed to be devfreq->nb)
269 * @type: not used
270 * @devp: not used
a3c98b8b
MH
271 *
272 * Called by a notifier that uses devfreq->nb.
273 */
274static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
275 void *devp)
276{
277 struct devfreq *devfreq = container_of(nb, struct devfreq, nb);
278 int ret;
279
280 mutex_lock(&devfreq->lock);
281 ret = update_devfreq(devfreq);
282 mutex_unlock(&devfreq->lock);
283
284 return ret;
285}
286
287/**
7e6fdd4b 288 * _remove_devfreq() - Remove devfreq from the list and release its resources.
a3c98b8b
MH
289 * @devfreq: the devfreq struct
290 * @skip: skip calling device_unregister().
a3c98b8b
MH
291 */
292static void _remove_devfreq(struct devfreq *devfreq, bool skip)
293{
7e6fdd4b
RV
294 mutex_lock(&devfreq_list_lock);
295 if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
296 mutex_unlock(&devfreq_list_lock);
297 dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n");
a3c98b8b
MH
298 return;
299 }
7e6fdd4b
RV
300 list_del(&devfreq->node);
301 mutex_unlock(&devfreq_list_lock);
a3c98b8b 302
7e6fdd4b 303 devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_STOP, NULL);
a3c98b8b
MH
304
305 if (devfreq->profile->exit)
306 devfreq->profile->exit(devfreq->dev.parent);
307
a3c98b8b
MH
308 if (!skip && get_device(&devfreq->dev)) {
309 device_unregister(&devfreq->dev);
310 put_device(&devfreq->dev);
311 }
312
a3c98b8b 313 mutex_destroy(&devfreq->lock);
a3c98b8b
MH
314 kfree(devfreq);
315}
316
317/**
318 * devfreq_dev_release() - Callback for struct device to release the device.
319 * @dev: the devfreq device
320 *
321 * This calls _remove_devfreq() if _remove_devfreq() is not called.
322 * Note that devfreq_dev_release() could be called by _remove_devfreq() as
323 * well as by others unregistering the device.
324 */
325static void devfreq_dev_release(struct device *dev)
326{
327 struct devfreq *devfreq = to_devfreq(dev);
a3c98b8b 328
a3c98b8b 329 _remove_devfreq(devfreq, true);
a3c98b8b
MH
330}
331
332/**
333 * devfreq_add_device() - Add devfreq feature to the device
334 * @dev: the device to add devfreq feature.
335 * @profile: device-specific profile to run devfreq.
336 * @governor: the policy to choose frequency.
337 * @data: private data for the governor. The devfreq framework does not
338 * touch this value.
339 */
340struct devfreq *devfreq_add_device(struct device *dev,
341 struct devfreq_dev_profile *profile,
342 const struct devfreq_governor *governor,
343 void *data)
344{
345 struct devfreq *devfreq;
346 int err = 0;
347
348 if (!dev || !profile || !governor) {
349 dev_err(dev, "%s: Invalid parameters.\n", __func__);
350 return ERR_PTR(-EINVAL);
351 }
352
7e6fdd4b
RV
353 mutex_lock(&devfreq_list_lock);
354 devfreq = find_device_devfreq(dev);
355 mutex_unlock(&devfreq_list_lock);
356 if (!IS_ERR(devfreq)) {
357 dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__);
358 err = -EINVAL;
359 goto err_out;
a3c98b8b
MH
360 }
361
362 devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL);
363 if (!devfreq) {
364 dev_err(dev, "%s: Unable to create devfreq for the device\n",
365 __func__);
366 err = -ENOMEM;
3f19f08a 367 goto err_out;
a3c98b8b
MH
368 }
369
370 mutex_init(&devfreq->lock);
371 mutex_lock(&devfreq->lock);
372 devfreq->dev.parent = dev;
373 devfreq->dev.class = devfreq_class;
374 devfreq->dev.release = devfreq_dev_release;
375 devfreq->profile = profile;
376 devfreq->governor = governor;
377 devfreq->previous_freq = profile->initial_freq;
378 devfreq->data = data;
a3c98b8b
MH
379 devfreq->nb.notifier_call = devfreq_notifier_call;
380
381 dev_set_name(&devfreq->dev, dev_name(dev));
382 err = device_register(&devfreq->dev);
383 if (err) {
384 put_device(&devfreq->dev);
7e6fdd4b 385 mutex_unlock(&devfreq->lock);
a3c98b8b
MH
386 goto err_dev;
387 }
388
a3c98b8b
MH
389 mutex_unlock(&devfreq->lock);
390
a3c98b8b 391 mutex_lock(&devfreq_list_lock);
a3c98b8b 392 list_add(&devfreq->node, &devfreq_list);
7e6fdd4b 393 mutex_unlock(&devfreq_list_lock);
a3c98b8b 394
7e6fdd4b
RV
395 err = devfreq->governor->event_handler(devfreq,
396 DEVFREQ_GOV_START, NULL);
397 if (err) {
398 dev_err(dev, "%s: Unable to start governor for the device\n",
399 __func__);
400 goto err_init;
a3c98b8b 401 }
7e6fdd4b 402
3f19f08a
AL
403 return devfreq;
404
a3c98b8b 405err_init:
7e6fdd4b 406 list_del(&devfreq->node);
a3c98b8b
MH
407 device_unregister(&devfreq->dev);
408err_dev:
a3c98b8b 409 kfree(devfreq);
3f19f08a
AL
410err_out:
411 return ERR_PTR(err);
a3c98b8b 412}
7e6fdd4b 413EXPORT_SYMBOL(devfreq_add_device);
a3c98b8b
MH
414
415/**
416 * devfreq_remove_device() - Remove devfreq feature from a device.
c5b4a1c1 417 * @devfreq: the devfreq instance to be removed
a3c98b8b
MH
418 */
419int devfreq_remove_device(struct devfreq *devfreq)
420{
421 if (!devfreq)
422 return -EINVAL;
423
7e6fdd4b 424 _remove_devfreq(devfreq, false);
a3c98b8b
MH
425
426 return 0;
427}
7e6fdd4b 428EXPORT_SYMBOL(devfreq_remove_device);
a3c98b8b 429
206c30cf
RV
430/**
431 * devfreq_suspend_device() - Suspend devfreq of a device.
432 * @devfreq: the devfreq instance to be suspended
433 */
434int devfreq_suspend_device(struct devfreq *devfreq)
435{
436 if (!devfreq)
437 return -EINVAL;
438
439 return devfreq->governor->event_handler(devfreq,
440 DEVFREQ_GOV_SUSPEND, NULL);
441}
442EXPORT_SYMBOL(devfreq_suspend_device);
443
444/**
445 * devfreq_resume_device() - Resume devfreq of a device.
446 * @devfreq: the devfreq instance to be resumed
447 */
448int devfreq_resume_device(struct devfreq *devfreq)
449{
450 if (!devfreq)
451 return -EINVAL;
452
453 return devfreq->governor->event_handler(devfreq,
454 DEVFREQ_GOV_RESUME, NULL);
455}
456EXPORT_SYMBOL(devfreq_resume_device);
457
9005b650
MH
458static ssize_t show_governor(struct device *dev,
459 struct device_attribute *attr, char *buf)
460{
461 return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name);
462}
463
464static ssize_t show_freq(struct device *dev,
465 struct device_attribute *attr, char *buf)
7f98a905
RV
466{
467 unsigned long freq;
468 struct devfreq *devfreq = to_devfreq(dev);
469
470 if (devfreq->profile->get_cur_freq &&
471 !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
472 return sprintf(buf, "%lu\n", freq);
473
474 return sprintf(buf, "%lu\n", devfreq->previous_freq);
475}
476
477static ssize_t show_target_freq(struct device *dev,
478 struct device_attribute *attr, char *buf)
9005b650
MH
479{
480 return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq);
481}
482
483static ssize_t show_polling_interval(struct device *dev,
484 struct device_attribute *attr, char *buf)
485{
486 return sprintf(buf, "%d\n", to_devfreq(dev)->profile->polling_ms);
487}
488
489static ssize_t store_polling_interval(struct device *dev,
490 struct device_attribute *attr,
491 const char *buf, size_t count)
492{
493 struct devfreq *df = to_devfreq(dev);
494 unsigned int value;
495 int ret;
496
497 ret = sscanf(buf, "%u", &value);
498 if (ret != 1)
12e26265 499 return -EINVAL;
9005b650 500
7e6fdd4b 501 df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value);
9005b650
MH
502 ret = count;
503
9005b650
MH
504 return ret;
505}
506
6530b9de
MH
507static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr,
508 const char *buf, size_t count)
509{
510 struct devfreq *df = to_devfreq(dev);
511 unsigned long value;
512 int ret;
513 unsigned long max;
514
515 ret = sscanf(buf, "%lu", &value);
516 if (ret != 1)
12e26265 517 return -EINVAL;
6530b9de
MH
518
519 mutex_lock(&df->lock);
520 max = df->max_freq;
521 if (value && max && value > max) {
522 ret = -EINVAL;
523 goto unlock;
524 }
525
526 df->min_freq = value;
527 update_devfreq(df);
528 ret = count;
529unlock:
530 mutex_unlock(&df->lock);
6530b9de
MH
531 return ret;
532}
533
534static ssize_t show_min_freq(struct device *dev, struct device_attribute *attr,
535 char *buf)
536{
537 return sprintf(buf, "%lu\n", to_devfreq(dev)->min_freq);
538}
539
540static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr,
541 const char *buf, size_t count)
542{
543 struct devfreq *df = to_devfreq(dev);
544 unsigned long value;
545 int ret;
546 unsigned long min;
547
548 ret = sscanf(buf, "%lu", &value);
549 if (ret != 1)
12e26265 550 return -EINVAL;
6530b9de
MH
551
552 mutex_lock(&df->lock);
553 min = df->min_freq;
554 if (value && min && value < min) {
555 ret = -EINVAL;
556 goto unlock;
557 }
558
559 df->max_freq = value;
560 update_devfreq(df);
561 ret = count;
562unlock:
563 mutex_unlock(&df->lock);
6530b9de
MH
564 return ret;
565}
566
567static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr,
568 char *buf)
569{
570 return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq);
571}
572
9005b650
MH
573static struct device_attribute devfreq_attrs[] = {
574 __ATTR(governor, S_IRUGO, show_governor, NULL),
575 __ATTR(cur_freq, S_IRUGO, show_freq, NULL),
7f98a905 576 __ATTR(target_freq, S_IRUGO, show_target_freq, NULL),
9005b650
MH
577 __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval,
578 store_polling_interval),
6530b9de
MH
579 __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq),
580 __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq),
9005b650
MH
581 { },
582};
583
a3c98b8b
MH
584static int __init devfreq_init(void)
585{
586 devfreq_class = class_create(THIS_MODULE, "devfreq");
587 if (IS_ERR(devfreq_class)) {
588 pr_err("%s: couldn't create class\n", __FILE__);
589 return PTR_ERR(devfreq_class);
590 }
7e6fdd4b
RV
591
592 devfreq_wq = create_freezable_workqueue("devfreq_wq");
593 if (IS_ERR(devfreq_wq)) {
594 class_destroy(devfreq_class);
595 pr_err("%s: couldn't create workqueue\n", __FILE__);
596 return PTR_ERR(devfreq_wq);
597 }
9005b650 598 devfreq_class->dev_attrs = devfreq_attrs;
7e6fdd4b 599
a3c98b8b
MH
600 return 0;
601}
602subsys_initcall(devfreq_init);
603
604static void __exit devfreq_exit(void)
605{
606 class_destroy(devfreq_class);
7e6fdd4b 607 destroy_workqueue(devfreq_wq);
a3c98b8b
MH
608}
609module_exit(devfreq_exit);
610
611/*
612 * The followings are helper functions for devfreq user device drivers with
613 * OPP framework.
614 */
615
616/**
617 * devfreq_recommended_opp() - Helper function to get proper OPP for the
618 * freq value given to target callback.
c5b4a1c1
NM
619 * @dev: The devfreq user device. (parent of devfreq)
620 * @freq: The frequency given to target function
621 * @flags: Flags handed from devfreq framework.
a3c98b8b
MH
622 *
623 */
ab5f299f
MH
624struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq,
625 u32 flags)
a3c98b8b 626{
ab5f299f 627 struct opp *opp;
a3c98b8b 628
ab5f299f
MH
629 if (flags & DEVFREQ_FLAG_LEAST_UPPER_BOUND) {
630 /* The freq is an upper bound. opp should be lower */
a3c98b8b 631 opp = opp_find_freq_floor(dev, freq);
ab5f299f
MH
632
633 /* If not available, use the closest opp */
634 if (opp == ERR_PTR(-ENODEV))
635 opp = opp_find_freq_ceil(dev, freq);
636 } else {
637 /* The freq is an lower bound. opp should be higher */
638 opp = opp_find_freq_ceil(dev, freq);
639
640 /* If not available, use the closest opp */
641 if (opp == ERR_PTR(-ENODEV))
642 opp = opp_find_freq_floor(dev, freq);
643 }
644
a3c98b8b
MH
645 return opp;
646}
647
648/**
649 * devfreq_register_opp_notifier() - Helper function to get devfreq notified
650 * for any changes in the OPP availability
651 * changes
c5b4a1c1
NM
652 * @dev: The devfreq user device. (parent of devfreq)
653 * @devfreq: The devfreq object.
a3c98b8b
MH
654 */
655int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
656{
657 struct srcu_notifier_head *nh = opp_get_notifier(dev);
658
659 if (IS_ERR(nh))
660 return PTR_ERR(nh);
661 return srcu_notifier_chain_register(nh, &devfreq->nb);
662}
663
664/**
665 * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq
666 * notified for any changes in the OPP
667 * availability changes anymore.
c5b4a1c1
NM
668 * @dev: The devfreq user device. (parent of devfreq)
669 * @devfreq: The devfreq object.
a3c98b8b
MH
670 *
671 * At exit() callback of devfreq_dev_profile, this must be included if
672 * devfreq_recommended_opp is used.
673 */
674int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
675{
676 struct srcu_notifier_head *nh = opp_get_notifier(dev);
677
678 if (IS_ERR(nh))
679 return PTR_ERR(nh);
680 return srcu_notifier_chain_unregister(nh, &devfreq->nb);
681}
682
683MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
684MODULE_DESCRIPTION("devfreq class support");
685MODULE_LICENSE("GPL");