/* * 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.
*/ staticconstunsignedint ad7606_16bit_hw_scale_avail[2][2] = {
{ 0, 152588 }, { 0, 305176 }
};
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);
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;
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);
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;
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;
}
staticint 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;
}
staticint 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;
}
staticint 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;
}
/* * 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;
/* * 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);
}
/* * 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;
readval = st->bops->reg_read(st, addr); if (readval < 0) return readval;
readval &= ~mask;
readval |= val;
return st->bops->reg_write(st, addr, readval);
}
staticint ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{ struct ad7606_state *st = iio_priv(indio_dev); unsignedint 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));
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);
staticint 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;
}
/* * 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);
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;
} elseif (!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");
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.