aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/opp/core.c
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2016-02-09 00:00:33 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-02-09 19:11:53 -0500
commit9f8ea969d5cfdd4353d2adb004e8e2286b984369 (patch)
tree89a110d6f65b74a62667b490e241bc3968dad687 /drivers/base/power/opp/core.c
parent388f7b1d6e8ca06762e2454d28d6c3c55ad0fe95 (diff)
PM / OPP: get/put regulators from OPP core
This allows the OPP core to request/free the regulator resource, attached to a device OPP. The regulator device is fetched using the name provided by the driver, while calling: dev_pm_opp_set_regulator(). This will work for both OPP-v1 and v2 bindings. This is a preliminary step for moving the OPP switching logic into the OPP core. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base/power/opp/core.c')
-rw-r--r--drivers/base/power/opp/core.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index cf351d3dab1c..1e22b71abf1e 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -19,6 +19,7 @@
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/export.h> 21#include <linux/export.h>
22#include <linux/regulator/consumer.h>
22 23
23#include "opp.h" 24#include "opp.h"
24 25
@@ -565,6 +566,9 @@ static void _remove_device_opp(struct device_opp *dev_opp)
565 if (dev_opp->prop_name) 566 if (dev_opp->prop_name)
566 return; 567 return;
567 568
569 if (!IS_ERR_OR_NULL(dev_opp->regulator))
570 return;
571
568 list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp, 572 list_dev = list_first_entry(&dev_opp->dev_list, struct device_list_opp,
569 node); 573 node);
570 574
@@ -1085,6 +1089,113 @@ unlock:
1085} 1089}
1086EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name); 1090EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
1087 1091
1092/**
1093 * dev_pm_opp_set_regulator() - Set regulator name for the device
1094 * @dev: Device for which regulator name is being set.
1095 * @name: Name of the regulator.
1096 *
1097 * In order to support OPP switching, OPP layer needs to know the name of the
1098 * device's regulator, as the core would be required to switch voltages as well.
1099 *
1100 * This must be called before any OPPs are initialized for the device.
1101 *
1102 * Locking: The internal device_opp and opp structures are RCU protected.
1103 * Hence this function internally uses RCU updater strategy with mutex locks
1104 * to keep the integrity of the internal data structures. Callers should ensure
1105 * that this function is *NOT* called under RCU protection or in contexts where
1106 * mutex cannot be locked.
1107 */
1108int dev_pm_opp_set_regulator(struct device *dev, const char *name)
1109{
1110 struct device_opp *dev_opp;
1111 struct regulator *reg;
1112 int ret;
1113
1114 mutex_lock(&dev_opp_list_lock);
1115
1116 dev_opp = _add_device_opp(dev);
1117 if (!dev_opp) {
1118 ret = -ENOMEM;
1119 goto unlock;
1120 }
1121
1122 /* This should be called before OPPs are initialized */
1123 if (WARN_ON(!list_empty(&dev_opp->opp_list))) {
1124 ret = -EBUSY;
1125 goto err;
1126 }
1127
1128 /* Already have a regulator set */
1129 if (WARN_ON(!IS_ERR_OR_NULL(dev_opp->regulator))) {
1130 ret = -EBUSY;
1131 goto err;
1132 }
1133 /* Allocate the regulator */
1134 reg = regulator_get_optional(dev, name);
1135 if (IS_ERR(reg)) {
1136 ret = PTR_ERR(reg);
1137 if (ret != -EPROBE_DEFER)
1138 dev_err(dev, "%s: no regulator (%s) found: %d\n",
1139 __func__, name, ret);
1140 goto err;
1141 }
1142
1143 dev_opp->regulator = reg;
1144
1145 mutex_unlock(&dev_opp_list_lock);
1146 return 0;
1147
1148err:
1149 _remove_device_opp(dev_opp);
1150unlock:
1151 mutex_unlock(&dev_opp_list_lock);
1152
1153 return ret;
1154}
1155EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
1156
1157/**
1158 * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
1159 * @dev: Device for which regulator was set.
1160 *
1161 * Locking: The internal device_opp and opp structures are RCU protected.
1162 * Hence this function internally uses RCU updater strategy with mutex locks
1163 * to keep the integrity of the internal data structures. Callers should ensure
1164 * that this function is *NOT* called under RCU protection or in contexts where
1165 * mutex cannot be locked.
1166 */
1167void dev_pm_opp_put_regulator(struct device *dev)
1168{
1169 struct device_opp *dev_opp;
1170
1171 mutex_lock(&dev_opp_list_lock);
1172
1173 /* Check for existing list for 'dev' first */
1174 dev_opp = _find_device_opp(dev);
1175 if (IS_ERR(dev_opp)) {
1176 dev_err(dev, "Failed to find dev_opp: %ld\n", PTR_ERR(dev_opp));
1177 goto unlock;
1178 }
1179
1180 if (IS_ERR_OR_NULL(dev_opp->regulator)) {
1181 dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
1182 goto unlock;
1183 }
1184
1185 /* Make sure there are no concurrent readers while updating dev_opp */
1186 WARN_ON(!list_empty(&dev_opp->opp_list));
1187
1188 regulator_put(dev_opp->regulator);
1189 dev_opp->regulator = ERR_PTR(-EINVAL);
1190
1191 /* Try freeing device_opp if this was the last blocking resource */
1192 _remove_device_opp(dev_opp);
1193
1194unlock:
1195 mutex_unlock(&dev_opp_list_lock);
1196}
1197EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
1198
1088static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp, 1199static bool _opp_is_supported(struct device *dev, struct device_opp *dev_opp,
1089 struct device_node *np) 1200 struct device_node *np)
1090{ 1201{