|
12 | 12 |
|
13 | 13 | #include <linux/devfreq.h>
|
14 | 14 | #include <linux/devfreq_cooling.h>
|
| 15 | +#include <linux/energy_model.h> |
15 | 16 | #include <linux/export.h>
|
16 | 17 | #include <linux/idr.h>
|
17 | 18 | #include <linux/slab.h>
|
@@ -576,22 +577,73 @@ struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df)
|
576 | 577 | }
|
577 | 578 | EXPORT_SYMBOL_GPL(devfreq_cooling_register);
|
578 | 579 |
|
| 580 | +/** |
| 581 | + * devfreq_cooling_em_register_power() - Register devfreq cooling device with |
| 582 | + * power information and automatically register Energy Model (EM) |
| 583 | + * @df: Pointer to devfreq device. |
| 584 | + * @dfc_power: Pointer to devfreq_cooling_power. |
| 585 | + * |
| 586 | + * Register a devfreq cooling device and automatically register EM. The |
| 587 | + * available OPPs must be registered for the device. |
| 588 | + * |
| 589 | + * If @dfc_power is provided, the cooling device is registered with the |
| 590 | + * power extensions. It is using the simple Energy Model which requires |
| 591 | + * "dynamic-power-coefficient" a devicetree property. To not break drivers |
| 592 | + * which miss that DT property, the function won't bail out when the EM |
| 593 | + * registration failed. The cooling device will be registered if everything |
| 594 | + * else is OK. |
| 595 | + */ |
| 596 | +struct thermal_cooling_device * |
| 597 | +devfreq_cooling_em_register(struct devfreq *df, |
| 598 | + struct devfreq_cooling_power *dfc_power) |
| 599 | +{ |
| 600 | + struct thermal_cooling_device *cdev; |
| 601 | + struct device *dev; |
| 602 | + int ret; |
| 603 | + |
| 604 | + if (IS_ERR_OR_NULL(df)) |
| 605 | + return ERR_PTR(-EINVAL); |
| 606 | + |
| 607 | + dev = df->dev.parent; |
| 608 | + |
| 609 | + ret = dev_pm_opp_of_register_em(dev, NULL); |
| 610 | + if (ret) |
| 611 | + dev_dbg(dev, "Unable to register EM for devfreq cooling device (%d)\n", |
| 612 | + ret); |
| 613 | + |
| 614 | + cdev = of_devfreq_cooling_register_power(dev->of_node, df, dfc_power); |
| 615 | + |
| 616 | + if (IS_ERR_OR_NULL(cdev)) |
| 617 | + em_dev_unregister_perf_domain(dev); |
| 618 | + |
| 619 | + return cdev; |
| 620 | +} |
| 621 | +EXPORT_SYMBOL_GPL(devfreq_cooling_em_register); |
| 622 | + |
579 | 623 | /**
|
580 | 624 | * devfreq_cooling_unregister() - Unregister devfreq cooling device.
|
581 | 625 | * @cdev: Pointer to devfreq cooling device to unregister.
|
| 626 | + * |
| 627 | + * Unregisters devfreq cooling device and related Energy Model if it was |
| 628 | + * present. |
582 | 629 | */
|
583 | 630 | void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
584 | 631 | {
|
585 | 632 | struct devfreq_cooling_device *dfc;
|
| 633 | + struct device *dev; |
586 | 634 |
|
587 |
| - if (!cdev) |
| 635 | + if (IS_ERR_OR_NULL(cdev)) |
588 | 636 | return;
|
589 | 637 |
|
590 | 638 | dfc = cdev->devdata;
|
| 639 | + dev = dfc->devfreq->dev.parent; |
591 | 640 |
|
592 | 641 | thermal_cooling_device_unregister(dfc->cdev);
|
593 | 642 | ida_simple_remove(&devfreq_ida, dfc->id);
|
594 | 643 | dev_pm_qos_remove_request(&dfc->req_max_freq);
|
| 644 | + |
| 645 | + em_dev_unregister_perf_domain(dev); |
| 646 | + |
595 | 647 | kfree(dfc->power_table);
|
596 | 648 | kfree(dfc->freq_table);
|
597 | 649 |
|
|
0 commit comments