diff options
Diffstat (limited to 'drivers/base/power/opp.c')
| -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..95706fa24c73 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_CAST(dev_opp); /* matching type */ | ||
| 673 | |||
| 674 | return &dev_opp->head; | ||
| 675 | } | ||
