[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <9831ddde-5db8-04db-a712-8cd7f73d32d0@fi.rohmeurope.com>
Date: Tue, 28 Feb 2023 09:09:39 +0000
From: "Vaittinen, Matti" <Matti.Vaittinen@...rohmeurope.com>
To: Jonathan Cameron <jic23@...nel.org>,
Matti Vaittinen <mazziesaccount@...il.com>
CC: Lars-Peter Clausen <lars@...afoo.de>,
Rob Herring <robh+dt@...nel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@...aro.org>,
Shreeya Patel <shreeya.patel@...labora.com>,
Zhigang Shi <Zhigang.Shi@...eon.com>,
Paul Gazzillo <paul@...zz.com>,
Dmitry Osipenko <dmitry.osipenko@...labora.com>,
Liam Beguin <liambeguin@...il.com>,
Peter Rosin <peda@...ntia.se>,
Randy Dunlap <rdunlap@...radead.org>,
Masahiro Yamada <masahiroy@...nel.org>,
"linux-iio@...r.kernel.org" <linux-iio@...r.kernel.org>,
"devicetree@...r.kernel.org" <devicetree@...r.kernel.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
Subject: Re: [RFC PATCH 2/6] iio: light: Add gain-time-scale helpers
On 2/26/23 18:21, Jonathan Cameron wrote:
> On Wed, 22 Feb 2023 18:14:45 +0200
> Matti Vaittinen <mazziesaccount@...il.com> wrote:
>
>> Some light sensors can adjust both the HW-gain and integration time.
>> There are cases where adjusting the integration time has similar impact
>> to the scale of the reported values as gain setting has.
>>
>> IIO users do typically expect to handle scale by a single writable 'scale'
>> entry. Driver should then adjust the gain/time accordingly.
>>
>> It however is difficult for a driver to know whether it should change
>> gain or integration time to meet the requested scale. Usually it is
>> preferred to have longer integration time which usually improves
>> accuracy, but there may be use-cases where long measurement times can be
>> an issue. Thus it can be preferable to allow also changing the
>> integration time - but mitigate the scale impact by also changing the gain
>> underneath. Eg, if integration time change doubles the measured values,
>> the driver can reduce the HW-gain to half.
>>
>> The theory of the computations of gain-time-scale is simple. However,
>> some people (undersigned) got that implemented wrong for more than once.
>
> Do you allow for approximately correct gains? Often there are significant
> restrictions in what is possible and it would be reasonable to allow a little
> slack (though obviously the sysfs value would change a bit to reflect that).
Right now I did accept only the exact scales/gains. It keeps the code
simpler. As you say, the consequence is that the user-space must be able
to ask the exactly supported scales - which for any generic usage pretty
much requires that the available scales are advertised by the driver.
I think we could take the same approach as with the 'linear_range'
helpers and - when required - add gain-time-scale APIs which return the
next supported lower gain (or higher scale) if the exact computed one is
not supported.
>>
>> Add some gain-time-scale helpers in order to not dublicate errors in all
>> drivers needing these computations.
>>
>> Signed-off-by: Matti Vaittinen <mazziesaccount@...il.com>
>
> I was going to suggest just rolling this into the IIO core, but as it's a
> less than trivial amount of code, maybe not!
I think this warrants it's own file. And, I would not be surprized if
this was gaining extensions in the future - like the 'find closest lower
gain' stuff mentioned above.
Actually, the theory is not at all gain-time-scale specific - but could
be generally applicable also for other cases where a value (total gain)
is formed by multiplying two other values (time and hw-gain) and where
some conversion to inverse (scale) value is needed.
Yet, in order to keep things simple we need to make assumptions for
example about the sizes of integers - and giving abstract names to
gain/time/scale variables would have resulted quite a mess... Making a
'generic helper' out of this would have probably ended up me to
providing fancy named wrappers around the very basic arithmetic
operations :) But yes, I was initially wondering if this could be
written using more re-usable naming and be put under the /lib.
After all this talk - I think the file name is too long and should be
prefixed with iio. Maybe iio-gts-helpers.c and iio-gts-helpers.h
I will see the comments below and fix the issues to v2 :) Thanks for the
review!
-- Matti
>
>>
>> ---
>> Currently it is only BU27034 using these in this series. I am however working
>> with drivers for RGB sensors BU27008 and BU27010 which have similar
>> [gain - integration time - scale] - relation. I hope sending those
>> follows soon after the BU27034 is done.
>> ---
>> drivers/iio/light/Kconfig | 3 +
>> drivers/iio/light/Makefile | 1 +
>> drivers/iio/light/gain-time-scale-helper.c | 446 +++++++++++++++++++++
>> drivers/iio/light/gain-time-scale-helper.h | 111 +++++
>> 4 files changed, 561 insertions(+)
>> create mode 100644 drivers/iio/light/gain-time-scale-helper.c
>> create mode 100644 drivers/iio/light/gain-time-scale-helper.h
>>
>> diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
>> index 0d4447df7200..671d84f98c56 100644
>> --- a/drivers/iio/light/Kconfig
>> +++ b/drivers/iio/light/Kconfig
>> @@ -183,6 +183,9 @@ config IIO_CROS_EC_LIGHT_PROX
>> To compile this driver as a module, choose M here:
>> the module will be called cros_ec_light_prox.
>>
>> +config IIO_GTS_HELPER
>> + tristate
>> +
>> config GP2AP002
>> tristate "Sharp GP2AP002 Proximity/ALS sensor"
>> depends on I2C
>> diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
>> index 6f23817fae6f..f4705fac7a96 100644
>> --- a/drivers/iio/light/Makefile
>> +++ b/drivers/iio/light/Makefile
>> @@ -20,6 +20,7 @@ obj-$(CONFIG_CM3323) += cm3323.o
>> obj-$(CONFIG_CM3605) += cm3605.o
>> obj-$(CONFIG_CM36651) += cm36651.o
>> obj-$(CONFIG_IIO_CROS_EC_LIGHT_PROX) += cros_ec_light_prox.o
>> +obj-$(CONFIG_IIO_GTS_HELPER) += gain-time-scale-helper.o
>> obj-$(CONFIG_GP2AP002) += gp2ap002.o
>> obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
>> obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
>> diff --git a/drivers/iio/light/gain-time-scale-helper.c b/drivers/iio/light/gain-time-scale-helper.c
>> new file mode 100644
>> index 000000000000..bd8fc11802ee
>> --- /dev/null
>> +++ b/drivers/iio/light/gain-time-scale-helper.c
>> @@ -0,0 +1,446 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/* gain-time-scale conversion helpers for IIO light sensors
>> + *
>> + * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@...il.com>
>> + */
>> +
>> +#include <linux/errno.h>
>> +#include <linux/export.h>
>> +#include <linux/module.h>
>> +#include <linux/units.h>
>> +
>> +#include "gain-time-scale-helper.h"
>> +
>> +static int iio_gts_get_gain(const u64 max, u64 scale)
>
> trivial but scale equally const in here.
> Not immediately obvious what this function does from name, so add
> some docs.
>
>> +{
>> + int tmp = 1;
>> +
>> + if (scale > max || !scale)
>> + return -EINVAL;
>> +
>> + if (0xffffffffffffffffLLU - max < scale) {
>
> U64_MAX from limits.h?
>
>> + /* Risk of overflow */
>> + if (max - scale < scale)
>> + return 1;
>> +
>> + while (max - scale > scale * (u64) tmp)
>> + tmp++;
>> +
>> + return tmp + 1;
>> + }
>> +
>> + while (max > scale * (u64) tmp)
>> + tmp++;
>> +
>> + return tmp;
>> +}
>> +
>> +static int gain_get_scale_fraction(const u64 max, u64 scale, int known,
>> + int *unknown)
>
> Needs some basic docs.
>
>> +{
>> + int tot_gain;
>> +
>> + if (!known)
>> + return -EINVAL;
>
> We don't normally bother checking for NULL pointers unless calling with one
> is meaningful or the compiler is warning. If it's warning add a comment to say this
> is to suppress the warning.
>
>> +
>> + tot_gain = iio_gts_get_gain(max, scale);
>> + if (tot_gain < 0)
>> + return tot_gain;
>> +
>> + *unknown = tot_gain/known;gts_valid_gain
> spaces around /
>> +
>> + /* We require total gain to be exact multiple of known * unknown */
>> + if (!*unknown || *unknown * known != tot_gain)
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +
>> +static const struct iio_itime_sel_mul *
>> + iio_gts_find_itime_by_time(struct iio_gts *gts, int time)
>> +{
>> + int i;
>> +
>> + if (!gts->num_itime)
>> + return NULL;
>> +
>> + for (i = 0; i < gts->num_itime; i++)
>> + if (gts->itime_table[i].time_us == time)
>> + return >s->itime_table[i];
>> +
>> + return NULL;
>> +}
>> +
>> +static const struct iio_itime_sel_mul *
>> + iio_gts_find_itime_by_sel(struct iio_gts *gts, int sel)
>> +{
>> + int i;
>> +
>> + if (!gts->num_itime)
>> + return NULL;
>
> As mentioned below. I'd check this in the init function and after that
> assume that it is fine. In this particular case for loop won't do anything
> anwyay as i = 0 is not less than 0
>
>> +
>> + for (i = 0; i < gts->num_itime; i++)
>> + if (gts->itime_table[i].sel == sel)
>> + return >s->itime_table[i];
>> +
>> + return NULL;
>> +}
>> +
>> +static int iio_gts_delinearize(u64 lin_scale, int *scale_whole, int *scale_nano,
>> + unsigned long scaler)
>
> Same comment as below about about parameter ordering.
>
>> +{
>> + int frac;
>> +
>> + if (scaler > NANO || !scaler)
>> + return -EINVAL;
>> +
>> + frac = do_div(lin_scale, scaler);
>> +
>> + *scale_whole = lin_scale;
>> + *scale_nano = frac * (NANO / scaler);
>> +
>> + return 0;
>> +}
>> +
>> +static int iio_gts_linearize(int scale_whole, int scale_nano, u64 *lin_scale,
>> + unsigned long scaler)
>
> Mixing up inputs and outputs in parameter order is not a common thing to do.
> I'd do all the inputs first then the outputs.
>
>> +{
>> + /*
>> + * Expect scale to be (mostly) NANO or MICRO. Divide divider instead of
>> + * multiplication followed by division to avoid overflow
>> + */
>> + if (scaler > NANO || !scaler)
>> + return -EINVAL;
>> +
>> + *lin_scale = (u64) scale_whole * (u64)scaler + (u64)(scale_nano
>> + / (NANO / scaler));
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * iio_init_iio_gts - Initialize the gain-time-scale helper
>> + * @max_scale_int: integer part of the maximum scale value
>> + * @max_scale_nano: fraction part of the maximum scale value
>> + * @gain_tbl: table describing supported gains
>> + * @num_gain: number of gains in the gaintable
>> + * @tim_tbl: table describing supported integration times
>> + * @num_times: number of times in the time table
>> + * @gts: pointer to the helper struct
>> + *
>> + * Initialize the gain-time-scale helper for use. Please, provide the
>> + * integration time table sorted so that the preferred integration time is
>> + * in the first array index.
>
> Document that in the parameter descriptions not here. And skip the please :)
>
>
>> The search functions like the
>> + * iio_gts_find_time_and_gain_sel_for_scale() start search from first
>> + * provided time.
>> + *
>> + * Return: 0 on success.
>> + */
>> +int iio_init_iio_gts(int max_scale_int, int max_scale_nano,
>> + const struct iio_gain_sel_pair *gain_tbl, int num_gain,
>> + const struct iio_itime_sel_mul *tim_tbl, int num_times,
>> + struct iio_gts *gts)
>> +{
>> + int ret;
>> +
>> + ret = iio_gts_linearize(max_scale_int, max_scale_nano,
>> + >s->max_scale, NANO);
>> + if (ret)
>> + return ret;
>> +
>> + gts->hwgain_table = gain_tbl;
>> + gts->num_hwgain = num_gain;
>> + gts->itime_table = tim_tbl;
>> + gts->num_itime = num_times;
>
> I think all these need to be provided for this to do anything useful.
> So check them here and drop the checks in the various other functions.
>
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_init_iio_gts);
>> +
>> +bool iio_gts_valid_time(struct iio_gts *gts, int time_us)
>> +{
>> + return !!iio_gts_find_itime_by_time(gts, time_us);
>
> it's return a bool, no need for the !! dance.
>
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_valid_time);
>> +
>> +int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < gts->num_hwgain; i++)
>> + if (gts->hwgain_table[i].gain == gain)
>> + return gts->hwgain_table[i].sel;
>> +
>> + return -EINVAL;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_sel_by_gain);
>> +
>> +bool iio_gts_valid_gain(struct iio_gts *gts, int gain)
>> +{
>> + return !(iio_gts_find_sel_by_gain(gts, gain) < 0);
>
> return iio_gts_find_sel_by_gain >= 0;
>
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_valid_gain);
>> +
>> +int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < gts->num_hwgain; i++)
>> + if (gts->hwgain_table[i].sel == sel)
>> + return gts->hwgain_table[i].gain;
>> +
>> + return -EINVAL;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_gain_by_sel);
>> +
>> +int iio_gts_get_int_time_gain_multiplier_by_sel(struct iio_gts *gts,
>> + int sel)
>> +{
>> + const struct iio_itime_sel_mul *time;
>> +
>> + time = iio_gts_find_itime_by_sel(gts, sel);
>> + if (!time)
>> + return -EINVAL;
>> +
>> + return time->mul;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_get_int_time_gain_multiplier_by_sel);
>> +
>> +/**
>> + * iio_gts_find_gain_for_scale_using_time - Find gain by time and scale
>> + * @gts: Gain time scale descriptor
>> + * @time_sel: Integration time selector correspondig to the time gain is
>> + * searhed for
>> + * @scale_int: Integral part of the scale (typically val1)
>> + * @scale_nano: Fractional part of the scale (nano or ppb)
>> + * @gain: Pointer to value where gain is stored.
>> + *
>> + * In some cases the light sensors may want to find a gain setting which
>> + * corresponds given scale and integration time. Sensors which fill the
>> + * gain and time tables may use this helper to retrieve the gain.
>> + *
>> + * Return: 0 on success. -EINVAL if gain matching the parameters is not
>> + * found.
>> + */
>> +int iio_gts_find_gain_for_scale_using_time(struct iio_gts *gts, int time_sel,
>> + int scale_int, int scale_nano,
>> + int *gain)
>> +{
>> + u64 scale_linear;
>> + int ret, mul;
>> +
>> + ret = iio_gts_linearize(scale_int, scale_nano, &scale_linear, NANO);
>> + if (ret)
>> + return ret;
>> +
>> + ret = iio_gts_get_int_time_gain_multiplier_by_sel(gts, time_sel);
>> + if (ret < 0)
>> + return ret;
>> +
>> + mul = ret;
>> +
>> + ret = gain_get_scale_fraction(gts->max_scale, scale_linear, mul, gain);
>> +
>> + if (ret || !iio_gts_valid_gain(gts, *gain))gts
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_gain_for_scale_using_time);
>> +
>> +/*
>> + * iio_gts_find_gain_sel_for_scale_using_time - Fetch gain selector.
>> + * See iio_gts_find_gain_for_scale_using_time() for more information
>> + */
>> +int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel,
>> + int scale_int, int scale_nano,
>> + int *gain_sel)
>> +{
>> + int gain, ret;
>> +
>> + ret = iio_gts_find_gain_for_scale_using_time(gts, time_sel, scale_int,
>> + scale_nano, &gain);
>> + if (ret)
>> + return ret;
>> +
>> + ret = iio_gts_find_sel_by_gain(gts, gain);
>> + if (ret < 0)
>> + return ret;
>> +
>> + *gain_sel = ret;
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_gain_sel_for_scale_using_time);
>> +
>> +int iio_gts_find_time_and_gain_sel_for_scale(struct iio_gts *gts, int scale_int,
>> + int scale_nano, int *gain_sel,
>> + int *time_sel)
>> +{
>> + int ret, i;
>> +
>> + for (i = 0; i < gts->num_itime; i++) {
>> + *time_sel = gts->itime_table[i].sel;
>> + ret = iio_gts_find_gain_sel_for_scale_using_time(gts, *time_sel,
>> + scale_int, scale_nano, gain_sel);
>> + if (!ret)
>> + return 0;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_time_and_gain_sel_for_scale);
>> +
>> +int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel)
>> +{
>> + const struct iio_itime_sel_mul *itime;
>> +
>> + itime = iio_gts_find_itime_by_sel(gts, sel);
>> + if (!itime)
>> + return -EINVAL;
>> +
>> + return itime->time_us;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_int_time_by_sel);
>> +
>> +int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time)
>> +{
>> + const struct iio_itime_sel_mul *itime;
>> +
>> + itime = iio_gts_find_itime_by_time(gts, time);
>> + if (!itime)
>> + return -EINVAL;
>> +
>> + return itime->sel;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_sel_by_int_time);
>> +
>> +int iio_gts_get_total_gain_by_sel(struct iio_gts *gts, int gsel, int tsel)
>> +{
>> + int ret, tmp;
>> +
>> + ret = iio_gts_find_gain_by_sel(gts, gsel);
>> + if (ret < 0)
>> + return ret;
>> +
>> + tmp = ret;
>> +
>> + /*
>> + * TODO: Would these helpers provde any value for cases where we just
>> + * use table of gains and no integration time? This would be a standard
>> + * format for gain table representation and regval => gain / gain =>
>> + * regval conversions. OTOH, a dummy table based conversion is a memory
>> + * hog in cases where the gain could be computed simply based on simple
>> + * multiplication / bit-shift or by linear_ranges helpers.
>> + *
>> + * Currently we return an error if int-time table is not populated.
>> + */
>> + ret = iio_gts_get_int_time_gain_multiplier_by_sel(gts, tsel);
>> + if (ret < 0)
>> + return ret;
>> +
>> + return tmp * ret;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_get_total_gain_by_sel);
>> +
>> +int iio_gts_get_total_gain(struct iio_gts *gts, int gain, int time)
>> +{
>> + const struct iio_itime_sel_mul *itime;
>> +
>> + if (!iio_gts_valid_gain(gts, gain))
>> + return -EINVAL;
>> +
>> + if (!gts->num_itime)
>> + return gain;
>> +
>> + itime = iio_gts_find_itime_by_time(gts, time);
>> + if (!itime)
>> + return -EINVAL;
>> +
>> + return gain * itime->mul;
>> +}
>> +EXPORT_SYMBOL(iio_gts_get_total_gain);
>> +
>> +static int iio_gts_get_scale_linear(struct iio_gts *gts, int gain, int time,
>> + u64 *scale)
>> +{
>> + int total_gain;
>> + u64 tmp;
>> +
>> + total_gain = iio_gts_get_total_gain(gts, gain, time);
>> + if (total_gain < 0)
>> + return total_gain;
>> +
>> + tmp = gts->max_scale;
>> +
>> + do_div(tmp, total_gain);
>> +
>> + *scale = tmp;
>> +
>> + return 0;
>> +}
>> +
>> +int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int,
>> + int *scale_nano)
>> +{
>> + u64 lin_scale;
>> + int ret;
>> +
>> + ret = iio_gts_get_scale_linear(gts, gain, time, &lin_scale);
>> + if (ret)
>> + return ret;
>> +
>> + return iio_gts_delinearize(lin_scale, scale_int, scale_nano, NANO);
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_get_scale);
>> +
>> +/**
>> + * iio_gts_find_new_gain_sel_by_old_gain_time - compensate time change
>> + * @gts: Gain time scale descriptor
>> + * @old_gain: Previously set gain
>> + * @old_time_sel: Selector corresponding previously set time
>> + * @new_time_sel: Selector corresponding new time to be set
>> + * @new_gain: Pointer to value where new gain is to be written
>> + *
>> + * We may want to mitigate the scale change caused by setting a new integration
>> + * time (for a light sensor) by also updating the (HW)gain. This helper computes
>> + * new gain value to maintain the scale with new integration time.
>> + *
>> + * Return: 0 on success. -EINVAL if gain matching the new time is not found.
>> + */
>> +int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts,
>> + int old_gain, int old_time_sel,
>> + int new_time_sel, int *new_gain)
>> +{
>> + const struct iio_itime_sel_mul *itime_old, *itime_new;
>> + u64 scale;
>> + int ret;
>> +
>> + itime_old = iio_gts_find_itime_by_sel(gts, old_time_sel);
>> + if (!itime_old)
>> + return -EINVAL;
>> +
>> + itime_new = iio_gts_find_itime_by_sel(gts, new_time_sel);
>> + if (!itime_new)
>> + return -EINVAL;
>> +
>> + ret = iio_gts_get_scale_linear(gts, old_gain, itime_old->time_us,
>> + &scale);
>> + if (ret)
>> + return ret;
>> +
>> + ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul,
>> + new_gain);
>> + if (ret)
>> + return -EINVAL;
>> +
>> + if (!iio_gts_valid_gain(gts, *new_gain))
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_gts_find_new_gain_sel_by_old_gain_time);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@...il.com>");
>> +MODULE_DESCRIPTION("IIO light sensor gain-time-scale helpers");
>> diff --git a/drivers/iio/light/gain-time-scale-helper.h b/drivers/iio/light/gain-time-scale-helper.h
>> new file mode 100644
>> index 000000000000..70a952a8de92
>> --- /dev/null
>> +++ b/drivers/iio/light/gain-time-scale-helper.h
>> @@ -0,0 +1,111 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/* gain-time-scale conversion helpers for IIO light sensors
>> + *
>> + * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@...il.com>
>> + */
>> +
>> +#ifndef __GAIN_TIME_SCALE_HELPER__
>> +#define ___GAIN_TIME_SCALE_HELPER__
>> +
>> +/**
>> + * struct iio_gain_sel_pair - gain - selector values
>> + *
>> + * In many cases devices like light sensors allow setting signal amplification
>> + * (gain) using a register interface. This structure describes amplification
>> + * and corresponding selector (register value)
>> + *
>> + * @gain: Gain (multiplication) value.
>> + * @sel: Selector (usually register value) used to indicate this gain
>> + */
>> +struct iio_gain_sel_pair {
>> + int gain;
>> + int sel;
>> +};
>> +
>> +/**
>> + * struct iio_itime_sel_mul - integration time description
>> + *
>> + * In many cases devices like light sensors allow setting the duration of
>> + * collecting data. Typically this duration has also an impact to the magnitude
>> + * of measured values (gain). This structure describes the relation of
>> + * integration time and amplification as well as corresponding selector
>> + * (register value).
>> + *
>> + * An example could be a sensor allowing 50, 100, 200 and 400 mS times. The
>> + * respective multiplication values could be 50 mS => 1, 100 mS => 2,
>> + * 200 mS => 4 and 400 mS => 8 assuming the impact of integration time would be
>> + * linear in a way that when collecting data for 50 mS caused value X, doubling
>> + * the data collection time caused value 2X etc..
>> + *
>> + * @time_us: Integration time in microseconds.
>> + * @sel: Selector (usually register value) used to indicate this time
>> + * @mul: Multiplication to the values caused by this time.
>> + */
>> +struct iio_itime_sel_mul {
>> + int time_us;
>> + int sel;
>> + int mul;
>> +};
>> +
>> +struct iio_gts {
>> + u64 max_scale;
>> + const struct iio_gain_sel_pair *hwgain_table;
>> + int num_hwgain;
>> + const struct iio_itime_sel_mul *itime_table;
>> + int num_itime;
>> +};
>> +
>> +#define GAIN_SCALE_GAIN(_gain, _sel) \
>> +{ \
>> + .gain = (_gain), \
>> + .sel = (_sel), \
>> +}
>> +
>> +#define GAIN_SCALE_ITIME_MS(_itime, _sel, _mul) \
>> +{ \
>> + .time_us = (_itime) * 1000, \
>
> Not sure this macro adds much. Just use the * 1000 at callers.
>
>> + .sel = (_sel), \
>> + .mul = (_mul), \
>> +}
>> +
>> +#define GAIN_SCALE_ITIME_US(_itime, _sel, _mul) \
>> +{ \
>> + .time_us = (_itime), \
>> + .sel = (_sel), \
>> + .mul = (_mul), \
>> +}
>> +
>> +int iio_init_iio_gts(int max_scale_int, int max_scale_nano,
>> + const struct iio_gain_sel_pair *gain_tbl, int num_gain,
>> + const struct iio_itime_sel_mul *tim_tbl, int num_times,
>> + struct iio_gts *gts);
>> +
>> +bool iio_gts_valid_gain(struct iio_gts *gts, int gain);
>> +bool iio_gts_valid_time(struct iio_gts *gts, int time_us);
>> +
>> +int iio_gts_get_total_gain_by_sel(struct iio_gts *gts, int gsel, int tsel);
>> +int iio_gts_get_total_gain(struct iio_gts *gts, int gain, int time);
>> +
>> +int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel);
>> +int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain);
>> +int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel);
>> +int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time);
>> +
>> +int iio_gts_get_int_time_gain_multiplier_by_sel(struct iio_gts *gts,
>> + int sel);
>> +int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel,
>> + int scale_int, int scale_nano,
>> + int *gain_sel);
>> +int iio_gts_find_gain_for_scale_using_time(struct iio_gts *gts, int time_sel,
>> + int scale_int, int scale_nano,
>> + int *gain);
>> +int iio_gts_find_time_and_gain_sel_for_scale(struct iio_gts *gts, int scale_int,
>> + int scale_nano, int *gain_sel,
>> + int *time_sel);
>> +int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int,
>> + int *scale_nano);
>> +int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts,
>> + int old_gain, int old_time_sel,
>> + int new_time_sel, int *new_gain);
>> +
>> +#endif
>
--
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland
~~ When things go utterly wrong vim users can always type :help! ~~
Powered by blists - more mailing lists