Skip to content

Commit 498efcd

Browse files
masneybjic23
authored andcommitted
staging: iio: tsl2x7x: correct integration time and lux equation
The integration_time sysfs attribute did not report the correct time. Changing the integration time would cause the reported lux to change wildly. Once the integration time was corrected, all of the equations, and lux tables needed to be corrected to match what the data sheets expected. This patch corrects all of this, and adds some more comments about how some of the constants were derived. Here are the results from testing a TSL2772 hooked up to a Raspberry Pi 2: # cat in_intensity0_integration_time 0.002730 # watch -n .1 cat in_illuminance0_input ; Lux hovers around 55 # echo 0.65 > in_intensity0_integration_time # cat in_intensity0_integration_time 0.649740 # watch -n .1 cat in_illuminance0_input ; Lux hovers around 55 with noticeable lag to lux changes in watch ; process. ; Now test the ALS calibration routine. # cat in_intensity0_calibbias 1000 # cat in_illuminance0_target_input 150 # echo 1 > in_illuminance0_calibrate # cat in_intensity0_calibbias 2777 # watch -n .1 cat in_illuminance0_input ; Lux now hovers around 150-155 The returned lux values were tested on a TSL2772 in various lighting conditions and the results are within the lux ranges described at https://en.wikipedia.org/wiki/Lux. The driver was primarily tested using a TSL2772, however some quick tests were also ran against the devices TSL2771, TSL2572, and TMD2772. Signed-off-by: Brian Masney <[email protected]> Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 11031d7 commit 498efcd

File tree

2 files changed

+79
-98
lines changed

2 files changed

+79
-98
lines changed

drivers/staging/iio/light/tsl2x7x.c

Lines changed: 78 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ struct tsl2X7X_chip {
148148
struct tsl2x7x_als_info als_cur_info;
149149
struct tsl2x7x_settings settings;
150150
struct tsl2X7X_platform_data *pdata;
151-
int als_time_scale;
151+
int als_gain_time_scale;
152152
int als_saturation;
153153
int tsl2x7x_chip_status;
154154
u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
@@ -163,29 +163,36 @@ struct tsl2X7X_chip {
163163
struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
164164
};
165165

166-
/* Different devices require different coefficents */
166+
/*
167+
* Different devices require different coefficents, and these numbers were
168+
* derived from the 'Lux Equation' section of the various device datasheets.
169+
* All of these coefficients assume a Glass Attenuation (GA) factor of 1.
170+
* The coefficients are multiplied by 1000 to avoid floating point operations.
171+
* The two rows in each table correspond to the Lux1 and Lux2 equations from
172+
* the datasheets.
173+
*/
167174
static const struct tsl2x7x_lux tsl2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
168-
{ 14461, 611, 1211 },
169-
{ 18540, 352, 623 },
170-
{ 0, 0, 0 },
175+
{ 53000, 106000 },
176+
{ 31800, 53000 },
177+
{ 0, 0 },
171178
};
172179

173180
static const struct tsl2x7x_lux tmd2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
174-
{ 11635, 115, 256 },
175-
{ 15536, 87, 179 },
176-
{ 0, 0, 0 },
181+
{ 24000, 48000 },
182+
{ 14400, 24000 },
183+
{ 0, 0 },
177184
};
178185

179186
static const struct tsl2x7x_lux tsl2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
180-
{ 14013, 466, 917 },
181-
{ 18222, 310, 552 },
182-
{ 0, 0, 0 },
187+
{ 60000, 112200 },
188+
{ 37800, 60000 },
189+
{ 0, 0 },
183190
};
184191

185192
static const struct tsl2x7x_lux tmd2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
186-
{ 13218, 130, 262 },
187-
{ 17592, 92, 169 },
188-
{ 0, 0, 0 },
193+
{ 20000, 35000 },
194+
{ 12600, 20000 },
195+
{ 0, 0 },
189196
};
190197

191198
static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
@@ -343,22 +350,18 @@ static int tsl2x7x_read_autoinc_regs(struct tsl2X7X_chip *chip, int lower_reg,
343350
* @indio_dev: pointer to IIO device
344351
*
345352
* The raw ch0 and ch1 values of the ambient light sensed in the last
346-
* integration cycle are read from the device. Time scale factor array values
347-
* are adjusted based on the integration time. The raw values are multiplied
348-
* by a scale factor, and device gain is obtained using gain index. Limit
349-
* checks are done next, then the ratio of a multiple of ch1 value, to the
350-
* ch0 value, is calculated. Array tsl2x7x_device_lux[] is then scanned to
351-
* find the first ratio value that is just above the ratio we just calculated.
352-
* The ch0 and ch1 multiplier constants in the array are then used along with
353-
* the time scale factor array values, to calculate the lux.
353+
* integration cycle are read from the device. The raw values are multiplied
354+
* by a device-specific scale factor, and divided by the integration time and
355+
* device gain. The code supports multiple lux equations through the lux table
356+
* coefficients. A lux gain trim is applied to each lux equation, and then the
357+
* maximum lux within the interval 0..65535 is selected.
354358
*/
355359
static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
356360
{
357361
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
358362
struct tsl2x7x_lux *p;
359-
u32 lux, ratio;
360-
u64 lux64;
361-
int ret;
363+
int max_lux, ret;
364+
bool overflow;
362365

363366
mutex_lock(&chip->als_mutex);
364367

@@ -392,10 +395,9 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
392395
goto out_unlock;
393396
chip->als_cur_info.als_ch1 = ret;
394397

395-
if (chip->als_cur_info.als_ch0 >= chip->als_saturation ||
396-
chip->als_cur_info.als_ch1 >= chip->als_saturation) {
397-
lux = TSL2X7X_LUX_CALC_OVER_FLOW;
398-
goto return_max;
398+
if (chip->als_cur_info.als_ch0 >= chip->als_saturation) {
399+
max_lux = TSL2X7X_LUX_CALC_OVER_FLOW;
400+
goto update_struct_with_max_lux;
399401
}
400402

401403
if (!chip->als_cur_info.als_ch0) {
@@ -404,51 +406,38 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
404406
goto out_unlock;
405407
}
406408

407-
/* calculate ratio */
408-
ratio = (chip->als_cur_info.als_ch1 << 15) / chip->als_cur_info.als_ch0;
409-
410-
/* convert to unscaled lux using the pointer to the table */
411-
p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux;
412-
while (p->ratio != 0 && p->ratio < ratio)
413-
p++;
409+
max_lux = 0;
410+
overflow = false;
411+
for (p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; p->ch0 != 0;
412+
p++) {
413+
int lux;
414+
415+
lux = ((chip->als_cur_info.als_ch0 * p->ch0) -
416+
(chip->als_cur_info.als_ch1 * p->ch1)) /
417+
chip->als_gain_time_scale;
418+
419+
/*
420+
* The als_gain_trim can have a value within the range 250..4000
421+
* and is a multiplier for the lux. A trim of 1000 makes no
422+
* changes to the lux, less than 1000 scales it down, and
423+
* greater than 1000 scales it up.
424+
*/
425+
lux = (lux * chip->settings.als_gain_trim) / 1000;
426+
427+
if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) {
428+
overflow = true;
429+
continue;
430+
}
414431

415-
if (p->ratio == 0) {
416-
lux = 0;
417-
} else {
418-
lux = DIV_ROUND_UP(chip->als_cur_info.als_ch0 * p->ch0,
419-
tsl2x7x_als_gain[chip->settings.als_gain]) -
420-
DIV_ROUND_UP(chip->als_cur_info.als_ch1 * p->ch1,
421-
tsl2x7x_als_gain[chip->settings.als_gain]);
432+
max_lux = max(max_lux, lux);
422433
}
423434

424-
/* adjust for active time scale */
425-
if (chip->als_time_scale == 0)
426-
lux = 0;
427-
else
428-
lux = (lux + (chip->als_time_scale >> 1)) /
429-
chip->als_time_scale;
430-
431-
/*
432-
* adjust for active gain scale. The tsl2x7x_device_lux tables have a
433-
* factor of 256 built-in. User-specified gain provides a multiplier.
434-
* Apply user-specified gain before shifting right to retain precision.
435-
* Use 64 bits to avoid overflow on multiplication. Then go back to
436-
* 32 bits before division to avoid using div_u64().
437-
*/
438-
439-
lux64 = lux;
440-
lux64 = lux64 * chip->settings.als_gain_trim;
441-
lux64 >>= 8;
442-
lux = lux64;
443-
lux = (lux + 500) / 1000;
435+
if (overflow && max_lux == 0)
436+
max_lux = TSL2X7X_LUX_CALC_OVER_FLOW;
444437

445-
if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
446-
lux = TSL2X7X_LUX_CALC_OVER_FLOW;
447-
448-
/* Update the structure with the latest lux. */
449-
return_max:
450-
chip->als_cur_info.lux = lux;
451-
ret = lux;
438+
update_struct_with_max_lux:
439+
chip->als_cur_info.lux = max_lux;
440+
ret = max_lux;
452441

453442
out_unlock:
454443
mutex_unlock(&chip->als_mutex);
@@ -525,7 +514,7 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
525514
sizeof(tsl2x7x_default_settings));
526515

527516
/* Load up the proper lux table. */
528-
if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
517+
if (chip->pdata && chip->pdata->platform_lux_table[0].ch0 != 0)
529518
memcpy(chip->tsl2x7x_device_lux,
530519
chip->pdata->platform_lux_table,
531520
sizeof(chip->pdata->platform_lux_table));
@@ -588,10 +577,11 @@ static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
588577
static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
589578
{
590579
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
591-
int ret, i, als_count, als_time;
580+
int ret, i, als_count, als_time_us;
592581
u8 *dev_reg, reg_val;
593582

594583
/* Non calculated parameters */
584+
chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = chip->settings.als_time;
595585
chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prox_time;
596586
chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time;
597587
chip->tsl2x7x_config[TSL2X7X_ALS_PRX_CONFIG] =
@@ -627,25 +617,19 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
627617
return -EINVAL;
628618
}
629619

630-
/* determine als integration register */
631-
als_count = (chip->settings.als_time * 100 + 135) / 270;
632-
if (!als_count)
633-
als_count = 1; /* ensure at least one cycle */
634-
635-
/* convert back to time (encompasses overrides) */
636-
als_time = (als_count * 27 + 5) / 10;
637-
chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
638-
639620
/* Set the gain based on tsl2x7x_settings struct */
640621
chip->tsl2x7x_config[TSL2X7X_GAIN] =
641622
(chip->settings.als_gain & 0xFF) |
642623
((chip->settings.prox_gain & 0xFF) << 2) |
643624
(chip->settings.prox_diode << 4) |
644625
(chip->settings.prox_power << 6);
645626

646-
/* set chip struct re scaling and saturation */
647-
chip->als_saturation = als_count * 922; /* 90% of full scale */
648-
chip->als_time_scale = (als_time + 25) / 50;
627+
/* set chip time scaling and saturation */
628+
als_count = 256 - chip->settings.als_time;
629+
als_time_us = als_count * 2720;
630+
chip->als_saturation = als_count * 768; /* 75% of full scale */
631+
chip->als_gain_time_scale = als_time_us *
632+
tsl2x7x_als_gain[chip->settings.als_gain];
649633

650634
/*
651635
* TSL2X7X Specific power-on / adc enable sequence
@@ -843,11 +827,10 @@ static ssize_t in_illuminance0_lux_table_show(struct device *dev,
843827
int offset = 0;
844828

845829
while (i < TSL2X7X_MAX_LUX_TABLE_SIZE) {
846-
offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
847-
chip->tsl2x7x_device_lux[i].ratio,
830+
offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,",
848831
chip->tsl2x7x_device_lux[i].ch0,
849832
chip->tsl2x7x_device_lux[i].ch1);
850-
if (chip->tsl2x7x_device_lux[i].ratio == 0) {
833+
if (chip->tsl2x7x_device_lux[i].ch0 == 0) {
851834
/*
852835
* We just printed the first "0" entry.
853836
* Now get rid of the extra "," and break.
@@ -868,23 +851,23 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev,
868851
{
869852
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
870853
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
871-
int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1];
854+
int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 2 + 1];
872855
int n, ret;
873856

874857
get_options(buf, ARRAY_SIZE(value), value);
875858

876859
/*
877860
* We now have an array of ints starting at value[1], and
878861
* enumerated by value[0].
879-
* We expect each group of three ints is one table entry,
862+
* We expect each group of two ints to be one table entry,
880863
* and the last table entry is all 0.
881864
*/
882865
n = value[0];
883-
if ((n % 3) || n < 6 ||
884-
n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3))
866+
if ((n % 2) || n < 4 ||
867+
n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 2))
885868
return -EINVAL;
886869

887-
if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0)
870+
if ((value[(n - 1)] | value[n]) != 0)
888871
return -EINVAL;
889872

890873
if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
@@ -1140,8 +1123,8 @@ static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
11401123
ret = IIO_VAL_INT;
11411124
break;
11421125
case IIO_CHAN_INFO_INT_TIME:
1143-
*val = (TSL2X7X_MAX_TIMER_CNT - chip->settings.als_time) + 1;
1144-
*val2 = ((*val * TSL2X7X_MIN_ITIME) % 1000) / 1000;
1126+
*val = 0;
1127+
*val2 = (256 - chip->settings.als_time) * 2720;
11451128
ret = IIO_VAL_INT_PLUS_MICRO;
11461129
break;
11471130
default:
@@ -1201,8 +1184,7 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
12011184
chip->settings.als_gain_trim = val;
12021185
break;
12031186
case IIO_CHAN_INFO_INT_TIME:
1204-
chip->settings.als_time =
1205-
TSL2X7X_MAX_TIMER_CNT - (val2 / TSL2X7X_MIN_ITIME);
1187+
chip->settings.als_time = 256 - (val2 / 2720);
12061188
break;
12071189
default:
12081190
return -EINVAL;

drivers/staging/iio/light/tsl2x7x.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@
1010
#define __TSL2X7X_H
1111

1212
struct tsl2x7x_lux {
13-
unsigned int ratio;
1413
unsigned int ch0;
1514
unsigned int ch1;
1615
};
1716

1817
/* Max number of segments allowable in LUX table */
19-
#define TSL2X7X_MAX_LUX_TABLE_SIZE 9
18+
#define TSL2X7X_MAX_LUX_TABLE_SIZE 6
2019
/* The default LUX tables all have 3 elements. */
2120
#define TSL2X7X_DEF_LUX_TABLE_SZ 3
2221
#define TSL2X7X_DEFAULT_TABLE_BYTES (sizeof(struct tsl2x7x_lux) * \

0 commit comments

Comments
 (0)