Commit 9979cc64 authored by Jinjie Ruan's avatar Jinjie Ruan Committed by Jonathan Cameron

iio: frequency: adf4350: Use device managed functions and fix power down issue.

The devm_clk_get_enabled() helper:
    - calls devm_clk_get()
    - calls clk_prepare_enable() and registers what is needed in order to
      call clk_disable_unprepare() when needed, as a managed resource.

Also replace devm_regulator_get() and regulator_enable() with
devm_regulator_get_enable() helper and remove regulator_disable().

Replace iio_device_register() with devm_iio_device_register() and remove
iio_device_unregister().

And st->reg is not used anymore, so remove it.

As Jonathan pointed out, couple of things that are wrong:

1) The device is powered down 'before' we unregister it with the
   subsystem and as such userspace interfaces are still exposed which
   probably won't do the right thing if the chip is powered down.

2) This isn't done in the error paths in probe.

To solve this problem, register a new callback adf4350_power_down()
with devm_add_action_or_reset(), to enable software power down in both
error and device detach path. So the remove function can be removed.

Remove spi_set_drvdata() from the probe function, since spi_get_drvdata()
is not used anymore.

Fixes: e31166f0 ("iio: frequency: New driver for Analog Devices ADF4350/ADF4351 Wideband Synthesizers")
Signed-off-by: default avatarJinjie Ruan <ruanjinjie@huawei.com>
Link: https://lore.kernel.org/r/20230828062717.2310219-1-ruanjinjie@huawei.comSigned-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent da2737c9
...@@ -33,7 +33,6 @@ enum { ...@@ -33,7 +33,6 @@ enum {
struct adf4350_state { struct adf4350_state {
struct spi_device *spi; struct spi_device *spi;
struct regulator *reg;
struct gpio_desc *lock_detect_gpiod; struct gpio_desc *lock_detect_gpiod;
struct adf4350_platform_data *pdata; struct adf4350_platform_data *pdata;
struct clk *clk; struct clk *clk;
...@@ -469,6 +468,15 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev) ...@@ -469,6 +468,15 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
return pdata; return pdata;
} }
static void adf4350_power_down(void *data)
{
struct iio_dev *indio_dev = data;
struct adf4350_state *st = iio_priv(indio_dev);
st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
adf4350_sync_config(st);
}
static int adf4350_probe(struct spi_device *spi) static int adf4350_probe(struct spi_device *spi)
{ {
struct adf4350_platform_data *pdata; struct adf4350_platform_data *pdata;
...@@ -491,31 +499,21 @@ static int adf4350_probe(struct spi_device *spi) ...@@ -491,31 +499,21 @@ static int adf4350_probe(struct spi_device *spi)
} }
if (!pdata->clkin) { if (!pdata->clkin) {
clk = devm_clk_get(&spi->dev, "clkin"); clk = devm_clk_get_enabled(&spi->dev, "clkin");
if (IS_ERR(clk)) if (IS_ERR(clk))
return -EPROBE_DEFER; return PTR_ERR(clk);
ret = clk_prepare_enable(clk);
if (ret < 0)
return ret;
} }
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL) { if (indio_dev == NULL)
ret = -ENOMEM; return -ENOMEM;
goto error_disable_clk;
}
st = iio_priv(indio_dev); st = iio_priv(indio_dev);
st->reg = devm_regulator_get(&spi->dev, "vcc"); ret = devm_regulator_get_enable(&spi->dev, "vcc");
if (!IS_ERR(st->reg)) { if (ret)
ret = regulator_enable(st->reg); return ret;
if (ret)
goto error_disable_clk;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi; st->spi = spi;
st->pdata = pdata; st->pdata = pdata;
...@@ -544,47 +542,21 @@ static int adf4350_probe(struct spi_device *spi) ...@@ -544,47 +542,21 @@ static int adf4350_probe(struct spi_device *spi)
st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL, st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL,
GPIOD_IN); GPIOD_IN);
if (IS_ERR(st->lock_detect_gpiod)) { if (IS_ERR(st->lock_detect_gpiod))
ret = PTR_ERR(st->lock_detect_gpiod); return PTR_ERR(st->lock_detect_gpiod);
goto error_disable_reg;
}
if (pdata->power_up_frequency) { if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency); ret = adf4350_set_freq(st, pdata->power_up_frequency);
if (ret) if (ret)
goto error_disable_reg; return ret;
} }
ret = iio_device_register(indio_dev); ret = devm_add_action_or_reset(&spi->dev, adf4350_power_down, indio_dev);
if (ret) if (ret)
goto error_disable_reg; return dev_err_probe(&spi->dev, ret,
"Failed to add action to managed power down\n");
return 0;
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
error_disable_clk:
clk_disable_unprepare(clk);
return ret;
}
static void adf4350_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adf4350_state *st = iio_priv(indio_dev);
struct regulator *reg = st->reg;
st->regs[ADF4350_REG2] |= ADF4350_REG2_POWER_DOWN_EN;
adf4350_sync_config(st);
iio_device_unregister(indio_dev);
clk_disable_unprepare(st->clk);
if (!IS_ERR(reg)) return devm_iio_device_register(&spi->dev, indio_dev);
regulator_disable(reg);
} }
static const struct of_device_id adf4350_of_match[] = { static const struct of_device_id adf4350_of_match[] = {
...@@ -607,7 +579,6 @@ static struct spi_driver adf4350_driver = { ...@@ -607,7 +579,6 @@ static struct spi_driver adf4350_driver = {
.of_match_table = adf4350_of_match, .of_match_table = adf4350_of_match,
}, },
.probe = adf4350_probe, .probe = adf4350_probe,
.remove = adf4350_remove,
.id_table = adf4350_id, .id_table = adf4350_id,
}; };
module_spi_driver(adf4350_driver); module_spi_driver(adf4350_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment