/* * AD4170 registers * Multibyte register addresses point to the most significant byte which is the * address to use to get the most significant byte first (address accessed is * decremented by one for each data byte) * * Each register address define follows the AD4170_<REG_NAME>_REG format. * Each mask follows the AD4170_<REG_NAME>_<FIELD_NAME> format. * E.g. AD4170_PIN_MUXING_DIG_AUX1_CTRL_MSK is for accessing DIG_AUX1_CTRL field * of PIN_MUXING_REG. * Each constant follows the AD4170_<REG_NAME>_<FIELD_NAME>_<FUNCTION> format. * E.g. AD4170_PIN_MUXING_DIG_AUX1_DISABLED is the value written to * DIG_AUX1_CTRL field of PIN_MUXING register to disable DIG_AUX1 pin. * Some register names and register field names are shortened versions of * their datasheet counterpart names to provide better code readability.
*/ #define AD4170_CONFIG_A_REG 0x00 #define AD4170_DATA_24B_REG 0x1E #define AD4170_PIN_MUXING_REG 0x69 #define AD4170_CLOCK_CTRL_REG 0x6B #define AD4170_ADC_CTRL_REG 0x71 #define AD4170_CHAN_EN_REG 0x79 #define AD4170_CHAN_SETUP_REG(x) (0x81 + 4 * (x)) #define AD4170_CHAN_MAP_REG(x) (0x83 + 4 * (x)) #define AD4170_MISC_REG(x) (0xC1 + 14 * (x)) #define AD4170_AFE_REG(x) (0xC3 + 14 * (x)) #define AD4170_FILTER_REG(x) (0xC5 + 14 * (x)) #define AD4170_FILTER_FS_REG(x) (0xC7 + 14 * (x)) #define AD4170_OFFSET_REG(x) (0xCA + 14 * (x)) #define AD4170_GAIN_REG(x) (0xCD + 14 * (x)) #define AD4170_V_BIAS_REG 0x135 #define AD4170_CURRENT_SRC_REG(x) (0x139 + 2 * (x)) #define AD4170_GPIO_MODE_REG 0x191 #define AD4170_GPIO_OUTPUT_REG 0x193 #define AD4170_GPIO_INPUT_REG 0x195 #define AD4170_ADC_CTRL_CONT_READ_EXIT_REG 0x200 /* virtual reg */
/* * There are 8 of each MISC, AFE, FILTER, FILTER_FS, OFFSET, and GAIN * configuration registers. That is, there are 8 miscellaneous registers, MISC0 * to MISC7. Each MISC register is associated with a setup; MISCN is associated * with setup number N. The other 5 above mentioned types of registers have * analogous structure. A setup is a set of those registers. For example, * setup 1 comprises of MISC1, AFE1, FILTER1, FILTER_FS1, OFFSET1, and GAIN1 * registers. Also, there are 16 CHANNEL_SETUP registers (CHANNEL_SETUP0 to * CHANNEL_SETUP15). Each channel setup is associated with one of the 8 possible * setups. Thus, AD4170 can support up to 16 channels but, since there are only * 8 available setups, channels must share settings if more than 8 channels are * configured. * * If this struct is modified, ad4170_setup_eq() will probably need to be * updated too.
*/ struct ad4170_setup {
u16 misc;
u16 afe;
u16 filter;
u16 filter_fs;
u32 offset; /* For calibration purposes */
u32 gain; /* For calibration purposes */
};
/* * The ODR can be calculated the same way for sinc5+avg, sinc5, and * sinc3 filter types with the exception that sinc5 filter has a * narrowed range of allowed FILTER_FS values.
*/ for (i = 0; i < ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl); i++) {
tmp0 = div_u64_rem(st->mclk_hz, 32 * ad4170_sinc3_filt_fs_tbl[i],
&tmp1);
tmp1 = mult_frac(tmp1, MICRO, 32 * ad4170_sinc3_filt_fs_tbl[i]); /* Fill sinc5+avg filter SPS table */
st->sps_tbl[AD4170_SINC5_AVG][i][0] = tmp0; /* Integer part */
st->sps_tbl[AD4170_SINC5_AVG][i][1] = tmp1; /* Fractional part */
/* Fill sinc3 filter SPS table */
st->sps_tbl[AD4170_SINC3][i][0] = tmp0; /* Integer part */
st->sps_tbl[AD4170_SINC3][i][1] = tmp1; /* Fractional part */
} /* Sinc5 filter ODR doesn't use all FILTER_FS bits */ for (i = 0; i < ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl); i++) {
tmp0 = div_u64_rem(st->mclk_hz, 32 * ad4170_sinc5_filt_fs_tbl[i],
&tmp1);
tmp1 = mult_frac(tmp1, MICRO, 32 * ad4170_sinc5_filt_fs_tbl[i]); /* Fill sinc5 filter SPS table */
st->sps_tbl[AD4170_SINC5][i][0] = tmp0; /* Integer part */
st->sps_tbl[AD4170_SINC5][i][1] = tmp1; /* Fractional part */
}
}
for (i = 0; i < AD4170_MAX_SETUPS; i++) { struct ad4170_setup_info *setup_info = &st->setup_infos[i];
/* Immediately accept a matching setup. */ if (ad4170_setup_eq(target_setup, &setup_info->setup)) {
*setup_num = i; return 0;
}
/* Ignore all setups which are used by enabled channels. */ if (setup_info->enabled_channels) continue;
/* Find the least used slot. */ if (*setup_num == AD4170_INVALID_SETUP ||
setup_info->channels < st->setup_infos[*setup_num].channels)
*setup_num = i;
}
if (*setup_num == AD4170_INVALID_SETUP) return -EINVAL;
/* * It is recommended to place the ADC in standby mode or idle mode to * write to OFFSET and GAIN registers.
*/
ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
AD4170_ADC_CTRL_MODE_MSK,
FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
AD4170_ADC_CTRL_MODE_IDLE)); if (ret) return ret;
ret = regmap_write(st->regmap, AD4170_MISC_REG(setup_num), setup->misc); if (ret) return ret;
ret = regmap_write(st->regmap, AD4170_AFE_REG(setup_num), setup->afe); if (ret) return ret;
ret = regmap_write(st->regmap, AD4170_FILTER_REG(setup_num),
setup->filter); if (ret) return ret;
ret = regmap_write(st->regmap, AD4170_FILTER_FS_REG(setup_num),
setup->filter_fs); if (ret) return ret;
ret = regmap_write(st->regmap, AD4170_OFFSET_REG(setup_num),
setup->offset); if (ret) return ret;
ret = regmap_write(st->regmap, AD4170_GAIN_REG(setup_num), setup->gain); if (ret) return ret;
staticint ad4170_write_channel_setup(struct ad4170_state *st, unsignedint chan_addr, bool on_enable)
{ struct ad4170_chan_info *chan_info = &st->chan_infos[chan_addr]; bool overwrite; int setup_num; int ret;
/* * Similar to AD4130 driver, the following cases need to be handled. * * 1. Enabled and linked channel with setup changes: * - Find a setup. If not possible, return error. * - Unlink channel from current setup. * - If the setup found has only disabled channels linked to it, * unlink all channels, and write the new setup to it. * - Link channel to new setup. * * 2. Soon to be enabled and unlinked channel: * - Find a setup. If not possible, return error. * - If the setup found has only disabled channels linked to it, * unlink all channels, and write the new setup to it. * - Link channel to the setup. * * 3. Disabled and linked channel with setup changes: * - Unlink channel from current setup. * * 4. Soon to be enabled and linked channel: * 5. Disabled and unlinked channel with setup changes: * - Do nothing.
*/
/* Cases 3, 4, and 5 */ if (chan_info->setup_num != AD4170_INVALID_SETUP) { /* Case 4 */ if (on_enable) return 0;
/* Case 3 */ if (!chan_info->enabled) {
ad4170_unlink_channel(st, chan_addr); return 0;
}
} elseif (!on_enable && !chan_info->enabled) { /* Case 5 */ return 0;
}
/* Cases 1 & 2 */
ret = ad4170_find_setup(st, &chan_info->setup, &setup_num, &overwrite); if (ret) return ret;
if (chan_info->setup_num != AD4170_INVALID_SETUP) /* Case 1 */
ad4170_unlink_channel(st, chan_addr);
if (overwrite) {
ret = ad4170_unlink_setup(st, setup_num); if (ret) return ret;
ret = ad4170_write_setup(st, setup_num, &chan_info->setup); if (ret) return ret;
}
switch (val) { case AD4170_SINC5_AVG:
filter_type_conf = AD4170_FILTER_FILTER_TYPE_SINC5_AVG; break; case AD4170_SINC5:
filter_type_conf = AD4170_FILTER_FILTER_TYPE_SINC5; break; case AD4170_SINC3:
filter_type_conf = AD4170_FILTER_FILTER_TYPE_SINC3; break; default: return -EINVAL;
}
/* * The filters provide the same ODR for a given filter_fs value but * there are different minimum and maximum filter_fs limits for each * filter. The filter_fs value will be adjusted if the current filter_fs * is out of the limits of the just requested filter. Since the * filter_fs value affects the ODR (sampling_frequency), changing the * filter may lead to a change in the sampling frequency.
*/
scoped_guard(mutex, &st->lock) { if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
if (val == AD4170_SINC5_AVG || val == AD4170_SINC3)
setup->filter_fs = clamp(val, AD4170_SINC3_MIN_FS,
AD4170_SINC3_MAX_FS); else
setup->filter_fs = clamp(val, AD4170_SINC5_MIN_FS,
AD4170_SINC5_MAX_FS);
/* * Receives the number of a multiplexed AD4170 input (ain_n), and stores the * voltage (in µV) of the specified input into ain_voltage. If the input number * is a ordinary analog input (AIN0 to AIN8), stores zero into ain_voltage. * If a voltage regulator required by a special input is unavailable, return * error code. Return 0 on success.
*/ staticint ad4170_get_ain_voltage_uv(struct ad4170_state *st, int ain_n, int *ain_voltage)
{ struct device *dev = &st->spi->dev; int v_diff;
*ain_voltage = 0; /* * The voltage bias (vbias) sets the common-mode voltage of the channel * to (AVDD + AVSS)/2. If provided, AVSS supply provides the magnitude * (absolute value) of the negative voltage supplied to the AVSS pin. * So, we do AVDD - AVSS to compute the DC voltage generated by the bias * voltage generator.
*/ if (st->pins_fn[ain_n] & AD4170_PIN_VBIAS) { int v_diff = st->vrefs_uv[AD4170_AVDD_SUP] - st->vrefs_uv[AD4170_AVSS_SUP];
*ain_voltage = v_diff / 2; return 0;
}
if (ain_n <= AD4170_CHAN_MAP_TEMP_SENSOR) return 0;
switch (ain_n) { case AD4170_CHAN_MAP_AVDD_AVSS_N:
v_diff = st->vrefs_uv[AD4170_AVDD_SUP] - st->vrefs_uv[AD4170_AVSS_SUP];
*ain_voltage = v_diff / 5; return 0; case AD4170_CHAN_MAP_IOVDD_DGND_N:
*ain_voltage = st->vrefs_uv[AD4170_IOVDD_SUP] / 5; return 0; case AD4170_CHAN_MAP_AVSS:
*ain_voltage = st->vrefs_uv[AD4170_AVSS_SUP]; return 0; case AD4170_CHAN_MAP_DGND:
*ain_voltage = 0; return 0; case AD4170_CHAN_MAP_REFIN1_P: if (st->vrefs_uv[AD4170_REFIN1P_SUP] == -ENODEV) return dev_err_probe(dev, -ENODEV, "input set to REFIN+ but ref not provided\n");
*ain_voltage = st->vrefs_uv[AD4170_REFIN1P_SUP]; return 0; case AD4170_CHAN_MAP_REFIN1_N: if (st->vrefs_uv[AD4170_REFIN1N_SUP] == -ENODEV) return dev_err_probe(dev, -ENODEV, "input set to REFIN- but ref not provided\n");
*ain_voltage = st->vrefs_uv[AD4170_REFIN1N_SUP]; return 0; case AD4170_CHAN_MAP_REFIN2_P: if (st->vrefs_uv[AD4170_REFIN2P_SUP] == -ENODEV) return dev_err_probe(dev, -ENODEV, "input set to REFIN2+ but ref not provided\n");
*ain_voltage = st->vrefs_uv[AD4170_REFIN2P_SUP]; return 0; case AD4170_CHAN_MAP_REFIN2_N: if (st->vrefs_uv[AD4170_REFIN2N_SUP] == -ENODEV) return dev_err_probe(dev, -ENODEV, "input set to REFIN2- but ref not provided\n");
*ain_voltage = st->vrefs_uv[AD4170_REFIN2N_SUP]; return 0; case AD4170_CHAN_MAP_REFOUT: /* REFOUT is 2.5V relative to AVSS so take that into account */
*ain_voltage = st->vrefs_uv[AD4170_AVSS_SUP] + AD4170_INT_REF_2_5V; return 0; default: return -EINVAL;
}
}
staticint ad4170_validate_analog_input(struct ad4170_state *st, int pin)
{ if (pin <= AD4170_MAX_ANALOG_PINS) { if (st->pins_fn[pin] & AD4170_PIN_CURRENT_OUT) return dev_err_probe(&st->spi->dev, -EINVAL, "Pin %d already used with fn %u.\n",
pin, st->pins_fn[pin]);
staticint ad4170_validate_channel_input(struct ad4170_state *st, int pin, bool com)
{ /* Check common-mode input pin is mapped to a special input. */ if (com && (pin < AD4170_CHAN_MAP_AVDD_AVSS_P || pin > AD4170_CHAN_MAP_REFOUT)) return dev_err_probe(&st->spi->dev, -EINVAL, "Invalid common-mode input pin number. %d\n",
pin);
/* Check differential input pin is mapped to a analog input pin. */ if (!com && pin > AD4170_MAX_ANALOG_PINS) return dev_err_probe(&st->spi->dev, -EINVAL, "Invalid analog input pin number. %d\n",
pin);
return ad4170_validate_analog_input(st, pin);
}
/* * Verifies whether the channel input configuration is valid by checking the * input numbers. * Returns 0 on valid channel input configuration. -EINVAL otherwise.
*/ staticint ad4170_validate_channel(struct ad4170_state *st, struct iio_chan_spec const *chan)
{ int ret;
ret = ad4170_validate_channel_input(st, chan->channel, false); if (ret) return ret;
/* * Verifies whether the channel configuration is valid by checking the provided * input type, polarity, and voltage references result in a sane input range. * Returns negative error code on failure.
*/ staticint ad4170_get_input_range(struct ad4170_state *st, struct iio_chan_spec const *chan, unsignedint ch_reg, unsignedint ref_sel)
{ bool bipolar = chan->scan_type.sign == 's'; struct device *dev = &st->spi->dev; int refp, refn, ain_voltage, ret;
switch (ref_sel) { case AD4170_REF_REFIN1: if (st->vrefs_uv[AD4170_REFIN1P_SUP] == -ENODEV ||
st->vrefs_uv[AD4170_REFIN1N_SUP] == -ENODEV) return dev_err_probe(dev, -ENODEV, "REFIN± selected but not provided\n");
refp = st->vrefs_uv[AD4170_REFIN1P_SUP];
refn = st->vrefs_uv[AD4170_REFIN1N_SUP]; break; case AD4170_REF_REFIN2: if (st->vrefs_uv[AD4170_REFIN2P_SUP] == -ENODEV ||
st->vrefs_uv[AD4170_REFIN2N_SUP] == -ENODEV) return dev_err_probe(dev, -ENODEV, "REFIN2± selected but not provided\n");
refp = st->vrefs_uv[AD4170_REFIN2P_SUP];
refn = st->vrefs_uv[AD4170_REFIN2N_SUP]; break; case AD4170_REF_AVDD:
refp = st->vrefs_uv[AD4170_AVDD_SUP];
refn = st->vrefs_uv[AD4170_AVSS_SUP]; break; case AD4170_REF_REFOUT: /* REFOUT is 2.5 V relative to AVSS */
refp = st->vrefs_uv[AD4170_AVSS_SUP] + AD4170_INT_REF_2_5V;
refn = st->vrefs_uv[AD4170_AVSS_SUP]; break; default: return -EINVAL;
}
/* * Find out the analog input range from the channel type, polarity, and * voltage reference selection. * AD4170 channels are either differential or pseudo-differential. * Diff input voltage range: −VREF/gain to +VREF/gain (datasheet page 6) * Pseudo-diff input voltage range: 0 to VREF/gain (datasheet page 6)
*/ if (chan->differential) { if (!bipolar) return dev_err_probe(dev, -EINVAL, "Channel %u differential unipolar\n",
ch_reg);
/* * Differential bipolar channel. * avss-supply is never above 0V. * Assuming refin1n-supply not above 0V. * Assuming refin2n-supply not above 0V.
*/ return refp + abs(refn);
} /* * Some configurations can lead to invalid setups. * For example, if AVSS = -2.5V, REF_SELECT set to REFOUT (REFOUT/AVSS), * and pseudo-diff channel configuration set, then the input range * should go from 0V to +VREF (single-ended - datasheet pg 10), but * REFOUT/AVSS range would be -2.5V to 0V. * Check the positive reference is higher than 0V for pseudo-diff * channels. * Note that at this point in the code, refp can only be >= 0 since all * error codes from reading the regulator voltage have been checked * either at ad4170_regulator_setup() or above in this function.
*/ if (refp == 0) return dev_err_probe(dev, -EINVAL, "REF+ == GND for pseudo-diff chan %u\n",
ch_reg);
if (bipolar) return refp;
/* * Pseudo-differential unipolar channel. * Input expected to swing from IN- to +VREF.
*/
ret = ad4170_get_ain_voltage_uv(st, chan->channel2, &ain_voltage); if (ret) return ret;
if (refp - ain_voltage <= 0) return dev_err_probe(dev, -EINVAL, "Negative input >= REF+ for pseudo-diff chan %u\n",
ch_reg);
return refp - ain_voltage;
}
staticint __ad4170_read_sample(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val)
{ struct ad4170_state *st = iio_priv(indio_dev); unsignedlong settling_time_ms; int ret;
reinit_completion(&st->completion);
ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
AD4170_ADC_CTRL_MODE_MSK,
FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
AD4170_ADC_CTRL_MODE_SINGLE)); if (ret) return ret;
/* * When a channel is manually selected by the user, the ADC needs an * extra time to provide the first stable conversion. The ADC settling * time depends on the filter type, filter frequency, and ADC clock * frequency (see datasheet page 53). The maximum settling time among * all filter configurations is 6291164 / fCLK. Use that formula to wait * for sufficient time whatever the filter configuration may be.
*/
settling_time_ms = DIV_ROUND_UP(6291164 * MILLI, st->mclk_hz);
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(settling_time_ms)); if (!ret)
dev_dbg(&st->spi->dev, "No Data Ready signal. Reading after delay.\n");
ret = regmap_read(st->regmap, AD4170_DATA_24B_REG, val); if (ret) return ret;
if (chan->scan_type.sign == 's')
*val = sign_extend32(*val, chan->scan_type.realbits - 1);
/* * The ADC sequences through all enabled channels. That can lead to * incorrect channel being sampled if a previous read would have left a * different channel enabled. Thus, always enable and disable the * channel on single-shot read.
*/
ret = ad4170_set_channel_enable(st, chan->address, true); if (ret) return ret;
ret = __ad4170_read_sample(indio_dev, chan, val); if (ret) {
dev_err(dev, "failed to read sample: %d\n", ret);
ret2 = ad4170_set_channel_enable(st, chan->address, false); if (ret2)
dev_err(dev, "failed to disable channel: %d\n", ret2);
return ret;
}
ret = ad4170_set_channel_enable(st, chan->address, false); if (ret) return ret;
return IIO_VAL_INT;
}
staticint ad4170_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long info)
{ struct ad4170_state *st = iio_priv(indio_dev); struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address]; struct ad4170_setup *setup = &chan_info->setup; enum ad4170_filter_type f_type; unsignedint pga, fs_idx; int ret;
guard(mutex)(&st->lock); switch (info) { case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
ret = ad4170_read_sample(indio_dev, chan, val);
iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE:
pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe); switch (chan->type) { case IIO_VOLTAGE:
*val = chan_info->scale_tbl[pga][0];
*val2 = chan_info->scale_tbl[pga][1]; return IIO_VAL_INT_PLUS_NANO; case IIO_TEMP: /* * The scale_tbl converts output codes to mV units so * multiply by MILLI to make the factor convert to µV. * Then, apply the temperature sensor change sensitivity * of 477 μV/K. Finally, multiply the result by MILLI * again to comply with milli degrees Celsius IIO ABI.
*/
*val = 0;
*val2 = DIV_ROUND_CLOSEST(chan_info->scale_tbl[pga][1] * MILLI, 477) *
MILLI; return IIO_VAL_INT_PLUS_NANO; default: return -EINVAL;
} case IIO_CHAN_INFO_OFFSET:
pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
*val = chan_info->offset_tbl[pga]; return IIO_VAL_INT; case IIO_CHAN_INFO_SAMP_FREQ:
f_type = __ad4170_get_filter_type(setup->filter); switch (f_type) { case AD4170_SINC5_AVG: case AD4170_SINC3:
fs_idx = find_closest(setup->filter_fs,
ad4170_sinc3_filt_fs_tbl,
ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl));
*val = st->sps_tbl[f_type][fs_idx][0];
*val2 = st->sps_tbl[f_type][fs_idx][1]; return IIO_VAL_INT_PLUS_MICRO; case AD4170_SINC5:
fs_idx = find_closest(setup->filter_fs,
ad4170_sinc5_filt_fs_tbl,
ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl));
*val = st->sps_tbl[f_type][fs_idx][0];
*val2 = st->sps_tbl[f_type][fs_idx][1]; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL;
} case IIO_CHAN_INFO_CALIBBIAS:
*val = setup->offset; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBSCALE:
*val = setup->gain; return IIO_VAL_INT; default: return -EINVAL;
}
}
ainm_voltage = 0;
ret = ad4170_get_ain_voltage_uv(st, chan->channel2, &ainm_voltage); if (ret < 0) return dev_err_probe(dev, ret, "Failed to fill scale table\n");
/* * The PGA options are numbered from 0 to 9, with option 0 being * a gain of 2^0 (no actual gain), and 7 meaning a gain of 2^7. * Option 8, though, sets a gain of 0.5, so the input signal can * be attenuated by 2 rather than amplified. Option 9, allows * the signal to bypass the PGA circuitry (no gain). * * The scale factor to get ADC output codes to values in mV * units is given by: * _scale = (input_range / gain) / 2^precision * AD4170 gain is a power of 2 so the above can be written as * _scale = input_range / 2^(precision + gain) * Keep the input range in µV to avoid truncating the less * significant bits when right shifting it so to preserve scale * precision.
*/
nv = (u64)chan_info->input_range_uv * NANO;
lshift = !!(pga & BIT(3)); /* handle PGA options 8 and 9 */
rshift = precision_bits - bipolar + (pga & GENMASK(2, 0)) - lshift;
chan_info->scale_tbl[pga][0] = 0;
chan_info->scale_tbl[pga][1] = div_u64(nv >> rshift, MILLI);
/* * If the negative input is not at GND, the conversion result * (which is relative to IN-) will be offset by the level at IN-. * Use the scale factor the other way around to go from a known * voltage to the corresponding ADC output code. * With that, we are able to get to what would be the output * code for the voltage at the negative input. * If the negative input is not fixed, there is no offset.
*/
offset = ((unsignedlonglong)abs(ainm_voltage)) * MICRO;
offset = DIV_ROUND_CLOSEST_ULL(offset, chan_info->scale_tbl[pga][1]);
/* * After divided by the scale, offset will always fit into 31 * bits. For _raw + _offset to be relative to GND, the value * provided as _offset is of opposite sign than the real offset.
*/ if (ainm_voltage > 0)
chan_info->offset_tbl[pga] = -(int)(offset); else
chan_info->offset_tbl[pga] = (int)(offset);
} return 0;
}
staticint ad4170_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, constint **vals, int *type, int *length, long info)
{ struct ad4170_state *st = iio_priv(indio_dev); struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address]; enum ad4170_filter_type f_type;
switch (info) { case IIO_CHAN_INFO_SCALE:
*vals = (int *)chan_info->scale_tbl;
*length = ARRAY_SIZE(chan_info->scale_tbl) * 2;
*type = IIO_VAL_INT_PLUS_NANO; return IIO_AVAIL_LIST; case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
f_type = ad4170_get_filter_type(indio_dev, chan); switch (f_type) { case AD4170_SINC5_AVG: case AD4170_SINC3: /* Read sps_tbl here to ensure in bounds array access */
*vals = (int *)st->sps_tbl[f_type];
*length = ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl) * 2; return IIO_AVAIL_LIST; case AD4170_SINC5: /* Read sps_tbl here to ensure in bounds array access */
*vals = (int *)st->sps_tbl[f_type];
*length = ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl) * 2; return IIO_AVAIL_LIST; default: return -EINVAL;
} default: return -EINVAL;
}
}
switch (f_type) { case AD4170_SINC5_AVG: case AD4170_SINC3:
filt_fs_tbl_size = ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl); break; case AD4170_SINC5:
filt_fs_tbl_size = ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl); break;
}
for (i = 0; i < filt_fs_tbl_size; i++) { if (st->sps_tbl[f_type][i][0] == val &&
st->sps_tbl[f_type][i][1] == val2) break;
} if (i == filt_fs_tbl_size) return -EINVAL;
if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
ret = regmap_read(st->regmap, AD4170_GPIO_MODE_REG, &val); if (ret) goto err_release;
/* * If the GPIO is configured as an input, read the current value from * AD4170_GPIO_INPUT_REG. Otherwise, read the input value from * AD4170_GPIO_OUTPUT_REG.
*/ if (val & BIT(offset * 2))
ret = regmap_read(st->regmap, AD4170_GPIO_INPUT_REG, &val); else
ret = regmap_read(st->regmap, AD4170_GPIO_OUTPUT_REG, &val); if (ret) goto err_release;
ret = !!(val & BIT(offset));
err_release:
iio_device_release_direct(indio_dev);
/* Only expose GPIOs that were not assigned any other function. */ for (i = 0; i < ngpios; i++) { bool valid = st->gpio_fn[i] == AD4170_GPIO_UNASSIGNED;
/* Check the pin number is valid */ for (i = 0; i < ARRAY_SIZE(ad4170_iout_pin_tbl); i++) if (ad4170_iout_pin_tbl[i] == pin) break;
if (i == ARRAY_SIZE(ad4170_iout_pin_tbl)) return dev_err_probe(dev, -EINVAL, "Invalid excitation pin: %u\n",
pin);
/* Check the pin is available */ if (pin <= AD4170_MAX_ANALOG_PINS) { if (st->pins_fn[pin] != AD4170_PIN_UNASSIGNED) return dev_err_probe(dev, -EINVAL, "Pin %u already used with fn %u\n",
pin, st->pins_fn[pin]);
/* * Parses firmware data describing output current source setup. There are 4 * excitation currents (IOUT0 to IOUT3) that can be configured independently. * Excitation currents are added if they are output on the same pin.
*/ staticint ad4170_parse_exc_current(struct ad4170_state *st, struct fwnode_handle *child, unsignedint *exc_pins, unsignedint *exc_curs, unsignedint *num_exc_pins)
{ struct device *dev = &st->spi->dev; unsignedint num_pins, i, j;
u32 pin, val; int ret;
num_pins = 0; for (i = 0; i < AD4170_NUM_CURRENT_SRC; i++) { /* Parse excitation current output pin properties. */
pin = AD4170_CURRENT_SRC_I_OUT_PIN_AIN(0);
ret = fwnode_property_read_u32(child, ad4170_i_out_pin_dt_props[i],
&pin); if (ret) continue;
exc_pins[num_pins] = pin;
/* Parse excitation current value properties. */
val = ad4170_iout_current_ua_tbl[0];
fwnode_property_read_u32(child,
ad4170_i_out_val_dt_props[i], &val);
for (j = 0; j < ARRAY_SIZE(ad4170_iout_current_ua_tbl); j++) if (ad4170_iout_current_ua_tbl[j] == val) break;
if (num_exc_pins < 2) return dev_err_probe(&st->spi->dev, -EINVAL, "Current chopping requested but only one pin provided: %u\n",
exc_pins[0]);
/* * Two use cases to handle here: * - 2 pairs of excitation currents; * - 1 pair of excitation currents.
*/ if (num_exc_pins == 4) { for (i = 0; i < AD4170_NUM_CURRENT_SRC; i++) if (st->cur_src_pins[i] != exc_pins[i]) return dev_err_probe(&st->spi->dev, -EINVAL, "Unable to use 4 exc pins\n");
} else { /* * Excitation current chopping is configured in pairs. Current * sources IOUT0 and IOUT1 form pair 1, IOUT2 and IOUT3 make up * pair 2. So, if current chopping was requested, check if the * first end of the first pair of excitation currents is * available. Try the next pair if IOUT0 has already been * configured for another channel.
*/
i = st->cur_src_pins[0] == exc_pins[0] ? 0 : 2;
if (st->cur_src_pins[i] != exc_pins[0] ||
st->cur_src_pins[i + 1] != exc_pins[1]) return dev_err_probe(&st->spi->dev, -EINVAL, "Failed to setup current chopping\n");
if (i == 0)
exc_cur_pair = AD4170_MISC_CHOP_IEXC_PAIR1; else
exc_cur_pair = AD4170_MISC_CHOP_IEXC_PAIR2;
}
/* * Configure excitation current chopping. * Chop both pairs if using four excitation pins.
*/
setup->misc |= FIELD_PREP(AD4170_MISC_CHOP_IEXC_MSK,
num_exc_pins == 2 ?
exc_cur_pair :
AD4170_MISC_CHOP_IEXC_BOTH);
/* * If a specific current is provided through * adi,excitation-current-n-microamp, set excitation pins provided * through adi,excitation-pin-n to excite the bridge circuit.
*/ for (i = 0; i < num_exc_pins; i++) if (exc_curs[i] > 0) return ad4170_setup_current_src(st, child, setup, exc_pins,
exc_curs, num_exc_pins,
ac_excited);
/* * Else, use predefined ACX1, ACX1 negated, ACX2, ACX2 negated signals * to AC excite the bridge. Those signals are output on GPIO2, GPIO0, * GPIO3, and GPIO1, respectively. If only two pins are specified for AC * excitation, use ACX1 and ACX2 (GPIO2 and GPIO3). * * Also, to avoid any short-circuit condition when more than one channel * is enabled, set GPIO2 and GPIO0 high, and set GPIO1 and GPIO3 low to * DC excite the bridge whenever a channel without AC excitation is * selected. That is needed because GPIO pins are controlled by the next * highest priority GPIO function when a channel doesn't enable AC * excitation. See datasheet Figure 113 Weigh Scale (AC Excitation) for * the reference circuit diagram.
*/ if (num_exc_pins == 2) {
setup->misc |= FIELD_PREP(AD4170_MISC_CHOP_ADC_MSK, 0x3);
gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK | AD4170_GPIO_MODE_GPIO2_MSK;
ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
FIELD_PREP(AD4170_GPIO_MODE_GPIO3_MSK,
AD4170_GPIO_MODE_GPIO_OUTPUT) |
FIELD_PREP(AD4170_GPIO_MODE_GPIO2_MSK,
AD4170_GPIO_MODE_GPIO_OUTPUT)); if (ret) return ret;
/* * Set GPIO2 high and GPIO3 low to DC excite the bridge when * a different channel is selected.
*/
gpio_mask = AD4170_GPIO_OUTPUT_GPIO_MSK(3) |
AD4170_GPIO_OUTPUT_GPIO_MSK(2);
ret = regmap_update_bits(st->regmap, AD4170_GPIO_OUTPUT_REG, gpio_mask,
FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(3), 0) |
FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(2), 1)); if (ret) return ret;
/* * Set GPIO2 and GPIO0 high, and set GPIO1 and GPIO3 low to DC * excite the bridge when a different channel is selected.
*/
gpio_mask = AD4170_GPIO_OUTPUT_GPIO_MSK(3) |
AD4170_GPIO_OUTPUT_GPIO_MSK(2) |
AD4170_GPIO_OUTPUT_GPIO_MSK(1) |
AD4170_GPIO_OUTPUT_GPIO_MSK(0);
ret = regmap_update_bits(st->regmap, AD4170_GPIO_OUTPUT_REG, gpio_mask,
FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(3), 0) |
FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(2), 1) |
FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(1), 0) |
FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(0), 1)); if (ret) return ret;
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.