regulator: devres: add API for reference voltage supplies
authorDavid Lechner <dlechner@baylibre.com>
Mon, 29 Apr 2024 23:40:09 +0000 (18:40 -0500)
committerMark Brown <broonie@kernel.org>
Fri, 3 May 2024 02:08:12 +0000 (11:08 +0900)
A common use case for regulators is to supply a reference voltage to an
analog input or output device. This adds a new devres API to get,
enable, and get the voltage in a single call. This allows eliminating
boilerplate code in drivers that use reference supplies in this way.

Signed-off-by: David Lechner <dlechner@baylibre.com>
Link: https://lore.kernel.org/r/20240429-regulator-get-enable-get-votlage-v2-1-b1f11ab766c1@baylibre.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Documentation/driver-api/driver-model/devres.rst
drivers/regulator/devres.c
include/linux/regulator/consumer.h

index 7be8b8dd5f00ad0a0dd816fc2d9fcaeff3278064..18caebad73767cbc32621b61980b2d78696ba68d 100644 (file)
@@ -433,6 +433,7 @@ REGULATOR
   devm_regulator_bulk_put()
   devm_regulator_get()
   devm_regulator_get_enable()
+  devm_regulator_get_enable_read_voltage()
   devm_regulator_get_enable_optional()
   devm_regulator_get_exclusive()
   devm_regulator_get_optional()
index 90bb0d178885afa881678a6ed32b08752e7b5cdc..4f290b9b559b9f20f432bcf39aa88701a58b9a57 100644 (file)
@@ -145,6 +145,65 @@ struct regulator *devm_regulator_get_optional(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_regulator_get_optional);
 
+/**
+ * devm_regulator_get_enable_read_voltage - Resource managed regulator get and
+ *                                          enable that returns the voltage
+ * @dev: device to supply
+ * @id:  supply name or regulator ID.
+ *
+ * Get and enable regulator for duration of the device life-time.
+ * regulator_disable() and regulator_put() are automatically called on driver
+ * detach. See regulator_get_optional(), regulator_enable(), and
+ * regulator_get_voltage() for more information.
+ *
+ * This is a convenience function for supplies that provide a reference voltage
+ * where the consumer driver just needs to know the voltage and keep the
+ * regulator enabled.
+ *
+ * In cases where the supply is not strictly required, callers can check for
+ * -ENODEV error and handle it accordingly.
+ *
+ * Returns: voltage in microvolts on success, or an error code on failure.
+ */
+int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id)
+{
+       struct regulator *r;
+       int ret;
+
+       /*
+        * Since we need a real voltage, we use devm_regulator_get_optional()
+        * rather than getting a dummy regulator with devm_regulator_get() and
+        * then letting regulator_get_voltage() fail with -EINVAL. This way, the
+        * caller can handle the -ENODEV error code if needed instead of the
+        * ambiguous -EINVAL.
+        */
+       r = devm_regulator_get_optional(dev, id);
+       if (IS_ERR(r))
+               return PTR_ERR(r);
+
+       ret = regulator_enable(r);
+       if (ret)
+               goto err_regulator_put;
+
+       ret = devm_add_action_or_reset(dev, regulator_action_disable, r);
+       if (ret)
+               goto err_regulator_put;
+
+       ret = regulator_get_voltage(r);
+       if (ret < 0)
+               goto err_release_action;
+
+       return 0;
+
+err_release_action:
+       devm_release_action(dev, regulator_action_disable, r);
+err_regulator_put:
+       devm_regulator_put(r);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(devm_regulator_get_enable_read_voltage);
+
 static int devm_regulator_match(struct device *dev, void *res, void *data)
 {
        struct regulator **r = res;
index 4660582a33022fc15946a811105318199ccaca42..6f41a11c92e79e8e4abbaa59ca51bc41fe2815e2 100644 (file)
@@ -164,6 +164,7 @@ struct regulator *__must_check devm_regulator_get_optional(struct device *dev,
                                                           const char *id);
 int devm_regulator_get_enable(struct device *dev, const char *id);
 int devm_regulator_get_enable_optional(struct device *dev, const char *id);
+int devm_regulator_get_enable_read_voltage(struct device *dev, const char *id);
 void regulator_put(struct regulator *regulator);
 void devm_regulator_put(struct regulator *regulator);
 
@@ -329,6 +330,12 @@ static inline int devm_regulator_get_enable_optional(struct device *dev,
        return -ENODEV;
 }
 
+static inline int devm_regulator_get_enable_read_voltage(struct device *dev,
+                                                        const char *id)
+{
+       return -ENODEV;
+}
+
 static inline struct regulator *__must_check
 regulator_get_optional(struct device *dev, const char *id)
 {