diff options
Diffstat (limited to 'drivers/iio/frequency/ad9523.c')
| -rw-r--r-- | drivers/iio/frequency/ad9523.c | 185 |
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"); |
