Re: [PATCH v2 3/9] iio: adc: Add support for ad4062
From: Jorge Marques
Date: Thu Dec 04 2025 - 16:37:42 EST
On Fri, Nov 28, 2025 at 09:25:50PM +0200, Andy Shevchenko wrote:
Hi Andy,
> On Fri, Nov 28, 2025 at 07:50:02PM +0100, Jorge Marques wrote:
> > On Thu, Nov 27, 2025 at 10:58:24AM +0200, Andy Shevchenko wrote:
> > > On Wed, Nov 26, 2025 at 12:40:00PM +0100, Jorge Marques wrote:
> > > > On Mon, Nov 24, 2025 at 12:20:57PM +0200, Andy Shevchenko wrote:
> > > > > On Mon, Nov 24, 2025 at 10:18:02AM +0100, Jorge Marques wrote:
>
> > static int ad4062_calc_sampling_frequency(int fosc, unsigned int oversamp_ratio)
>
> Shouldn't fosc be unsigned?
>
Yep
> > {
> > /* See datasheet page 31 */
>
> It's fine, but better to add a formula here or more information about
> the calculations done in the function.
>
> > u32 period = NSEC_PER_SEC / fosc;
>
> period_ns ?
>
> (We usually add units to this kind of variables for better understanding
> of the calculations)
>
Ack.
> > > > static int ad4062_set_chan_calibscale(struct ad4062_state *st, int gain_int,
> > > > int gain_frac)
> > > > {
> > > > ...
> > > >
> > > > if (gain > 1999970)
> > >
> > > But this magic should be changed to what you explained to me
> > > (as in 0xffff/0x8000 with the proper precision, and this
> > > can be done in 32-bit space).
> > >
> > > Or even better
> > >
> > > if (gain_int < 0 || gain_int > 1)
> > > return -EINVAL;
> > >
> > > if (gain_int == 1 && gain_frac > 0x7fff) // did I get this right?
> > > return -EINVAL;
>
> > gain_frac would be 999999 max, or 999970 for the limit that fits in the
> > register after the math. I think > 1.999.970 is self explanatory.
>
> On the place of unprepared reader this is a complete magic number without
> scale, without understanding where it came from, etc.
>
> So, can you define it as a derivative from the other constants and with
> a comment perhaps?
>
(my proposal is after all your comments below)
> > > > return -EINVAL;
> > > >
> > > > put_unaligned_be16(DIV_ROUND_CLOSEST_ULL((u64)gain * AD4062_MON_VAL_MIDDLE_POINT,
> > > > MICRO),
> > >
> > > ...with temporary variable at minimum.
> > >
> > > But again, I still don't see the need for 64-bit space.
> >
> > Well, by dividing mon_val and micro values by a common divisor the
> > operation fit in 32-bits:
> >
> > static int ad4062_set_chan_calibscale(struct ad4062_state *st, int gain_int,
> > int gain_frac)
> > {
>
> /* Divide numerator and denumerator by known great common divider */
>
> > const u32 mon_val = AD4062_MON_VAL_MIDDLE_POINT / 64;
> > const u32 micro = MICRO / 64;
>
> Yep, I suggested the same in another patch under review (not yours) for
> the similar cases where we definitely may easily avoid overflow.
>
> Alternatively you can use gcd().
>
> > put_unaligned_be16(DIV_ROUND_CLOSEST(gain * mon_val, micro), st->buf.bytes);
>
> Btw, I think you can move this check up and save in a temporary variable which
> might affect the binary size of the compiled object as accesses to the gain_int
> and gain_frac will be grouped in the same place with potential of the reusing
> the CPU register(s)..
>
> > }
>
I believe this is clear and fits all points:
/* Divide numerator and denumerator by known great common divider */
const u32 mon_val = AD4062_MON_VAL_MIDDLE_POINT / 64;
const u32 micro = MICRO / 64;
const u32 gain_fp = gain_int * MICRO + gain_frac;
const u32 reg_val = DIV_ROUND_CLOSEST(gain_fp * mon_val, micro);
int ret;
/* Checks if the gain is in range and the value fits the field */
if (gain_int < 0 || gain_int > 1 || reg_val > BIT(16) - 1)
return -EINVAL;
put_unaligned_be16(reg_val, st->buf.bytes);
Explains 64 value. Checks if is in range [0, 2), then if fits the
register field for corner case of range (1.999970, 2) (0x10000). Full
formula is in the previous method ad4062_get_chan_calibscale.
> > > > st->buf.bytes);
> > > >
> > > > ret = regmap_bulk_write(st->regmap, AD4062_REG_MON_VAL,
> > > > &st->buf.be16, sizeof(st->buf.be16));
> > > > if (ret)
> > > > return ret;
> > > >
> > > > /* Enable scale if gain is not equal to one */
> > > > return regmap_update_bits(st->regmap, AD4062_REG_ADC_CONFIG,
> > > > AD4062_REG_ADC_CONFIG_SCALE_EN_MSK,
> > > > FIELD_PREP(AD4062_REG_ADC_CONFIG_SCALE_EN_MSK,
> > > > !(gain_int == 1 && gain_frac == 0)));
> > > > }
> > > >
> > > > To provide the enough resolution to compute every step (e.g., 0xFFFF and
> > > > 0xFFFE) with the arbitrary user input.
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
Best Regards,
Jorge