diff options
author | MyungJoo Ham <myungjoo.ham@samsung.com> | 2011-09-30 16:35:12 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-09-30 16:35:12 -0400 |
commit | 03ca370fbf7b76d6d002380dbdc2cdc2319f9c80 (patch) | |
tree | d6978f3139f109755e0b2966995527a44c2e4681 /drivers/base | |
parent | a102a9ece5489e1718cd7543aa079082450ac3a2 (diff) |
PM / OPP: Add OPP availability change notifier.
The patch enables to register notifier_block for an OPP-device in order
to get notified for any changes in the availability of OPPs of the
device. For example, if a new OPP is inserted or enable/disable status
of an OPP is changed, the notifier is executed.
This enables the usage of opp_add, opp_enable, and opp_disable to
directly take effect with any connected entities such as cpufreq or
devfreq.
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Reviewed-by: Mike Turquette <mturquette@ti.com>
Reviewed-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/opp.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index b23de185cb04..434a6c011675 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c | |||
@@ -73,6 +73,7 @@ struct opp { | |||
73 | * RCU usage: nodes are not modified in the list of device_opp, | 73 | * RCU usage: nodes are not modified in the list of device_opp, |
74 | * however addition is possible and is secured by dev_opp_list_lock | 74 | * however addition is possible and is secured by dev_opp_list_lock |
75 | * @dev: device pointer | 75 | * @dev: device pointer |
76 | * @head: notifier head to notify the OPP availability changes. | ||
76 | * @opp_list: list of opps | 77 | * @opp_list: list of opps |
77 | * | 78 | * |
78 | * This is an internal data structure maintaining the link to opps attached to | 79 | * This is an internal data structure maintaining the link to opps attached to |
@@ -83,6 +84,7 @@ struct device_opp { | |||
83 | struct list_head node; | 84 | struct list_head node; |
84 | 85 | ||
85 | struct device *dev; | 86 | struct device *dev; |
87 | struct srcu_notifier_head head; | ||
86 | struct list_head opp_list; | 88 | struct list_head opp_list; |
87 | }; | 89 | }; |
88 | 90 | ||
@@ -404,6 +406,7 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | |||
404 | } | 406 | } |
405 | 407 | ||
406 | dev_opp->dev = dev; | 408 | dev_opp->dev = dev; |
409 | srcu_init_notifier_head(&dev_opp->head); | ||
407 | INIT_LIST_HEAD(&dev_opp->opp_list); | 410 | INIT_LIST_HEAD(&dev_opp->opp_list); |
408 | 411 | ||
409 | /* Secure the device list modification */ | 412 | /* Secure the device list modification */ |
@@ -428,6 +431,11 @@ int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) | |||
428 | list_add_rcu(&new_opp->node, head); | 431 | list_add_rcu(&new_opp->node, head); |
429 | mutex_unlock(&dev_opp_list_lock); | 432 | mutex_unlock(&dev_opp_list_lock); |
430 | 433 | ||
434 | /* | ||
435 | * Notify the changes in the availability of the operable | ||
436 | * frequency/voltage list. | ||
437 | */ | ||
438 | srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp); | ||
431 | return 0; | 439 | return 0; |
432 | } | 440 | } |
433 | 441 | ||
@@ -504,6 +512,14 @@ static int opp_set_availability(struct device *dev, unsigned long freq, | |||
504 | mutex_unlock(&dev_opp_list_lock); | 512 | mutex_unlock(&dev_opp_list_lock); |
505 | synchronize_rcu(); | 513 | synchronize_rcu(); |
506 | 514 | ||
515 | /* Notify the change of the OPP availability */ | ||
516 | if (availability_req) | ||
517 | srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ENABLE, | ||
518 | new_opp); | ||
519 | else | ||
520 | srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, | ||
521 | new_opp); | ||
522 | |||
507 | /* clean up old opp */ | 523 | /* clean up old opp */ |
508 | new_opp = opp; | 524 | new_opp = opp; |
509 | goto out; | 525 | goto out; |
@@ -643,3 +659,17 @@ void opp_free_cpufreq_table(struct device *dev, | |||
643 | *table = NULL; | 659 | *table = NULL; |
644 | } | 660 | } |
645 | #endif /* CONFIG_CPU_FREQ */ | 661 | #endif /* CONFIG_CPU_FREQ */ |
662 | |||
663 | /** | ||
664 | * opp_get_notifier() - find notifier_head of the device with opp | ||
665 | * @dev: device pointer used to lookup device OPPs. | ||
666 | */ | ||
667 | struct srcu_notifier_head *opp_get_notifier(struct device *dev) | ||
668 | { | ||
669 | struct device_opp *dev_opp = find_device_opp(dev); | ||
670 | |||
671 | if (IS_ERR(dev_opp)) | ||
672 | return ERR_PTR(PTR_ERR(dev_opp)); /* matching type */ | ||
673 | |||
674 | return &dev_opp->head; | ||
675 | } | ||