From: Jonathan Cameron <jic23@kernel.org>
To: Trevor Gamblin <tgamblin@baylibre.com>
Cc: "Michael Hennerich" <michael.hennerich@analog.com>,
"Nuno Sá" <nuno.sa@analog.com>,
"David Lechner" <dlechner@baylibre.com>,
"Lars-Peter Clausen" <lars@metafoo.de>,
"Jonathan Corbet" <corbet@lwn.net>,
linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org
Subject: Re: [PATCH 1/2] iio: adc: ad4695: add offload-based oversampling support
Date: Sat, 4 Jan 2025 12:30:29 +0000 [thread overview]
Message-ID: <20250104123029.12a4e19e@jic23-huawei> (raw)
In-Reply-To: <1c641b37-475a-4153-bcfc-e0e72d79fa76@baylibre.com>
On Thu, 2 Jan 2025 13:19:19 -0500
Trevor Gamblin <tgamblin@baylibre.com> wrote:
> On 2024-12-19 11:13, Jonathan Cameron wrote:
> > On Tue, 17 Dec 2024 16:47:28 -0500
> > Trevor Gamblin <tgamblin@baylibre.com> wrote:
> >
> >> Add support for the ad4695's oversampling feature when SPI offload is
> >> available. This allows the ad4695 to set oversampling ratios on a
> >> per-channel basis, raising the effective-number-of-bits from 16
> >> (OSR == 1) to 17 (4), 18 (16), or 19 (64) for a given sample (i.e. one
> >> full cycle through the auto-sequencer). The logic for reading and
> >> writing sampling frequency for a given channel is also adjusted based on
> >> the current oversampling ratio.
> >>
> >> The non-offload case isn't supported as there isn't a good way to
> >> trigger the CNV pin in this mode. Support could be added in the future
> >> if a use-case arises.
> >>
> >> Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
> > Hi Trevor,
> >
> > The clamping fun of get_calibbias seems overkill. If this isn't going to ever
> > overflow an s64 maybe just use the high precision to do it the easy way.
> > I'm not sure you can't just fit it in an s32 for that matter. I've just
> > not done the maths to check.
> >
> > Jonathan
> >
> >
> >> +static unsigned int ad4695_get_calibbias(int val, int val2, int osr)
> >> +{
> >> + unsigned int reg_val;
> >> +
> >> + switch (osr) {
> >> + case 4:
> >> + if (val2 >= 0 && val > S16_MAX / 2)
> >> + reg_val = S16_MAX;
> >> + else if ((val2 < 0 ? -val : val) < S16_MIN / 2)
> > It has been a while, but IIRC if val2 < 0 then val == 0 as otherwise
> > we carry the sign in the val part. Sometimes we generalize that to
> > make life easier for driver writers but I think you can use that here
> > to simplify things.
> >
> > (for background look at __iio_str_to_fixpoint() - it's a bit of a hack
> > to deal with integers have no negative 0)
> >
> > if (val > S16_MAX / 2)
> > ...
> > else if (val < S16_MIN / 2)
> > ...
> > else if (val2 < 0) etc
> >
> > You may feel it is better to keep the code considering the val2 < 0 when
> > val != 0 case and I don't mind that as it's not wrong, just overly complex!
> >
> > If you can easily clamp the overall range you can just do some maths
> > with enough precision to get one number (probably a s64) and clamp that.
> > Easy to sanity check for overflow based on val to ensure no overflows.
>
> Hi Jonathan,
>
> I'm reviewing this again but I'm not entirely clear what you mean.
>
> Are you suggesting that the entire switch block could be simplified
> (i.e. eliminating the previous simplification for the val2 < 0 case in
> the process), or that the calls to clamp_t can be combined?
>
> I've tested out simplifying the val2 < 0 case locally and driver
> functionality still seems OK. Maybe I'm missing a third option.
The extra info we can use is that val2 is always positive
if val != 0 and it never takes a value beyond +- MICRO because
otherwise val would be non 0 instead.
Taking original code and ruling out cases.
+ case 4:
+ if (val2 >= 0 && val > S16_MAX / 2)
// If val is non 0 then val2 is postive, so
// if (val > S16_MAX / 2)
// reg_val = S16_MAX;
+ reg_val = S16_MAX;
+ else if ((val2 < 0 ? -val : val) < S16_MIN / 2)
// If val2 < 0 then val == 0 which is never less than S16_MIN / 2
// So this condition never happens.
+ reg_val = S16_MIN;
+ else if (val2 < 0)
// likewise, this is actually clamping val2 * 2 / MICRO which
// is never going to be anywhere near S16_MIN or S16_MAX as I think
// it is always between +1 and -1 as val2 itself is limited to -MICRO to MICRO
+ reg_val = clamp_t(int,
+ -(val * 2 + -val2 * 2 / MICRO),
+ S16_MIN, S16_MAX);
+ else if (val < 0)
//This one is fine.
+ reg_val = clamp_t(int,
+ val * 2 - val2 * 2 / MICRO,
+ S16_MIN, S16_MAX);
+ else
//As is this one
+ reg_val = clamp_t(int,
+ val * 2 + val2 * 2 / MICRO,
+ S16_MIN, S16_MAX);
+ return reg_val;
Maybe trick is to reorder into 3 conditions and set the value in a temporary integer.
int val_calc;
if (val > 0)
val_calc = val * 2 + val2 * 2 / MICRO;
else if (val < 0)
val_calc = -(val * 2 - val2 * 2 / MICRO);
else /* Only now does val2 sign matter as val == 0 */
val_calc = val2 * 2 / MICRO;
Which can simplify because we know val is 0 for last case.
Whether this is worth doing depends on trade off between
docs needed to explain the code and shorter code.
/* Note that val2 > 0 if val != 0 and val2 range +- MICRO */
if (val < 0)
val_calc = val * 2 - val2 * 2 / MICRO;
else
val_calc = val * 2 + val2 * 2 / MICRO;
reg_val = clamp_t(int, val_calc, S16_MIN, S16_MAX);
One trivial additional simplication below.
You might also be able to scale temporary up by 2 and ust
have the switch statement set a scaling value.
In this case scale == 4 in other cases below, 2, 1, and 8 for the default
if (val < 0)
val_calc = val * scale - val2 * scale / MICRO;
else
val_calc = val * scale + val2 * scale / MICRO;
val_calc /= 2; /* to remove the factor of 2 */
reg_val = clamp_t (int, val_calc, S16_MIN, S16_MAX);
after the switch statement with comments when setting scale on the * 2
multiplier to avoid the / 2 for case 64.
>
> - Trevor
>
> >
> >
> >
> >
> >> + reg_val = S16_MIN;
> >> + else if (val2 < 0)
> >> + reg_val = clamp_t(int,
> >> + -(val * 2 + -val2 * 2 / MICRO),
> >> + S16_MIN, S16_MAX);
> >> + else if (val < 0)
> >> + reg_val = clamp_t(int,
> >> + val * 2 - val2 * 2 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + else
> >> + reg_val = clamp_t(int,
> >> + val * 2 + val2 * 2 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + return reg_val;
> >> + case 16:
> >> + if (val2 >= 0 && val > S16_MAX)
> >> + reg_val = S16_MAX;
> >> + else if ((val2 < 0 ? -val : val) < S16_MIN)
> >> + reg_val = S16_MIN;
> >> + else if (val2 < 0)
> >> + reg_val = clamp_t(int,
> >> + -(val + -val2 / MICRO),
> >> + S16_MIN, S16_MAX);
> >> + else if (val < 0)
> >> + reg_val = clamp_t(int,
> >> + val - val2 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + else
> >> + reg_val = clamp_t(int,
> >> + val + val2 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + return reg_val;
> >> + case 64:
> >> + if (val2 >= 0 && val > S16_MAX * 2)
> >> + reg_val = S16_MAX;
> >> + else if ((val2 < 0 ? -val : val) < S16_MIN * 2)
> >> + reg_val = S16_MIN;
> >> + else if (val2 < 0)
> >> + reg_val = clamp_t(int,
> >> + -(val / 2 + -val2 / 2 / MICRO),
> >> + S16_MIN, S16_MAX);
> >> + else if (val < 0)
> >> + reg_val = clamp_t(int,
> >> + val / 2 - val2 / 2 / MICRO,
For these val2 / 2 / MICRO always 0 so value of val2 never matters.
> >> + S16_MIN, S16_MAX);
> >> + else
> >> + reg_val = clamp_t(int,
> >> + val / 2 + val2 / 2 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + return reg_val;
> >> + default:
> >> + if (val2 >= 0 && val > S16_MAX / 4)
> >> + reg_val = S16_MAX;
> >> + else if ((val2 < 0 ? -val : val) < S16_MIN / 4)
> >> + reg_val = S16_MIN;
> >> + else if (val2 < 0)
> >> + reg_val = clamp_t(int,
> >> + -(val * 4 + -val2 * 4 / MICRO),
> >> + S16_MIN, S16_MAX);
> >> + else if (val < 0)
> >> + reg_val = clamp_t(int,
> >> + val * 4 - val2 * 4 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + else
> >> + reg_val = clamp_t(int,
> >> + val * 4 + val2 * 4 / MICRO,
> >> + S16_MIN, S16_MAX);
> >> + return reg_val;
> >> + }
> >> +}
> >> +
next prev parent reply other threads:[~2025-01-04 12:30 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-17 21:47 [PATCH 0/2] iio: adc: ad4695: add oversampling support Trevor Gamblin
2024-12-17 21:47 ` [PATCH 1/2] iio: adc: ad4695: add offload-based " Trevor Gamblin
2024-12-19 16:13 ` Jonathan Cameron
2024-12-23 16:33 ` Trevor Gamblin
2025-01-02 18:19 ` Trevor Gamblin
2025-01-04 12:30 ` Jonathan Cameron [this message]
2025-01-07 20:21 ` Trevor Gamblin
2025-01-07 21:02 ` David Lechner
2025-01-08 19:54 ` Trevor Gamblin
2025-01-08 20:39 ` David Lechner
2024-12-17 21:47 ` [PATCH 2/2] doc: iio: ad4695: describe " Trevor Gamblin
2024-12-19 15:53 ` Jonathan Cameron
2024-12-19 15:46 ` [PATCH 0/2] iio: adc: ad4695: add " Jonathan Cameron
2025-01-09 18:09 ` Trevor Gamblin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250104123029.12a4e19e@jic23-huawei \
--to=jic23@kernel.org \
--cc=corbet@lwn.net \
--cc=dlechner@baylibre.com \
--cc=lars@metafoo.de \
--cc=linux-doc@vger.kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michael.hennerich@analog.com \
--cc=nuno.sa@analog.com \
--cc=tgamblin@baylibre.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox