summaryrefslogtreecommitdiff
path: root/drivers/iio/adc/ad9467.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/ad9467.c')
-rw-r--r--drivers/iio/adc/ad9467.c114
1 files changed, 79 insertions, 35 deletions
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index dbfc8517cb8a..ad94f0abc402 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -119,9 +119,9 @@ struct ad9467_state {
struct spi_device *spi;
struct clk *clk;
unsigned int output_mode;
+ unsigned int (*scales)[2];
struct gpio_desc *pwrdown_gpio;
- struct gpio_desc *reset_gpio;
};
static int ad9467_spi_read(struct spi_device *spi, unsigned int reg)
@@ -163,9 +163,10 @@ static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg,
if (readval == NULL) {
ret = ad9467_spi_write(spi, reg, writeval);
- ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
- AN877_ADC_TRANSFER_SYNC);
- return ret;
+ if (ret)
+ return ret;
+ return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
}
ret = ad9467_spi_read(spi, reg);
@@ -212,6 +213,7 @@ static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index,
.channel = _chan, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = _si, \
.scan_type = { \
.sign = _sign, \
@@ -273,10 +275,13 @@ static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2)
const struct ad9467_chip_info *info1 = to_ad9467_chip_info(info);
struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
unsigned int i, vref_val;
+ int ret;
- vref_val = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF);
+ ret = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF);
+ if (ret < 0)
+ return ret;
- vref_val &= info1->vref_mask;
+ vref_val = ret & info1->vref_mask;
for (i = 0; i < info->num_scales; i++) {
if (vref_val == info->scale_table[i][1])
@@ -297,6 +302,7 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
unsigned int scale_val[2];
unsigned int i;
+ int ret;
if (val != 0)
return -EINVAL;
@@ -306,11 +312,13 @@ static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2)
if (scale_val[0] != val || scale_val[1] != val2)
continue;
- ad9467_spi_write(st->spi, AN877_ADC_REG_VREF,
- info->scale_table[i][1]);
- ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
- AN877_ADC_TRANSFER_SYNC);
- return 0;
+ ret = ad9467_spi_write(st->spi, AN877_ADC_REG_VREF,
+ info->scale_table[i][1]);
+ if (ret < 0)
+ return ret;
+
+ return ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
}
return -EINVAL;
@@ -359,6 +367,26 @@ static int ad9467_write_raw(struct adi_axi_adc_conv *conv,
}
}
+static int ad9467_read_avail(struct adi_axi_adc_conv *conv,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ const struct adi_axi_adc_chip_info *info = conv->chip_info;
+ struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (const int *)st->scales;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ /* Values are stored in a 2D matrix */
+ *length = info->num_scales * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
{
int ret;
@@ -371,6 +399,26 @@ static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode)
AN877_ADC_TRANSFER_SYNC);
}
+static int ad9467_scale_fill(struct adi_axi_adc_conv *conv)
+{
+ const struct adi_axi_adc_chip_info *info = conv->chip_info;
+ struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
+ unsigned int i, val1, val2;
+
+ st->scales = devm_kmalloc_array(&st->spi->dev, info->num_scales,
+ sizeof(*st->scales), GFP_KERNEL);
+ if (!st->scales)
+ return -ENOMEM;
+
+ for (i = 0; i < info->num_scales; i++) {
+ __ad9467_get_scale(conv, i, &val1, &val2);
+ st->scales[i][0] = val1;
+ st->scales[i][1] = val2;
+ }
+
+ return 0;
+}
+
static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
{
struct ad9467_state *st = adi_axi_adc_conv_priv(conv);
@@ -378,11 +426,19 @@ static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
return ad9467_outputmode_set(st->spi, st->output_mode);
}
-static void ad9467_clk_disable(void *data)
+static int ad9467_reset(struct device *dev)
{
- struct ad9467_state *st = data;
+ struct gpio_desc *gpio;
- clk_disable_unprepare(st->clk);
+ gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR_OR_NULL(gpio))
+ return PTR_ERR_OR_ZERO(gpio);
+
+ fsleep(1);
+ gpiod_set_value_cansleep(gpio, 0);
+ fsleep(10 * USEC_PER_MSEC);
+
+ return 0;
}
static int ad9467_probe(struct spi_device *spi)
@@ -404,38 +460,25 @@ static int ad9467_probe(struct spi_device *spi)
st = adi_axi_adc_conv_priv(conv);
st->spi = spi;
- st->clk = devm_clk_get(&spi->dev, "adc-clk");
+ st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
if (IS_ERR(st->clk))
return PTR_ERR(st->clk);
- ret = clk_prepare_enable(st->clk);
- if (ret < 0)
- return ret;
-
- ret = devm_add_action_or_reset(&spi->dev, ad9467_clk_disable, st);
- if (ret)
- return ret;
-
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
GPIOD_OUT_LOW);
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);
- ret = gpiod_direction_output(st->reset_gpio, 1);
- if (ret)
- return ret;
- mdelay(10);
- }
+ ret = ad9467_reset(&spi->dev);
+ if (ret)
+ return ret;
conv->chip_info = &info->axi_adc_info;
+ ret = ad9467_scale_fill(conv);
+ if (ret)
+ return ret;
+
id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID);
if (id != conv->chip_info->id) {
dev_err(&spi->dev, "Mismatch CHIP_ID, got 0x%X, expected 0x%X\n",
@@ -446,6 +489,7 @@ static int ad9467_probe(struct spi_device *spi)
conv->reg_access = ad9467_reg_access;
conv->write_raw = ad9467_write_raw;
conv->read_raw = ad9467_read_raw;
+ conv->read_avail = ad9467_read_avail;
conv->preenable_setup = ad9467_preenable_setup;
st->output_mode = info->default_output_mode |