aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2016-12-01 05:58:20 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-12-05 20:27:59 -0500
commit947355850fcb3bb6549294316667d0f53bc03082 (patch)
tree2e70450b998e003395897fbc13ec3ab3af55f883
parentdfbe4678d709e25e0f36e6b6333e2a7a67aefb7e (diff)
PM / OPP: Separate out _generic_set_opp()
Later patches would add support for custom set_opp() callbacks. This patch separates out the code for _generic_set_opp() handler in order to prepare for that. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Tested-by: Dave Gerlach <d-gerlach@ti.com> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/base/power/opp/core.c181
-rw-r--r--drivers/base/power/opp/opp.h3
-rw-r--r--include/linux/pm_opp.h35
3 files changed, 166 insertions, 53 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index b4da31c5a5eb..e33198ce41b4 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -610,6 +610,69 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
610 return ret; 610 return ret;
611} 611}
612 612
613static inline int
614_generic_set_opp_clk_only(struct device *dev, struct clk *clk,
615 unsigned long old_freq, unsigned long freq)
616{
617 int ret;
618
619 ret = clk_set_rate(clk, freq);
620 if (ret) {
621 dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
622 ret);
623 }
624
625 return ret;
626}
627
628static int _generic_set_opp(struct dev_pm_set_opp_data *data)
629{
630 struct dev_pm_opp_supply *old_supply = data->old_opp.supplies;
631 struct dev_pm_opp_supply *new_supply = data->new_opp.supplies;
632 unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
633 struct regulator *reg = data->regulators[0];
634 struct device *dev= data->dev;
635 int ret;
636
637 /* This function only supports single regulator per device */
638 if (WARN_ON(data->regulator_count > 1)) {
639 dev_err(dev, "multiple regulators are not supported\n");
640 return -EINVAL;
641 }
642
643 /* Scaling up? Scale voltage before frequency */
644 if (freq > old_freq) {
645 ret = _set_opp_voltage(dev, reg, new_supply);
646 if (ret)
647 goto restore_voltage;
648 }
649
650 /* Change frequency */
651 ret = _generic_set_opp_clk_only(dev, data->clk, old_freq, freq);
652 if (ret)
653 goto restore_voltage;
654
655 /* Scaling down? Scale voltage after frequency */
656 if (freq < old_freq) {
657 ret = _set_opp_voltage(dev, reg, new_supply);
658 if (ret)
659 goto restore_freq;
660 }
661
662 return 0;
663
664restore_freq:
665 if (_generic_set_opp_clk_only(dev, data->clk, freq, old_freq))
666 dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
667 __func__, old_freq);
668restore_voltage:
669 /* This shouldn't harm even if the voltages weren't updated earlier */
670 if (old_supply->u_volt)
671 _set_opp_voltage(dev, reg, old_supply);
672
673 return ret;
674}
675
613/** 676/**
614 * dev_pm_opp_set_rate() - Configure new OPP based on frequency 677 * dev_pm_opp_set_rate() - Configure new OPP based on frequency
615 * @dev: device for which we do this operation 678 * @dev: device for which we do this operation
@@ -623,12 +686,12 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
623int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) 686int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
624{ 687{
625 struct opp_table *opp_table; 688 struct opp_table *opp_table;
689 unsigned long freq, old_freq;
626 struct dev_pm_opp *old_opp, *opp; 690 struct dev_pm_opp *old_opp, *opp;
627 struct regulator *reg = ERR_PTR(-ENXIO); 691 struct regulator **regulators;
692 struct dev_pm_set_opp_data *data;
628 struct clk *clk; 693 struct clk *clk;
629 unsigned long freq, old_freq; 694 int ret, size;
630 struct dev_pm_opp_supply old_supply, new_supply;
631 int ret;
632 695
633 if (unlikely(!target_freq)) { 696 if (unlikely(!target_freq)) {
634 dev_err(dev, "%s: Invalid target frequency %lu\n", __func__, 697 dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
@@ -677,64 +740,36 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
677 return ret; 740 return ret;
678 } 741 }
679 742
680 if (opp_table->regulators) { 743 dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
681 /* This function only supports single regulator per device */ 744 old_freq, freq);
682 if (WARN_ON(opp_table->regulator_count > 1)) {
683 dev_err(dev, "multiple regulators not supported\n");
684 rcu_read_unlock();
685 return -EINVAL;
686 }
687 745
688 reg = opp_table->regulators[0]; 746 regulators = opp_table->regulators;
747
748 /* Only frequency scaling */
749 if (!regulators) {
750 rcu_read_unlock();
751 return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
689 } 752 }
690 753
754 data = opp_table->set_opp_data;
755 data->regulators = regulators;
756 data->regulator_count = opp_table->regulator_count;
757 data->clk = clk;
758 data->dev = dev;
759
760 data->old_opp.rate = old_freq;
761 size = sizeof(*opp->supplies) * opp_table->regulator_count;
691 if (IS_ERR(old_opp)) 762 if (IS_ERR(old_opp))
692 old_supply.u_volt = 0; 763 memset(data->old_opp.supplies, 0, size);
693 else 764 else
694 memcpy(&old_supply, old_opp->supplies, sizeof(old_supply)); 765 memcpy(data->old_opp.supplies, old_opp->supplies, size);
695 766
696 memcpy(&new_supply, opp->supplies, sizeof(new_supply)); 767 data->new_opp.rate = freq;
768 memcpy(data->new_opp.supplies, opp->supplies, size);
697 769
698 rcu_read_unlock(); 770 rcu_read_unlock();
699 771
700 /* Scaling up? Scale voltage before frequency */ 772 return _generic_set_opp(data);
701 if (freq > old_freq) {
702 ret = _set_opp_voltage(dev, reg, &new_supply);
703 if (ret)
704 goto restore_voltage;
705 }
706
707 /* Change frequency */
708
709 dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
710 __func__, old_freq, freq);
711
712 ret = clk_set_rate(clk, freq);
713 if (ret) {
714 dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
715 ret);
716 goto restore_voltage;
717 }
718
719 /* Scaling down? Scale voltage after frequency */
720 if (freq < old_freq) {
721 ret = _set_opp_voltage(dev, reg, &new_supply);
722 if (ret)
723 goto restore_freq;
724 }
725
726 return 0;
727
728restore_freq:
729 if (clk_set_rate(clk, old_freq))
730 dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
731 __func__, old_freq);
732restore_voltage:
733 /* This shouldn't harm even if the voltages weren't updated earlier */
734 if (old_supply.u_volt)
735 _set_opp_voltage(dev, reg, &old_supply);
736
737 return ret;
738} 773}
739EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate); 774EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);
740 775
@@ -1368,6 +1403,38 @@ unlock:
1368} 1403}
1369EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name); 1404EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
1370 1405
1406static int _allocate_set_opp_data(struct opp_table *opp_table)
1407{
1408 struct dev_pm_set_opp_data *data;
1409 int len, count = opp_table->regulator_count;
1410
1411 if (WARN_ON(!count))
1412 return -EINVAL;
1413
1414 /* space for set_opp_data */
1415 len = sizeof(*data);
1416
1417 /* space for old_opp.supplies and new_opp.supplies */
1418 len += 2 * sizeof(struct dev_pm_opp_supply) * count;
1419
1420 data = kzalloc(len, GFP_KERNEL);
1421 if (!data)
1422 return -ENOMEM;
1423
1424 data->old_opp.supplies = (void *)(data + 1);
1425 data->new_opp.supplies = data->old_opp.supplies + count;
1426
1427 opp_table->set_opp_data = data;
1428
1429 return 0;
1430}
1431
1432static void _free_set_opp_data(struct opp_table *opp_table)
1433{
1434 kfree(opp_table->set_opp_data);
1435 opp_table->set_opp_data = NULL;
1436}
1437
1371/** 1438/**
1372 * dev_pm_opp_set_regulators() - Set regulator names for the device 1439 * dev_pm_opp_set_regulators() - Set regulator names for the device
1373 * @dev: Device for which regulator name is being set. 1440 * @dev: Device for which regulator name is being set.
@@ -1437,6 +1504,11 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
1437 1504
1438 opp_table->regulator_count = count; 1505 opp_table->regulator_count = count;
1439 1506
1507 /* Allocate block only once to pass to set_opp() routines */
1508 ret = _allocate_set_opp_data(opp_table);
1509 if (ret)
1510 goto free_regulators;
1511
1440 mutex_unlock(&opp_table_lock); 1512 mutex_unlock(&opp_table_lock);
1441 return opp_table; 1513 return opp_table;
1442 1514
@@ -1446,6 +1518,7 @@ free_regulators:
1446 1518
1447 kfree(opp_table->regulators); 1519 kfree(opp_table->regulators);
1448 opp_table->regulators = NULL; 1520 opp_table->regulators = NULL;
1521 opp_table->regulator_count = 0;
1449err: 1522err:
1450 _remove_opp_table(opp_table); 1523 _remove_opp_table(opp_table);
1451unlock: 1524unlock:
@@ -1482,6 +1555,8 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table)
1482 for (i = opp_table->regulator_count - 1; i >= 0; i--) 1555 for (i = opp_table->regulator_count - 1; i >= 0; i--)
1483 regulator_put(opp_table->regulators[i]); 1556 regulator_put(opp_table->regulators[i]);
1484 1557
1558 _free_set_opp_data(opp_table);
1559
1485 kfree(opp_table->regulators); 1560 kfree(opp_table->regulators);
1486 opp_table->regulators = NULL; 1561 opp_table->regulators = NULL;
1487 opp_table->regulator_count = 0; 1562 opp_table->regulator_count = 0;
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 5b0f7e53bede..a05e43912c6b 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -141,6 +141,7 @@ enum opp_table_access {
141 * @clk: Device's clock handle 141 * @clk: Device's clock handle
142 * @regulators: Supply regulators 142 * @regulators: Supply regulators
143 * @regulator_count: Number of power supply regulators 143 * @regulator_count: Number of power supply regulators
144 * @set_opp_data: Data to be passed to set_opp callback
144 * @dentry: debugfs dentry pointer of the real device directory (not links). 145 * @dentry: debugfs dentry pointer of the real device directory (not links).
145 * @dentry_name: Name of the real dentry. 146 * @dentry_name: Name of the real dentry.
146 * 147 *
@@ -178,6 +179,8 @@ struct opp_table {
178 struct regulator **regulators; 179 struct regulator **regulators;
179 unsigned int regulator_count; 180 unsigned int regulator_count;
180 181
182 struct dev_pm_set_opp_data *set_opp_data;
183
181#ifdef CONFIG_DEBUG_FS 184#ifdef CONFIG_DEBUG_FS
182 struct dentry *dentry; 185 struct dentry *dentry;
183 char dentry_name[NAME_MAX]; 186 char dentry_name[NAME_MAX];
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 9a825ae78653..779b40a9287d 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -17,6 +17,8 @@
17#include <linux/err.h> 17#include <linux/err.h>
18#include <linux/notifier.h> 18#include <linux/notifier.h>
19 19
20struct clk;
21struct regulator;
20struct dev_pm_opp; 22struct dev_pm_opp;
21struct device; 23struct device;
22struct opp_table; 24struct opp_table;
@@ -41,6 +43,39 @@ struct dev_pm_opp_supply {
41 unsigned long u_amp; 43 unsigned long u_amp;
42}; 44};
43 45
46/**
47 * struct dev_pm_opp_info - OPP freq/voltage/current values
48 * @rate: Target clk rate in hz
49 * @supplies: Array of voltage/current values for all power supplies
50 *
51 * This structure stores the freq/voltage/current values for a single OPP.
52 */
53struct dev_pm_opp_info {
54 unsigned long rate;
55 struct dev_pm_opp_supply *supplies;
56};
57
58/**
59 * struct dev_pm_set_opp_data - Set OPP data
60 * @old_opp: Old OPP info
61 * @new_opp: New OPP info
62 * @regulators: Array of regulator pointers
63 * @regulator_count: Number of regulators
64 * @clk: Pointer to clk
65 * @dev: Pointer to the struct device
66 *
67 * This structure contains all information required for setting an OPP.
68 */
69struct dev_pm_set_opp_data {
70 struct dev_pm_opp_info old_opp;
71 struct dev_pm_opp_info new_opp;
72
73 struct regulator **regulators;
74 unsigned int regulator_count;
75 struct clk *clk;
76 struct device *dev;
77};
78
44#if defined(CONFIG_PM_OPP) 79#if defined(CONFIG_PM_OPP)
45 80
46unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); 81unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);