Message ID | 20221111112657.1521307-4-mitja@lxnav.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp685144wru; Fri, 11 Nov 2022 03:31:13 -0800 (PST) X-Google-Smtp-Source: AA0mqf6qeCJa33dyXok9uZpiJWDfxROqoI0N8Q632PDRibO3KapMgJGkJVF/EURdV5sAFCQzprw/ X-Received: by 2002:a17:90a:1904:b0:213:22d:b2e2 with SMTP id 4-20020a17090a190400b00213022db2e2mr1431538pjg.148.1668166273599; Fri, 11 Nov 2022 03:31:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668166273; cv=none; d=google.com; s=arc-20160816; b=D6cgmlJamukapsjIj1MLRYAPjps+z4ZtlZPUpEgIiO4Gsc5qzWJd3tqlSId0mmV6A1 CPzVJ1rTMIsORbos/exEAt4dwXS5VyZYDy/OwkeuDrojnSFW/NllKkOhDUvcYfTypwU1 05N+HtTf0lZEZixrsJJ3tBkCX+RuIoa1Tfh2f1fLFEnEo3uCqaX1XikUyKt9cFyit/jB r1iEsaGHy2fPOk2wE2ndRsPZYrDe9uQpe+9v6tmOJYVoyEtXjqbACPFT2lR8aWkeAgQD 2/pDO0OsKpg0h2GRabdE7WJkvtUp8GTQ5x1i1gtel+ov3zmXTUo1raRlZ4y3NrVtybEL gx3g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=NqvSjeOULQZbj3EUjH7dknKYQjo14gTb8HTU0Fd3y2A=; b=eo3bTrcZ5xVmHqJWjMAsZGMNo04DVqgsMeVanGtRg0dJtPHnFhzw9eVRZU1DK6BVO1 PqBjQNQK72RVWMsMTcdc2+csSmhTl3pV3+PMs9wCyV4MC9Vj8AEEXyfgBaXBe4AwEOh+ 2NtASuXzQGD6BT1gbJZviiG3qaeWpTCbRWk3wenQ6BxNgaxYmKnSleo15GPTRfVNl1Yv H/6N4Tc5zCTT0SQbAcMwE8UcOJrtsHaqIv1ropl7aYDd4ezA9iyg+Gsvm9Fn13mWAMt3 KZqQDvRbjdU0Po0MoIt7kuYJTGq2UAv3jvlCQl/XJ/aMZ8DExx6rOau2BzvPfoq6vecF 9LHQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lxnav.com header.s=dhl header.b=hYtyX2wI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=lxnav.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j1-20020a170902690100b001887a1ffb17si1952657plk.223.2022.11.11.03.30.59; Fri, 11 Nov 2022 03:31:13 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@lxnav.com header.s=dhl header.b=hYtyX2wI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=lxnav.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233518AbiKKL2i (ORCPT <rfc822;winker.wchi@gmail.com> + 99 others); Fri, 11 Nov 2022 06:28:38 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233288AbiKKL2S (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 11 Nov 2022 06:28:18 -0500 Received: from dhl.lxnav.com (dhl.lxnav.com [IPv6:2a01:4f8:c010:2f07::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B351569DC9 for <linux-kernel@vger.kernel.org>; Fri, 11 Nov 2022 03:28:09 -0800 (PST) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 1E82040768; Fri, 11 Nov 2022 12:28:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lxnav.com; s=dhl; t=1668166085; h=from:subject:date:message-id:to:mime-version: content-transfer-encoding:in-reply-to:references; bh=NqvSjeOULQZbj3EUjH7dknKYQjo14gTb8HTU0Fd3y2A=; b=hYtyX2wIlbpRse+AYLKuwh4QMTwz+d6nnySOhp5qQRVLJviQ613mUP4sJZtegxv8cMGmte nhI8wp+T8NjKNqbOm9W/KRQIwkFC94s6Rv8aXZlmOBJFoxE4Kin3W/Sr7gva9ohi5J043I ZILyXvw1M71C/kaI/gO/KksqNXI5gt1qPD9vdZqkw655oQxRs4Yk0z0ZHk0nLw2hD9nJB7 fCsRc4Lh/uj00LPqmEJVFrrRI9rjLMMO30Ecccdha44/3JURIwe5PrIOk1QrRAiYk6pCm6 1qiKhmLqrLduxacyuSXsE9KikRzdlFFeZTCw+nhw/j3b9hzw3o43lJUgQ/tEkw== From: Mitja Spes <mitja@lxnav.com> To: Jonathan Cameron <jic23@kernel.org>, Lars-Peter Clausen <lars@metafoo.de>, Mitja Spes <mitja@lxnav.com>, Angelo Compagnucci <angelo.compagnucci@gmail.com>, linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/4] iio: adc: mcp3422: add hardware gain attribute Date: Fri, 11 Nov 2022 12:26:55 +0100 Message-Id: <20221111112657.1521307-4-mitja@lxnav.com> In-Reply-To: <20221111112657.1521307-1-mitja@lxnav.com> References: <20221111112657.1521307-1-mitja@lxnav.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749199118915831138?= X-GMAIL-MSGID: =?utf-8?q?1749199118915831138?= |
Series |
iio: adc: mcp3422 improvements
|
|
Commit Message
Mitja Špes
Nov. 11, 2022, 11:26 a.m. UTC
Allows setting gain separately from scale.
Signed-off-by: Mitja Spes <mitja@lxnav.com>
---
drivers/iio/adc/mcp3422.c | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
Comments
On Fri, 11 Nov 2022 12:26:55 +0100 Mitja Spes <mitja@lxnav.com> wrote: > Allows setting gain separately from scale. How are the separate? We normally only use hardwaregain if changing it has no input on the scale that we need to apply in userspace to raw channels. This normally happens for two reasons 1) There is a micro controller on the sensor that is doing a bunch of maths so whilst changing the PGA value changes the range measurable it doesn't affect the representation when we read from the device. 2) The hardware gain is controlling say the sensitivity of a light sensor in a time of flight device - it affects if we can get a measurement, but not the measurement itself. Any of that true here? If not, we shouldn't be adding a hardwaregain attribute - which is why almost no ADCs have them... Jonathan > > Signed-off-by: Mitja Spes <mitja@lxnav.com> > --- > drivers/iio/adc/mcp3422.c | 32 +++++++++++++++++++++++++++++++- > 1 file changed, 31 insertions(+), 1 deletion(-) > > diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c > index cfb629b964af..eef35fb2fc22 100644 > --- a/drivers/iio/adc/mcp3422.c > +++ b/drivers/iio/adc/mcp3422.c > @@ -58,7 +58,8 @@ > .channel = _index, \ > .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ > | BIT(IIO_CHAN_INFO_SCALE) \ > - | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ > + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ > + | BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ > } > > static const int mcp3422_scales[MCP3422_SRATE_COUNT][MCP3422_PGA_COUNT] = { > @@ -184,6 +185,10 @@ static int mcp3422_read_raw(struct iio_dev *iio, > *val1 = mcp3422_sample_rates[sample_rate]; > return IIO_VAL_INT; > > + case IIO_CHAN_INFO_HARDWAREGAIN: > + *val1 = (1 << pga); > + return IIO_VAL_INT; > + > default: > break; > } > @@ -245,6 +250,29 @@ static int mcp3422_write_raw(struct iio_dev *iio, > adc->ch_config[req_channel] = config; > return 0; > > + case IIO_CHAN_INFO_HARDWAREGAIN: > + switch (val1) { > + case 1: > + temp = MCP3422_PGA_1; > + break; > + case 2: > + temp = MCP3422_PGA_2; > + break; > + case 4: > + temp = MCP3422_PGA_4; > + break; > + case 8: > + temp = MCP3422_PGA_8; > + break; > + default: > + return -EINVAL; > + } > + > + config &= ~MCP3422_PGA_MASK; > + config |= MCP3422_PGA_VALUE(temp); > + adc->ch_config[req_channel] = config; > + return 0; > + > default: > break; > } > @@ -260,6 +288,8 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, > return IIO_VAL_INT_PLUS_NANO; > case IIO_CHAN_INFO_SAMP_FREQ: > return IIO_VAL_INT_PLUS_MICRO; > + case IIO_CHAN_INFO_HARDWAREGAIN: > + return IIO_VAL_INT_PLUS_MICRO; > default: > return -EINVAL; > }
Hi Jonathan, On Sat, Nov 12, 2022 at 6:20 PM Jonathan Cameron <jic23@kernel.org> wrote: > How are the separate? We normally only use hardwaregain if > changing it has no input on the scale that we need to apply in userspace > to raw channels. This normally happens for two reasons > 1) There is a micro controller on the sensor that is doing a bunch of > maths so whilst changing the PGA value changes the range measurable it > doesn't affect the representation when we read from the device. > 2) The hardware gain is controlling say the sensitivity of a light sensor > in a time of flight device - it affects if we can get a measurement, but > not the measurement itself. > > Any of that true here? No. I see I misunderstood the hardwaregain attribute. For me this is a user friendly way of setting the gain and subsequently scale. What I don't understand is why set scale at all? It's a result of sampling rate and gain settings. Using it as a setting, for which input value range also changes depending on another attribute is quite cumbersome. To use a sensor the program has to do this: 1. set the sampling rate 2. read available scales for this sampling rate 3. set the scale according to desired gain or know the scales for each sampling rate in advance...which makes available scales attribute quite useless. Kind regards, Mitja
On Sat, 12 Nov 2022 22:19:07 +0100 Mitja Špes <mitja@lxnav.com> wrote: > Hi Jonathan, > > On Sat, Nov 12, 2022 at 6:20 PM Jonathan Cameron <jic23@kernel.org> wrote: > > How are the separate? We normally only use hardwaregain if > > changing it has no input on the scale that we need to apply in userspace > > to raw channels. This normally happens for two reasons > > 1) There is a micro controller on the sensor that is doing a bunch of > > maths so whilst changing the PGA value changes the range measurable it > > doesn't affect the representation when we read from the device. > > 2) The hardware gain is controlling say the sensitivity of a light sensor > > in a time of flight device - it affects if we can get a measurement, but > > not the measurement itself. > > > > Any of that true here? > No. I see I misunderstood the hardwaregain attribute. For me this is a user > friendly way of setting the gain and subsequently scale. > > What I don't understand is why set scale at all? Key issue here is the ABI is not designed against one part. It is designed against many. Also it is inherently biased in favour of the parts that were around when we originally created it - I'll note that at that time the trade off of resolution against sampling period (oversampling or cutting off the measurement) was not common. That means userspace code has been written that assumes a certain set of attributes. The cost of starting to use new attributes is high because no userspace code knows about them. Hence we put a lot of effort into avoiding doing so. I agree that your argument makes sense for your particular device - it doesn't for many other ADCs. Many ADCs (I'd go as far as to say most though I could be wrong on that) do not couple scale and sampling frequency at all. > It's a result of sampling > rate and gain settings. Using it as a setting, for which input value range also > changes depending on another attribute is quite cumbersome. > To use a sensor the program has to do this: > 1. set the sampling rate > 2. read available scales for this sampling rate > 3. set the scale according to desired gain > or know the scales for each sampling rate in advance...which makes available > scales attribute quite useless. For this last point, I think trying to match against previous scale makes a lot of sense as there is considerable overlap available here between the different rates. I think that would be an improvement. Another improvement would be to at least expose the current resolution - that can be done by providing and _available for the raw reading. Not an idea way to undestand what is going on but it would make more data available to userspace. (_raw_available(max) * scale would give the range of the device and allow an adjustment of the scale to achieve what the user wants). ABI design is hard. We don't always get it right and often there is no right answer. Reality is that sometimes userspace code needs to search the space if it is trying to get as close as possible to a particular set of constraints. However lets assume in most cases the code has limits of: 1) A minimum data rate with which it is happy (controls the sampling frequency - higher is normally fine, but wastes power etc). To get best possible power usage (and in case of this device resolution) it will pick the lowest sampling frequency to meet this constraint. 2) A range of values it is interested in (here related to the PGA settings but not the sampling frequency). Adding _raw_avail would help it to have visibility of what the range is. 3) A resolution it cares about getting data at (scale) We have to present 'scale' because that's necessary to allow userspace to calculate the actual voltage. That adds a constraint to the ABI design. We also don't want to provide more overlapping controls than absolutely necessary as that makes it hard for userspace to know which one to use. So upshot is that userspace has to search to find a value that works for it. In this particular case the set of ranges at all sampling frequencies are the same. So if we assume a constraint on how often data is wanted is more important than the resolution (have to pick one or the other to be more important) then we set that first to the minimum value to meet the requirement. Then scale is tweaked to set the PGA to match the range desired. Sure, not super clean but consistent with the ABI as it stands (and we can't change that other than very very carefully). As a fun side note, if the device (or driver) had justified the lower resolutions the other way (so the zeros ended up in least significant bits) a common solution would have been to just present that to userspace as is, thus the scale would have been decoupled from the sampling frequency. Not this is what oversampling devices normally do... We obviously could fake that now, but the issue would then be that it was a major driver ABI change. So we can't. Jonathan > > Kind regards, > Mitja
Thank you for the explanations. Kind regards, Mitja On Sun, Nov 13, 2022 at 1:21 PM Jonathan Cameron <jic23@kernel.org> wrote: > > On Sat, 12 Nov 2022 22:19:07 +0100 > Mitja Špes <mitja@lxnav.com> wrote: > > > Hi Jonathan, > > > > On Sat, Nov 12, 2022 at 6:20 PM Jonathan Cameron <jic23@kernel.org> wrote: > > > How are the separate? We normally only use hardwaregain if > > > changing it has no input on the scale that we need to apply in userspace > > > to raw channels. This normally happens for two reasons > > > 1) There is a micro controller on the sensor that is doing a bunch of > > > maths so whilst changing the PGA value changes the range measurable it > > > doesn't affect the representation when we read from the device. > > > 2) The hardware gain is controlling say the sensitivity of a light sensor > > > in a time of flight device - it affects if we can get a measurement, but > > > not the measurement itself. > > > > > > Any of that true here? > > No. I see I misunderstood the hardwaregain attribute. For me this is a user > > friendly way of setting the gain and subsequently scale. > > > > What I don't understand is why set scale at all? > > Key issue here is the ABI is not designed against one part. It is designed against > many. Also it is inherently biased in favour of the parts that were around when > we originally created it - I'll note that at that time the trade off of resolution > against sampling period (oversampling or cutting off the measurement) was not common. > > That means userspace code has been written that assumes a certain set of attributes. > The cost of starting to use new attributes is high because no userspace code knows > about them. Hence we put a lot of effort into avoiding doing so. I agree that your > argument makes sense for your particular device - it doesn't for many other ADCs. > > Many ADCs (I'd go as far as to say most though I could be wrong on that) do not > couple scale and sampling frequency at all. > > > It's a result of sampling > > rate and gain settings. Using it as a setting, for which input value range also > > changes depending on another attribute is quite cumbersome. > > To use a sensor the program has to do this: > > 1. set the sampling rate > > 2. read available scales for this sampling rate > > 3. set the scale according to desired gain > > or know the scales for each sampling rate in advance...which makes available > > scales attribute quite useless. > > For this last point, I think trying to match against previous scale makes a lot of > sense as there is considerable overlap available here between the different rates. > I think that would be an improvement. Another improvement would be to at least > expose the current resolution - that can be done by providing and _available > for the raw reading. Not an idea way to undestand what is going on but it would > make more data available to userspace. (_raw_available(max) * scale would give > the range of the device and allow an adjustment of the scale to achieve what the > user wants). > > ABI design is hard. We don't always get it right and often there is no right answer. > Reality is that sometimes userspace code needs to search the space if it is trying > to get as close as possible to a particular set of constraints. However lets assume > in most cases the code has limits of: > > 1) A minimum data rate with which it is happy (controls > the sampling frequency - higher is normally fine, but wastes power etc). > To get best possible power usage (and in case of this device resolution) it will pick > the lowest sampling frequency to meet this constraint. > > 2) A range of values it is interested in (here related to the PGA settings but not > the sampling frequency). Adding _raw_avail would help it to have visibility of > what the range is. > > 3) A resolution it cares about getting data at (scale) > > We have to present 'scale' because that's necessary to allow userspace to calculate the > actual voltage. That adds a constraint to the ABI design. We also don't want to provide > more overlapping controls than absolutely necessary as that makes it hard for userspace > to know which one to use. > > So upshot is that userspace has to search to find a value that works for it. > > In this particular case the set of ranges at all sampling frequencies are the same. > So if we assume a constraint on how often data is wanted is more important than the > resolution (have to pick one or the other to be more important) then we set that > first to the minimum value to meet the requirement. Then scale is tweaked to set > the PGA to match the range desired. Sure, not super clean but consistent with the > ABI as it stands (and we can't change that other than very very carefully). > > As a fun side note, if the device (or driver) had justified the lower resolutions the other way > (so the zeros ended up in least significant bits) a common solution would have been > to just present that to userspace as is, thus the scale would have been decoupled from > the sampling frequency. Not this is what oversampling devices normally do... > We obviously could fake that now, but the issue would then be that it was a major > driver ABI change. So we can't. > > Jonathan > > > > > > > > > > Kind regards, > > Mitja >
diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index cfb629b964af..eef35fb2fc22 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -58,7 +58,8 @@ .channel = _index, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ | BIT(IIO_CHAN_INFO_SCALE) \ - | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + | BIT(IIO_CHAN_INFO_SAMP_FREQ) \ + | BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ } static const int mcp3422_scales[MCP3422_SRATE_COUNT][MCP3422_PGA_COUNT] = { @@ -184,6 +185,10 @@ static int mcp3422_read_raw(struct iio_dev *iio, *val1 = mcp3422_sample_rates[sample_rate]; return IIO_VAL_INT; + case IIO_CHAN_INFO_HARDWAREGAIN: + *val1 = (1 << pga); + return IIO_VAL_INT; + default: break; } @@ -245,6 +250,29 @@ static int mcp3422_write_raw(struct iio_dev *iio, adc->ch_config[req_channel] = config; return 0; + case IIO_CHAN_INFO_HARDWAREGAIN: + switch (val1) { + case 1: + temp = MCP3422_PGA_1; + break; + case 2: + temp = MCP3422_PGA_2; + break; + case 4: + temp = MCP3422_PGA_4; + break; + case 8: + temp = MCP3422_PGA_8; + break; + default: + return -EINVAL; + } + + config &= ~MCP3422_PGA_MASK; + config |= MCP3422_PGA_VALUE(temp); + adc->ch_config[req_channel] = config; + return 0; + default: break; } @@ -260,6 +288,8 @@ static int mcp3422_write_raw_get_fmt(struct iio_dev *indio_dev, return IIO_VAL_INT_PLUS_NANO; case IIO_CHAN_INFO_SAMP_FREQ: return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_HARDWAREGAIN: + return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL; }