Re: [PATCH 3/4] iio: adc: ti-ads112c14: implement gain on internal short SYS_MON channel
From: Andy Shevchenko
Date: Tue Jun 16 2026 - 03:59:02 EST
On Mon, Jun 15, 2026 at 05:00:01PM -0500, David Lechner (TI) wrote:
> Implement support for the programmable gain amplifier on the internal
> short SYS_MON channel. This channel is used for calibration, so it is
> useful to be able to set the PGA to the same gain as the external
> channels. The gain setting is implemented via the `_scale` attribute.
>
> In the future, we may want to support different reference voltages for
> this channel, so the scale_available table is populated during probe
> rather than being a static table.
...
> + switch (chan->channel) {
> + case ADS112C14_SYS_MON_CHANNEL_SHORT: {
> + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim);
> + if (IIO_DEV_ACQUIRE_FAILED(claim))
> + return -EBUSY;
> +
> + for (u32 i = 0; i < ARRAY_SIZE(data->sys_mon_chan_short_scale_available); i++) {
u32 here looks confusing. the entire loop can be made readable with a temporary
for the array item I believe.
> + if (val == data->sys_mon_chan_short_scale_available[i][0] &&
> + val2 == data->sys_mon_chan_short_scale_available[i][1]) {
> + data->sys_mon_chan_short_gain_val = i;
> + return 0;
> + }
> + }
for (size_t i = 0; i < ARRAY_SIZE(data->sys_mon_chan_short_scale_available); i++) {
const int *sa = data->sys_mon_chan_short_scale_available[i];
if (val == sa[0] && val2 == sa[1]) {
data->sys_mon_chan_short_gain_val = i;
return 0;
}
}
> + return -EINVAL;
> + }
> + default:
> + return -EINVAL;
> + }
> +}
...
> +static void ads112c14_populate_tables(struct ads112c14_data *data)
> +{
> + u32 vref_uV, fsr_bits;
> + int i;
size_t? unsigned int?
> + /* For now, assuming we are using 2.5V reference. */
> + vref_uV = ads112c14_internal_ref_uV[ADS112C14_REFERENCE_CFG_REF_VAL_2_5V];
> + fsr_bits = data->chip_info->resolution_bits - 1;
> +
> + for (i = 0; i < ARRAY_SIZE(ads112c14_pga_gains_x10); i++) {
> + int *scale_avail = &data->sys_mon_chan_short_scale_available[i][0];
> + u32 gain_x10 = ads112c14_pga_gains_x10[i];
> +
> + /* NB: slightly odd arrangement to avoid overflow. */
> + scale_avail[0] = div_u64_rem(div_u64((u64)NANO * 10 /
> + (MICRO / MILLI) * vref_uV /
> + gain_x10,
> + BIT(fsr_bits)),
> + NANO, &scale_avail[1]);
Oh, what about temporary variable for the inner division? Also note one trick
to avoid casting (and making it shorter).
u64 foo;
foo = div_u64(10ULL * NANO / (MICRO / MILLI) * vref_uV / gain_x10, BIT(fsr_bits));
/* NB: slightly odd arrangement to avoid overflow. */
scale_avail[0] = div_u64_rem(foo, NANO, &scale_avail[1]);
Now, with much more readability, it's visible that the first division is just a right shift.
u64 foo;
/* ...a comment to explain voodoo calculations... */
foo = (10ULL * NANO / (MICRO / MILLI) * vref_uV / gain_x10) >> fsr_bits;
scale_avail[0] = div_u64_rem(foo, NANO, &scale_avail[1]);
> + }
> +}
--
With Best Regards,
Andy Shevchenko