aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/devfreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/devfreq/devfreq.c')
-rw-r--r--drivers/devfreq/devfreq.c125
1 files changed, 115 insertions, 10 deletions
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 2042ec3656ba..9f90369dd6bd 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -394,7 +394,7 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
394 * @devfreq: the devfreq struct 394 * @devfreq: the devfreq struct
395 * @skip: skip calling device_unregister(). 395 * @skip: skip calling device_unregister().
396 */ 396 */
397static void _remove_devfreq(struct devfreq *devfreq, bool skip) 397static void _remove_devfreq(struct devfreq *devfreq)
398{ 398{
399 mutex_lock(&devfreq_list_lock); 399 mutex_lock(&devfreq_list_lock);
400 if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { 400 if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
@@ -412,11 +412,6 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
412 if (devfreq->profile->exit) 412 if (devfreq->profile->exit)
413 devfreq->profile->exit(devfreq->dev.parent); 413 devfreq->profile->exit(devfreq->dev.parent);
414 414
415 if (!skip && get_device(&devfreq->dev)) {
416 device_unregister(&devfreq->dev);
417 put_device(&devfreq->dev);
418 }
419
420 mutex_destroy(&devfreq->lock); 415 mutex_destroy(&devfreq->lock);
421 kfree(devfreq); 416 kfree(devfreq);
422} 417}
@@ -426,14 +421,12 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
426 * @dev: the devfreq device 421 * @dev: the devfreq device
427 * 422 *
428 * This calls _remove_devfreq() if _remove_devfreq() is not called. 423 * This calls _remove_devfreq() if _remove_devfreq() is not called.
429 * Note that devfreq_dev_release() could be called by _remove_devfreq() as
430 * well as by others unregistering the device.
431 */ 424 */
432static void devfreq_dev_release(struct device *dev) 425static void devfreq_dev_release(struct device *dev)
433{ 426{
434 struct devfreq *devfreq = to_devfreq(dev); 427 struct devfreq *devfreq = to_devfreq(dev);
435 428
436 _remove_devfreq(devfreq, true); 429 _remove_devfreq(devfreq);
437} 430}
438 431
439/** 432/**
@@ -544,12 +537,76 @@ int devfreq_remove_device(struct devfreq *devfreq)
544 if (!devfreq) 537 if (!devfreq)
545 return -EINVAL; 538 return -EINVAL;
546 539
547 _remove_devfreq(devfreq, false); 540 device_unregister(&devfreq->dev);
541 put_device(&devfreq->dev);
548 542
549 return 0; 543 return 0;
550} 544}
551EXPORT_SYMBOL(devfreq_remove_device); 545EXPORT_SYMBOL(devfreq_remove_device);
552 546
547static int devm_devfreq_dev_match(struct device *dev, void *res, void *data)
548{
549 struct devfreq **r = res;
550
551 if (WARN_ON(!r || !*r))
552 return 0;
553
554 return *r == data;
555}
556
557static void devm_devfreq_dev_release(struct device *dev, void *res)
558{
559 devfreq_remove_device(*(struct devfreq **)res);
560}
561
562/**
563 * devm_devfreq_add_device() - Resource-managed devfreq_add_device()
564 * @dev: the device to add devfreq feature.
565 * @profile: device-specific profile to run devfreq.
566 * @governor_name: name of the policy to choose frequency.
567 * @data: private data for the governor. The devfreq framework does not
568 * touch this value.
569 *
570 * This function manages automatically the memory of devfreq device using device
571 * resource management and simplify the free operation for memory of devfreq
572 * device.
573 */
574struct devfreq *devm_devfreq_add_device(struct device *dev,
575 struct devfreq_dev_profile *profile,
576 const char *governor_name,
577 void *data)
578{
579 struct devfreq **ptr, *devfreq;
580
581 ptr = devres_alloc(devm_devfreq_dev_release, sizeof(*ptr), GFP_KERNEL);
582 if (!ptr)
583 return ERR_PTR(-ENOMEM);
584
585 devfreq = devfreq_add_device(dev, profile, governor_name, data);
586 if (IS_ERR(devfreq)) {
587 devres_free(ptr);
588 return ERR_PTR(-ENOMEM);
589 }
590
591 *ptr = devfreq;
592 devres_add(dev, ptr);
593
594 return devfreq;
595}
596EXPORT_SYMBOL(devm_devfreq_add_device);
597
598/**
599 * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
600 * @dev: the device to add devfreq feature.
601 * @devfreq: the devfreq instance to be removed
602 */
603void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq)
604{
605 WARN_ON(devres_release(dev, devm_devfreq_dev_release,
606 devm_devfreq_dev_match, devfreq));
607}
608EXPORT_SYMBOL(devm_devfreq_remove_device);
609
553/** 610/**
554 * devfreq_suspend_device() - Suspend devfreq of a device. 611 * devfreq_suspend_device() - Suspend devfreq of a device.
555 * @devfreq: the devfreq instance to be suspended 612 * @devfreq: the devfreq instance to be suspended
@@ -1112,6 +1169,54 @@ int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
1112 return ret; 1169 return ret;
1113} 1170}
1114 1171
1172static void devm_devfreq_opp_release(struct device *dev, void *res)
1173{
1174 devfreq_unregister_opp_notifier(dev, *(struct devfreq **)res);
1175}
1176
1177/**
1178 * devm_ devfreq_register_opp_notifier()
1179 * - Resource-managed devfreq_register_opp_notifier()
1180 * @dev: The devfreq user device. (parent of devfreq)
1181 * @devfreq: The devfreq object.
1182 */
1183int devm_devfreq_register_opp_notifier(struct device *dev,
1184 struct devfreq *devfreq)
1185{
1186 struct devfreq **ptr;
1187 int ret;
1188
1189 ptr = devres_alloc(devm_devfreq_opp_release, sizeof(*ptr), GFP_KERNEL);
1190 if (!ptr)
1191 return -ENOMEM;
1192
1193 ret = devfreq_register_opp_notifier(dev, devfreq);
1194 if (ret) {
1195 devres_free(ptr);
1196 return ret;
1197 }
1198
1199 *ptr = devfreq;
1200 devres_add(dev, ptr);
1201
1202 return 0;
1203}
1204EXPORT_SYMBOL(devm_devfreq_register_opp_notifier);
1205
1206/**
1207 * devm_devfreq_unregister_opp_notifier()
1208 * - Resource-managed devfreq_unregister_opp_notifier()
1209 * @dev: The devfreq user device. (parent of devfreq)
1210 * @devfreq: The devfreq object.
1211 */
1212void devm_devfreq_unregister_opp_notifier(struct device *dev,
1213 struct devfreq *devfreq)
1214{
1215 WARN_ON(devres_release(dev, devm_devfreq_opp_release,
1216 devm_devfreq_dev_match, devfreq));
1217}
1218EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
1219
1115MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); 1220MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
1116MODULE_DESCRIPTION("devfreq class support"); 1221MODULE_DESCRIPTION("devfreq class support");
1117MODULE_LICENSE("GPL"); 1222MODULE_LICENSE("GPL");