struct ad7124_channel_config { bool live; unsignedint cfg_slot; /* * Following fields are used to compare for equality. If you * make adaptations in it, you most likely also have to adapt * ad7124_find_similar_live_cfg(), too.
*/
struct_group(config_props, enum ad7124_ref_sel refsel; bool bipolar; bool buf_positive; bool buf_negative; unsignedint vref_mv; unsignedint pga_bits; unsignedint odr; unsignedint odr_sel_bits; unsignedint filter_type; unsignedint calibration_offset; unsignedint calibration_gain;
);
};
struct ad7124_state { conststruct ad7124_chip_info *chip_info; struct ad_sigma_delta sd; struct ad7124_channel *channels; struct regulator *vref[4]; unsignedint adc_control; unsignedint num_channels; struct mutex cfgs_lock; /* lock for configs access */ unsignedlong cfg_slots_status; /* bitmap with slot status (1 means it is used) */
/* * Stores the power-on reset value for the GAIN(x) registers which are * needed for measurements at gain 1 (i.e. CONFIG(x).PGA == 0)
*/ unsignedint gain_default;
DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS);
};
/* * FS[10:0] = fCLK / (fADC x 32) where: * fADC is the output data rate * fCLK is the master clock frequency * FS[10:0] are the bits in the filter register * FS[10:0] can have a value from 1 to 2047
*/
odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * 32); if (odr_sel_bits < 1)
odr_sel_bits = 1; elseif (odr_sel_bits > 2047)
odr_sel_bits = 2047;
if (odr_sel_bits != st->channels[channel].cfg.odr_sel_bits)
st->channels[channel].cfg.live = false;
/* * This is just to make sure that the comparison is adapted after * struct ad7124_channel_config was changed.
*/
static_assert(sizeof_field(struct ad7124_channel_config, config_props) == sizeof(struct { enum ad7124_ref_sel refsel; bool bipolar; bool buf_positive; bool buf_negative; unsignedint vref_mv; unsignedint pga_bits; unsignedint odr; unsignedint odr_sel_bits; unsignedint filter_type; unsignedint calibration_offset; unsignedint calibration_gain;
}));
for (i = 0; i < st->num_channels; i++) {
cfg_aux = &st->channels[i].cfg;
free_cfg_slot = find_first_zero_bit(&st->cfg_slots_status, AD7124_MAX_CONFIGS); if (free_cfg_slot == AD7124_MAX_CONFIGS) return -1;
return free_cfg_slot;
}
/* Only called during probe, so dev_err_probe() can be used */ staticint ad7124_init_config_vref(struct ad7124_state *st, struct ad7124_channel_config *cfg)
{ struct device *dev = &st->sd.spi->dev; unsignedint refsel = cfg->refsel;
switch (refsel) { case AD7124_REFIN1: case AD7124_REFIN2: case AD7124_AVDD_REF: if (IS_ERR(st->vref[refsel])) return dev_err_probe(dev, PTR_ERR(st->vref[refsel]), "Error, trying to use external voltage reference without a %s regulator.\n",
ad7124_ref_names[refsel]);
staticstruct ad7124_channel_config *ad7124_pop_config(struct ad7124_state *st)
{ struct ad7124_channel_config *lru_cfg; struct ad7124_channel_config *cfg; int ret; int i;
/* * Pop least recently used config from the fifo * in order to make room for the new one
*/
ret = kfifo_get(&st->live_cfgs_fifo, &lru_cfg); if (ret <= 0) return NULL;
lru_cfg->live = false;
/* mark slot as free */
assign_bit(lru_cfg->cfg_slot, &st->cfg_slots_status, 0);
/* invalidate all other configs that pointed to this one */ for (i = 0; i < st->num_channels; i++) {
cfg = &st->channels[i].cfg;
if (cfg->cfg_slot == lru_cfg->cfg_slot)
cfg->live = false;
}
free_cfg_slot = ad7124_find_free_config_slot(st); if (free_cfg_slot >= 0) { /* push the new config in configs queue */
kfifo_put(&st->live_cfgs_fifo, cfg);
} else { /* pop one config to make room for the new one */
lru_cfg = ad7124_pop_config(st); if (!lru_cfg) return -EINVAL;
/* push the new config in configs queue */
free_cfg_slot = lru_cfg->cfg_slot;
kfifo_put(&st->live_cfgs_fifo, cfg);
}
/* mark slot as used */
assign_bit(free_cfg_slot, &st->cfg_slots_status, 1);
/* * Before doing any reads assign the channel a configuration. * Check if channel's config is on the device
*/ if (!cfg->live) { /* check if config matches another one */
live_cfg = ad7124_find_similar_live_cfg(st, cfg); if (!live_cfg)
ad7124_push_config(st, cfg); else
cfg->cfg_slot = live_cfg->cfg_slot;
}
/* point channel to the config slot and enable */ return ad7124_enable_channel(st, &st->channels[address]);
}
case IIO_TEMP: /* * According to the data sheet * Temperature (°C) * = ((Conversion − 0x800000)/13584) − 272.5 * = (Conversion − 0x800000 - 13584 * 272.5) / 13584 * = (Conversion − 12090248) / 13584 * So scale with 1000/13584 to yield °mC. Reduce by 8 to * 125/1698.
*/
*val = 125;
*val2 = 1698; return IIO_VAL_FRACTIONAL;
default: return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET: switch (chan->type) { case IIO_VOLTAGE:
mutex_lock(&st->cfgs_lock); if (st->channels[chan->address].cfg.bipolar)
*val = -(1 << (chan->scan_type.realbits - 1)); else
*val = 0;
mutex_unlock(&st->cfgs_lock); return IIO_VAL_INT;
case IIO_TEMP: /* see calculation above */
*val = -12090248; return IIO_VAL_INT;
default: return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&st->cfgs_lock);
*val = st->channels[chan->address].cfg.odr;
mutex_unlock(&st->cfgs_lock);
return IIO_VAL_INT; case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
mutex_lock(&st->cfgs_lock);
*val = ad7124_get_3db_filter_freq(st, chan->scan_index);
mutex_unlock(&st->cfgs_lock);
return IIO_VAL_INT; default: return -EINVAL;
}
}
staticint ad7124_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long info)
{ struct ad7124_state *st = iio_priv(indio_dev); unsignedint res, gain, full_scale, vref; int ret = 0;
mutex_lock(&st->cfgs_lock);
switch (info) { case IIO_CHAN_INFO_SAMP_FREQ: if (val2 != 0 || val == 0) {
ret = -EINVAL; break;
}
ad7124_set_channel_odr(st, chan->address, val); break; case IIO_CHAN_INFO_SCALE: if (val != 0) {
ret = -EINVAL; break;
}
if (reg >= ARRAY_SIZE(ad7124_reg_size)) return -EINVAL;
if (readval)
ret = ad_sd_read_reg(&st->sd, reg, ad7124_reg_size[reg],
readval); else
ret = ad_sd_write_reg(&st->sd, reg, ad7124_reg_size[reg],
writeval);
staticint ad7124_update_scan_mode(struct iio_dev *indio_dev, constunsignedlong *scan_mask)
{ struct ad7124_state *st = iio_priv(indio_dev); bool bit_set; int ret; int i;
mutex_lock(&st->cfgs_lock); for (i = 0; i < st->num_channels; i++) {
bit_set = test_bit(i, scan_mask); if (bit_set)
ret = __ad7124_set_channel(&st->sd, i); else
ret = ad7124_spi_write_mask(st, AD7124_CHANNEL(i), AD7124_CHANNEL_ENABLE,
0, 2); if (ret < 0) {
mutex_unlock(&st->cfgs_lock);
/* Only called during probe, so dev_err_probe() can be used */ staticint ad7124_soft_reset(struct ad7124_state *st)
{ struct device *dev = &st->sd.spi->dev; unsignedint readval, timeout; int ret;
ret = ad_sd_reset(&st->sd); if (ret < 0) return ret;
fsleep(200);
timeout = 100; do {
ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval); if (ret < 0) return dev_err_probe(dev, ret, "Error reading status register\n");
if (!(readval & AD7124_STATUS_POR_FLAG)) break;
/* The AD7124 requires typically 2ms to power up and settle */
usleep_range(100, 2000);
} while (--timeout);
if (readval & AD7124_STATUS_POR_FLAG) return dev_err_probe(dev, -EIO, "Soft reset failed\n");
ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(0), 3, &st->gain_default); if (ret < 0) return dev_err_probe(dev, ret, "Error reading gain register\n");
dev_dbg(dev, "Reset value of GAIN register is 0x%x\n", st->gain_default);
/* * Input specifiers 8 - 15 are explicitly reserved for ad7124-4 * while they are fine for ad7124-8. Values above 31 don't fit * into the register field and so are invalid for sure.
*/ staticbool ad7124_valid_input_select(unsignedint ain, conststruct ad7124_chip_info *info)
{ if (ain >= info->num_inputs && ain < 16) returnfalse;
/* * The driver assigns each logical channel defined in the device tree * statically one channel register. So only accept 16 such logical * channels to not treat CONFIG_0 (i.e. the register following * CHANNEL_15) as an additional channel register. The driver could be * improved to lift this limitation.
*/ if (num_channels > AD7124_MAX_CHANNELS) return dev_err_probe(dev, -EINVAL, "Too many channels defined\n");
/* Add one for temperature */
st->num_channels = min(num_channels + 1, AD7124_MAX_CHANNELS);
chan = devm_kcalloc(dev, st->num_channels, sizeof(*chan), GFP_KERNEL); if (!chan) return -ENOMEM;
channels = devm_kcalloc(dev, st->num_channels, sizeof(*channels),
GFP_KERNEL); if (!channels) return -ENOMEM;
device_for_each_child_node_scoped(dev, child) {
ret = fwnode_property_read_u32(child, "reg", &channel); if (ret) return dev_err_probe(dev, ret, "Failed to parse reg property of %pfwP\n", child);
if (channel >= num_channels) return dev_err_probe(dev, -EINVAL, "Channel index >= number of channels in %pfwP\n", child);
ret = fwnode_property_read_u32_array(child, "diff-channels",
ain, 2); if (ret) return dev_err_probe(dev, ret, "Failed to parse diff-channels property of %pfwP\n", child);
if (!ad7124_valid_input_select(ain[0], st->chip_info) ||
!ad7124_valid_input_select(ain[1], st->chip_info)) return dev_err_probe(dev, -EINVAL, "diff-channels property of %pfwP contains invalid data\n", child);
chan[num_channels] = (struct iio_chan_spec) {
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_type = { /* * You might find it strange that a bipolar * measurement yields an unsigned value, but * this matches the device's manual.
*/
.sign = 'u',
.realbits = 24,
.storagebits = 32,
.endianness = IIO_BE,
},
.address = num_channels,
.scan_index = num_channels,
};
}
return 0;
}
staticint ad7124_setup(struct ad7124_state *st)
{ struct device *dev = &st->sd.spi->dev; unsignedint power_mode; struct clk *mclk; int i, ret;
/* * Always use full power mode for max performance. If needed, the driver * could be adapted to use a dynamic power mode based on the requested * output data rate.
*/
power_mode = AD7124_ADC_CONTROL_POWER_MODE_FULL;
/* * This "mclk" business is needed for backwards compatibility with old * devicetrees that specified a fake clock named "mclk" to select the * power mode.
*/
mclk = devm_clk_get_optional_enabled(dev, "mclk"); if (IS_ERR(mclk)) return dev_err_probe(dev, PTR_ERR(mclk), "Failed to get mclk\n");
if (mclk) { unsignedlong mclk_hz;
mclk_hz = clk_get_rate(mclk); if (!mclk_hz) return dev_err_probe(dev, -EINVAL, "Failed to get mclk rate\n");
/* * This logic is a bit backwards, which is why it is only here * for backwards compatibility. The driver should be able to set * the power mode as it sees fit and the f_clk/mclk rate should * be dynamic accordingly. But here, we are selecting a fixed * power mode based on the given "mclk" rate.
*/
power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
ARRAY_SIZE(ad7124_master_clk_freq_hz), mclk_hz);
if (mclk_hz != ad7124_master_clk_freq_hz[power_mode]) {
ret = clk_set_rate(mclk, mclk_hz); if (ret) return dev_err_probe(dev, ret, "Failed to set mclk rate\n");
}
}
/* Set the power mode */
st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE;
st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, power_mode);
mutex_init(&st->cfgs_lock);
INIT_KFIFO(st->live_cfgs_fifo); for (i = 0; i < st->num_channels; i++) {
ret = ad7124_init_config_vref(st, &st->channels[i].cfg); if (ret < 0) return ret;
/* * 9.38 SPS is the minimum output data rate supported * regardless of the selected power mode. Round it up to 10 and * set all channels to this default value.
*/
ad7124_set_channel_odr(st, i, 10);
}
ad7124_disable_all(&st->sd);
ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control); if (ret < 0) return dev_err_probe(dev, ret, "Failed to setup CONTROL register\n");
if (indio_dev->channels[i].type != IIO_VOLTAGE) continue;
/* * For calibration the OFFSET register should hold its reset default * value. For the GAIN register there is no such requirement but * for gain 1 it should hold the reset default value, too. So to * simplify matters use the reset default value for both.
*/
st->channels[i].cfg.calibration_offset = 0x800000;
st->channels[i].cfg.calibration_gain = st->gain_default;
/* * Full-scale calibration isn't supported at gain 1, so skip in * that case. Note that untypically full-scale calibration has * to happen before zero-scale calibration. This only applies to * the internal calibration. For system calibration it's as * usual: first zero-scale then full-scale calibration.
*/ if (st->channels[i].cfg.pga_bits > 0) {
ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_INT_GAIN_CALIB, i); if (ret < 0) return ret;
/* * read out the resulting value of GAIN * after full-scale calibration because the next * ad_sd_calibrate() call overwrites this via * ad_sigma_delta_set_channel() -> ad7124_set_channel() * ... -> ad7124_enable_channel().
*/
ret = ad_sd_read_reg(&st->sd, AD7124_GAIN(st->channels[i].cfg.cfg_slot), 3,
&st->channels[i].cfg.calibration_gain); if (ret < 0) return ret;
}
ret = ad_sd_calibrate(&st->sd, AD7124_ADC_CONTROL_MODE_INT_OFFSET_CALIB, i); if (ret < 0) return ret;
ret = ad_sd_read_reg(&st->sd, AD7124_OFFSET(st->channels[i].cfg.cfg_slot), 3,
&st->channels[i].cfg.calibration_offset); if (ret < 0) return ret;
dev_dbg(dev, "offset and gain for channel %d = 0x%x + 0x%x\n", i,
st->channels[i].cfg.calibration_offset,
st->channels[i].cfg.calibration_gain);
}
/* * Calibration isn't supported at full power, so speed down a bit. * Setting .adc_control is enough here because the control register is * written as part of ad_sd_calibrate() -> ad_sigma_delta_set_mode(). * The resulting calibration is then also valid for high-speed, so just * restore adc_control afterwards.
*/ if (FIELD_GET(AD7124_ADC_CONTROL_POWER_MODE, adc_control) >= AD7124_FULL_POWER) {
st->adc_control &= ~AD7124_ADC_CONTROL_POWER_MODE;
st->adc_control |= FIELD_PREP(AD7124_ADC_CONTROL_POWER_MODE, AD7124_MID_POWER);
}
ret = regulator_enable(st->vref[i]); if (ret) return dev_err_probe(dev, ret, "Failed to enable regulator #%d\n", i);
ret = devm_add_action_or_reset(&spi->dev, ad7124_reg_disable,
st->vref[i]); if (ret) return dev_err_probe(dev, ret, "Failed to register disable handler for regulator #%d\n", i);
}
ret = ad7124_soft_reset(st); if (ret < 0) return ret;
ret = ad7124_check_chip_id(st); if (ret) return ret;
ret = ad7124_setup(st); if (ret < 0) return ret;
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev); if (ret < 0) return dev_err_probe(dev, ret, "Failed to setup triggers\n");
ret = ad7124_calibrate_all(st, indio_dev); if (ret) return ret;
ret = devm_iio_device_register(&spi->dev, indio_dev); if (ret < 0) return dev_err_probe(dev, ret, "Failed to register iio device\n");
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.