Re: [PATCH] RFT: iio: gp2ap002: Replace LUT with math

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Linus,

After implementing a small shim from the voltage ADC on my device, I was able to test this.
Please see my inline comments.

On 2020-02-08 4:33 a.m., Linus Walleij wrote:
> This replaces the current-to-lux look up table with some
> integer math using int_pow() from <linux/kernel.h>.
> Drop the unused <linux/math64.h> in the process.
> 
> Cc: Jonathan Bakker <xc-racer2@xxxxxxx>
> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
> ---
> I would appreciate testing that this give the right
> result. Using math does look a lot better.
> ---
>  drivers/iio/light/gp2ap002.c | 94 +++---------------------------------
>  1 file changed, 7 insertions(+), 87 deletions(-)
> 
> diff --git a/drivers/iio/light/gp2ap002.c b/drivers/iio/light/gp2ap002.c
> index 433907619268..153ae0a163ab 100644
> --- a/drivers/iio/light/gp2ap002.c
> +++ b/drivers/iio/light/gp2ap002.c
> @@ -33,7 +33,6 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/interrupt.h>
>  #include <linux/bits.h>
> -#include <linux/math64.h>
>  #include <linux/pm.h>
>  
>  #define GP2AP002_PROX_CHANNEL 0
> @@ -205,71 +204,10 @@ static irqreturn_t gp2ap002_prox_irq(int irq, void *d)
>  	return IRQ_HANDLED;
>  }
>  
> -struct gp2ap002_illuminance {
> -	unsigned int curr;
> -	unsigned int lux;
> -};
> -
> -/*
> - * This array maps current and lux.
> - *
> - * Ambient light sensing range is 3 to 55000 lux.
> - *
> - * This mapping is based on the following formula.
> - * illuminance = 10 ^ (current / 10)
> - */
> -static const struct gp2ap002_illuminance gp2ap002_illuminance_table[] = {
> -	{ .curr		= 5, .lux	= 3 },
> -	{ .curr		= 6, .lux	= 4 },
> -	{ .curr		= 7, .lux	= 5 },
> -	{ .curr		= 8, .lux	= 6 },
> -	{ .curr		= 9, .lux	= 8 },
> -	{ .curr		= 10, .lux	= 10 },
> -	{ .curr		= 11, .lux	= 12 },
> -	{ .curr		= 12, .lux	= 16 },
> -	{ .curr		= 13, .lux	= 20 },
> -	{ .curr		= 14, .lux	= 25 },
> -	{ .curr		= 15, .lux	= 32 },
> -	{ .curr		= 16, .lux	= 40 },
> -	{ .curr		= 17, .lux	= 50 },
> -	{ .curr		= 18, .lux	= 63 },
> -	{ .curr		= 19, .lux	= 79 },
> -	{ .curr		= 20, .lux	= 100 },
> -	{ .curr		= 21, .lux	= 126 },
> -	{ .curr		= 22, .lux	= 158 },
> -	{ .curr		= 23, .lux	= 200 },
> -	{ .curr		= 24, .lux	= 251 },
> -	{ .curr		= 25, .lux	= 316 },
> -	{ .curr		= 26, .lux	= 398 },
> -	{ .curr		= 27, .lux	= 501 },
> -	{ .curr		= 28, .lux	= 631 },
> -	{ .curr		= 29, .lux	= 794 },
> -	{ .curr		= 30, .lux	= 1000 },
> -	{ .curr		= 31, .lux	= 1259 },
> -	{ .curr		= 32, .lux	= 1585 },
> -	{ .curr		= 33, .lux	= 1995 },
> -	{ .curr		= 34, .lux	= 2512 },
> -	{ .curr		= 35, .lux	= 3162 },
> -	{ .curr		= 36, .lux	= 3981 },
> -	{ .curr		= 37, .lux	= 5012 },
> -	{ .curr		= 38, .lux	= 6310 },
> -	{ .curr		= 39, .lux	= 7943 },
> -	{ .curr		= 40, .lux	= 10000 },
> -	{ .curr		= 41, .lux	= 12589 },
> -	{ .curr		= 42, .lux	= 15849 },
> -	{ .curr		= 43, .lux	= 19953 },
> -	{ .curr		= 44, .lux	= 25119 },
> -	{ .curr		= 45, .lux	= 31623 },
> -	{ .curr		= 46, .lux	= 39811 },
> -	{ .curr		= 47, .lux	= 50119 },
> -};
> -
>  static int gp2ap002_get_lux(struct gp2ap002 *gp2ap002)
>  {
> -	const struct gp2ap002_illuminance *ill1;
> -	const struct gp2ap002_illuminance *ill2;
>  	int ret, res;
> -	int i;
> +	u64 lux;
>  
>  	ret = iio_read_channel_processed(gp2ap002->alsout, &res);
>  	if (ret < 0)
> @@ -277,31 +215,13 @@ static int gp2ap002_get_lux(struct gp2ap002 *gp2ap002)
>  
>  	dev_dbg(gp2ap002->dev, "read %d mA from ADC\n", res);
>  
> -	ill1 = &gp2ap002_illuminance_table[0];
> -	if (res < ill1->curr) {
> -		dev_dbg(gp2ap002->dev, "total darkness\n");
> -		return 0;
> -	}
> -	for (i = 0; i < ARRAY_SIZE(gp2ap002_illuminance_table) - 1; i++) {
> -		ill1 = &gp2ap002_illuminance_table[i];
> -		ill2 = &gp2ap002_illuminance_table[i + 1];
> -
> -		if (res > ill2->curr)
> -			continue;
> -		if ((res <= ill1->curr) && (res >= ill2->curr))
> -			break;
> +	lux = int_pow(10, (res/10));

Unfortunately, this doesn't seem to work.  Since it's integer math, it means we
only have an output of 100, 1000, or 10000 depending on the reading.  A LUT is
probably a much better solution.

> +	if (lux > INT_MAX) {
> +		dev_err(gp2ap002->dev, "lux overflow, capped\n");
> +		lux = INT_MAX;
>  	}
> -	if (res > ill2->curr) {
> -		dev_info_once(gp2ap002->dev, "max current overflow\n");
> -		return ill2->curr;
> -	}
> -	/* Interpolate and return */
> -	dev_dbg(gp2ap002->dev, "interpolate index %d and %d\n", i, i + 1);
> -	/* How many steps along the curve */
> -	i = res - ill1->curr; /* x - x0 */
> -	/* Linear interpolation */
> -	return ill1->lux + i *
> -		((ill2->lux - ill1->lux) / (ill2->curr - ill1->curr));

However, this also apparently didn't really work either as I was having what appeared to be
overflow errors (ie when a raw ADC value of 37, this calculation pulls out -52961).

Here's a few entries after add a debug print right after the gp2ap002_get_lux() call in
gp2ap002_read_raw():

gp2ap002 11-0044: read 33 mA from ADC
iio iio:device4: read value of -94193
gp2ap002 11-0044: read 37 mA from ADC
iio iio:device4: read value of -52961
gp2ap002 11-0044: read 39 mA from ADC
iio iio:device4: read value of -32345
gp2ap002 11-0044: read 42 mA from ADC
iio iio:device4: read value of -1421
gp2ap002 11-0044: read 39 mA from ADC
iio iio:device4: read value of -32345
gp2ap002 11-0044: read 29 mA from ADC
iio iio:device4: read value of -135425
gp2ap002 11-0044: read 48 mA from ADC
gp2ap002 11-0044: max current overflow
iio iio:device4: read value of 47
gp2ap002 11-0044: read 33 mA from ADC

My apologies for not catching this first time around.

> +
> +	return (int)lux;
>  }
>  
>  static int gp2ap002_read_raw(struct iio_dev *indio_dev,
> 

Thanks,
Jonathan Bakker



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux