From f9dbd14631c577a9adcf0eb1196cf1150c577a46 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 28 Sep 2018 11:23:40 +0200 Subject: [PATCH] iio: ad5064: Fix regulator handling commit 8911a43bc198877fad9f4b0246a866b26bb547ab upstream. The correct way to handle errors returned by regualtor_get() and friends is to propagate the error since that means that an regulator was specified, but something went wrong when requesting it. For handling optional regulators, e.g. when the device has an internal vref, regulator_get_optional() should be used to avoid getting the dummy regulator that the regulator core otherwise provides. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron [bwh: Backported to 3.16: Keep using ad5064_write() instead of ad5064_set_config().] Signed-off-by: Ben Hutchings --- drivers/iio/dac/ad5064.c | 55 ++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index aac16fecdfa8..ed76d8c88e91 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -469,6 +469,41 @@ static const char * const ad5064_vref_name(struct ad5064_state *st, return st->chip_info->shared_vref ? "vref" : ad5064_vref_names[vref]; } +static int ad5064_request_vref(struct ad5064_state *st, struct device *dev) +{ + unsigned int i; + int ret; + + for (i = 0; i < ad5064_num_vref(st); ++i) + st->vref_reg[i].supply = ad5064_vref_name(st, i); + + if (!st->chip_info->internal_vref) + return devm_regulator_bulk_get(dev, ad5064_num_vref(st), + st->vref_reg); + + /* + * This assumes that when the regulator has an internal VREF + * there is only one external VREF connection, which is + * currently the case for all supported devices. + */ + st->vref_reg[0].consumer = devm_regulator_get_optional(dev, "vref"); + if (!IS_ERR(st->vref_reg[0].consumer)) + return 0; + + ret = PTR_ERR(st->vref_reg[0].consumer); + if (ret != -ENODEV) + return ret; + + /* If no external regulator was supplied use the internal VREF */ + st->use_internal_vref = true; + ret = ad5064_write(st, AD5064_CMD_CONFIG, 0, + AD5064_CONFIG_INT_VREF_ENABLE, 0); + if (ret) + dev_err(dev, "Failed to enable internal vref: %d\n", ret); + + return ret; +} + static int ad5064_probe(struct device *dev, enum ad5064_type type, const char *name, ad5064_write_func write) { @@ -489,23 +524,11 @@ static int ad5064_probe(struct device *dev, enum ad5064_type type, st->dev = dev; st->write = write; - for (i = 0; i < ad5064_num_vref(st); ++i) - st->vref_reg[i].supply = ad5064_vref_name(st, i); + ret = ad5064_request_vref(st, dev); + if (ret) + return ret; - ret = devm_regulator_bulk_get(dev, ad5064_num_vref(st), - st->vref_reg); - if (ret) { - if (!st->chip_info->internal_vref) - return ret; - st->use_internal_vref = true; - ret = ad5064_write(st, AD5064_CMD_CONFIG, 0, - AD5064_CONFIG_INT_VREF_ENABLE, 0); - if (ret) { - dev_err(dev, "Failed to enable internal vref: %d\n", - ret); - return ret; - } - } else { + if (!st->use_internal_vref) { ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg); if (ret) return ret;