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,
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_offset_avail = ad7606_calib_offset_avail,
+ .calib_phase_avail = ad7606b_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_offset_avail = ad7606_calib_offset_avail,
+ .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_offset_avail = ad7606c_18bit_calib_offset_avail,
+ .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
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,
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;
}
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,
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;
}
*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;
}
.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,
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