// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2021 Joe Sandom <joe.g.sandom@gmail.com>
*
* Datasheet: https://ams.com/tsl25911#tab/documents
*
* Device driver for the TAOS TSL2591. This is a very-high sensitivity
* light-to-digital converter that transforms light intensity into a digital
* signal.
*/
#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/sysfs.h>
#include <linux/unaligned.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* ADC integration time, field value to time in ms */
#define TSL2591_FVAL_TO_MSEC(x) (((x) + 1) * 100)
/* ADC integration time, field value to time in seconds */
#define TSL2591_FVAL_TO_SEC(x) ((x) + 1)
/* ADC integration time, time in seconds to field value */
#define TSL2591_SEC_TO_FVAL(x) ((x) - 1)
/* TSL2591 register set */
#define TSL2591_ENABLE 0x00
#define TSL2591_CONTROL 0x01
#define TSL2591_AILTL 0x04
#define TSL2591_AILTH 0x05
#define TSL2591_AIHTL 0x06
#define TSL2591_AIHTH 0x07
#define TSL2591_NP_AILTL 0x08
#define TSL2591_NP_AILTH 0x09
#define TSL2591_NP_AIHTL 0x0A
#define TSL2591_NP_AIHTH 0x0B
#define TSL2591_PERSIST 0x0C
#define TSL2591_PACKAGE_ID 0x11
#define TSL2591_DEVICE_ID 0x12
#define TSL2591_STATUS 0x13
#define TSL2591_C0_DATAL 0x14
#define TSL2591_C0_DATAH 0x15
#define TSL2591_C1_DATAL 0x16
#define TSL2591_C1_DATAH 0x17
/* TSL2591 command register definitions */
#define TSL2591_CMD_NOP 0xA0
#define TSL2591_CMD_SF_INTSET 0xE4
#define TSL2591_CMD_SF_CALS_I 0xE5
#define TSL2591_CMD_SF_CALS_NPI 0xE7
#define TSL2591_CMD_SF_CNP_ALSI 0xEA
/* TSL2591 enable register definitions */
#define TSL2591_PWR_ON 0x01
#define TSL2591_PWR_OFF 0x00
#define TSL2591_ENABLE_ALS 0x02
#define TSL2591_ENABLE_ALS_INT 0x10
#define TSL2591_ENABLE_SLEEP_INT 0x40
#define TSL2591_ENABLE_NP_INT 0x80
/* TSL2591 control register definitions */
#define TSL2591_CTRL_ALS_INTEGRATION_100MS 0x00
#define TSL2591_CTRL_ALS_INTEGRATION_200MS 0x01
#define TSL2591_CTRL_ALS_INTEGRATION_300MS 0x02
#define TSL2591_CTRL_ALS_INTEGRATION_400MS 0x03
#define TSL2591_CTRL_ALS_INTEGRATION_500MS 0x04
#define TSL2591_CTRL_ALS_INTEGRATION_600MS 0x05
#define TSL2591_CTRL_ALS_LOW_GAIN 0x00
#define TSL2591_CTRL_ALS_MED_GAIN 0x10
#define TSL2591_CTRL_ALS_HIGH_GAIN 0x20
#define TSL2591_CTRL_ALS_MAX_GAIN 0x30
#define TSL2591_CTRL_SYS_RESET 0x80
/* TSL2591 persist register definitions */
#define TSL2591_PRST_ALS_INT_CYCLE_0 0x00
#define TSL2591_PRST_ALS_INT_CYCLE_ANY 0x01
#define TSL2591_PRST_ALS_INT_CYCLE_2 0x02
#define TSL2591_PRST_ALS_INT_CYCLE_3 0x03
#define TSL2591_PRST_ALS_INT_CYCLE_5 0x04
#define TSL2591_PRST_ALS_INT_CYCLE_10 0x05
#define TSL2591_PRST_ALS_INT_CYCLE_15 0x06
#define TSL2591_PRST_ALS_INT_CYCLE_20 0x07
#define TSL2591_PRST_ALS_INT_CYCLE_25 0x08
#define TSL2591_PRST_ALS_INT_CYCLE_30 0x09
#define TSL2591_PRST_ALS_INT_CYCLE_35 0x0A
#define TSL2591_PRST_ALS_INT_CYCLE_40 0x0B
#define TSL2591_PRST_ALS_INT_CYCLE_45 0x0C
#define TSL2591_PRST_ALS_INT_CYCLE_50 0x0D
#define TSL2591_PRST_ALS_INT_CYCLE_55 0x0E
#define TSL2591_PRST_ALS_INT_CYCLE_60 0x0F
#define TSL2591_PRST_ALS_INT_CYCLE_MAX (BIT(4) - 1)
/* TSL2591 PID register mask */
#define TSL2591_PACKAGE_ID_MASK GENMASK(5, 4)
/* TSL2591 ID register mask */
#define TSL2591_DEVICE_ID_MASK GENMASK(7, 0)
/* TSL2591 status register masks */
#define TSL2591_STS_ALS_VALID_MASK BIT(0)
#define TSL2591_STS_ALS_INT_MASK BIT(4)
#define TSL2591_STS_NPERS_INT_MASK BIT(5)
#define TSL2591_STS_VAL_HIGH_MASK BIT(0)
/* TSL2591 constant values */
#define TSL2591_PACKAGE_ID_VAL 0x00
#define TSL2591_DEVICE_ID_VAL 0x50
/* Power off suspend delay time MS */
#define TSL2591_POWER_OFF_DELAY_MS 2000
/* TSL2591 default values */
#define TSL2591_DEFAULT_ALS_INT_TIME TSL2591_CTRL_ALS_INTEGRATION_300MS
#define TSL2591_DEFAULT_ALS_GAIN TSL2591_CTRL_ALS_MED_GAIN
#define TSL2591_DEFAULT_ALS_PERSIST TSL2591_PRST_ALS_INT_CYCLE_ANY
#define TSL2591_DEFAULT_ALS_LOWER_THRESH 100
#define TSL2591_DEFAULT_ALS_UPPER_THRESH 1500
/* TSL2591 number of data registers */
#define TSL2591_NUM_DATA_REGISTERS 4
/* TSL2591 number of valid status reads on ADC complete */
#define TSL2591_ALS_STS_VALID_COUNT 10
/* TSL2591 delay period between polls when checking for ALS valid flag */
#define TSL2591_DELAY_PERIOD_US 10000
/* TSL2591 maximum values */
#define TSL2591_MAX_ALS_INT_TIME_MS 600
#define TSL2591_ALS_MAX_VALUE (BIT(16) - 1)
/*
* LUX calculations;
* AGAIN values from Adafruit's TSL2591 Arduino library
* https://github.com/adafruit/Adafruit_TSL2591_Library
*/
#define TSL2591_CTRL_ALS_LOW_GAIN_MULTIPLIER 1
#define TSL2591_CTRL_ALS_MED_GAIN_MULTIPLIER 25
#define TSL2591_CTRL_ALS_HIGH_GAIN_MULTIPLIER 428
#define TSL2591_CTRL_ALS_MAX_GAIN_MULTIPLIER 9876
#define TSL2591_LUX_COEFFICIENT 408
struct tsl2591_als_settings {
u16 als_lower_thresh;
u16 als_upper_thresh;
u8 als_int_time;
u8 als_persist;
u8 als_gain;
};
struct tsl2591_chip {
struct tsl2591_als_settings als_settings;
struct i2c_client *client;
/*
* Keep als_settings in sync with hardware state
* and ensure multiple readers are serialized.
*/
struct mutex als_mutex;
bool events_enabled;
};
/*
* Period table is ALS persist cycle x integration time setting
* Integration times: 100ms, 200ms, 300ms, 400ms, 500ms, 600ms
* ALS cycles: 1, 2, 3, 5, 10, 20, 25, 30, 35, 40, 45, 50, 55, 60
*/
static const char * const tsl2591_als_period_list[] = {
"0.1 0.2 0.3 0.5 1.0 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0",
"0.2 0.4 0.6 1.0 2.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0",
"0.3 0.6 0.9 1.5 3.0 6.0 7.5 9.0 10.5 12.0 13.5 15.0 16.5 18.0",
"0.4 0.8 1.2 2.0 4.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0 22.0 24.0",
"0.5 1.0 1.5 2.5 5.0 10.0 12.5 15.0 17.5 20.0 22.5 25.0 27.5 30.0",
"0.6 1.2 1.8 3.0 6.0 12.0 15.0 18.0 21.0 24.0 27.0 30.0 33.0 36.0",
};
static const int tsl2591_int_time_available[] = {
1, 2, 3, 4, 5, 6,
};
static const int tsl2591_calibscale_available[] = {