regulator: Add regmap helper for ramp-delay setting
authorMatti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Mon, 29 Mar 2021 12:59:04 +0000 (15:59 +0300)
committerMark Brown <broonie@kernel.org>
Fri, 2 Apr 2021 17:33:59 +0000 (18:33 +0100)
Quite a few regulator ICs do support setting ramp-delay by writing a value
matching the delay to a ramp-delay register.

Provide a simple helper for table-based delay setting.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Link: https://lore.kernel.org/r/f101f1db564cf32cb58719c77af0b00d7236bb89.1617020713.git.matti.vaittinen@fi.rohmeurope.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/regulator/helpers.c
include/linux/regulator/driver.h

index 3e19ecb..0e16e31 100644 (file)
@@ -901,3 +901,68 @@ bool regulator_is_equal(struct regulator *reg1, struct regulator *reg2)
        return reg1->rdev == reg2->rdev;
 }
 EXPORT_SYMBOL_GPL(regulator_is_equal);
+
+static int find_closest_bigger(unsigned int target, const unsigned int *table,
+                              unsigned int num_sel, unsigned int *sel)
+{
+       unsigned int s, tmp, max, maxsel = 0;
+       bool found = false;
+
+       max = table[0];
+
+       for (s = 0; s < num_sel; s++) {
+               if (table[s] > max) {
+                       max = table[s];
+                       maxsel = s;
+               }
+               if (table[s] >= target) {
+                       if (!found || table[s] - target < tmp - target) {
+                               tmp = table[s];
+                               *sel = s;
+                               found = true;
+                               if (tmp == target)
+                                       break;
+                       }
+               }
+       }
+
+       if (!found) {
+               *sel = maxsel;
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * regulator_set_ramp_delay_regmap - set_ramp_delay() helper
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the ramp_reg
+ * and ramp_mask fields in their descriptor and then use this as their
+ * set_ramp_delay operation, saving some code.
+ */
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
+{
+       int ret;
+       unsigned int sel;
+
+       if (!rdev->desc->n_ramp_values)
+               return -EINVAL;
+
+       ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
+                                 rdev->desc->n_ramp_values, &sel);
+
+       if (ret) {
+               dev_warn(rdev_get_dev(rdev),
+                        "Can't set ramp-delay %u, setting %u\n", ramp_delay,
+                        rdev->desc->ramp_delay_table[sel]);
+       }
+
+       sel <<= ffs(rdev->desc->ramp_mask) - 1;
+
+       return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg,
+                                 rdev->desc->ramp_mask, sel);
+}
+EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap);
index 39a5401..597ed11 100644 (file)
@@ -373,6 +373,10 @@ struct regulator_desc {
        unsigned int pull_down_reg;
        unsigned int pull_down_mask;
        unsigned int pull_down_val_on;
+       unsigned int ramp_reg;
+       unsigned int ramp_mask;
+       const unsigned int *ramp_delay_table;
+       unsigned int n_ramp_values;
 
        unsigned int enable_time;
 
@@ -535,6 +539,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev *rdev,
                                       int min_uA, int max_uA);
 int regulator_get_current_limit_regmap(struct regulator_dev *rdev);
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay);
 
 /*
  * Helper functions intended to be used by regulator drivers prior registering