Re: [PATCH 2/2] iio: light: veml6030: fix scale to conform to ABI

From: Matti Vaittinen
Date: Tue Jan 14 2025 - 01:44:14 EST


ti 14.1.2025 klo 0.32 Javier Carrasco (javier.carrasco.cruz@xxxxxxxxx)
kirjoitti:
>
> On Mon Jan 13, 2025 at 8:52 PM CET, Matti Vaittinen wrote:
> > ma 13.1.2025 klo 17.05 Javier Carrasco
> > (javier.carrasco.cruz@xxxxxxxxx) kirjoitti:
> > >
> > > On Mon Jan 13, 2025 at 12:56 PM CET, Matti Vaittinen wrote:
> > > > On 07/01/2025 22:50, Javier Carrasco wrote:
> > > > > The current scale is not ABI-compliant as it is just the sensor gain
> > > > > instead of the value that acts as a multiplier to be applied to the raw
> > > > > value (there is no offset).
> > > > >
> > > > > Use the iio-gts helpers to obtain the proper scale values according to
> > > > > the gain and integration time to match the resolution tables from the
> > > > > datasheet and drop dedicated variables to store the current values of
> > > > > the integration time, gain and resolution. When at it, use 'scale'
> > > > > instead of 'gain' consistently for the get/set functions to avoid
> > > > > misunderstandings.
> > > > >
> > > > > Fixes: 7b779f573c48 ("iio: light: add driver for veml6030 ambient light sensor")
> > > > > Signed-off-by: Javier Carrasco <javier.carrasco.cruz@xxxxxxxxx>
> > > >
> > > > Thanks for the patch Javier.
> > > >
> > > > And, sorry for a review which is more about questions than suggested
> > > > improvements. I find it hard to focus on reading code today.
> > > >
> > > > > ---
> > > > > drivers/iio/light/Kconfig | 1 +
> > > > > drivers/iio/light/veml6030.c | 499 ++++++++++++++++---------------------------
> > > > > 2 files changed, 189 insertions(+), 311 deletions(-)
> > > > ...
> > > >
> > > > > +
> > > > > +static int veml6030_process_als(struct veml6030_data *data, int raw,
> > > > > + int *val, int *val2)
> > > > > +{
> > > > > + int ret, scale_int, scale_nano;
> > > > > + u64 tmp;
> > > > > +
> > > > > + ret = veml6030_get_scale(data, &scale_int, &scale_nano);
> > > > > + if (ret < 0)
> > > > > + return ret;
> > > > > +
> > > > > + tmp = (u64)raw * scale_nano;
> > > > > + *val = raw * scale_int + div_u64(tmp, NANO);
> > > > > + *val2 = div_u64(do_div(tmp, NANO), MILLI);
> > > >
> > > > do_div() is horrible on some platforms. Or, at least it used to be. Is
> > > > there really no way to go without it? We're dealing with 16bit data and
> > > > maximum of 512x total gain only, so maybe there was a way(?)
> > > >
> > > > Maybe a stupid question (in which case I blame mucus in my head) - could
> > > > you just divide the raw value by the total gain?
> > > >
> > >
> > > In its current form we need the 64-bit operations to handle the scale,
> > > and it will probably have to stay like that for the reasons I give you
> > > below.
> >
> > Still, I wonder if multiplying by scale really differs from dividing
> > by the total gain? I think the scale is inversely proportional to the
> > total gain, right?
> >
> I am sorry, but I am not sure if I got your point here. The scale is the
> multiplier to get lux from raw, and for example it's not just 1/512 for
> the maximum total gain, as that is not taking the intrinsic resolution
> of the sensor. Maybe I am misunderstanding something, but I don't see the
> way around raw * scale with the scale being one of the discrete values
> provided in the application note.
>
> I will give you a simple example, so you can tell me where my reasoning
> fails:
>
> raw = 100 counts
> scale = 2.1504 lux/count (when IT=25ms and GAIN=1/8)
> processed = 215.04 lux (raw * scale, ABI compliant for IIO_LIGHT)
>
> The reply to your comment below explains why we have a PROCESSED
> IIO_LIGHT in the first place.
>
> > > > > static irqreturn_t veml6030_event_handler(int irq, void *private)
> > > > > @@ -1084,6 +968,13 @@ static int veml6030_hw_init(struct iio_dev *indio_dev, struct device *dev)
> > > > > int ret, val;
> > > > > struct veml6030_data *data = iio_priv(indio_dev);
> > > > >
> > > > > + ret = devm_iio_init_iio_gts(dev, 2, 150400000,
> > > >
> > > > Can you please explain the seemingly odd choice for the max scale?
> > > >
> > > > Just a quick look at the sensor spec and this driver allows me to assume
> > > > following:
> > > >
> > > > Maximum 'total gain' from both HWGAIN and integration time is 16 * 32 = 512.
> > > >
> > > > If we chose the 'total gain' 1x to match scale 1, then the smallest
> > > > scale would be 1/512 = 0.001 953 125
> > > >
> > > > This is 1953125 NANOs. This would mean the max-scale 1X => gain 1X would
> > > > not cause precision loss. (Well, I'm not at my sharpest as I've caught
> > > > cold - but I _think_ this is true, right?)
> > > >
> > > > If I read this correctly, the only channel where the scale gets applied
> > > > is the INTENSITY channel, right? Hence it should be possible to chose
> > > > the scale as we see best. (Unless the idea of this seemingly odd scale
> > > > is to maintain the old intensity / scale values in order to not shake
> > > > userland any more - in which case this could be mentioned).
> > > >
> > >
> > > The scale is applied to an IIO_LIGHT channel, not to the INTENSITY,
> >
> > Isn't the IIO_LIGHT channel a PROCESSED one? I thought the scale
> > shouldn't be applied to it. (Driver may still apply scale internally,
> > but users should not see it, right? And if the driver does it only
> > internally, then the driver can also multiply values using (N *
> > scale). Well, I suppose you can as well use this "fitted MAX SCALE" -
> > but maybe it warrants a comment.
>
> IIO_LIGHT provides RAW and PROCESSED values,

Thanks. This explains why you chose the MAX SCALE in IIo init to be
this oddish looking value :)

> which shouldn't have
> happened in the first place as PROCESSED is just raw * scale, if scale
> had been right from the beginning. Actually, when I took over this
> driver, I was tempted to drop the PROCESSED value, but it was too late
> for that without breaking ABI. My guess is that the processed value was
> provided because in_illuminance_scale was not the right multiplier, only
> the gain.
> Note that in_illuminance_scale is also provided to the user, and that
> must comply with the ABI definitions.

Sure. Raw * scale must be lux. You still could use some driver
internal scale multiplier which you
applied before pushing the lux values to users, but this would make
the available scales handling more complicated. Hence, I now fully
agree with you using the
2, 150400000, in devm_iio_init_iio_gts() as max scale. Thank you for
the patience :)

I copied part of your reply below as I think this is the right order
of discussion:

> I will give you a simple example, so you can tell me where my reasoning
> fails:
>
> raw = 100 counts
> scale = 2.1504 lux/count (when IT=25ms and GAIN=1/8)
> processed = 215.04 lux (raw * scale, ABI compliant for IIO_LIGHT)

Your reasoning does not fail. But, the scale = 1 / (N * total_gain),
right? (N here depends on how we choose the scale/gain values) Here,
the total_gain means the effect of both the hardware_gain and the
integration time.

Hence,
processed = X * (raw * scale)

=> processed = X * (raw * (1 / (N * total_gain))
=> processed = X * raw / (N * total_gain);

Hence I thought you might be able to get rid of this 64bit division by
using the total_gain from the iio_gts_get_total_gain() instead of
using the scale. Or, am I missing something?

Yours,
-- Matti

--

Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~

Discuss - Estimate - Plan - Report and finally accomplish this:
void do_work(int time) __attribute__ ((const));