All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Jonathan Bakker <xc-racer2@live.ca>
Cc: "Linus Walleij" <linus.walleij@linaro.org>,
	"linux-iio@vger.kernel.org" <linux-iio@vger.kernel.org>,
	"Hartmut Knaack" <knaack.h@gmx.de>,
	"Lars-Peter Clausen" <lars@metafoo.de>,
	"Peter Meerwald-Stadler" <pmeerw@pmeerw.net>,
	"linux-input@vger.kernel.org" <linux-input@vger.kernel.org>,
	"Stephan Gerhold" <stephan@gerhold.net>,
	"Minkyu Kang" <mk7.kang@samsung.com>,
	"Paweł Chmiel" <pawel.mikolaj.chmiel@gmail.com>,
	"Oskar Andero" <oskar.andero@gmail.com>,
	"Dmitry Torokhov" <dmitry.torokhov@gmail.com>
Subject: Re: [PATCH 2/2 v5] iio: light: Add a driver for Sharp GP2AP002x00F
Date: Sun, 2 Feb 2020 15:08:43 +0000	[thread overview]
Message-ID: <20200202150843.762c6897@archlinux> (raw)
In-Reply-To: <BYAPR10MB3479E348502A3E94F293559DA3080@BYAPR10MB3479.namprd10.prod.outlook.com>

On Sun, 26 Jan 2020 20:27:22 +0000
Jonathan Bakker <xc-racer2@live.ca> wrote:

> Hi Linus,
> 
> On 2020-01-26 7:16 a.m., Linus Walleij wrote:
> > On Fri, Jan 24, 2020 at 1:47 AM Jonathan Bakker <xc-racer2@live.ca> wrote:
> >   
> >> Thanks for the driver, I've tested it on a first-gen Galaxy S
> >> device with a GP2AP002A00F.  I have a few comments that I've put inline
> >> based on my experiences.  
> > 
> > Thanks a lot!
> >   
> >> Both shortly after probe (when runtime pm timeout occurs?) and after
> >> manually disabling the proximity event, this
> >> irq handler is called.  Since the chip is in low power state, it obviously
> >> fails to read the proximity value and write to the OCON register below, eg
> >>
> >> [    7.215875] gp2ap002 11-0044: error reading proximity
> >> [    8.105878] gp2ap002 11-0044: error setting up VOUT control 1
> >>
> >> Can we do something like disable_irq() in the runtime pm function to prevent
> >> this?  
> > 
> > I added that in v6, I hope this solves your problem.  
> 
> Yep, it appears to.  Thanks.
> 
> >   
> >> The gp2ap002s00f_regmap_i2c_read function works on the gp2ap002a00f as well,
> >> so this can be simplified/dropped.  
> > 
> > Fixed this too in v6.
> >   
> >>> +             if (ch_type != IIO_CURRENT) {
> >>> +                     dev_err(dev,
> >>> +                             "wrong type of IIO channel specified for ALSOUT\n");
> >>> +                     return -EINVAL;
> >>> +             }  
> >>
> >> This enforces a current ADC, while several devices besides mine (eg Galaxy Nexus)
> >> use a resistor and a voltage ADC.  For this case, could we add a device property such as
> >> sharp,adc-adjustment-ratio to convert from the raw ADC values to a "current" that
> >> could be used in the lookup table?  So the "current" would be the raw ADC divided
> >> by that special value.
> >>
> >> Instructions for converting the ADC back to the current can be found eg at
> >> https://android.googlesource.com/device/samsung/crespo/+/2e0ab7265e3039fee787c2216e0c98d92ea0b49e%5E%21/#F0  
> > 
> > I'd like to keep that as a future enhancement unless someone is very eager
> > to get it and has a device they can test it on. Otherwise it will be
> > just dry-coding
> > on my part.  
> 
> Well, I've got such a device and can test :)
> 
> > 
> > I think the property we would add in the device tree in that case should
> > be the resistance value. This is based on the following assumption
> > which is indeed a bit of speculation since there is no proper datasheet
> > for the light sensor part of the component:
> > 
> > - The light sensor part is simply a photodiode
> > - This emits a nonlinear current in relation to how many
> >   photons hit the photodiode in a time interval, the relationship
> >   is described in the curren->lux table we have
> > - Some vendors do not have any current ADC, so they connect
> >   this to a resistor, and measure the voltage over the
> >   resistor because the have a voltage ADC
> > 
> > Since current is linear to the voltage over the resistor, we should
> > include the resistance in the device tree, then using that the
> > corresponding current can be calculated and we use the same
> > look-up table to find the lux. Probably each system may need
> > to also subtract some bias voltage or so.  
> 
> Yes, this is my understanding of it as well (I also have no datasheet).
> 
> Given V = actual voltage in V, Vref = reference voltage of ADC in V, ADC = value
> read from ADC, ADCmax = maximum possible value read from ADC, I = current in amps,
> R = resistor value in ohms, uA = current in microamps
> 
> V / Vref = ADC / ADCmax
> V = (ADC / ADCmax) * Vref
> 
> V = I * R
> I * R = (ADC / ADCmax) * Vref
> I = ADC * Vref / ADCmax / R
> 
> However, because we want the current in uA for the table, (note, your comment says
> that the table is based on mA, but I believe that it should actually be uA)
> 
> uA = ADC * Vref / ADCmax / R * 1000000
> 
> Then, in order to avoid multiplying by a decimal, the uA is the ADC value divided
> by the inverse of
> 
> (1000000 * Vref / ADCmax / R)
> 
> For example, on the first gen Galaxy S series and the Nexus S, the Vref is 3.3V,
> the ADC is 12 bit (2^12 = 4096, so high value is 4095), the resistor is 47000ohms,
> 
> inverse of (1000000 * 3.3 / 4095 / 47000) = 58
> 
> so we need to divide the raw ADC reading by 58 in order to get the uA for the current->lux
> table.
> 
> A quick patch that I used for testing (based off of v5) is
> 
> diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
> index a5897959f70d..b98aec337f8b 100644
> --- a/drivers/iio/light/gp2ap002.c
> +++ b/drivers/iio/light/gp2ap002.c
> @@ -130,6 +130,7 @@
>   * @vdd: regulator controlling VDD
>   * @vio: regulator controlling VIO
>   * @alsout: IIO ADC channel to convert the ALSOUT signal
> + * @adc_adj: conversion factor if voltage ADC used instead of current ADC
>   * @is_gp2ap002s00f: this is the GP2AP002F variant of the chip
>   * @enabled: we cannot read the status of the hardware so we need to
>   * keep track of whether the event is enabled using this state variable
> @@ -143,6 +144,7 @@ struct gp2ap002 {
>  	enum iio_event_direction dir;
>  	u8 hys_far;
>  	u8 hys_close;
> +	u8 adc_adj;
>  	bool is_gp2ap002s00f;
>  	bool enabled;
>  };
> @@ -272,6 +274,9 @@ static int gp2ap002_get_lux(struct gp2ap002 *gp2ap002)
>  	if (ret < 0)
>  		return ret;
>  
> +	if (gp2ap002->adc_adj)
> +		res /= gp2ap002->adc_adj;
> +
>  	dev_dbg(gp2ap002->dev, "read %d mA from ADC\n", res);
>  
>  	ill1 = &gp2ap002_illuminance_table[0];
> @@ -588,7 +593,16 @@ static int gp2ap002_probe(struct i2c_client *client,
>  		ret = iio_get_channel_type(gp2ap002->alsout, &ch_type);
>  		if (ret < 0)
>  			return ret;
> -		if (ch_type != IIO_CURRENT) {
> +		if (ch_type == IIO_VOLTAGE) {
> +			ret = device_property_read_u8(dev,
> +				"sharp,adc-adjustment-ratio", &val);
> +			if (ret) {
> +				dev_err(dev,
> +					"failed to obtain adc conversion\n");
> +				return -EINVAL;
> +			}
> +			gp2ap002->adc_adj = val;
> +		} else if (ch_type != IIO_CURRENT) {
>  			dev_err(dev,
>  				"wrong type of IIO channel specified for ALSOUT\n");
>  			return -EINVAL;
> 
> Alternatively, you could collect the resistor value, the ADC precision (this doesn't
> appear to be queryable via the IIO layer), and the reference voltage level - but I'm
> not sure how you'd do the inverse calculation in the kernel.

An alternative to doing this is to represent the resistor circuit explicitly.

You end up with a really small ADC driver that is a consumer of a voltage
and provides a current channel.  That has all the properties of the
circuit via DT.

We do some stuff a bit similar to this in the envelope detector driver.

In general I would prefer we handle this sort of conversion generically
rather than bolting it into a light sensor driver like you are doing here,
even if it comes at the cost of a bit more complexity.

Jonathan

> 
> > 
> > But we definately need something to test on to do this right> 
> > Yours,
> > Linus Walleij
> >   
> 
> Thanks,
> Jonathan Bakker


  reply	other threads:[~2020-02-02 15:08 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-01-21 21:04 [PATCH 1/2 v5] iio: light: Add DT bindings for GP2AP002 Linus Walleij
2020-01-21 21:04 ` [PATCH 2/2 v5] iio: light: Add a driver for Sharp GP2AP002x00F Linus Walleij
2020-01-24  0:47   ` Jonathan Bakker
2020-01-26 15:16     ` Linus Walleij
2020-01-26 20:27       ` Jonathan Bakker
2020-02-02 15:08         ` Jonathan Cameron [this message]
2020-02-08 12:35           ` Linus Walleij

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=20200202150843.762c6897@archlinux \
    --to=jic23@kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=knaack.h@gmx.de \
    --cc=lars@metafoo.de \
    --cc=linus.walleij@linaro.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=mk7.kang@samsung.com \
    --cc=oskar.andero@gmail.com \
    --cc=pawel.mikolaj.chmiel@gmail.com \
    --cc=pmeerw@pmeerw.net \
    --cc=stephan@gerhold.net \
    --cc=xc-racer2@live.ca \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.