From: Jonathan Cameron <jic23@kernel.org>
To: "Patrik Dahlström" <risca@dalakolonin.se>
Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org,
letux-kernel@openphoenux.org, kernel@pyra-handheld.com,
pgoudagunta@nvidia.com, hns@goldelico.com, lars@metafoo.de,
linux-omap@vger.kernel.org
Subject: Re: [PATCH v3 6/7] iio: adc: palmas: add support for iio threshold events
Date: Fri, 7 Apr 2023 18:19:47 +0100 [thread overview]
Message-ID: <20230407181947.667614ed@jic23-huawei> (raw)
In-Reply-To: <20230405212233.4167986-7-risca@dalakolonin.se>
On Wed, 5 Apr 2023 23:22:32 +0200
Patrik Dahlström <risca@dalakolonin.se> wrote:
> The palmas gpadc block has support for monitoring up to 2 ADC channels
> and issue an interrupt if they reach past a set threshold. This change
> hooks into the IIO events system and exposes to userspace the ability to
> configure these threshold values for each channel, but only allow up to
> 2 such thresholds to be enabled at any given time. Trying to enable a
> third channel will result in an error.
>
> Userspace is expected to input calibrated, as opposed to raw, values as
> threshold. However, it is not enough to do the opposite of what is done
> when converting the other way around. To account for tolerances in the
> ADC, the calculated raw threshold should be adjusted based on the ADC
> specifications for the device. These specifications include the integral
> nonlinearity (INL), offset, and gain error. To adjust the high
> threshold, use the following equation:
>
> (calibrated value + INL) * Gain error + offset = maximum value [1]
>
> Likewise, use the following equation for the low threshold:
>
> (calibrated value - INL) * Gain error - offset = minimum value
>
> The gain error is a combination of gain error, as listed in the
> datasheet, and gain error drift due to temperature and supply. The exact
> values for these specifications vary between palmas devices. This patch
> sets the values found in TWL6035, TWL6037 datasheet.
>
> [1] TI Application Report, SLIA087A, Guide to Using the GPADC in
> TPS65903x, TPS65917-Q1, TPS65919-Q1, and TPS65916 Devices.
>
> Signed-off-by: Patrik Dahlström <risca@dalakolonin.se>
Hi Patrik,
A few really trivial formatting things inline. If we don't end up
with a v4 for other reasons I can tidy this stuff up whilst applying.
Jonathan
>
> +/**
Not kernel-doc so /* only
Even if it were the indent for the following should align the * with the first * not
the second one.
> + * The high and low threshold values are calculated based on the advice given
> + * in TI Application Report SLIA087A, "Guide to Using the GPADC in PS65903x,
> + * TPS65917-Q1, TPS65919-Q1, and TPS65916 Devices". This document recommend
> + * taking ADC tolerances into account and is based on the device integral non-
> + * linearity (INL), offset error and gain error:
> + *
> + * raw high threshold = (ideal threshold + INL) * gain error + offset error
> + *
> + * The gain error include both gain error, as specified in the datasheet, and
> + * the gain error drift. These paramenters vary depending on device and whether
> + * the the channel is calibrated (trimmed) or not.
> + */
> +static int palmas_gpadc_threshold_with_tolerance(int val, const int INL,
> + const int gain_error,
> + const int offset_error)
> +{
> + val = ((val + INL) * (1000 + gain_error)) / 1000 + offset_error;
> +
> + return clamp(val, 0, 0xFFF);
> +}
> +
> +/**
/*
> + * The values below are taken from the datasheet of TWL6035, TWL6037.
> + * todo: get max INL, gain error, and offset error from OF.
> + */
> +static int palmas_gpadc_get_high_threshold_raw(struct palmas_gpadc *adc,
> + struct palmas_adc_event *ev)
> +{
> + const int adc_chan = ev->channel;
> + int val = adc->thresholds[adc_chan].high;
> + /* integral nonlinearity, measured in LSB */
> + const int max_INL = 2;
> + /* measured in LSB */
> + int max_offset_error;
> + /* 0.2% when calibrated */
> + int max_gain_error = 2;
> +
> + val = (val * 1000) / adc->adc_info[adc_chan].gain;
> +
> + if (adc->adc_info[adc_chan].is_uncalibrated) {
> + /* 2% worse */
> + max_gain_error += 20;
> + max_offset_error = 36;
> + } else {
> + val = (val * adc->adc_info[adc_chan].gain_error +
> + adc->adc_info[adc_chan].offset) /
> + 1000;
> + max_offset_error = 2;
> + }
> +
> + return palmas_gpadc_threshold_with_tolerance(val,
> + max_INL,
> + max_gain_error,
> + max_offset_error);
> +}
> +
> +/**
This isn't kernel-doc so just /*
> + * The values below are taken from the datasheet of TWL6035, TWL6037.
> + * todo: get min INL, gain error, and offset error from OF.
> + */
> +static int palmas_gpadc_get_low_threshold_raw(struct palmas_gpadc *adc,
> + struct palmas_adc_event *ev)
> +{
> + const int adc_chan = ev->channel;
> + int val = adc->thresholds[adc_chan].low;
> + /* integral nonlinearity, measured in LSB */
> + const int min_INL = -2;
> + /* measured in LSB */
> + int min_offset_error;
> + /* -0.6% when calibrated */
> + int min_gain_error = -6;
> +
> + val = (val * 1000) / adc->adc_info[adc_chan].gain;
> +
> + if (adc->adc_info[adc_chan].is_uncalibrated) {
> + /* 2% worse */
> + min_gain_error -= 20;
> + min_offset_error = -36;
> + } else {
> + val = (val * adc->adc_info[adc_chan].gain_error -
> + adc->adc_info[adc_chan].offset) /
> + 1000;
> + min_offset_error = -2;
> + }
> +
> + return palmas_gpadc_threshold_with_tolerance(val,
> + min_INL,
> + min_gain_error,
> + min_offset_error);
> +}
> +
> static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
> struct iio_chan_spec const *chan, int *val, int *val2, long mask)
> {
> @@ -437,8 +586,221 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
> return ret;
> }
>
> +static int palmas_gpadc_read_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir)
> +{
> + struct palmas_gpadc *adc = iio_priv(indio_dev);
> + int adc_chan = chan->channel;
> + int ret = 0;
> +
> + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
> + return -EINVAL;
> +
> + mutex_lock(&adc->lock);
> +
> + if (palmas_gpadc_get_event(adc, adc_chan, dir)) {
> + ret = 1;
Trivial: No brackets needed here for kernel style.
> + }
> +
> + mutex_unlock(&adc->lock);
> +
> + return ret;
> +}
...
> +static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + int state)
> +{
> + struct palmas_gpadc *adc = iio_priv(indio_dev);
> + int adc_chan = chan->channel;
> + int ret = 0;
This initial value isn't used so shouldn't be set.
One of the static analysis tools will spot this so if we don't tidy it up
now chances of it getting 'fixed' later is high. Better to avoid the
overhead of such a patch.
> +
> + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
> + return -EINVAL;
> +
> + mutex_lock(&adc->lock);
> +
> + if (state)
> + ret = palmas_gpadc_enable_event_config(adc, chan, dir);
> + else
> + ret = palmas_gpadc_disable_event_config(adc, chan, dir);
> +
> + mutex_unlock(&adc->lock);
> +
> + return ret;
> +}
> +
> +static int palmas_gpadc_read_event_value(struct iio_dev *indio_dev,
> + const struct iio_chan_spec *chan,
> + enum iio_event_type type,
> + enum iio_event_direction dir,
> + enum iio_event_info info,
> + int *val, int *val2)
> +{
> + struct palmas_gpadc *adc = iio_priv(indio_dev);
> + int adc_chan = chan->channel;
> + int ret = 0;
Trivial: I can't see a path where this initial value is used so it
shouldn't be initialized here.
> +
> + if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
> + return -EINVAL;
> +
> + mutex_lock(&adc->lock);
> +
> + switch (info) {
> + case IIO_EV_INFO_VALUE:
> + *val = (dir == IIO_EV_DIR_RISING) ?
> + adc->thresholds[adc_chan].high :
> + adc->thresholds[adc_chan].low;
> + ret = IIO_VAL_INT;
> + break;
> + default:
> + ret = -EINVAL;
> + break;
> + }
> +
> + mutex_unlock(&adc->lock);
> +
> + return ret;
> +}
> +
next prev parent reply other threads:[~2023-04-07 17:04 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-04-05 21:22 [PATCH v3 0/7] iio: adc: palmas_gpadc: add iio events Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 1/7] iio: adc: palmas: remove adc_wakeupX_data Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 2/7] iio: adc: palmas: replace "wakeup" with "event" Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 3/7] iio: adc: palmas: use iio_event_direction for threshold polarity Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 4/7] iio: adc: palmas: move eventX_enable into palmas_adc_event Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 5/7] iio: adc: palmas: always reset events on unload Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 6/7] iio: adc: palmas: add support for iio threshold events Patrik Dahlström
2023-04-07 17:19 ` Jonathan Cameron [this message]
2023-04-08 11:31 ` Patrik Dahlström
2023-04-05 21:22 ` [PATCH v3 7/7] iio: adc: palmas: don't alter event config on suspend/resume Patrik Dahlström
2023-04-07 17:22 ` Jonathan Cameron
2023-04-07 17:04 ` [PATCH v3 0/7] iio: adc: palmas_gpadc: add iio events Jonathan Cameron
2023-04-07 17:09 ` Jonathan Cameron
2023-04-08 10:51 ` Patrik Dahlström
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=20230407181947.667614ed@jic23-huawei \
--to=jic23@kernel.org \
--cc=hns@goldelico.com \
--cc=kernel@pyra-handheld.com \
--cc=lars@metafoo.de \
--cc=letux-kernel@openphoenux.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=pgoudagunta@nvidia.com \
--cc=risca@dalakolonin.se \
/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