Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/iio/adc/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 44 kB image not shown  

Quelle  ad7606.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * AD7606 SPI ADC driver
 *
 * Copyright 2011 Analog Devices Inc.
 */


#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regulator/consumer.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/units.h>
#include <linux/util_macros.h>

#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>

#include "ad7606.h"

#define AD7606_CALIB_GAIN_MIN 0
#define AD7606_CALIB_GAIN_STEP 1024
#define AD7606_CALIB_GAIN_MAX (63 * AD7606_CALIB_GAIN_STEP)

/*
 * Scales are computed as 5000/32768 and 10000/32768 respectively,
 * so that when applied to the raw values they provide mV values.
 * The scale arrays are kept as IIO_VAL_INT_PLUS_MICRO, so index
 * X is the integer part and X + 1 is the fractional part.
 */

static const unsigned int ad7606_16bit_hw_scale_avail[2][2] = {
 { 0, 152588 }, { 0, 305176 }
};

static const unsigned int ad7606_18bit_hw_scale_avail[2][2] = {
 { 0, 38147 }, { 0, 76294 }
};

static const unsigned int ad7606c_16bit_single_ended_unipolar_scale_avail[3][2] = {
 { 0, 76294 }, { 0, 152588 }, { 0, 190735 }
};

static const unsigned int ad7606c_16bit_single_ended_bipolar_scale_avail[5][2] = {
 { 0, 76294 }, { 0, 152588 }, { 0, 190735 }, { 0, 305176 }, { 0, 381470 }
};

static const unsigned int ad7606c_16bit_differential_bipolar_scale_avail[4][2] = {
 { 0, 152588 }, { 0, 305176 }, { 0, 381470 }, { 0, 610352 }
};

static const unsigned int ad7606c_18bit_single_ended_unipolar_scale_avail[3][2] = {
 { 0, 19073 }, { 0, 38147 }, { 0, 47684 }
};

static const unsigned int ad7606c_18bit_single_ended_bipolar_scale_avail[5][2] = {
 { 0, 19073 }, { 0, 38147 }, { 0, 47684 }, { 0, 76294 }, { 0, 95367 }
};

static const unsigned int ad7606c_18bit_differential_bipolar_scale_avail[4][2] = {
 { 0, 38147 }, { 0, 76294 }, { 0, 95367 }, { 0, 152588 }
};

static const unsigned int ad7606_16bit_sw_scale_avail[3][2] = {
 { 0, 76293 }, { 0, 152588 }, { 0, 305176 }
};

static const unsigned int ad7607_hw_scale_avail[2][2] = {
 { 0, 610352 }, { 1, 220703 }
};

static const unsigned int ad7609_hw_scale_avail[2][2] = {
 { 0, 152588 }, { 0, 305176 }
};

static const unsigned int ad7606_oversampling_avail[7] = {
 1, 2, 4, 8, 16, 32, 64,
};

static const unsigned int ad7606b_oversampling_avail[9] = {
 1, 2, 4, 8, 16, 32, 64, 128, 256,
};

static const unsigned int ad7616_oversampling_avail[8] = {
 1, 2, 4, 8, 16, 32, 64, 128,
};

static const int ad7606_calib_offset_avail[3] = {
 -128, 1, 127,
};

static const int ad7606c_18bit_calib_offset_avail[3] = {
 -512, 4, 508,
};

static const int ad7606b_calib_phase_avail[][2] = {
 { 0, 0 }, { 0, 1250 }, { 0, 318750 },
};

static const int ad7606c_calib_phase_avail[][2] = {
 { 0, 0 }, { 0, 1000 }, { 0, 255000 },
};

static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan);
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan);
static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
      struct iio_chan_spec *chan);
static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan);
static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan);
static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan);
static int ad7616_sw_mode_setup(struct iio_dev *indio_dev);
static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev);

const struct ad7606_chip_info ad7605_4_info = {
 .max_samplerate = 300 * KILO,
 .name = "ad7605-4",
 .bits = 16,
 .num_adc_channels = 4,
 .scale_setup_cb = ad7606_16bit_chan_scale_setup,
};
EXPORT_SYMBOL_NS_GPL(ad7605_4_info, "IIO_AD7606");

const struct ad7606_chip_info ad7606_8_info = {
 .max_samplerate = 200 * KILO,
 .name = "ad7606-8",
 .bits = 16,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7606_16bit_chan_scale_setup,
};
EXPORT_SYMBOL_NS_GPL(ad7606_8_info, "IIO_AD7606");

const struct ad7606_chip_info ad7606_6_info = {
 .max_samplerate = 200 * KILO,
 .name = "ad7606-6",
 .bits = 16,
 .num_adc_channels = 6,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7606_16bit_chan_scale_setup,
 .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606_6_info, "IIO_AD7606");

const struct ad7606_chip_info ad7606_4_info = {
 .max_samplerate = 200 * KILO,
 .name = "ad7606-4",
 .bits = 16,
 .num_adc_channels = 4,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7606_16bit_chan_scale_setup,
 .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7606_4_info, "IIO_AD7606");

const struct ad7606_chip_info ad7606b_info = {
 .max_samplerate = 800 * KILO,
 .name = "ad7606b",
 .bits = 16,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7606_16bit_chan_scale_setup,
 .sw_setup_cb = ad7606b_sw_mode_setup,
 .offload_storagebits = 32,
 .calib_gain_avail = true,
 .calib_offset_avail = ad7606_calib_offset_avail,
 .calib_phase_avail = ad7606b_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");

const struct ad7606_chip_info ad7606c_16_info = {
 .max_samplerate = 1 * MEGA,
 .name = "ad7606c16",
 .bits = 16,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7606c_16bit_chan_scale_setup,
 .sw_setup_cb = ad7606b_sw_mode_setup,
 .offload_storagebits = 32,
 .calib_gain_avail = true,
 .calib_offset_avail = ad7606_calib_offset_avail,
 .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");

const struct ad7606_chip_info ad7607_info = {
 .max_samplerate = 200 * KILO,
 .name = "ad7607",
 .bits = 14,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7607_chan_scale_setup,
 .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7607_info, "IIO_AD7606");

const struct ad7606_chip_info ad7608_info = {
 .max_samplerate = 200 * KILO,
 .name = "ad7608",
 .bits = 18,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7608_chan_scale_setup,
 .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7608_info, "IIO_AD7606");

const struct ad7606_chip_info ad7609_info = {
 .max_samplerate = 200 * KILO,
 .name = "ad7609",
 .bits = 18,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7609_chan_scale_setup,
 .offload_storagebits = 32,
};
EXPORT_SYMBOL_NS_GPL(ad7609_info, "IIO_AD7606");

const struct ad7606_chip_info ad7606c_18_info = {
 .max_samplerate = 1 * MEGA,
 .name = "ad7606c18",
 .bits = 18,
 .num_adc_channels = 8,
 .oversampling_avail = ad7606_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7606_oversampling_avail),
 .scale_setup_cb = ad7606c_18bit_chan_scale_setup,
 .sw_setup_cb = ad7606b_sw_mode_setup,
 .offload_storagebits = 32,
 .calib_gain_avail = true,
 .calib_offset_avail = ad7606c_18bit_calib_offset_avail,
 .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");

const struct ad7606_chip_info ad7616_info = {
 .max_samplerate = 1 * MEGA,
 .init_delay_ms = 15,
 .name = "ad7616",
 .bits = 16,
 .num_adc_channels = 16,
 .oversampling_avail = ad7616_oversampling_avail,
 .oversampling_num = ARRAY_SIZE(ad7616_oversampling_avail),
 .os_req_reset = true,
 .scale_setup_cb = ad7606_16bit_chan_scale_setup,
 .sw_setup_cb = ad7616_sw_mode_setup,
 .offload_storagebits = 16,
};
EXPORT_SYMBOL_NS_GPL(ad7616_info, "IIO_AD7606");

int ad7606_reset(struct ad7606_state *st)
{
 if (st->gpio_reset) {
  gpiod_set_value(st->gpio_reset, 1);
  ndelay(100); /* t_reset >= 100ns */
  gpiod_set_value(st->gpio_reset, 0);
  return 0;
 }

 return -ENODEV;
}
EXPORT_SYMBOL_NS_GPL(ad7606_reset, "IIO_AD7606");

static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
      struct iio_chan_spec *chan)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];

 if (!st->sw_mode_en) {
  /* tied to logic low, analog input range is +/- 5V */
  ci->range = 0;
  ci->scale_avail = ad7606_16bit_hw_scale_avail;
  ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
  return 0;
 }

 /* Scale of 0.076293 is only available in sw mode */
 /* After reset, in software mode, ±10 V is set by default */
 ci->range = 2;
 ci->scale_avail = ad7606_16bit_sw_scale_avail;
 ci->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);

 return 0;
}

static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
      bool *bipolar, bool *differential)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci;
 unsigned int num_channels = st->chip_info->num_adc_channels;
 struct device *dev = st->dev;
 int ret;

 *bipolar = false;
 *differential = false;

 device_for_each_child_node_scoped(dev, child) {
  u32 pins[2];
  int reg;

  ret = fwnode_property_read_u32(child, "reg", ®);
  if (ret)
   return ret;

  /* channel number (here) is from 1 to num_channels */
  if (reg < 1 || reg > num_channels)
   return -EINVAL;

  /* Loop until we are in the right channel. */
  if (reg != (ch + 1))
   continue;

  *bipolar = fwnode_property_read_bool(child, "bipolar");

  ret = fwnode_property_read_u32_array(child, "diff-channels",
           pins, ARRAY_SIZE(pins));
  /* Channel is differential, if pins are the same as 'reg' */
  if (ret == 0 && (pins[0] != reg || pins[1] != reg)) {
   dev_err(dev,
    "Differential pins must be the same as 'reg'");
   return -EINVAL;
  }

  *differential = (ret == 0);

  if (*differential && !*bipolar) {
   dev_err(dev,
    "'bipolar' must be added for diff channel %d\n",
    reg);
   return -EINVAL;
  }

  ci = &st->chan_info[reg - 1];

  ci->r_gain = 0;
  ret = fwnode_property_read_u32(child, "adi,rfilter-ohms",
            &ci->r_gain);
  if (ret == 0 && ci->r_gain > AD7606_CALIB_GAIN_MAX)
   return -EINVAL;

  return 0;
 }

 return 0;
}

static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
 bool bipolar, differential;
 int ret;

 if (!st->sw_mode_en) {
  ci->range = 0;
  ci->scale_avail = ad7606_18bit_hw_scale_avail;
  ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
  return 0;
 }

 ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar,
         &differential);
 if (ret)
  return ret;

 if (differential) {
  ci->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
  ci->num_scales =
   ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail);
  /* Bipolar differential ranges start at 8 (b1000) */
  ci->reg_offset = 8;
  ci->range = 1;
  chan->differential = 1;
  chan->channel2 = chan->channel;

  return 0;
 }

 chan->differential = 0;

 if (bipolar) {
  ci->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
  ci->num_scales =
   ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail);
  /* Bipolar single-ended ranges start at 0 (b0000) */
  ci->reg_offset = 0;
  ci->range = 3;
  chan->scan_type.sign = 's';

  return 0;
 }

 ci->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
 ci->num_scales =
  ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail);
 /* Unipolar single-ended ranges start at 5 (b0101) */
 ci->reg_offset = 5;
 ci->range = 1;
 chan->scan_type.sign = 'u';

 return 0;
}

static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
 bool bipolar, differential;
 int ret;

 if (!st->sw_mode_en) {
  ci->range = 0;
  ci->scale_avail = ad7606_16bit_hw_scale_avail;
  ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
  return 0;
 }

 ret = ad7606_get_chan_config(indio_dev, chan->scan_index, &bipolar,
         &differential);
 if (ret)
  return ret;

 if (differential) {
  ci->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
  ci->num_scales =
   ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail);
  /* Bipolar differential ranges start at 8 (b1000) */
  ci->reg_offset = 8;
  ci->range = 1;
  chan->differential = 1;
  chan->channel2 = chan->channel;
  chan->scan_type.sign = 's';

  return 0;
 }

 chan->differential = 0;

 if (bipolar) {
  ci->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
  ci->num_scales =
   ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail);
  /* Bipolar single-ended ranges start at 0 (b0000) */
  ci->reg_offset = 0;
  ci->range = 3;
  chan->scan_type.sign = 's';

  return 0;
 }

 ci->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
 ci->num_scales =
  ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail);
 /* Unipolar single-ended ranges start at 5 (b0101) */
 ci->reg_offset = 5;
 ci->range = 1;
 chan->scan_type.sign = 'u';

 return 0;
}

static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];

 ci->range = 0;
 ci->scale_avail = ad7607_hw_scale_avail;
 ci->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
 return 0;
}

static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];

 ci->range = 0;
 ci->scale_avail = ad7606_18bit_hw_scale_avail;
 ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
 return 0;
}

static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
       struct iio_chan_spec *chan)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];

 ci->range = 0;
 ci->scale_avail = ad7609_hw_scale_avail;
 ci->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
 return 0;
}

static int ad7606_reg_access(struct iio_dev *indio_dev,
        unsigned int reg,
        unsigned int writeval,
        unsigned int *readval)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 int ret;

 guard(mutex)(&st->lock);

 if (readval) {
  ret = st->bops->reg_read(st, reg);
  if (ret < 0)
   return ret;
  *readval = ret;
  return 0;
 } else {
  return st->bops->reg_write(st, reg, writeval);
 }
}

static int ad7606_pwm_set_high(struct ad7606_state *st)
{
 struct pwm_state cnvst_pwm_state;
 int ret;

 pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
 cnvst_pwm_state.enabled = true;
 cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;

 ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);

 return ret;
}

int ad7606_pwm_set_low(struct ad7606_state *st)
{
 struct pwm_state cnvst_pwm_state;
 int ret;

 pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
 cnvst_pwm_state.enabled = true;
 cnvst_pwm_state.duty_cycle = 0;

 ret = pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);

 return ret;
}
EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_low, "IIO_AD7606");

int ad7606_pwm_set_swing(struct ad7606_state *st)
{
 struct pwm_state cnvst_pwm_state;

 pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
 cnvst_pwm_state.enabled = true;
 cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;

 return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
}
EXPORT_SYMBOL_NS_GPL(ad7606_pwm_set_swing, "IIO_AD7606");

static bool ad7606_pwm_is_swinging(struct ad7606_state *st)
{
 struct pwm_state cnvst_pwm_state;

 pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);

 return cnvst_pwm_state.duty_cycle != cnvst_pwm_state.period &&
        cnvst_pwm_state.duty_cycle != 0;
}

static int ad7606_set_sampling_freq(struct ad7606_state *st, unsigned long freq)
{
 struct pwm_state cnvst_pwm_state;
 bool is_swinging = ad7606_pwm_is_swinging(st);
 bool is_high;

 if (freq == 0)
  return -EINVAL;

 /* Retrieve the previous state. */
 pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
 is_high = cnvst_pwm_state.duty_cycle == cnvst_pwm_state.period;

 cnvst_pwm_state.period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, freq);
 cnvst_pwm_state.polarity = PWM_POLARITY_NORMAL;
 if (is_high)
  cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period;
 else if (is_swinging)
  cnvst_pwm_state.duty_cycle = cnvst_pwm_state.period / 2;
 else
  cnvst_pwm_state.duty_cycle = 0;

 return pwm_apply_might_sleep(st->cnvst_pwm, &cnvst_pwm_state);
}

static int ad7606_read_samples(struct ad7606_state *st)
{
 unsigned int num = st->chip_info->num_adc_channels;

 return st->bops->read_block(st->dev, num, &st->data);
}

static irqreturn_t ad7606_trigger_handler(int irq, void *p)
{
 struct iio_poll_func *pf = p;
 struct iio_dev *indio_dev = pf->indio_dev;
 struct ad7606_state *st = iio_priv(indio_dev);
 int ret;

 guard(mutex)(&st->lock);

 ret = ad7606_read_samples(st);
 if (ret)
  goto error_ret;

 iio_push_to_buffers_with_ts(indio_dev, &st->data, sizeof(st->data),
        iio_get_time_ns(indio_dev));
error_ret:
 iio_trigger_notify_done(indio_dev->trig);
 /* The rising edge of the CONVST signal starts a new conversion. */
 gpiod_set_value(st->gpio_convst, 1);

 return IRQ_HANDLED;
}

static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
         int *val)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 const struct iio_chan_spec *chan;
 unsigned int realbits;
 int ret;

 if (st->gpio_convst) {
  gpiod_set_value(st->gpio_convst, 1);
 } else {
  ret = ad7606_pwm_set_high(st);
  if (ret < 0)
   return ret;
 }

 /*
 * If no backend, wait for the interruption on busy pin, otherwise just add
 * a delay to leave time for the data to be available. For now, the latter
 * will not happen because IIO_CHAN_INFO_RAW is not supported for the backend.
 * TODO: Add support for reading a single value when the backend is used.
 */

 if (st->trig) {
  ret = wait_for_completion_timeout(&st->completion,
        msecs_to_jiffies(1000));
  if (!ret) {
   ret = -ETIMEDOUT;
   goto error_ret;
  }
 } else {
  /*
 * If the BUSY interrupt is not available, wait enough time for
 * the longest possible conversion (max for the whole family is
 * around 350us).
 */

  fsleep(400);
 }

 ret = ad7606_read_samples(st);
 if (ret)
  goto error_ret;

 chan = &indio_dev->channels[ch];
 realbits = chan->scan_type.realbits;

 if (realbits > 16)
  *val = st->data.buf32[ch];
 else
  *val = st->data.buf16[ch];

 *val &= GENMASK(realbits - 1, 0);

 if (chan->scan_type.sign == 's')
  *val = sign_extend32(*val, realbits - 1);

error_ret:
 if (!st->gpio_convst) {
  ret = ad7606_pwm_set_low(st);
  if (ret < 0)
   return ret;
 }
 gpiod_set_value(st->gpio_convst, 0);

 return ret;
}

static int ad7606_get_calib_offset(struct ad7606_state *st, int ch, int *val)
{
 int ret;

 ret = st->bops->reg_read(st, AD7606_CALIB_OFFSET(ch));
 if (ret < 0)
  return ret;

 *val = st->chip_info->calib_offset_avail[0] +
        ret * st->chip_info->calib_offset_avail[1];

 return 0;
}

static int ad7606_get_calib_phase(struct ad7606_state *st, int ch, int *val,
      int *val2)
{
 int ret;

 ret = st->bops->reg_read(st, AD7606_CALIB_PHASE(ch));
 if (ret < 0)
  return ret;

 *val = 0;

 /*
 * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
 * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
 */

 *val2 = ret * st->chip_info->calib_phase_avail[1][1];

 return 0;
}

static int ad7606_read_raw(struct iio_dev *indio_dev,
      struct iio_chan_spec const *chan,
      int *val,
      int *val2,
      long m)
{
 int ret, ch = 0;
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci;
 struct pwm_state cnvst_pwm_state;

 switch (m) {
 case IIO_CHAN_INFO_RAW:
  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = ad7606_scan_direct(indio_dev, chan->scan_index, val);
  iio_device_release_direct(indio_dev);
  if (ret < 0)
   return ret;
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_SCALE:
  if (st->sw_mode_en)
   ch = chan->scan_index;
  ci = &st->chan_info[ch];
  *val = ci->scale_avail[ci->range][0];
  *val2 = ci->scale_avail[ci->range][1];
  return IIO_VAL_INT_PLUS_MICRO;
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
  *val = st->oversampling;
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_SAMP_FREQ:
  pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
  *val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_CALIBBIAS:
  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = ad7606_get_calib_offset(st, chan->scan_index, val);
  iio_device_release_direct(indio_dev);
  if (ret)
   return ret;
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_CONVDELAY:
  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = ad7606_get_calib_phase(st, chan->scan_index, val, val2);
  iio_device_release_direct(indio_dev);
  if (ret)
   return ret;
  return IIO_VAL_INT_PLUS_NANO;
 }
 return -EINVAL;
}

static ssize_t in_voltage_scale_available_show(struct device *dev,
            struct device_attribute *attr,
            char *buf)
{
 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci = &st->chan_info[0];
 const unsigned int (*vals)[2] = ci->scale_avail;
 unsigned int i;
 size_t len = 0;

 for (i = 0; i < ci->num_scales; i++)
  len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
     vals[i][0], vals[i][1]);
 buf[len - 1] = '\n';

 return len;
}

static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);

static int ad7606_write_scale_hw(struct iio_dev *indio_dev, int ch, int val)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 gpiod_set_value(st->gpio_range, val);

 return 0;
}

static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 DECLARE_BITMAP(values, 3);

 values[0] = val & GENMASK(2, 0);

 gpiod_multi_set_value_cansleep(st->gpio_os, values);

 /* AD7616 requires a reset to update value */
 if (st->chip_info->os_req_reset)
  ad7606_reset(st);

 return 0;
}

static int ad7606_set_calib_offset(struct ad7606_state *st, int ch, int val)
{
 int start_val, step_val, stop_val;
 int offset;

 start_val = st->chip_info->calib_offset_avail[0];
 step_val = st->chip_info->calib_offset_avail[1];
 stop_val = st->chip_info->calib_offset_avail[2];

 if (val < start_val || val > stop_val)
  return -EINVAL;

 offset = (val - start_val) / step_val;

 return st->bops->reg_write(st, AD7606_CALIB_OFFSET(ch), offset);
}

static int ad7606_set_calib_phase(struct ad7606_state *st, int ch, int val,
      int val2)
{
 int wreg, start_ns, step_ns, stop_ns;

 if (val != 0)
  return -EINVAL;

 start_ns = st->chip_info->calib_phase_avail[0][1];
 step_ns = st->chip_info->calib_phase_avail[1][1];
 stop_ns = st->chip_info->calib_phase_avail[2][1];

 /*
 * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
 * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
 */

 if (val2 < start_ns || val2 > stop_ns)
  return -EINVAL;

 wreg = val2 / step_ns;

 return st->bops->reg_write(st, AD7606_CALIB_PHASE(ch), wreg);
}

static int ad7606_write_raw_get_fmt(struct iio_dev *indio_dev,
        struct iio_chan_spec const *chan, long info)
{
 switch (info) {
 case IIO_CHAN_INFO_SCALE:
  return IIO_VAL_INT_PLUS_MICRO;
 case IIO_CHAN_INFO_SAMP_FREQ:
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
 case IIO_CHAN_INFO_CALIBBIAS:
  return IIO_VAL_INT;
 case IIO_CHAN_INFO_CONVDELAY:
  return IIO_VAL_INT_PLUS_NANO;
 default:
  return -EINVAL;
 }
}

static int ad7606_write_raw(struct iio_dev *indio_dev,
       struct iio_chan_spec const *chan,
       int val,
       int val2,
       long mask)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 unsigned int scale_avail_uv[AD760X_MAX_SCALES];
 struct ad7606_chan_info *ci;
 int i, ret, ch = 0;

 guard(mutex)(&st->lock);

 switch (mask) {
 case IIO_CHAN_INFO_SCALE:
  if (st->sw_mode_en)
   ch = chan->scan_index;
  ci = &st->chan_info[ch];
  for (i = 0; i < ci->num_scales; i++) {
   scale_avail_uv[i] = ci->scale_avail[i][0] * MICRO +
         ci->scale_avail[i][1];
  }
  val = (val * MICRO) + val2;
  i = find_closest(val, scale_avail_uv, ci->num_scales);

  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = st->write_scale(indio_dev, ch, i + ci->reg_offset);
  iio_device_release_direct(indio_dev);
  if (ret < 0)
   return ret;
  ci->range = i;

  return 0;
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
  if (val2)
   return -EINVAL;
  i = find_closest(val, st->oversampling_avail,
     st->num_os_ratios);

  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = st->write_os(indio_dev, i);
  iio_device_release_direct(indio_dev);
  if (ret < 0)
   return ret;
  st->oversampling = st->oversampling_avail[i];

  return 0;
 case IIO_CHAN_INFO_SAMP_FREQ:
  if (val < 0 && val2 != 0)
   return -EINVAL;
  return ad7606_set_sampling_freq(st, val);
 case IIO_CHAN_INFO_CALIBBIAS:
  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = ad7606_set_calib_offset(st, chan->scan_index, val);
  iio_device_release_direct(indio_dev);
  return ret;
 case IIO_CHAN_INFO_CONVDELAY:
  if (!iio_device_claim_direct(indio_dev))
   return -EBUSY;
  ret = ad7606_set_calib_phase(st, chan->scan_index, val, val2);
  iio_device_release_direct(indio_dev);
  return ret;
 default:
  return -EINVAL;
 }
}

static ssize_t ad7606_oversampling_ratio_avail(struct device *dev,
            struct device_attribute *attr,
            char *buf)
{
 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 struct ad7606_state *st = iio_priv(indio_dev);
 const unsigned int *vals = st->oversampling_avail;
 unsigned int i;
 size_t len = 0;

 for (i = 0; i < st->num_os_ratios; i++)
  len += scnprintf(buf + len, PAGE_SIZE - len, "%u ", vals[i]);
 buf[len - 1] = '\n';

 return len;
}

static IIO_DEVICE_ATTR(oversampling_ratio_available, 0444,
         ad7606_oversampling_ratio_avail, NULL, 0);

static struct attribute *ad7606_attributes_os_and_range[] = {
 &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
 &iio_dev_attr_oversampling_ratio_available.dev_attr.attr,
 NULL,
};

static const struct attribute_group ad7606_attribute_group_os_and_range = {
 .attrs = ad7606_attributes_os_and_range,
};

static struct attribute *ad7606_attributes_os[] = {
 &iio_dev_attr_oversampling_ratio_available.dev_attr.attr,
 NULL,
};

static const struct attribute_group ad7606_attribute_group_os = {
 .attrs = ad7606_attributes_os,
};

static struct attribute *ad7606_attributes_range[] = {
 &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
 NULL,
};

static const struct attribute_group ad7606_attribute_group_range = {
 .attrs = ad7606_attributes_range,
};

static int ad7606_request_gpios(struct ad7606_state *st)
{
 struct device *dev = st->dev;

 st->gpio_convst = devm_gpiod_get_optional(dev, "adi,conversion-start",
        GPIOD_OUT_LOW);

 if (IS_ERR(st->gpio_convst))
  return PTR_ERR(st->gpio_convst);

 st->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 if (IS_ERR(st->gpio_reset))
  return PTR_ERR(st->gpio_reset);

 st->gpio_range = devm_gpiod_get_optional(dev, "adi,range",
       GPIOD_OUT_LOW);
 if (IS_ERR(st->gpio_range))
  return PTR_ERR(st->gpio_range);

 st->gpio_standby = devm_gpiod_get_optional(dev, "standby",
         GPIOD_OUT_LOW);
 if (IS_ERR(st->gpio_standby))
  return PTR_ERR(st->gpio_standby);

 st->gpio_frstdata = devm_gpiod_get_optional(dev, "adi,first-data",
          GPIOD_IN);
 if (IS_ERR(st->gpio_frstdata))
  return PTR_ERR(st->gpio_frstdata);

 if (!st->chip_info->oversampling_num)
  return 0;

 st->gpio_os = devm_gpiod_get_array_optional(dev,
          "adi,oversampling-ratio",
          GPIOD_OUT_LOW);
 return PTR_ERR_OR_ZERO(st->gpio_os);
}

/*
 * The BUSY signal indicates when conversions are in progress, so when a rising
 * edge of CONVST is applied, BUSY goes logic high and transitions low at the
 * end of the entire conversion process. The falling edge of the BUSY signal
 * triggers this interrupt.
 */

static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
{
 struct iio_dev *indio_dev = dev_id;
 struct ad7606_state *st = iio_priv(indio_dev);
 int ret;

 if (iio_buffer_enabled(indio_dev)) {
  if (st->gpio_convst) {
   gpiod_set_value(st->gpio_convst, 0);
  } else {
   ret = ad7606_pwm_set_low(st);
   if (ret < 0) {
    dev_err(st->dev, "PWM set low failed");
    goto done;
   }
  }
  iio_trigger_poll_nested(st->trig);
 } else {
  complete(&st->completion);
 }

done:
 return IRQ_HANDLED;
};

static int ad7606_validate_trigger(struct iio_dev *indio_dev,
       struct iio_trigger *trig)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 if (st->trig != trig)
  return -EINVAL;

 return 0;
}

static int ad7606_buffer_postenable(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 gpiod_set_value(st->gpio_convst, 1);

 return 0;
}

static int ad7606_buffer_predisable(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 gpiod_set_value(st->gpio_convst, 0);

 return 0;
}

static int ad7606_read_avail(struct iio_dev *indio_dev,
        struct iio_chan_spec const *chan,
        const int **vals, int *type, int *length,
        long info)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct ad7606_chan_info *ci;
 unsigned int ch = 0;

 switch (info) {
 case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
  *vals = st->oversampling_avail;
  *length = st->num_os_ratios;
  *type = IIO_VAL_INT;

  return IIO_AVAIL_LIST;

 case IIO_CHAN_INFO_SCALE:
  if (st->sw_mode_en)
   ch = chan->scan_index;

  ci = &st->chan_info[ch];
  *vals = (int *)ci->scale_avail;
  *length = ci->num_scales * 2;
  *type = IIO_VAL_INT_PLUS_MICRO;

  return IIO_AVAIL_LIST;
 case IIO_CHAN_INFO_CALIBBIAS:
  *vals = st->chip_info->calib_offset_avail;
  *type = IIO_VAL_INT;
  return IIO_AVAIL_RANGE;
 case IIO_CHAN_INFO_CONVDELAY:
  *vals = (const int *)st->chip_info->calib_phase_avail;
  *type = IIO_VAL_INT_PLUS_NANO;
  return IIO_AVAIL_RANGE;
 }
 return -EINVAL;
}

static int ad7606_backend_buffer_postenable(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 return ad7606_pwm_set_swing(st);
}

static int ad7606_backend_buffer_predisable(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 return ad7606_pwm_set_low(st);
}

static int ad7606_update_scan_mode(struct iio_dev *indio_dev,
       const unsigned long *scan_mask)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 /*
 * The update scan mode is only for iio backend compatible drivers.
 * If the specific update_scan_mode is not defined in the bus ops,
 * just do nothing and return 0.
 */

 if (!st->bops->update_scan_mode)
  return 0;

 return st->bops->update_scan_mode(indio_dev, scan_mask);
}

static const struct iio_buffer_setup_ops ad7606_buffer_ops = {
 .postenable = &ad7606_buffer_postenable,
 .predisable = &ad7606_buffer_predisable,
};

static const struct iio_buffer_setup_ops ad7606_backend_buffer_ops = {
 .postenable = &ad7606_backend_buffer_postenable,
 .predisable = &ad7606_backend_buffer_predisable,
};

static const struct iio_info ad7606_info_no_os_or_range = {
 .read_raw = &ad7606_read_raw,
 .validate_trigger = &ad7606_validate_trigger,
 .update_scan_mode = &ad7606_update_scan_mode,
};

static const struct iio_info ad7606_info_os_and_range = {
 .read_raw = &ad7606_read_raw,
 .write_raw = &ad7606_write_raw,
 .attrs = &ad7606_attribute_group_os_and_range,
 .validate_trigger = &ad7606_validate_trigger,
 .update_scan_mode = &ad7606_update_scan_mode,
};

static const struct iio_info ad7606_info_sw_mode = {
 .read_raw = &ad7606_read_raw,
 .write_raw = &ad7606_write_raw,
 .read_avail = &ad7606_read_avail,
 .write_raw_get_fmt = ad7606_write_raw_get_fmt,
 .debugfs_reg_access = &ad7606_reg_access,
 .validate_trigger = &ad7606_validate_trigger,
 .update_scan_mode = &ad7606_update_scan_mode,
};

static const struct iio_info ad7606_info_os = {
 .read_raw = &ad7606_read_raw,
 .write_raw = &ad7606_write_raw,
 .attrs = &ad7606_attribute_group_os,
 .validate_trigger = &ad7606_validate_trigger,
 .update_scan_mode = &ad7606_update_scan_mode,
};

static const struct iio_info ad7606_info_range = {
 .read_raw = &ad7606_read_raw,
 .write_raw = &ad7606_write_raw,
 .attrs = &ad7606_attribute_group_range,
 .validate_trigger = &ad7606_validate_trigger,
 .update_scan_mode = &ad7606_update_scan_mode,
};

static const struct iio_trigger_ops ad7606_trigger_ops = {
 .validate_device = iio_trigger_validate_own_device,
};

static int ad7606_write_mask(struct ad7606_state *st, unsigned int addr,
        unsigned long mask, unsigned int val)
{
 int readval;

 readval = st->bops->reg_read(st, addr);
 if (readval < 0)
  return readval;

 readval &= ~mask;
 readval |= val;

 return st->bops->reg_write(st, addr, readval);
}

static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 unsigned int ch_addr, mode, ch_index;

 /*
 * Ad7616 has 16 channels divided in group A and group B.
 * The range of channels from A are stored in registers with address 4
 * while channels from B are stored in register with address 6.
 * The last bit from channels determines if it is from group A or B
 * because the order of channels in iio is 0A, 0B, 1A, 1B...
 */

 ch_index = ch >> 1;

 ch_addr = AD7616_RANGE_CH_ADDR(ch_index);

 if ((ch & 0x1) == 0) /* channel A */
  ch_addr += AD7616_RANGE_CH_A_ADDR_OFF;
 else /* channel B */
  ch_addr += AD7616_RANGE_CH_B_ADDR_OFF;

 /* 0b01 for 2.5v, 0b10 for 5v and 0b11 for 10v */
 mode = AD7616_RANGE_CH_MODE(ch_index, ((val + 1) & 0b11));

 return ad7606_write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch_index),
     mode);
}

static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 return ad7606_write_mask(st, AD7616_CONFIGURATION_REGISTER,
     AD7616_OS_MASK, val << 2);
}

static int ad7606_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 return ad7606_write_mask(st, AD7606_RANGE_CH_ADDR(ch),
     AD7606_RANGE_CH_MSK(ch),
     AD7606_RANGE_CH_MODE(ch, val));
}

static int ad7606_write_os_sw(struct iio_dev *indio_dev, int val)
{
 struct ad7606_state *st = iio_priv(indio_dev);

 return st->bops->reg_write(st, AD7606_OS_MODE, val);
}

static int ad7616_sw_mode_setup(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 int ret;

 /*
 * Scale can be configured individually for each channel
 * in software mode.
 */


 st->write_scale = ad7616_write_scale_sw;
 st->write_os = &ad7616_write_os_sw;

 if (st->bops->sw_mode_config) {
  ret = st->bops->sw_mode_config(indio_dev);
  if (ret)
   return ret;
 }

 /* Activate Burst mode and SEQEN MODE */
 return ad7606_write_mask(st, AD7616_CONFIGURATION_REGISTER,
     AD7616_BURST_MODE | AD7616_SEQEN_MODE,
     AD7616_BURST_MODE | AD7616_SEQEN_MODE);
}

static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 DECLARE_BITMAP(os, 3);

 bitmap_fill(os, 3);
 /*
 * Software mode is enabled when all three oversampling
 * pins are set to high. If oversampling gpios are defined
 * in the device tree, then they need to be set to high,
 * otherwise, they must be hardwired to VDD
 */

 if (st->gpio_os)
  gpiod_multi_set_value_cansleep(st->gpio_os, os);

 /* OS of 128 and 256 are available only in software mode */
 st->oversampling_avail = ad7606b_oversampling_avail;
 st->num_os_ratios = ARRAY_SIZE(ad7606b_oversampling_avail);

 st->write_scale = ad7606_write_scale_sw;
 st->write_os = &ad7606_write_os_sw;

 if (!st->bops->sw_mode_config)
  return 0;

 return st->bops->sw_mode_config(indio_dev);
}

static int ad7606_set_gain_calib(struct ad7606_state *st)
{
 struct ad7606_chan_info *ci;
 int i, ret;

 for (i = 0; i < st->chip_info->num_adc_channels; i++) {
  ci = &st->chan_info[i];
  ret = st->bops->reg_write(st, AD7606_CALIB_GAIN(i),
       DIV_ROUND_CLOSEST(ci->r_gain,
      AD7606_CALIB_GAIN_STEP));
  if (ret)
   return ret;
 }

 return 0;
}

static int ad7606_probe_channels(struct iio_dev *indio_dev)
{
 struct ad7606_state *st = iio_priv(indio_dev);
 struct device *dev = indio_dev->dev.parent;
 struct iio_chan_spec *channels;
 bool slow_bus;
 int ret, i;

 slow_bus = !(st->bops->iio_backend_config || st->offload_en);
 indio_dev->num_channels = st->chip_info->num_adc_channels;

 /* Slow buses also get 1 more channel for soft timestamp */
 if (slow_bus)
  indio_dev->num_channels++;

 channels = devm_kcalloc(dev, indio_dev->num_channels, sizeof(*channels),
    GFP_KERNEL);
 if (!channels)
  return -ENOMEM;

 for (i = 0; i < st->chip_info->num_adc_channels; i++) {
  struct iio_chan_spec *chan = &channels[i];

  chan->type = IIO_VOLTAGE;
  chan->indexed = 1;
  chan->channel = i;
  chan->scan_index = i;
  chan->scan_type.sign = 's';
  chan->scan_type.realbits = st->chip_info->bits;
  /*
 * If in SPI offload mode, storagebits are set based
 * on the spi-engine hw implementation.
 */

  chan->scan_type.storagebits = st->offload_en ?
   st->chip_info->offload_storagebits :
   (st->chip_info->bits > 16 ? 32 : 16);

  chan->scan_type.endianness = IIO_CPU;

  if (indio_dev->modes & INDIO_DIRECT_MODE)
   chan->info_mask_separate |= BIT(IIO_CHAN_INFO_RAW);

  if (st->sw_mode_en) {
   chan->info_mask_separate |= BIT(IIO_CHAN_INFO_SCALE);
   chan->info_mask_separate_available |=
    BIT(IIO_CHAN_INFO_SCALE);

   if (st->chip_info->calib_offset_avail) {
    chan->info_mask_separate |=
     BIT(IIO_CHAN_INFO_CALIBBIAS) |
     BIT(IIO_CHAN_INFO_CONVDELAY);
    chan->info_mask_separate_available |=
     BIT(IIO_CHAN_INFO_CALIBBIAS) |
     BIT(IIO_CHAN_INFO_CONVDELAY);
   }

   /*
 * All chips with software mode support oversampling,
 * so we skip the oversampling_available check. And the
 * shared_by_type instead of shared_by_all on slow
 * buses is for backward compatibility.
 */

   if (slow_bus)
    chan->info_mask_shared_by_type |=
     BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
   else
    chan->info_mask_shared_by_all |=
     BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);

   chan->info_mask_shared_by_all_available |=
    BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
  } else {
   chan->info_mask_shared_by_type |=
    BIT(IIO_CHAN_INFO_SCALE);

   if (st->chip_info->oversampling_avail)
    chan->info_mask_shared_by_all |=
     BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO);
  }

  if (!slow_bus)
   chan->info_mask_shared_by_all |=
    BIT(IIO_CHAN_INFO_SAMP_FREQ);

  ret = st->chip_info->scale_setup_cb(indio_dev, chan);
  if (ret)
   return ret;
 }

 if (slow_bus)
  channels[i] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(i);

 indio_dev->channels = channels;

 return 0;
}

static void ad7606_pwm_disable(void *data)
{
 pwm_disable(data);
}

int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
   const struct ad7606_chip_info *chip_info,
   const struct ad7606_bus_ops *bops)
{
 struct ad7606_state *st;
 int ret;
 struct iio_dev *indio_dev;

 indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
 if (!indio_dev)
  return -ENOMEM;

 st = iio_priv(indio_dev);
 dev_set_drvdata(dev, indio_dev);

 ret = devm_mutex_init(dev, &st->lock);
 if (ret)
  return ret;

 st->dev = dev;
 st->bops = bops;
 st->base_address = base_address;
 st->oversampling = 1;
 st->sw_mode_en = device_property_read_bool(dev, "adi,sw-mode");

 if (st->sw_mode_en && !chip_info->sw_setup_cb)
  return dev_err_probe(dev, -EINVAL,
   "Software mode is not supported for this chip\n");

 ret = devm_regulator_get_enable(dev, "avcc");
 if (ret)
  return dev_err_probe(dev, ret,
         "Failed to enable specified AVcc supply\n");

 ret = devm_regulator_get_enable(dev, "vdrive");
 if (ret)
  return dev_err_probe(dev, ret,
         "Failed to enable Vdrive supply\n");

 ret = devm_regulator_get_enable_optional(dev, "refin");
 if (ret && ret != -ENODEV)
  return dev_err_probe(dev, ret,
         "Failed to enable REFIN supply\n");

 st->chip_info = chip_info;

 if (st->chip_info->oversampling_num) {
  st->oversampling_avail = st->chip_info->oversampling_avail;
  st->num_os_ratios = st->chip_info->oversampling_num;
 }

 ret = ad7606_request_gpios(st);
 if (ret)
  return ret;

 if (st->gpio_os) {
  if (st->gpio_range)
   indio_dev->info = &ad7606_info_os_and_range;
  else
   indio_dev->info = &ad7606_info_os;
 } else {
  if (st->gpio_range)
   indio_dev->info = &ad7606_info_range;
  else
   indio_dev->info = &ad7606_info_no_os_or_range;
 }

 /* AXI ADC backend doesn't support single read. */
 indio_dev->modes = st->bops->iio_backend_config ? 0 : INDIO_DIRECT_MODE;
 indio_dev->name = chip_info->name;

 /* Using spi-engine with offload support ? */
 if (st->bops->offload_config) {
  ret = st->bops->offload_config(dev, indio_dev);
  if (ret)
   return ret;
 }

 ret = ad7606_probe_channels(indio_dev);
 if (ret)
  return ret;

 ret = ad7606_reset(st);
 if (ret)
  dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");

 /* AD7616 requires al least 15ms to reconfigure after a reset */
 if (st->chip_info->init_delay_ms) {
  if (msleep_interruptible(st->chip_info->init_delay_ms))
   return -ERESTARTSYS;
 }

 /* If convst pin is not defined, setup PWM. */
 if (!st->gpio_convst || st->offload_en) {
  st->cnvst_pwm = devm_pwm_get(dev, NULL);
  if (IS_ERR(st->cnvst_pwm))
   return PTR_ERR(st->cnvst_pwm);

  /* The PWM is initialized at 1MHz to have a fast enough GPIO emulation. */
  ret = ad7606_set_sampling_freq(st, 1 * MEGA);
  if (ret)
   return ret;

  ret = ad7606_pwm_set_low(st);
  if (ret)
   return ret;

  /*
 * PWM is not disabled when sampling stops, but instead its duty cycle is set
 * to 0% to be sure we have a "low" state. After we unload the driver, let's
 * disable the PWM.
 */

  ret = devm_add_action_or_reset(dev, ad7606_pwm_disable,
            st->cnvst_pwm);
  if (ret)
   return ret;
 }

 if (st->bops->iio_backend_config) {
  /*
 * If there is a backend, the PWM should not overpass the maximum sampling
 * frequency the chip supports.
 */

  ret = ad7606_set_sampling_freq(st, chip_info->max_samplerate);
  if (ret)
   return ret;

  ret = st->bops->iio_backend_config(dev, indio_dev);
  if (ret)
   return ret;

  indio_dev->setup_ops = &ad7606_backend_buffer_ops;
 } else if (!st->offload_en) {
  /* Reserve the PWM use only for backend (force gpio_convst definition) */
  if (!st->gpio_convst)
   return dev_err_probe(dev, -EINVAL,
          "No backend, connect convst to a GPIO");

  init_completion(&st->completion);
  st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
        indio_dev->name,
        iio_device_id(indio_dev));
  if (!st->trig)
   return -ENOMEM;

  st->trig->ops = &ad7606_trigger_ops;
  iio_trigger_set_drvdata(st->trig, indio_dev);
  ret = devm_iio_trigger_register(dev, st->trig);
  if (ret)
   return ret;

  indio_dev->trig = iio_trigger_get(st->trig);

  ret = devm_request_threaded_irq(dev, irq, NULL, &ad7606_interrupt,
      IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
      chip_info->name, indio_dev);
  if (ret)
   return ret;

  ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
            &iio_pollfunc_store_time,
            &ad7606_trigger_handler,
            &ad7606_buffer_ops);
  if (ret)
   return ret;
 }

 st->write_scale = ad7606_write_scale_hw;
 st->write_os = ad7606_write_os_hw;

 /* Offload needs 1 DOUT line, applying this setting in sw_setup_cb. */
 if (st->sw_mode_en || st->offload_en) {
  indio_dev->info = &ad7606_info_sw_mode;
  st->chip_info->sw_setup_cb(indio_dev);
 }

 if (st->sw_mode_en && st->chip_info->calib_gain_avail) {
  ret = ad7606_set_gain_calib(st);
  if (ret)
   return ret;
 }

 return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");

#ifdef CONFIG_PM_SLEEP

static int ad7606_suspend(struct device *dev)
{
 struct iio_dev *indio_dev = dev_get_drvdata(dev);
 struct ad7606_state *st = iio_priv(indio_dev);

 if (st->gpio_standby) {
  gpiod_set_value(st->gpio_range, 1);
  gpiod_set_value(st->gpio_standby, 1);
 }

 return 0;
}

static int ad7606_resume(struct device *dev)
{
 struct iio_dev *indio_dev = dev_get_drvdata(dev);
 struct ad7606_state *st = iio_priv(indio_dev);

 if (st->gpio_standby) {
  gpiod_set_value(st->gpio_range, st->chan_info[0].range);
  gpiod_set_value(st->gpio_standby, 1);
  ad7606_reset(st);
 }

 return 0;
}

SIMPLE_DEV_PM_OPS(ad7606_pm_ops, ad7606_suspend, ad7606_resume);
EXPORT_SYMBOL_NS_GPL(ad7606_pm_ops, "IIO_AD7606");

#endif

MODULE_AUTHOR("Michael Hennerich ");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
MODULE_LICENSE("GPL v2");

Messung V0.5
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.