// SPDX-License-Identifier: GPL-2.0-only /* * drivers/iio/light/tsl2563.c * * Copyright (C) 2008 Nokia Corporation * * Written by Timo O. Karjalainen <timo.o.karjalainen@nokia.com> * Contact: Amit Kucheria <amit.kucheria@verdurent.com> * * Converted to IIO driver * Amit Kucheria <amit.kucheria@verdurent.com>
*/
/* * Return value is 0 for off, 1 for on, or a negative error * code if reading failed.
*/ staticint tsl2563_get_power(struct tsl2563_chip *chip)
{ struct i2c_client *client = chip->client; int ret;
ret = i2c_smbus_read_byte_data(client, TSL2563_CMD | TSL2563_REG_CTRL); if (ret < 0) return ret;
staticint tsl2563_configure(struct tsl2563_chip *chip)
{ int ret;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_TIMING,
chip->gainlevel->gaintime); if (ret) goto error_ret;
ret = i2c_smbus_write_word_data(chip->client,
TSL2563_CMD | TSL2563_REG_HIGH,
chip->high_thres); if (ret) goto error_ret;
ret = i2c_smbus_write_word_data(chip->client,
TSL2563_CMD | TSL2563_REG_LOW,
chip->low_thres); if (ret) goto error_ret; /* * Interrupt register is automatically written anyway if it is relevant * so is not here.
*/
error_ret: return ret;
}
ret = i2c_smbus_read_byte_data(client, TSL2563_CMD | TSL2563_REG_ID); if (ret < 0) return ret;
*id = ret;
return 0;
}
staticint tsl2563_configure_irq(struct tsl2563_chip *chip, bool enable)
{ int ret;
chip->intr &= ~TSL2563_INT_MASK; if (enable)
chip->intr |= TSL2563_INT_LEVEL;
ret = i2c_smbus_write_byte_data(chip->client,
TSL2563_CMD | TSL2563_REG_INT,
chip->intr); if (ret < 0) return ret;
chip->int_enabled = enable; return 0;
}
/* * "Normalized" ADC value is one obtained with 400ms of integration time and * 16x gain. This function returns the number of bits of shift needed to * convert between normalized values and HW values obtained using given * timing and gain settings.
*/ staticint tsl2563_adc_shiftbits(u8 timing)
{ int shift = 0;
switch (timing & TSL2563_TIMING_MASK) { case TSL2563_TIMING_13MS:
shift += 5; break; case TSL2563_TIMING_100MS:
shift += 2; break; case TSL2563_TIMING_400MS: /* no-op */ break;
}
if (!(timing & TSL2563_TIMING_GAIN16))
shift += 4;
return shift;
}
/* Convert a HW ADC value to normalized scale. */ static u32 tsl2563_normalize_adc(u16 adc, u8 timing)
{ return adc << tsl2563_adc_shiftbits(timing);
}
switch (chip->gainlevel->gaintime & TSL2563_TIMING_MASK) { case TSL2563_TIMING_13MS:
delay = 14; break; case TSL2563_TIMING_100MS:
delay = 101; break; default:
delay = 402;
} /* * TODO: Make sure that we wait at least required delay but why we * have to extend it one tick more?
*/
schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2);
}
staticint tsl2563_get_adc(struct tsl2563_chip *chip)
{ struct i2c_client *client = chip->client;
u16 adc0, adc1; int retry = 1; int ret = 0;
if (chip->suspended) goto out;
if (!chip->int_enabled) {
cancel_delayed_work_sync(&chip->poweroff_work);
if (!tsl2563_get_power(chip)) {
ret = tsl2563_set_power(chip, 1); if (ret) goto out;
ret = tsl2563_configure(chip); if (ret) goto out;
tsl2563_wait_adc(chip);
}
}
while (retry) {
ret = i2c_smbus_read_word_data(client,
TSL2563_CMD | TSL2563_REG_DATA0); if (ret < 0) goto out;
adc0 = ret;
ret = i2c_smbus_read_word_data(client,
TSL2563_CMD | TSL2563_REG_DATA1); if (ret < 0) goto out;
adc1 = ret;
staticinline u32 tsl2563_calib_from_sysfs(int value)
{ /* Make a fraction from a number n that was multiplied with b. */ return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS;
}
/* * Conversions between lux and ADC values. * * The basic formula is lux = c0 * adc0 - c1 * adc1, where c0 and c1 are * appropriate constants. Different constants are needed for different * kinds of light, determined by the ratio adc1/adc0 (basically the ratio * of the intensities in infrared and visible wavelengths). lux_table below * lists the upper threshold of the adc1/adc0 ratio and the corresponding * constants.
*/
mutex_lock(&chip->lock); if (state && !(chip->intr & TSL2563_INT_MASK)) { /* ensure the chip is actually on */
cancel_delayed_work_sync(&chip->poweroff_work); if (!tsl2563_get_power(chip)) {
ret = tsl2563_set_power(chip, 1); if (ret) goto out;
ret = tsl2563_configure(chip); if (ret) goto out;
}
ret = tsl2563_configure_irq(chip, true);
}
if (!state && (chip->intr & TSL2563_INT_MASK)) {
ret = tsl2563_configure_irq(chip, false); /* now the interrupt is not enabled, we can go to sleep */
schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
}
out:
mutex_unlock(&chip->lock);
iio_device_unregister(indio_dev); if (!chip->int_enabled)
cancel_delayed_work_sync(&chip->poweroff_work); /* Ensure that interrupts are disabled - then flush any bottom halves */
tsl2563_configure_irq(chip, false);
tsl2563_set_power(chip, 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.