struct tsl2x7x_als_info als_cur_info;
struct tsl2x7x_settings settings;
struct tsl2X7X_platform_data *pdata;
- int als_time_scale;
+ int als_gain_time_scale;
int als_saturation;
int tsl2x7x_chip_status;
u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
};
-/* Different devices require different coefficents */
+/*
+ * Different devices require different coefficents, and these numbers were
+ * derived from the 'Lux Equation' section of the various device datasheets.
+ * All of these coefficients assume a Glass Attenuation (GA) factor of 1.
+ * The coefficients are multiplied by 1000 to avoid floating point operations.
+ * The two rows in each table correspond to the Lux1 and Lux2 equations from
+ * the datasheets.
+ */
static const struct tsl2x7x_lux tsl2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 14461, 611, 1211 },
- { 18540, 352, 623 },
- { 0, 0, 0 },
+ { 53000, 106000 },
+ { 31800, 53000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux tmd2x71_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 11635, 115, 256 },
- { 15536, 87, 179 },
- { 0, 0, 0 },
+ { 24000, 48000 },
+ { 14400, 24000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux tsl2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 14013, 466, 917 },
- { 18222, 310, 552 },
- { 0, 0, 0 },
+ { 60000, 112200 },
+ { 37800, 60000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux tmd2x72_lux_table[TSL2X7X_DEF_LUX_TABLE_SZ] = {
- { 13218, 130, 262 },
- { 17592, 92, 169 },
- { 0, 0, 0 },
+ { 20000, 35000 },
+ { 12600, 20000 },
+ { 0, 0 },
};
static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
* @indio_dev: pointer to IIO device
*
* The raw ch0 and ch1 values of the ambient light sensed in the last
- * integration cycle are read from the device. Time scale factor array values
- * are adjusted based on the integration time. The raw values are multiplied
- * by a scale factor, and device gain is obtained using gain index. Limit
- * checks are done next, then the ratio of a multiple of ch1 value, to the
- * ch0 value, is calculated. Array tsl2x7x_device_lux[] is then scanned to
- * find the first ratio value that is just above the ratio we just calculated.
- * The ch0 and ch1 multiplier constants in the array are then used along with
- * the time scale factor array values, to calculate the lux.
+ * integration cycle are read from the device. The raw values are multiplied
+ * by a device-specific scale factor, and divided by the integration time and
+ * device gain. The code supports multiple lux equations through the lux table
+ * coefficients. A lux gain trim is applied to each lux equation, and then the
+ * maximum lux within the interval 0..65535 is selected.
*/
static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
{
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
struct tsl2x7x_lux *p;
- u32 lux, ratio;
- u64 lux64;
- int ret;
+ int max_lux, ret;
+ bool overflow;
mutex_lock(&chip->als_mutex);
goto out_unlock;
chip->als_cur_info.als_ch1 = ret;
- if (chip->als_cur_info.als_ch0 >= chip->als_saturation ||
- chip->als_cur_info.als_ch1 >= chip->als_saturation) {
- lux = TSL2X7X_LUX_CALC_OVER_FLOW;
- goto return_max;
+ if (chip->als_cur_info.als_ch0 >= chip->als_saturation) {
+ max_lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+ goto update_struct_with_max_lux;
}
if (!chip->als_cur_info.als_ch0) {
goto out_unlock;
}
- /* calculate ratio */
- ratio = (chip->als_cur_info.als_ch1 << 15) / chip->als_cur_info.als_ch0;
-
- /* convert to unscaled lux using the pointer to the table */
- p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux;
- while (p->ratio != 0 && p->ratio < ratio)
- p++;
+ max_lux = 0;
+ overflow = false;
+ for (p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux; p->ch0 != 0;
+ p++) {
+ int lux;
+
+ lux = ((chip->als_cur_info.als_ch0 * p->ch0) -
+ (chip->als_cur_info.als_ch1 * p->ch1)) /
+ chip->als_gain_time_scale;
+
+ /*
+ * The als_gain_trim can have a value within the range 250..4000
+ * and is a multiplier for the lux. A trim of 1000 makes no
+ * changes to the lux, less than 1000 scales it down, and
+ * greater than 1000 scales it up.
+ */
+ lux = (lux * chip->settings.als_gain_trim) / 1000;
+
+ if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) {
+ overflow = true;
+ continue;
+ }
- if (p->ratio == 0) {
- lux = 0;
- } else {
- lux = DIV_ROUND_UP(chip->als_cur_info.als_ch0 * p->ch0,
- tsl2x7x_als_gain[chip->settings.als_gain]) -
- DIV_ROUND_UP(chip->als_cur_info.als_ch1 * p->ch1,
- tsl2x7x_als_gain[chip->settings.als_gain]);
+ max_lux = max(max_lux, lux);
}
- /* adjust for active time scale */
- if (chip->als_time_scale == 0)
- lux = 0;
- else
- lux = (lux + (chip->als_time_scale >> 1)) /
- chip->als_time_scale;
-
- /*
- * adjust for active gain scale. The tsl2x7x_device_lux tables have a
- * factor of 256 built-in. User-specified gain provides a multiplier.
- * Apply user-specified gain before shifting right to retain precision.
- * Use 64 bits to avoid overflow on multiplication. Then go back to
- * 32 bits before division to avoid using div_u64().
- */
-
- lux64 = lux;
- lux64 = lux64 * chip->settings.als_gain_trim;
- lux64 >>= 8;
- lux = lux64;
- lux = (lux + 500) / 1000;
+ if (overflow && max_lux == 0)
+ max_lux = TSL2X7X_LUX_CALC_OVER_FLOW;
- if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
- lux = TSL2X7X_LUX_CALC_OVER_FLOW;
-
- /* Update the structure with the latest lux. */
-return_max:
- chip->als_cur_info.lux = lux;
- ret = lux;
+update_struct_with_max_lux:
+ chip->als_cur_info.lux = max_lux;
+ ret = max_lux;
out_unlock:
mutex_unlock(&chip->als_mutex);
sizeof(tsl2x7x_default_settings));
/* Load up the proper lux table. */
- if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
+ if (chip->pdata && chip->pdata->platform_lux_table[0].ch0 != 0)
memcpy(chip->tsl2x7x_device_lux,
chip->pdata->platform_lux_table,
sizeof(chip->pdata->platform_lux_table));
static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
{
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int ret, i, als_count, als_time;
+ int ret, i, als_count, als_time_us;
u8 *dev_reg, reg_val;
/* Non calculated parameters */
+ chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = chip->settings.als_time;
chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = chip->settings.prox_time;
chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = chip->settings.wait_time;
chip->tsl2x7x_config[TSL2X7X_ALS_PRX_CONFIG] =
return -EINVAL;
}
- /* determine als integration register */
- als_count = (chip->settings.als_time * 100 + 135) / 270;
- if (!als_count)
- als_count = 1; /* ensure at least one cycle */
-
- /* convert back to time (encompasses overrides) */
- als_time = (als_count * 27 + 5) / 10;
- chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
-
/* Set the gain based on tsl2x7x_settings struct */
chip->tsl2x7x_config[TSL2X7X_GAIN] =
(chip->settings.als_gain & 0xFF) |
(chip->settings.prox_diode << 4) |
(chip->settings.prox_power << 6);
- /* set chip struct re scaling and saturation */
- chip->als_saturation = als_count * 922; /* 90% of full scale */
- chip->als_time_scale = (als_time + 25) / 50;
+ /* set chip time scaling and saturation */
+ als_count = 256 - chip->settings.als_time;
+ als_time_us = als_count * 2720;
+ chip->als_saturation = als_count * 768; /* 75% of full scale */
+ chip->als_gain_time_scale = als_time_us *
+ tsl2x7x_als_gain[chip->settings.als_gain];
/*
* TSL2X7X Specific power-on / adc enable sequence
int offset = 0;
while (i < TSL2X7X_MAX_LUX_TABLE_SIZE) {
- offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
- chip->tsl2x7x_device_lux[i].ratio,
+ offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,",
chip->tsl2x7x_device_lux[i].ch0,
chip->tsl2x7x_device_lux[i].ch1);
- if (chip->tsl2x7x_device_lux[i].ratio == 0) {
+ if (chip->tsl2x7x_device_lux[i].ch0 == 0) {
/*
* We just printed the first "0" entry.
* Now get rid of the extra "," and break.
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2X7X_chip *chip = iio_priv(indio_dev);
- int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1];
+ int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 2 + 1];
int n, ret;
get_options(buf, ARRAY_SIZE(value), value);
/*
* We now have an array of ints starting at value[1], and
* enumerated by value[0].
- * We expect each group of three ints is one table entry,
+ * We expect each group of two ints to be one table entry,
* and the last table entry is all 0.
*/
n = value[0];
- if ((n % 3) || n < 6 ||
- n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3))
+ if ((n % 2) || n < 4 ||
+ n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 2))
return -EINVAL;
- if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0)
+ if ((value[(n - 1)] | value[n]) != 0)
return -EINVAL;
if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_INT_TIME:
- *val = (TSL2X7X_MAX_TIMER_CNT - chip->settings.als_time) + 1;
- *val2 = ((*val * TSL2X7X_MIN_ITIME) % 1000) / 1000;
+ *val = 0;
+ *val2 = (256 - chip->settings.als_time) * 2720;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
default:
chip->settings.als_gain_trim = val;
break;
case IIO_CHAN_INFO_INT_TIME:
- chip->settings.als_time =
- TSL2X7X_MAX_TIMER_CNT - (val2 / TSL2X7X_MIN_ITIME);
+ chip->settings.als_time = 256 - (val2 / 2720);
break;
default:
return -EINVAL;