summaryrefslogtreecommitdiff
path: root/drivers/iio/frequency/ad9523.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/frequency/ad9523.c')
-rw-r--r--drivers/iio/frequency/ad9523.c185
1 files changed, 93 insertions, 92 deletions
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 92276deeb026..63c485e9e44c 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* AD9523 SPI Low Jitter Clock Generator
*
* Copyright 2012 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
*/
#include <linux/device.h>
@@ -12,6 +11,7 @@
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/delay.h>
@@ -265,9 +265,11 @@ enum {
struct ad9523_state {
struct spi_device *spi;
- struct regulator *reg;
struct ad9523_platform_data *pdata;
struct iio_chan_spec ad9523_channels[AD9523_NUM_CHAN];
+ struct gpio_desc *pwrdown_gpio;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *sync_gpio;
unsigned long vcxo_freq;
unsigned long vco_freq;
@@ -275,16 +277,25 @@ struct ad9523_state {
unsigned char vco_out_map[AD9523_NUM_CHAN_ALT_CLK_SRC];
/*
- * DMA (thus cache coherency maintenance) requires the
- * transfer buffers to live in their own cache lines.
+ * Lock for accessing device registers. Some operations require
+ * multiple consecutive R/W operations, during which the device
+ * shouldn't be interrupted. The buffers are also shared across
+ * all operations so need to be protected on stand alone reads and
+ * writes.
+ */
+ struct mutex lock;
+
+ /*
+ * DMA (thus cache coherency maintenance) may require that
+ * transfer buffers live in their own cache lines.
*/
union {
__be32 d32;
u8 d8[4];
- } data[2] ____cacheline_aligned;
+ } data[2] __aligned(IIO_DMA_MINALIGN);
};
-static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
+static int ad9523_read(struct iio_dev *indio_dev, unsigned int addr)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
@@ -318,7 +329,8 @@ static int ad9523_read(struct iio_dev *indio_dev, unsigned addr)
return ret;
};
-static int ad9523_write(struct iio_dev *indio_dev, unsigned addr, unsigned val)
+static int ad9523_write(struct iio_dev *indio_dev,
+ unsigned int addr, unsigned int val)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
@@ -351,11 +363,11 @@ static int ad9523_io_update(struct iio_dev *indio_dev)
}
static int ad9523_vco_out_map(struct iio_dev *indio_dev,
- unsigned ch, unsigned out)
+ unsigned int ch, unsigned int out)
{
struct ad9523_state *st = iio_priv(indio_dev);
int ret;
- unsigned mask;
+ unsigned int mask;
switch (ch) {
case 0 ... 3:
@@ -405,7 +417,7 @@ static int ad9523_vco_out_map(struct iio_dev *indio_dev,
}
static int ad9523_set_clock_provider(struct iio_dev *indio_dev,
- unsigned ch, unsigned long freq)
+ unsigned int ch, unsigned long freq)
{
struct ad9523_state *st = iio_priv(indio_dev);
long tmp1, tmp2;
@@ -445,7 +457,7 @@ static int ad9523_store_eeprom(struct iio_dev *indio_dev)
tmp = 4;
do {
- msleep(16);
+ msleep(20);
ret = ad9523_read(indio_dev,
AD9523_EEPROM_DATA_XFER_STATUS);
if (ret < 0)
@@ -499,17 +511,18 @@ static ssize_t ad9523_store(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct ad9523_state *st = iio_priv(indio_dev);
bool state;
int ret;
- ret = strtobool(buf, &state);
+ ret = kstrtobool(buf, &state);
if (ret < 0)
return ret;
if (!state)
- return 0;
+ return len;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
switch ((u32)this_attr->address) {
case AD9523_SYNC:
ret = ad9523_sync(indio_dev);
@@ -520,7 +533,7 @@ static ssize_t ad9523_store(struct device *dev,
default:
ret = -ENODEV;
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret ? ret : len;
}
@@ -531,15 +544,16 @@ static ssize_t ad9523_show(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct ad9523_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
ret = ad9523_read(indio_dev, AD9523_READBACK_0);
if (ret >= 0) {
- ret = sprintf(buf, "%d\n", !!(ret & (1 <<
+ ret = sysfs_emit(buf, "%d\n", !!(ret & (1 <<
(u32)this_attr->address)));
}
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
@@ -619,12 +633,12 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad9523_state *st = iio_priv(indio_dev);
- unsigned code;
+ unsigned int code;
int ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
if (ret < 0)
return ret;
@@ -641,7 +655,7 @@ static int ad9523_read_raw(struct iio_dev *indio_dev,
code = (AD9523_CLK_DIST_DIV_PHASE_REV(ret) * 3141592) /
AD9523_CLK_DIST_DIV_REV(ret);
*val = code / 1000000;
- *val2 = (code % 1000000) * 10;
+ *val2 = code % 1000000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
@@ -655,10 +669,10 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad9523_state *st = iio_priv(indio_dev);
- unsigned reg;
+ unsigned int reg;
int ret, tmp, code;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
ret = ad9523_read(indio_dev, AD9523_CHANNEL_CLOCK_DIST(chan->channel));
if (ret < 0)
goto out;
@@ -704,17 +718,18 @@ static int ad9523_write_raw(struct iio_dev *indio_dev,
ad9523_io_update(indio_dev);
out:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
static int ad9523_reg_access(struct iio_dev *indio_dev,
- unsigned reg, unsigned writeval,
- unsigned *readval)
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
{
+ struct ad9523_state *st = iio_priv(indio_dev);
int ret;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
if (readval == NULL) {
ret = ad9523_write(indio_dev, reg | AD9523_R1B, writeval);
ad9523_io_update(indio_dev);
@@ -727,7 +742,7 @@ static int ad9523_reg_access(struct iio_dev *indio_dev,
}
out_unlock:
- mutex_unlock(&indio_dev->mlock);
+ mutex_unlock(&st->lock);
return ret;
}
@@ -737,7 +752,6 @@ static const struct iio_info ad9523_info = {
.write_raw = &ad9523_write_raw,
.debugfs_reg_access = &ad9523_reg_access,
.attrs = &ad9523_attribute_group,
- .driver_module = THIS_MODULE,
};
static int ad9523_setup(struct iio_dev *indio_dev)
@@ -846,9 +860,11 @@ static int ad9523_setup(struct iio_dev *indio_dev)
if (ret < 0)
return ret;
- st->vco_freq = (pdata->vcxo_freq * (pdata->pll2_freq_doubler_en ? 2 : 1)
- / pdata->pll2_r2_div) * AD9523_PLL2_FB_NDIV(pdata->
- pll2_ndiv_a_cnt, pdata->pll2_ndiv_b_cnt);
+ st->vco_freq = div_u64((unsigned long long)pdata->vcxo_freq *
+ (pdata->pll2_freq_doubler_en ? 2 : 1) *
+ AD9523_PLL2_FB_NDIV(pdata->pll2_ndiv_a_cnt,
+ pdata->pll2_ndiv_b_cnt),
+ pdata->pll2_r2_div);
ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_CTRL,
AD9523_PLL2_VCO_CALIBRATE);
@@ -856,22 +872,22 @@ static int ad9523_setup(struct iio_dev *indio_dev)
return ret;
ret = ad9523_write(indio_dev, AD9523_PLL2_VCO_DIVIDER,
- AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_diff_m1) |
- AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_diff_m2) |
- AD_IFE(pll2_vco_diff_m1, 0,
+ AD9523_PLL2_VCO_DIV_M1(pdata->pll2_vco_div_m1) |
+ AD9523_PLL2_VCO_DIV_M2(pdata->pll2_vco_div_m2) |
+ AD_IFE(pll2_vco_div_m1, 0,
AD9523_PLL2_VCO_DIV_M1_PWR_DOWN_EN) |
- AD_IFE(pll2_vco_diff_m2, 0,
+ AD_IFE(pll2_vco_div_m2, 0,
AD9523_PLL2_VCO_DIV_M2_PWR_DOWN_EN));
if (ret < 0)
return ret;
- if (pdata->pll2_vco_diff_m1)
+ if (pdata->pll2_vco_div_m1)
st->vco_out_freq[AD9523_VCO1] =
- st->vco_freq / pdata->pll2_vco_diff_m1;
+ st->vco_freq / pdata->pll2_vco_div_m1;
- if (pdata->pll2_vco_diff_m2)
+ if (pdata->pll2_vco_div_m2)
st->vco_out_freq[AD9523_VCO2] =
- st->vco_freq / pdata->pll2_vco_diff_m2;
+ st->vco_freq / pdata->pll2_vco_div_m2;
st->vco_out_freq[AD9523_VCXO] = pdata->vcxo_freq;
@@ -927,11 +943,14 @@ static int ad9523_setup(struct iio_dev *indio_dev)
}
}
- for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN)
- ad9523_write(indio_dev,
+ for_each_clear_bit(i, &active_mask, AD9523_NUM_CHAN) {
+ ret = ad9523_write(indio_dev,
AD9523_CHANNEL_CLOCK_DIST(i),
AD9523_CLK_DIST_DRIVER_MODE(TRISTATE) |
AD9523_CLK_DIST_PWR_DOWN_EN);
+ if (ret < 0)
+ return ret;
+ }
ret = ad9523_write(indio_dev, AD9523_POWER_DOWN_CTRL, 0);
if (ret < 0)
@@ -951,7 +970,7 @@ static int ad9523_setup(struct iio_dev *indio_dev)
static int ad9523_probe(struct spi_device *spi)
{
- struct ad9523_platform_data *pdata = spi->dev.platform_data;
+ struct ad9523_platform_data *pdata = dev_get_platdata(&spi->dev);
struct iio_dev *indio_dev;
struct ad9523_state *st;
int ret;
@@ -961,24 +980,42 @@ static int ad9523_probe(struct spi_device *spi)
return -EINVAL;
}
- indio_dev = iio_device_alloc(sizeof(*st));
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
- st->reg = regulator_get(&spi->dev, "vcc");
- if (!IS_ERR(st->reg)) {
- ret = regulator_enable(st->reg);
- if (ret)
- goto error_put_reg;
+ mutex_init(&st->lock);
+
+ ret = devm_regulator_get_enable(&spi->dev, "vcc");
+ if (ret)
+ return ret;
+
+ st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->pwrdown_gpio))
+ return PTR_ERR(st->pwrdown_gpio);
+
+ st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(st->reset_gpio))
+ return PTR_ERR(st->reset_gpio);
+
+ if (st->reset_gpio) {
+ udelay(1);
+ gpiod_direction_output(st->reset_gpio, 1);
}
+ st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(st->sync_gpio))
+ return PTR_ERR(st->sync_gpio);
+
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->pdata = pdata;
- indio_dev->dev.parent = &spi->dev;
indio_dev->name = (pdata->name[0] != 0) ? pdata->name :
spi_get_device_id(spi)->name;
indio_dev->info = &ad9523_info;
@@ -988,62 +1025,26 @@ static int ad9523_probe(struct spi_device *spi)
ret = ad9523_setup(indio_dev);
if (ret < 0)
- goto error_disable_reg;
-
- ret = iio_device_register(indio_dev);
- if (ret)
- goto error_disable_reg;
-
- dev_info(&spi->dev, "probed %s\n", indio_dev->name);
-
- return 0;
-
-error_disable_reg:
- if (!IS_ERR(st->reg))
- regulator_disable(st->reg);
-error_put_reg:
- if (!IS_ERR(st->reg))
- regulator_put(st->reg);
-
- iio_device_free(indio_dev);
-
- return ret;
-}
-
-static int ad9523_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
- struct ad9523_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
-
- if (!IS_ERR(st->reg)) {
- regulator_disable(st->reg);
- regulator_put(st->reg);
- }
-
- iio_device_free(indio_dev);
+ return ret;
- return 0;
+ return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id ad9523_id[] = {
{"ad9523-1", 9523},
- {}
+ { }
};
MODULE_DEVICE_TABLE(spi, ad9523_id);
static struct spi_driver ad9523_driver = {
.driver = {
.name = "ad9523",
- .owner = THIS_MODULE,
},
.probe = ad9523_probe,
- .remove = ad9523_remove,
.id_table = ad9523_id,
};
module_spi_driver(ad9523_driver);
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD9523 CLOCKDIST/PLL");
MODULE_LICENSE("GPL v2");