summaryrefslogtreecommitdiff
path: root/drivers/staging/iio/light
diff options
context:
space:
mode:
authorBryan Freed <bfreed@chromium.org>2012-09-05 20:55:00 +0100
committerJonathan Cameron <jic23@kernel.org>2012-09-08 10:25:10 +0100
commit932323b74e2535dbb6a1b245dfa1aa8cd2bbd8e2 (patch)
treedd7fda9f5b49de9d7c5260b44b63af1c86348eef /drivers/staging/iio/light
parent7b123c85bbb3fadbd02b82d77d5aee0c399b0e06 (diff)
iio: isl29018: Support fractional ALS scaling.
The Industrial IO framework supports scaling ADC values by fractions, but most drivers default to using whole numbers. This change turns on fractional scaling in the isl29018 driver. Signed-off-by: Bryan Freed <bfreed@chromium.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/staging/iio/light')
-rw-r--r--drivers/staging/iio/light/isl29018.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 31d22f5591ca..6ee5567d9813 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -63,6 +63,7 @@ struct isl29018_chip {
struct regmap *regmap;
struct mutex lock;
unsigned int lux_scale;
+ unsigned int lux_uscale;
unsigned int range;
unsigned int adc_bit;
int prox_scheme;
@@ -145,13 +146,22 @@ static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
{
int lux_data;
+ unsigned int data_x_range, lux_unshifted;
lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
if (lux_data < 0)
return lux_data;
- *lux = (lux_data * chip->range * chip->lux_scale) >> chip->adc_bit;
+ /* To support fractional scaling, separate the unshifted lux
+ * into two calculations: int scaling and micro-scaling.
+ * lux_uscale ranges from 0-999999, so about 20 bits. Split
+ * the /1,000,000 in two to reduce the risk of over/underflow.
+ */
+ data_x_range = lux_data * chip->range;
+ lux_unshifted = data_x_range * chip->lux_scale;
+ lux_unshifted += data_x_range / 1000 * chip->lux_uscale / 1000;
+ *lux = lux_unshifted >> chip->adc_bit;
return 0;
}
@@ -339,6 +349,8 @@ static int isl29018_write_raw(struct iio_dev *indio_dev,
mutex_lock(&chip->lock);
if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) {
chip->lux_scale = val;
+ /* With no write_raw_get_fmt(), val2 is a MICRO fraction. */
+ chip->lux_uscale = val2;
ret = 0;
}
mutex_unlock(&chip->lock);
@@ -379,7 +391,8 @@ static int isl29018_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBSCALE:
if (chan->type == IIO_LIGHT) {
*val = chip->lux_scale;
- ret = IIO_VAL_INT;
+ *val2 = chip->lux_uscale;
+ ret = IIO_VAL_INT_PLUS_MICRO;
}
break;
default: