This commit adds support for getting/setting current for all supported variants. Limits are adjusted per variant to match HW implementation. Signed-off-by: Adam Ward <Adam.Ward.opensource@xxxxxxxxxxx> --- drivers/regulator/da9121-regulator.c | 140 +++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c index 13b0aad..5d11c22 100644 --- a/drivers/regulator/da9121-regulator.c +++ b/drivers/regulator/da9121-regulator.c @@ -92,6 +92,144 @@ struct da9121_variant_info { { 1, 2, &da9121_6A_2phase_current }, //DA9121_TYPE_DA9217 }; +static bool da9121_rdev_to_buck_reg_mask(struct regulator_dev *rdev, bool mode, + unsigned int *reg, unsigned int *msk) +{ + struct da9121 *chip = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + + switch (id) { + case DA9121_IDX_BUCK1: + if (mode) { + *reg = DA9121_REG_BUCK_BUCK1_4; + *msk = DA9121_MASK_BUCK_BUCKx_4_CHx_A_MODE; + } else { + *reg = DA9121_REG_BUCK_BUCK1_2; + *msk = DA9121_MASK_BUCK_BUCKx_2_CHx_ILIM; + } + break; + case DA9121_IDX_BUCK2: + if (mode) { + *reg = DA9xxx_REG_BUCK_BUCK2_4; + *msk = DA9121_MASK_BUCK_BUCKx_4_CHx_A_MODE; + } else { + *reg = DA9xxx_REG_BUCK_BUCK2_2; + *msk = DA9121_MASK_BUCK_BUCKx_2_CHx_ILIM; + } + break; + default: + dev_err(chip->dev, "Invalid regulator ID\n"); + return false; + } + return true; +} + +static int da9121_get_current_limit(struct regulator_dev *rdev) +{ + struct da9121 *chip = rdev_get_drvdata(rdev); + struct da9121_range *range = + variant_parameters[chip->variant_id].current_range; + unsigned int reg = 0; + unsigned int msk = 0; + unsigned int val = 0; + int ret = 0; + + if (!da9121_rdev_to_buck_reg_mask(rdev, false, ®, &msk)) + return -EINVAL; + + ret = regmap_read(chip->regmap, reg, &val); + if (ret < 0) { + dev_err(chip->dev, "Cannot read BUCK register: %d\n", ret); + goto error; + } + + if (val < range->reg_min) { + ret = -EACCES; + goto error; + } + + if (val > range->reg_max) { + ret = -EINVAL; + goto error; + } + + return range->val_min + (range->val_stp * (val - range->reg_min)); +error: + return ret; +} + +static int da9121_ceiling_selector(struct regulator_dev *rdev, + int min, int max, + unsigned int *selector) +{ + struct da9121 *chip = rdev_get_drvdata(rdev); + struct da9121_range *range = + variant_parameters[chip->variant_id].current_range; + unsigned int level; + unsigned int i = 0; + unsigned int sel = 0; + int ret = 0; + + if (range->val_min > max || range->val_max < min) { + dev_err(chip->dev, + "Requested current out of regulator capability\n"); + ret = -EINVAL; + goto error; + } + + level = range->val_max; + for (i = range->reg_max; i >= range->reg_min; i--) { + if (level <= max) { + sel = i; + break; + } + level -= range->val_stp; + } + + if (level < min) { + dev_err(chip->dev, + "Best match falls below minimum requested current\n"); + ret = -EINVAL; + goto error; + } + + *selector = sel; +error: + return ret; +} + +static int da9121_set_current_limit(struct regulator_dev *rdev, + int min_ua, int max_ua) +{ + struct da9121 *chip = rdev_get_drvdata(rdev); + struct da9121_range *range = + variant_parameters[chip->variant_id].current_range; + unsigned int sel = 0; + unsigned int reg = 0; + unsigned int msk = 0; + int ret = 0; + + if (min_ua < range->val_min || + max_ua > range->val_max) { + ret = -EINVAL; + goto error; + } + + ret = da9121_ceiling_selector(rdev, min_ua, max_ua, &sel); + if (ret < 0) + goto error; + + if (!da9121_rdev_to_buck_reg_mask(rdev, false, ®, &msk)) + return -EINVAL; + + ret = regmap_update_bits(chip->regmap, reg, msk, (unsigned int)sel); + if (ret < 0) + dev_err(chip->dev, "Cannot update BUCK register %02x, err: %d\n", reg, ret); + +error: + return ret; +} + static const struct regulator_ops da9121_buck_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -99,6 +237,8 @@ struct da9121_variant_info { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, + .get_current_limit = da9121_get_current_limit, + .set_current_limit = da9121_set_current_limit, }; static struct of_regulator_match da9121_matches[] = { -- 1.9.1