@@ -14,7 +14,7 @@
#include "internal.h"
-static void devm_regulator_release(struct device *dev, void *res)
+void devm_regulator_release(struct device *dev, void *res)
{
regulator_put(*(struct regulator **)res);
}
@@ -131,4 +131,6 @@ struct regulator *_regulator_get(struct device *dev, const char *id,
enum regulator_get_type get_type);
int _regulator_bulk_get(struct device *dev, int num_consumers,
struct regulator_bulk_data *consumers, enum regulator_get_type get_type);
+
+void devm_regulator_release(struct device *dev, void *res);
#endif
@@ -704,6 +704,43 @@ struct regulator *of_regulator_get_optional(struct device *dev,
}
EXPORT_SYMBOL_GPL(of_regulator_get_optional);
+static struct regulator *_devm_of_regulator_get(struct device *dev, struct device_node *node,
+ const char *id, int get_type)
+{
+ struct regulator **ptr, *regulator;
+
+ ptr = devres_alloc(devm_regulator_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ regulator = _of_regulator_get(dev, node, id, get_type);
+ if (!IS_ERR(regulator)) {
+ *ptr = regulator;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return regulator;
+}
+
+/**
+ * devm_of_regulator_get_optional - Resource managed of_regulator_get_optional()
+ * @dev: device used for dev_printk() messages and resource lifetime management
+ * @node: device node for regulator "consumer"
+ * @id: supply name or regulator ID.
+ *
+ * Managed regulator_get_optional(). Regulators returned from this
+ * function are automatically regulator_put() on driver detach. See
+ * of_regulator_get_optional() for more information.
+ */
+struct regulator *devm_of_regulator_get_optional(struct device *dev, struct device_node *node,
+ const char *id)
+{
+ return _devm_of_regulator_get(dev, node, id, OPTIONAL_GET);
+}
+EXPORT_SYMBOL_GPL(devm_of_regulator_get_optional);
+
/*
* Returns number of regulators coupled with rdev.
*/
@@ -171,12 +171,20 @@ void devm_regulator_put(struct regulator *regulator);
#if IS_ENABLED(CONFIG_OF)
struct regulator *__must_check of_regulator_get_optional(
struct device *dev, struct device_node *node, const char *id);
+struct regulator *__must_check devm_of_regulator_get_optional(
+ struct device *dev, struct device_node *node, const char *id);
#else
static inline struct regulator *__must_check of_regulator_get_optional(
struct device *dev, struct device_node *node, const char *id)
{
return ERR_PTR(-ENODEV);
}
+
+static inline struct regulator *__must_check devm_of_regulator_get_optional(
+ struct device *dev, struct device_node *node, const char *id)
+{
+ return ERR_PTR(-ENODEV);
+}
#endif
int regulator_register_supply_alias(struct device *dev, const char *id,
@@ -367,6 +375,12 @@ static inline struct regulator *__must_check of_regulator_get_optional(
return ERR_PTR(-ENODEV);
}
+static inline struct regulator *__must_check devm_of_regulator_get_optional(
+ struct device *dev, struct device_node *node, const char *id)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline void regulator_put(struct regulator *regulator)
{
}
There are existing uses for a devres version of of_regulator_get_optional() in power domain drivers. On MediaTek platforms, power domains may have regulator supplies tied to them. The driver currently tries to use devm_regulator_get() to not have to manage the lifecycle, but ends up doing it in a very hacky way by replacing the device node of the power domain controller device to the device node of the power domain that is currently being registered, getting the supply, and reverting the device node. Provide a better API so that the hack can be replaced. Signed-off-by: Chen-Yu Tsai <wenst@chromium.org> --- Changes since v8: - Moved OF-specific devres version to of_regulator.c - Made _of_regulator_get() static again - Made devm_regulator_release non-static - Reformated stub versions with `clang-format` Changes since v7: - New patch --- drivers/regulator/devres.c | 2 +- drivers/regulator/internal.h | 2 ++ drivers/regulator/of_regulator.c | 37 ++++++++++++++++++++++++++++++ include/linux/regulator/consumer.h | 14 +++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-)