2018-05-04 05:53:09 +03:00
// SPDX-License-Identifier: GPL-2.0+
2012-04-24 20:56:49 +04:00
/*
2018-04-21 03:41:52 +03:00
* Device driver for monitoring ambient light intensity in ( lux ) and proximity
2018-05-11 03:12:22 +03:00
* detection ( prox ) within the TAOS TSL2571 , TSL2671 , TMD2671 , TSL2771 , TMD2771 ,
* TSL2572 , TSL2672 , TMD2672 , TSL2772 , and TMD2772 devices .
2012-04-24 20:56:49 +04:00
*
* Copyright ( c ) 2012 , TAOS Corporation .
2018-03-21 13:29:12 +03:00
* Copyright ( c ) 2017 - 2018 Brian Masney < masneyb @ onstation . org >
2012-04-24 20:56:49 +04:00
*/
# include <linux/delay.h>
2017-10-19 23:06:22 +03:00
# include <linux/errno.h>
# include <linux/i2c.h>
2012-04-24 20:56:49 +04:00
# include <linux/interrupt.h>
2017-10-19 23:06:22 +03:00
# include <linux/kernel.h>
2012-04-24 20:56:49 +04:00
# include <linux/module.h>
2017-10-19 23:06:22 +03:00
# include <linux/mutex.h>
# include <linux/slab.h>
2012-04-25 18:54:58 +04:00
# include <linux/iio/events.h>
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2018-05-11 03:12:23 +03:00
# include <linux/platform_data/tsl2772.h>
2018-08-03 03:18:56 +03:00
# include <linux/regulator/consumer.h>
2012-04-24 20:56:49 +04:00
2018-04-21 03:41:52 +03:00
/* Cal defs */
2017-10-19 23:06:24 +03:00
# define PROX_STAT_CAL 0
# define PROX_STAT_SAMP 1
# define MAX_SAMPLES_CAL 200
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
/* TSL2772 Device ID */
2017-10-19 23:06:24 +03:00
# define TRITON_ID 0x00
# define SWORDFISH_ID 0x30
# define HALIBUT_ID 0x20
2012-04-24 20:56:49 +04:00
/* Lux calculation constants */
2018-05-11 03:12:22 +03:00
# define TSL2772_LUX_CALC_OVER_FLOW 65535
2012-04-24 20:56:49 +04:00
2018-04-21 03:41:52 +03:00
/*
* TAOS Register definitions - Note : depending on device , some of these register
* are not used and the register address is benign .
2012-04-24 20:56:49 +04:00
*/
2018-04-21 03:41:52 +03:00
2018-05-11 03:12:22 +03:00
/* Register offsets */
# define TSL2772_MAX_CONFIG_REG 16
2012-04-24 20:56:49 +04:00
/* Device Registers and Masks */
2018-05-11 03:12:22 +03:00
# define TSL2772_CNTRL 0x00
# define TSL2772_ALS_TIME 0X01
# define TSL2772_PRX_TIME 0x02
# define TSL2772_WAIT_TIME 0x03
# define TSL2772_ALS_MINTHRESHLO 0X04
# define TSL2772_ALS_MINTHRESHHI 0X05
# define TSL2772_ALS_MAXTHRESHLO 0X06
# define TSL2772_ALS_MAXTHRESHHI 0X07
# define TSL2772_PRX_MINTHRESHLO 0X08
# define TSL2772_PRX_MINTHRESHHI 0X09
# define TSL2772_PRX_MAXTHRESHLO 0X0A
# define TSL2772_PRX_MAXTHRESHHI 0X0B
# define TSL2772_PERSISTENCE 0x0C
# define TSL2772_ALS_PRX_CONFIG 0x0D
# define TSL2772_PRX_COUNT 0x0E
# define TSL2772_GAIN 0x0F
# define TSL2772_NOTUSED 0x10
# define TSL2772_REVID 0x11
# define TSL2772_CHIPID 0x12
# define TSL2772_STATUS 0x13
# define TSL2772_ALS_CHAN0LO 0x14
# define TSL2772_ALS_CHAN0HI 0x15
# define TSL2772_ALS_CHAN1LO 0x16
# define TSL2772_ALS_CHAN1HI 0x17
# define TSL2772_PRX_LO 0x18
# define TSL2772_PRX_HI 0x19
/* tsl2772 cmd reg masks */
# define TSL2772_CMD_REG 0x80
# define TSL2772_CMD_SPL_FN 0x60
# define TSL2772_CMD_REPEAT_PROTO 0x00
# define TSL2772_CMD_AUTOINC_PROTO 0x20
# define TSL2772_CMD_PROX_INT_CLR 0X05
# define TSL2772_CMD_ALS_INT_CLR 0x06
# define TSL2772_CMD_PROXALS_INT_CLR 0X07
/* tsl2772 cntrl reg masks */
# define TSL2772_CNTL_ADC_ENBL 0x02
# define TSL2772_CNTL_PWR_ON 0x01
/* tsl2772 status reg masks */
# define TSL2772_STA_ADC_VALID 0x01
# define TSL2772_STA_PRX_VALID 0x02
# define TSL2772_STA_ADC_PRX_VALID (TSL2772_STA_ADC_VALID | \
TSL2772_STA_PRX_VALID )
# define TSL2772_STA_ALS_INTR 0x10
# define TSL2772_STA_PRX_INTR 0x20
/* tsl2772 cntrl reg masks */
# define TSL2772_CNTL_REG_CLEAR 0x00
# define TSL2772_CNTL_PROX_INT_ENBL 0X20
# define TSL2772_CNTL_ALS_INT_ENBL 0X10
# define TSL2772_CNTL_WAIT_TMR_ENBL 0X08
# define TSL2772_CNTL_PROX_DET_ENBL 0X04
# define TSL2772_CNTL_PWRON 0x01
# define TSL2772_CNTL_ALSPON_ENBL 0x03
# define TSL2772_CNTL_INTALSPON_ENBL 0x13
# define TSL2772_CNTL_PROXPON_ENBL 0x0F
# define TSL2772_CNTL_INTPROXPON_ENBL 0x2F
# define TSL2772_ALS_GAIN_TRIM_MIN 250
# define TSL2772_ALS_GAIN_TRIM_MAX 4000
2018-08-03 03:18:54 +03:00
# define TSL2772_MAX_PROX_LEDS 2
2018-08-03 03:18:56 +03:00
# define TSL2772_BOOT_MIN_SLEEP_TIME 10000
# define TSL2772_BOOT_MAX_SLEEP_TIME 28000
2018-05-11 03:12:22 +03:00
/* Device family members */
2012-04-24 20:56:49 +04:00
enum {
tsl2571 ,
tsl2671 ,
tmd2671 ,
tsl2771 ,
tmd2771 ,
tsl2572 ,
tsl2672 ,
tmd2672 ,
tsl2772 ,
2018-08-03 03:18:58 +03:00
tmd2772 ,
apds9930 ,
2012-04-24 20:56:49 +04:00
} ;
enum {
2018-05-11 03:12:22 +03:00
TSL2772_CHIP_UNKNOWN = 0 ,
TSL2772_CHIP_WORKING = 1 ,
TSL2772_CHIP_SUSPENDED = 2
2012-04-24 20:56:49 +04:00
} ;
2019-08-01 10:36:19 +03:00
enum {
TSL2772_SUPPLY_VDD = 0 ,
TSL2772_SUPPLY_VDDIO = 1 ,
TSL2772_NUM_SUPPLIES = 2
} ;
2012-04-24 20:56:49 +04:00
/* Per-device data */
2018-05-11 03:12:22 +03:00
struct tsl2772_als_info {
2012-04-24 20:56:49 +04:00
u16 als_ch0 ;
u16 als_ch1 ;
u16 lux ;
} ;
2018-05-11 03:12:22 +03:00
struct tsl2772_chip_info {
2012-04-24 20:56:49 +04:00
int chan_table_elements ;
2018-05-04 05:53:11 +03:00
struct iio_chan_spec channel_with_events [ 4 ] ;
struct iio_chan_spec channel_without_events [ 4 ] ;
const struct iio_info * info ;
2012-04-24 20:56:49 +04:00
} ;
2018-08-03 03:18:54 +03:00
static const int tsl2772_led_currents [ ] [ 2 ] = {
{ 100000 , TSL2772_100_mA } ,
{ 50000 , TSL2772_50_mA } ,
{ 25000 , TSL2772_25_mA } ,
{ 13000 , TSL2772_13_mA } ,
{ 0 , 0 }
} ;
2018-05-11 03:12:22 +03:00
struct tsl2772_chip {
2012-04-24 20:56:49 +04:00
kernel_ulong_t id ;
struct mutex prox_mutex ;
struct mutex als_mutex ;
struct i2c_client * client ;
2019-08-01 10:36:19 +03:00
struct regulator_bulk_data supplies [ TSL2772_NUM_SUPPLIES ] ;
2012-04-24 20:56:49 +04:00
u16 prox_data ;
2018-05-11 03:12:22 +03:00
struct tsl2772_als_info als_cur_info ;
struct tsl2772_settings settings ;
struct tsl2772_platform_data * pdata ;
2018-05-04 05:53:14 +03:00
int als_gain_time_scale ;
2012-04-24 20:56:49 +04:00
int als_saturation ;
2018-05-11 03:12:22 +03:00
int tsl2772_chip_status ;
u8 tsl2772_config [ TSL2772_MAX_CONFIG_REG ] ;
const struct tsl2772_chip_info * chip_info ;
2012-04-24 20:56:49 +04:00
const struct iio_info * info ;
s64 event_timestamp ;
2016-03-12 11:19:21 +03:00
/*
* This structure is intentionally large to accommodate
* updates via sysfs .
* Sized to 9 = max 8 segments + 1 termination segment
*/
2018-05-11 03:12:22 +03:00
struct tsl2772_lux tsl2772_device_lux [ TSL2772_MAX_LUX_TABLE_SIZE ] ;
2012-04-24 20:56:49 +04:00
} ;
2018-05-04 05:53:14 +03:00
/*
* 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 .
*/
2018-05-11 03:12:22 +03:00
static const struct tsl2772_lux tsl2x71_lux_table [ TSL2772_DEF_LUX_TABLE_SZ ] = {
2018-05-04 05:53:14 +03:00
{ 53000 , 106000 } ,
{ 31800 , 53000 } ,
{ 0 , 0 } ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static const struct tsl2772_lux tmd2x71_lux_table [ TSL2772_DEF_LUX_TABLE_SZ ] = {
2018-05-04 05:53:14 +03:00
{ 24000 , 48000 } ,
{ 14400 , 24000 } ,
{ 0 , 0 } ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static const struct tsl2772_lux tsl2x72_lux_table [ TSL2772_DEF_LUX_TABLE_SZ ] = {
2018-05-04 05:53:14 +03:00
{ 60000 , 112200 } ,
{ 37800 , 60000 } ,
{ 0 , 0 } ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static const struct tsl2772_lux tmd2x72_lux_table [ TSL2772_DEF_LUX_TABLE_SZ ] = {
2018-05-04 05:53:14 +03:00
{ 20000 , 35000 } ,
{ 12600 , 20000 } ,
{ 0 , 0 } ,
2012-04-24 20:56:49 +04:00
} ;
2018-08-03 03:18:58 +03:00
static const struct tsl2772_lux apds9930_lux_table [ TSL2772_DEF_LUX_TABLE_SZ ] = {
{ 52000 , 96824 } ,
{ 38792 , 67132 } ,
{ 0 , 0 } ,
} ;
2018-05-11 03:12:22 +03:00
static const struct tsl2772_lux * tsl2772_default_lux_table_group [ ] = {
2018-05-11 03:12:15 +03:00
[ tsl2571 ] = tsl2x71_lux_table ,
[ tsl2671 ] = tsl2x71_lux_table ,
[ tmd2671 ] = tmd2x71_lux_table ,
[ tsl2771 ] = tsl2x71_lux_table ,
[ tmd2771 ] = tmd2x71_lux_table ,
[ tsl2572 ] = tsl2x72_lux_table ,
[ tsl2672 ] = tsl2x72_lux_table ,
[ tmd2672 ] = tmd2x72_lux_table ,
[ tsl2772 ] = tsl2x72_lux_table ,
[ tmd2772 ] = tmd2x72_lux_table ,
2018-08-03 03:18:58 +03:00
[ apds9930 ] = apds9930_lux_table ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static const struct tsl2772_settings tsl2772_default_settings = {
2018-05-11 03:12:19 +03:00
. als_time = 255 , /* 2.72 / 2.73 ms */
2012-04-24 20:56:49 +04:00
. als_gain = 0 ,
2018-05-11 03:12:19 +03:00
. prox_time = 255 , /* 2.72 / 2.73 ms */
2018-03-04 04:49:42 +03:00
. prox_gain = 0 ,
2018-04-21 03:41:51 +03:00
. wait_time = 255 ,
2018-04-21 03:41:53 +03:00
. als_prox_config = 0 ,
2012-04-24 20:56:49 +04:00
. als_gain_trim = 1000 ,
. als_cal_target = 150 ,
2018-03-21 13:29:08 +03:00
. als_persistence = 1 ,
2018-03-21 13:29:06 +03:00
. als_interrupt_en = false ,
2012-04-24 20:56:49 +04:00
. als_thresh_low = 200 ,
. als_thresh_high = 256 ,
2018-03-21 13:29:08 +03:00
. prox_persistence = 1 ,
2018-03-21 13:29:06 +03:00
. prox_interrupt_en = false ,
2012-04-24 20:56:49 +04:00
. prox_thres_low = 0 ,
. prox_thres_high = 512 ,
. prox_max_samples_cal = 30 ,
2018-03-04 04:49:42 +03:00
. prox_pulse_count = 8 ,
2018-05-11 03:12:22 +03:00
. prox_diode = TSL2772_DIODE1 ,
. prox_power = TSL2772_100_mA
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static const s16 tsl2772_als_gain [ ] = {
2012-04-24 20:56:49 +04:00
1 ,
8 ,
16 ,
120
} ;
2018-05-11 03:12:22 +03:00
static const s16 tsl2772_prox_gain [ ] = {
2012-04-24 20:56:49 +04:00
1 ,
2 ,
4 ,
8
} ;
2018-05-11 03:12:22 +03:00
static const int tsl2772_int_time_avail [ ] [ 6 ] = {
2018-05-11 03:12:19 +03:00
[ tsl2571 ] = { 0 , 2720 , 0 , 2720 , 0 , 696000 } ,
[ tsl2671 ] = { 0 , 2720 , 0 , 2720 , 0 , 696000 } ,
[ tmd2671 ] = { 0 , 2720 , 0 , 2720 , 0 , 696000 } ,
[ tsl2771 ] = { 0 , 2720 , 0 , 2720 , 0 , 696000 } ,
[ tmd2771 ] = { 0 , 2720 , 0 , 2720 , 0 , 696000 } ,
[ tsl2572 ] = { 0 , 2730 , 0 , 2730 , 0 , 699000 } ,
[ tsl2672 ] = { 0 , 2730 , 0 , 2730 , 0 , 699000 } ,
[ tmd2672 ] = { 0 , 2730 , 0 , 2730 , 0 , 699000 } ,
[ tsl2772 ] = { 0 , 2730 , 0 , 2730 , 0 , 699000 } ,
[ tmd2772 ] = { 0 , 2730 , 0 , 2730 , 0 , 699000 } ,
2018-08-03 03:18:58 +03:00
[ apds9930 ] = { 0 , 2730 , 0 , 2730 , 0 , 699000 } ,
2018-05-11 03:12:19 +03:00
} ;
2018-05-11 03:12:22 +03:00
static int tsl2772_int_calibscale_avail [ ] = { 1 , 8 , 16 , 120 } ;
2018-05-11 03:12:19 +03:00
2018-05-11 03:12:22 +03:00
static int tsl2772_prox_calibscale_avail [ ] = { 1 , 2 , 4 , 8 } ;
2018-05-11 03:12:19 +03:00
2012-04-24 20:56:49 +04:00
/* Channel variations */
enum {
ALS ,
PRX ,
ALSPRX ,
PRX2 ,
ALSPRX2 ,
} ;
2012-04-25 02:59:10 +04:00
static const u8 device_channel_config [ ] = {
2018-05-04 05:53:16 +03:00
[ tsl2571 ] = ALS ,
[ tsl2671 ] = PRX ,
[ tmd2671 ] = PRX ,
[ tsl2771 ] = ALSPRX ,
[ tmd2771 ] = ALSPRX ,
[ tsl2572 ] = ALS ,
[ tsl2672 ] = PRX2 ,
[ tmd2672 ] = PRX2 ,
[ tsl2772 ] = ALSPRX2 ,
2018-08-03 03:18:58 +03:00
[ tmd2772 ] = ALSPRX2 ,
[ apds9930 ] = ALSPRX2 ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static int tsl2772_read_status ( struct tsl2772_chip * chip )
2018-03-04 04:49:33 +03:00
{
int ret ;
ret = i2c_smbus_read_byte_data ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_STATUS ) ;
2018-03-04 04:49:33 +03:00
if ( ret < 0 )
dev_err ( & chip - > client - > dev ,
" %s: failed to read STATUS register: %d \n " , __func__ ,
ret ) ;
return ret ;
}
2018-05-11 03:12:22 +03:00
static int tsl2772_write_control_reg ( struct tsl2772_chip * chip , u8 data )
2018-03-04 04:49:34 +03:00
{
int ret ;
ret = i2c_smbus_write_byte_data ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CNTRL , data ) ;
2018-03-04 04:49:34 +03:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: failed to write to control register %x: %d \n " ,
__func__ , data , ret ) ;
}
return ret ;
}
2018-05-11 03:12:22 +03:00
static int tsl2772_read_autoinc_regs ( struct tsl2772_chip * chip , int lower_reg ,
2018-03-24 23:05:52 +03:00
int upper_reg )
{
u8 buf [ 2 ] ;
int ret ;
ret = i2c_smbus_write_byte ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CMD_AUTOINC_PROTO |
2018-03-24 23:05:52 +03:00
lower_reg ) ;
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: failed to enable auto increment protocol: %d \n " ,
__func__ , ret ) ;
return ret ;
}
ret = i2c_smbus_read_byte_data ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | lower_reg ) ;
2018-03-24 23:05:52 +03:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: failed to read from register %x: %d \n " , __func__ ,
lower_reg , ret ) ;
return ret ;
}
buf [ 0 ] = ret ;
ret = i2c_smbus_read_byte_data ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | upper_reg ) ;
2018-03-24 23:05:52 +03:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: failed to read from register %x: %d \n " , __func__ ,
upper_reg , ret ) ;
return ret ;
}
buf [ 1 ] = ret ;
ret = i2c_smbus_write_byte ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CMD_REPEAT_PROTO |
2018-03-24 23:05:52 +03:00
lower_reg ) ;
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: failed to enable repeated byte protocol: %d \n " ,
__func__ , ret ) ;
return ret ;
}
return le16_to_cpup ( ( const __le16 * ) & buf [ 0 ] ) ;
}
2012-04-24 20:56:49 +04:00
/**
2018-05-11 03:12:22 +03:00
* tsl2772_get_lux ( ) - Reads and calculates current lux value .
2012-04-24 20:56:49 +04:00
* @ indio_dev : pointer to IIO device
*
* The raw ch0 and ch1 values of the ambient light sensed in the last
2018-05-04 05:53:14 +03:00
* 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 .
2012-04-24 20:56:49 +04:00
*/
2018-05-11 03:12:22 +03:00
static int tsl2772_get_lux ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
struct tsl2772_lux * p ;
2018-05-04 05:53:14 +03:00
int max_lux , ret ;
bool overflow ;
2012-04-24 20:56:49 +04:00
2018-03-04 04:49:35 +03:00
mutex_lock ( & chip - > als_mutex ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
if ( chip - > tsl2772_chip_status ! = TSL2772_CHIP_WORKING ) {
2012-04-24 20:56:49 +04:00
dev_err ( & chip - > client - > dev , " %s: device is not enabled \n " ,
2016-03-12 11:19:20 +03:00
__func__ ) ;
2014-03-16 18:56:27 +04:00
ret = - EBUSY ;
2012-04-24 20:56:49 +04:00
goto out_unlock ;
}
2018-05-11 03:12:22 +03:00
ret = tsl2772_read_status ( chip ) ;
2018-03-04 04:49:33 +03:00
if ( ret < 0 )
2012-04-24 20:56:49 +04:00
goto out_unlock ;
2018-03-04 04:49:33 +03:00
2018-05-11 03:12:22 +03:00
if ( ! ( ret & TSL2772_STA_ADC_VALID ) ) {
2012-04-24 20:56:49 +04:00
dev_err ( & chip - > client - > dev ,
" %s: data not valid yet \n " , __func__ ) ;
ret = chip - > als_cur_info . lux ; /* return LAST VALUE */
goto out_unlock ;
}
2018-05-11 03:12:22 +03:00
ret = tsl2772_read_autoinc_regs ( chip , TSL2772_ALS_CHAN0LO ,
TSL2772_ALS_CHAN0HI ) ;
2018-03-24 23:05:52 +03:00
if ( ret < 0 )
goto out_unlock ;
chip - > als_cur_info . als_ch0 = ret ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_read_autoinc_regs ( chip , TSL2772_ALS_CHAN1LO ,
TSL2772_ALS_CHAN1HI ) ;
2018-03-24 23:05:52 +03:00
if ( ret < 0 )
goto out_unlock ;
chip - > als_cur_info . als_ch1 = ret ;
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:14 +03:00
if ( chip - > als_cur_info . als_ch0 > = chip - > als_saturation ) {
2018-05-11 03:12:22 +03:00
max_lux = TSL2772_LUX_CALC_OVER_FLOW ;
2018-05-04 05:53:14 +03:00
goto update_struct_with_max_lux ;
2012-04-24 20:56:49 +04:00
}
2018-03-21 13:29:10 +03:00
if ( ! chip - > als_cur_info . als_ch0 ) {
2012-04-24 20:56:49 +04:00
/* have no data, so return LAST VALUE */
ret = chip - > als_cur_info . lux ;
goto out_unlock ;
}
2018-03-21 13:29:10 +03:00
2018-05-04 05:53:14 +03:00
max_lux = 0 ;
overflow = false ;
2018-05-11 03:12:22 +03:00
for ( p = ( struct tsl2772_lux * ) chip - > tsl2772_device_lux ; p - > ch0 ! = 0 ;
2018-05-04 05:53:14 +03:00
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 ;
2018-05-11 03:12:22 +03:00
if ( lux > TSL2772_LUX_CALC_OVER_FLOW ) {
2018-05-04 05:53:14 +03:00
overflow = true ;
continue ;
}
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:14 +03:00
max_lux = max ( max_lux , lux ) ;
}
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:14 +03:00
if ( overflow & & max_lux = = 0 )
2018-05-11 03:12:22 +03:00
max_lux = TSL2772_LUX_CALC_OVER_FLOW ;
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:14 +03:00
update_struct_with_max_lux :
chip - > als_cur_info . lux = max_lux ;
ret = max_lux ;
2012-04-24 20:56:49 +04:00
out_unlock :
mutex_unlock ( & chip - > als_mutex ) ;
return ret ;
}
/**
2018-05-11 03:12:22 +03:00
* tsl2772_get_prox ( ) - Reads proximity data registers and updates
2012-04-24 20:56:49 +04:00
* chip - > prox_data .
*
* @ indio_dev : pointer to IIO device
*/
2018-05-11 03:12:22 +03:00
static int tsl2772_get_prox ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2018-03-24 23:05:52 +03:00
int ret ;
2012-04-24 20:56:49 +04:00
2018-03-04 04:49:35 +03:00
mutex_lock ( & chip - > prox_mutex ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_read_status ( chip ) ;
2018-03-04 04:49:33 +03:00
if ( ret < 0 )
2012-04-24 20:56:49 +04:00
goto prox_poll_err ;
switch ( chip - > id ) {
case tsl2571 :
case tsl2671 :
case tmd2671 :
case tsl2771 :
case tmd2771 :
2018-05-11 03:12:22 +03:00
if ( ! ( ret & TSL2772_STA_ADC_VALID ) ) {
2018-03-04 04:49:36 +03:00
ret = - EINVAL ;
2012-04-24 20:56:49 +04:00
goto prox_poll_err ;
2018-03-04 04:49:36 +03:00
}
2017-10-19 23:06:30 +03:00
break ;
2012-04-24 20:56:49 +04:00
case tsl2572 :
case tsl2672 :
case tmd2672 :
case tsl2772 :
case tmd2772 :
2018-08-03 03:18:58 +03:00
case apds9930 :
2018-05-11 03:12:22 +03:00
if ( ! ( ret & TSL2772_STA_PRX_VALID ) ) {
2018-03-04 04:49:36 +03:00
ret = - EINVAL ;
2012-04-24 20:56:49 +04:00
goto prox_poll_err ;
2018-03-04 04:49:36 +03:00
}
2017-10-19 23:06:30 +03:00
break ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
ret = tsl2772_read_autoinc_regs ( chip , TSL2772_PRX_LO , TSL2772_PRX_HI ) ;
2018-03-24 23:05:52 +03:00
if ( ret < 0 )
goto prox_poll_err ;
chip - > prox_data = ret ;
2012-04-24 20:56:49 +04:00
prox_poll_err :
mutex_unlock ( & chip - > prox_mutex ) ;
2018-03-04 04:49:36 +03:00
return ret ;
2012-04-24 20:56:49 +04:00
}
2018-08-03 03:18:54 +03:00
static int tsl2772_read_prox_led_current ( struct tsl2772_chip * chip )
{
struct device_node * of_node = chip - > client - > dev . of_node ;
int ret , tmp , i ;
ret = of_property_read_u32 ( of_node , " led-max-microamp " , & tmp ) ;
if ( ret < 0 )
return ret ;
for ( i = 0 ; tsl2772_led_currents [ i ] [ 0 ] ! = 0 ; i + + ) {
if ( tmp = = tsl2772_led_currents [ i ] [ 0 ] ) {
chip - > settings . prox_power = tsl2772_led_currents [ i ] [ 1 ] ;
return 0 ;
}
}
dev_err ( & chip - > client - > dev , " Invalid value %d for led-max-microamp \n " ,
tmp ) ;
return - EINVAL ;
}
static int tsl2772_read_prox_diodes ( struct tsl2772_chip * chip )
{
struct device_node * of_node = chip - > client - > dev . of_node ;
int i , ret , num_leds , prox_diode_mask ;
u32 leds [ TSL2772_MAX_PROX_LEDS ] ;
ret = of_property_count_u32_elems ( of_node , " amstaos,proximity-diodes " ) ;
if ( ret < 0 )
return ret ;
num_leds = ret ;
if ( num_leds > TSL2772_MAX_PROX_LEDS )
num_leds = TSL2772_MAX_PROX_LEDS ;
ret = of_property_read_u32_array ( of_node , " amstaos,proximity-diodes " ,
leds , num_leds ) ;
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" Invalid value for amstaos,proximity-diodes: %d. \n " ,
ret ) ;
return ret ;
}
prox_diode_mask = 0 ;
for ( i = 0 ; i < num_leds ; i + + ) {
if ( leds [ i ] = = 0 )
prox_diode_mask | = TSL2772_DIODE0 ;
else if ( leds [ i ] = = 1 )
prox_diode_mask | = TSL2772_DIODE1 ;
else {
dev_err ( & chip - > client - > dev ,
" Invalid value %d in amstaos,proximity-diodes. \n " ,
leds [ i ] ) ;
return - EINVAL ;
}
}
return 0 ;
}
static void tsl2772_parse_dt ( struct tsl2772_chip * chip )
{
tsl2772_read_prox_led_current ( chip ) ;
tsl2772_read_prox_diodes ( chip ) ;
}
2012-04-24 20:56:49 +04:00
/**
2018-05-11 03:12:22 +03:00
* tsl2772_defaults ( ) - Populates the device nominal operating parameters
2012-04-24 20:56:49 +04:00
* with those provided by a ' platform ' data struct or
* with prefined defaults .
*
* @ chip : pointer to device structure .
*/
2018-05-11 03:12:22 +03:00
static void tsl2772_defaults ( struct tsl2772_chip * chip )
2012-04-24 20:56:49 +04:00
{
/* If Operational settings defined elsewhere.. */
2013-09-05 13:29:00 +04:00
if ( chip - > pdata & & chip - > pdata - > platform_default_settings )
2017-09-30 04:09:19 +03:00
memcpy ( & chip - > settings , chip - > pdata - > platform_default_settings ,
2018-05-11 03:12:22 +03:00
sizeof ( tsl2772_default_settings ) ) ;
2012-04-24 20:56:49 +04:00
else
2018-05-11 03:12:22 +03:00
memcpy ( & chip - > settings , & tsl2772_default_settings ,
sizeof ( tsl2772_default_settings ) ) ;
2012-04-24 20:56:49 +04:00
/* Load up the proper lux table. */
2018-05-04 05:53:14 +03:00
if ( chip - > pdata & & chip - > pdata - > platform_lux_table [ 0 ] . ch0 ! = 0 )
2018-05-11 03:12:22 +03:00
memcpy ( chip - > tsl2772_device_lux ,
2016-03-12 11:19:20 +03:00
chip - > pdata - > platform_lux_table ,
sizeof ( chip - > pdata - > platform_lux_table ) ) ;
2012-04-24 20:56:49 +04:00
else
2018-05-11 03:12:22 +03:00
memcpy ( chip - > tsl2772_device_lux ,
tsl2772_default_lux_table_group [ chip - > id ] ,
TSL2772_DEFAULT_TABLE_BYTES ) ;
2018-08-03 03:18:54 +03:00
tsl2772_parse_dt ( chip ) ;
2012-04-24 20:56:49 +04:00
}
/**
2018-05-11 03:12:22 +03:00
* tsl2772_als_calibrate ( ) - Obtain single reading and calculate
2012-04-24 20:56:49 +04:00
* the als_gain_trim .
*
* @ indio_dev : pointer to IIO device
*/
2018-05-11 03:12:22 +03:00
static int tsl2772_als_calibrate ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2017-09-30 04:09:19 +03:00
int ret , lux_val ;
2012-04-24 20:56:49 +04:00
2017-07-07 01:56:22 +03:00
ret = i2c_smbus_read_byte_data ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CNTRL ) ;
2012-04-24 20:56:49 +04:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
2017-07-07 01:56:22 +03:00
" %s: failed to read from the CNTRL register \n " ,
__func__ ) ;
2012-04-24 20:56:49 +04:00
return ret ;
}
2018-05-11 03:12:22 +03:00
if ( ( ret & ( TSL2772_CNTL_ADC_ENBL | TSL2772_CNTL_PWR_ON ) )
! = ( TSL2772_CNTL_ADC_ENBL | TSL2772_CNTL_PWR_ON ) ) {
2012-04-24 20:56:49 +04:00
dev_err ( & chip - > client - > dev ,
2017-07-07 01:56:22 +03:00
" %s: Device is not powered on and/or ADC is not enabled \n " ,
__func__ ) ;
return - EINVAL ;
2018-05-11 03:12:22 +03:00
} else if ( ( ret & TSL2772_STA_ADC_VALID ) ! = TSL2772_STA_ADC_VALID ) {
2012-04-24 20:56:49 +04:00
dev_err ( & chip - > client - > dev ,
2017-07-07 01:56:22 +03:00
" %s: The two ADC channels have not completed an integration cycle \n " ,
__func__ ) ;
2012-04-24 20:56:49 +04:00
return - ENODATA ;
}
2018-05-11 03:12:22 +03:00
lux_val = tsl2772_get_lux ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
if ( lux_val < 0 ) {
dev_err ( & chip - > client - > dev ,
2016-03-12 11:19:20 +03:00
" %s: failed to get lux \n " , __func__ ) ;
2012-04-24 20:56:49 +04:00
return lux_val ;
}
2018-05-30 21:19:36 +03:00
if ( lux_val = = 0 )
return - ERANGE ;
2012-04-24 20:56:49 +04:00
2017-09-30 04:09:19 +03:00
ret = ( chip - > settings . als_cal_target * chip - > settings . als_gain_trim ) /
lux_val ;
2018-05-11 03:12:22 +03:00
if ( ret < TSL2772_ALS_GAIN_TRIM_MIN | | ret > TSL2772_ALS_GAIN_TRIM_MAX )
2012-04-24 20:56:49 +04:00
return - ERANGE ;
2017-09-30 04:09:19 +03:00
chip - > settings . als_gain_trim = ret ;
2012-04-24 20:56:49 +04:00
2017-09-30 04:09:19 +03:00
return ret ;
2012-04-24 20:56:49 +04:00
}
2018-08-03 03:18:56 +03:00
static void tsl2772_disable_regulators_action ( void * _data )
{
struct tsl2772_chip * chip = _data ;
2019-08-01 10:36:19 +03:00
regulator_bulk_disable ( ARRAY_SIZE ( chip - > supplies ) , chip - > supplies ) ;
2018-08-03 03:18:56 +03:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_chip_on ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2018-05-04 05:53:14 +03:00
int ret , i , als_count , als_time_us ;
2018-03-21 13:29:11 +03:00
u8 * dev_reg , reg_val ;
2012-04-24 20:56:49 +04:00
/* Non calculated parameters */
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_ALS_TIME ] = chip - > settings . als_time ;
chip - > tsl2772_config [ TSL2772_PRX_TIME ] = chip - > settings . prox_time ;
chip - > tsl2772_config [ TSL2772_WAIT_TIME ] = chip - > settings . wait_time ;
chip - > tsl2772_config [ TSL2772_ALS_PRX_CONFIG ] =
2018-04-21 03:41:53 +03:00
chip - > settings . als_prox_config ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_ALS_MINTHRESHLO ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . als_thresh_low ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_ALS_MINTHRESHHI ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . als_thresh_low > > 8 ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_ALS_MAXTHRESHLO ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . als_thresh_high ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_ALS_MAXTHRESHHI ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . als_thresh_high > > 8 ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_PERSISTENCE ] =
2018-03-21 13:29:08 +03:00
( chip - > settings . prox_persistence & 0xFF ) < < 4 |
( chip - > settings . als_persistence & 0xFF ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_PRX_COUNT ] =
2017-09-30 04:09:19 +03:00
chip - > settings . prox_pulse_count ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_PRX_MINTHRESHLO ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . prox_thres_low ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_PRX_MINTHRESHHI ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . prox_thres_low > > 8 ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_PRX_MAXTHRESHLO ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . prox_thres_high ) & 0xFF ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_config [ TSL2772_PRX_MAXTHRESHHI ] =
2017-09-30 04:09:19 +03:00
( chip - > settings . prox_thres_high > > 8 ) & 0xFF ;
2012-04-24 20:56:49 +04:00
/* and make sure we're not already on */
2018-05-11 03:12:22 +03:00
if ( chip - > tsl2772_chip_status = = TSL2772_CHIP_WORKING ) {
2012-04-24 20:56:49 +04:00
/* if forcing a register update - turn off, then on */
dev_info ( & chip - > client - > dev , " device is already enabled \n " ) ;
return - EINVAL ;
}
2018-05-11 03:12:22 +03:00
/* Set the gain based on tsl2772_settings struct */
chip - > tsl2772_config [ TSL2772_GAIN ] =
2018-03-04 04:49:42 +03:00
( chip - > settings . als_gain & 0xFF ) |
( ( chip - > settings . prox_gain & 0xFF ) < < 2 ) |
( chip - > settings . prox_diode < < 4 ) |
( chip - > settings . prox_power < < 6 ) ;
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:14 +03:00
/* set chip time scaling and saturation */
als_count = 256 - chip - > settings . als_time ;
2018-05-11 03:12:22 +03:00
als_time_us = als_count * tsl2772_int_time_avail [ chip - > id ] [ 3 ] ;
2018-05-04 05:53:14 +03:00
chip - > als_saturation = als_count * 768 ; /* 75% of full scale */
chip - > als_gain_time_scale = als_time_us *
2018-05-11 03:12:22 +03:00
tsl2772_als_gain [ chip - > settings . als_gain ] ;
2012-04-24 20:56:49 +04:00
2016-03-12 11:19:21 +03:00
/*
2018-05-11 03:12:22 +03:00
* TSL2772 Specific power - on / adc enable sequence
2016-03-12 11:19:21 +03:00
* Power on the device 1 st .
*/
2018-05-11 03:12:22 +03:00
ret = tsl2772_write_control_reg ( chip , TSL2772_CNTL_PWR_ON ) ;
2018-03-04 04:49:34 +03:00
if ( ret < 0 )
2012-04-24 20:56:49 +04:00
return ret ;
2016-03-12 11:19:21 +03:00
/*
* Use the following shadow copy for our delay before enabling ADC .
* Write all the registers .
*/
2018-05-11 03:12:22 +03:00
for ( i = 0 , dev_reg = chip - > tsl2772_config ;
i < TSL2772_MAX_CONFIG_REG ; i + + ) {
int reg = TSL2772_CMD_REG + i ;
2018-03-21 13:29:07 +03:00
ret = i2c_smbus_write_byte_data ( chip - > client , reg ,
2016-03-12 11:19:20 +03:00
* dev_reg + + ) ;
2012-04-24 20:56:49 +04:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
2018-03-21 13:29:07 +03:00
" %s: failed to write to register %x: %d \n " ,
__func__ , reg , ret ) ;
2012-04-24 20:56:49 +04:00
return ret ;
}
}
2017-07-07 01:56:24 +03:00
/* Power-on settling time */
usleep_range ( 3000 , 3500 ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
reg_val = TSL2772_CNTL_PWR_ON | TSL2772_CNTL_ADC_ENBL |
TSL2772_CNTL_PROX_DET_ENBL ;
2018-03-21 13:29:06 +03:00
if ( chip - > settings . als_interrupt_en )
2018-05-11 03:12:22 +03:00
reg_val | = TSL2772_CNTL_ALS_INT_ENBL ;
2018-03-21 13:29:06 +03:00
if ( chip - > settings . prox_interrupt_en )
2018-05-11 03:12:22 +03:00
reg_val | = TSL2772_CNTL_PROX_INT_ENBL ;
2018-03-21 13:29:06 +03:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_write_control_reg ( chip , reg_val ) ;
2018-03-04 04:49:34 +03:00
if ( ret < 0 )
2012-04-24 20:56:49 +04:00
return ret ;
2018-04-21 03:41:44 +03:00
ret = i2c_smbus_write_byte ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CMD_SPL_FN |
TSL2772_CMD_PROXALS_INT_CLR ) ;
2018-04-21 03:41:44 +03:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: failed to clear interrupt status: %d \n " ,
__func__ , ret ) ;
2018-03-21 13:29:06 +03:00
return ret ;
2018-04-21 03:41:44 +03:00
}
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
chip - > tsl2772_chip_status = TSL2772_CHIP_WORKING ;
2012-04-24 20:56:49 +04:00
return ret ;
}
2018-05-11 03:12:22 +03:00
static int tsl2772_chip_off ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
/* turn device off */
2018-05-11 03:12:22 +03:00
chip - > tsl2772_chip_status = TSL2772_CHIP_SUSPENDED ;
return tsl2772_write_control_reg ( chip , 0x00 ) ;
2012-04-24 20:56:49 +04:00
}
2019-08-01 10:36:05 +03:00
static void tsl2772_chip_off_action ( void * data )
{
struct iio_dev * indio_dev = data ;
tsl2772_chip_off ( indio_dev ) ;
}
2012-04-24 20:56:49 +04:00
/**
2018-05-11 03:12:22 +03:00
* tsl2772_invoke_change - power cycle the device to implement the user
2018-04-21 03:41:52 +03:00
* parameters
2012-04-24 20:56:49 +04:00
* @ indio_dev : pointer to IIO device
*
2018-04-21 03:41:52 +03:00
* Obtain and lock both ALS and PROX resources , determine and save device state
* ( On / Off ) , cycle device to implement updated parameter , put device back into
* proper state , and unlock resource .
2012-04-24 20:56:49 +04:00
*/
2018-05-11 03:12:22 +03:00
static int tsl2772_invoke_change ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
int device_status = chip - > tsl2772_chip_status ;
2017-07-07 01:56:26 +03:00
int ret ;
2012-04-24 20:56:49 +04:00
mutex_lock ( & chip - > als_mutex ) ;
mutex_lock ( & chip - > prox_mutex ) ;
2018-05-11 03:12:22 +03:00
if ( device_status = = TSL2772_CHIP_WORKING ) {
ret = tsl2772_chip_off ( indio_dev ) ;
2017-07-07 01:56:26 +03:00
if ( ret < 0 )
goto unlock ;
}
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_chip_on ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
2017-07-07 01:56:26 +03:00
unlock :
2012-04-24 20:56:49 +04:00
mutex_unlock ( & chip - > prox_mutex ) ;
mutex_unlock ( & chip - > als_mutex ) ;
2017-07-07 01:56:26 +03:00
return ret ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_prox_cal ( struct iio_dev * indio_dev )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2018-03-21 13:29:05 +03:00
int prox_history [ MAX_SAMPLES_CAL + 1 ] ;
int i , ret , mean , max , sample_sum ;
2012-04-24 20:56:49 +04:00
2018-03-21 13:29:05 +03:00
if ( chip - > settings . prox_max_samples_cal < 1 | |
chip - > settings . prox_max_samples_cal > MAX_SAMPLES_CAL )
return - EINVAL ;
2012-04-24 20:56:49 +04:00
2017-09-30 04:09:19 +03:00
for ( i = 0 ; i < chip - > settings . prox_max_samples_cal ; i + + ) {
2017-07-07 01:56:24 +03:00
usleep_range ( 15000 , 17500 ) ;
2018-05-11 03:12:22 +03:00
ret = tsl2772_get_prox ( indio_dev ) ;
2018-03-04 04:49:38 +03:00
if ( ret < 0 )
return ret ;
2018-03-21 13:29:05 +03:00
2012-04-24 20:56:49 +04:00
prox_history [ i ] = chip - > prox_data ;
}
2018-03-21 13:29:05 +03:00
sample_sum = 0 ;
max = INT_MIN ;
for ( i = 0 ; i < chip - > settings . prox_max_samples_cal ; i + + ) {
sample_sum + = prox_history [ i ] ;
max = max ( max , prox_history [ i ] ) ;
2018-03-04 04:49:38 +03:00
}
2018-03-21 13:29:05 +03:00
mean = sample_sum / chip - > settings . prox_max_samples_cal ;
chip - > settings . prox_thres_high = ( max < < 1 ) - mean ;
2018-03-04 04:49:38 +03:00
2018-05-11 03:12:22 +03:00
return tsl2772_invoke_change ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_read_avail ( struct iio_dev * indio_dev ,
2018-05-11 03:12:19 +03:00
struct iio_chan_spec const * chan ,
const int * * vals , int * type , int * length ,
long mask )
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:19 +03:00
switch ( mask ) {
case IIO_CHAN_INFO_CALIBSCALE :
if ( chan - > type = = IIO_INTENSITY ) {
2018-05-11 03:12:22 +03:00
* length = ARRAY_SIZE ( tsl2772_int_calibscale_avail ) ;
* vals = tsl2772_int_calibscale_avail ;
2018-05-11 03:12:19 +03:00
} else {
2018-05-11 03:12:22 +03:00
* length = ARRAY_SIZE ( tsl2772_prox_calibscale_avail ) ;
* vals = tsl2772_prox_calibscale_avail ;
2018-05-11 03:12:19 +03:00
}
* type = IIO_VAL_INT ;
return IIO_AVAIL_LIST ;
case IIO_CHAN_INFO_INT_TIME :
2018-05-11 03:12:22 +03:00
* length = ARRAY_SIZE ( tsl2772_int_time_avail [ chip - > id ] ) ;
* vals = tsl2772_int_time_avail [ chip - > id ] ;
2018-05-11 03:12:19 +03:00
* type = IIO_VAL_INT_PLUS_MICRO ;
return IIO_AVAIL_RANGE ;
}
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:19 +03:00
return - EINVAL ;
}
2012-04-24 20:56:49 +04:00
2017-05-19 12:37:12 +03:00
static ssize_t in_illuminance0_target_input_show ( struct device * dev ,
2017-10-19 23:06:28 +03:00
struct device_attribute * attr ,
char * buf )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( dev_to_iio_dev ( dev ) ) ;
2012-04-24 20:56:49 +04:00
2020-03-16 15:49:41 +03:00
return scnprintf ( buf , PAGE_SIZE , " %d \n " , chip - > settings . als_cal_target ) ;
2012-04-24 20:56:49 +04:00
}
2017-05-19 12:37:12 +03:00
static ssize_t in_illuminance0_target_input_store ( struct device * dev ,
2017-10-19 23:06:28 +03:00
struct device_attribute * attr ,
const char * buf , size_t len )
2012-04-24 20:56:49 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2018-05-04 05:53:10 +03:00
u16 value ;
2017-07-07 01:56:26 +03:00
int ret ;
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:10 +03:00
if ( kstrtou16 ( buf , 0 , & value ) )
2012-04-24 20:56:49 +04:00
return - EINVAL ;
2018-05-04 05:53:10 +03:00
chip - > settings . als_cal_target = value ;
2018-05-11 03:12:22 +03:00
ret = tsl2772_invoke_change ( indio_dev ) ;
2017-07-07 01:56:26 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
return len ;
}
2017-05-19 12:37:12 +03:00
static ssize_t in_illuminance0_calibrate_store ( struct device * dev ,
2017-10-19 23:06:28 +03:00
struct device_attribute * attr ,
const char * buf , size_t len )
2012-04-24 20:56:49 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-04-24 20:56:49 +04:00
bool value ;
2017-07-07 01:56:26 +03:00
int ret ;
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:10 +03:00
if ( kstrtobool ( buf , & value ) | | ! value )
2012-04-24 20:56:49 +04:00
return - EINVAL ;
2018-05-11 03:12:22 +03:00
ret = tsl2772_als_calibrate ( indio_dev ) ;
2018-05-04 05:53:10 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_invoke_change ( indio_dev ) ;
2017-07-07 01:56:26 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
return len ;
}
2017-05-19 12:37:12 +03:00
static ssize_t in_illuminance0_lux_table_show ( struct device * dev ,
2017-10-19 23:06:28 +03:00
struct device_attribute * attr ,
char * buf )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( dev_to_iio_dev ( dev ) ) ;
2012-04-24 20:56:49 +04:00
int i = 0 ;
int offset = 0 ;
2018-05-11 03:12:22 +03:00
while ( i < TSL2772_MAX_LUX_TABLE_SIZE ) {
2020-03-16 15:49:41 +03:00
offset + = scnprintf ( buf + offset , PAGE_SIZE - offset , " %u,%u, " ,
2018-05-11 03:12:22 +03:00
chip - > tsl2772_device_lux [ i ] . ch0 ,
chip - > tsl2772_device_lux [ i ] . ch1 ) ;
if ( chip - > tsl2772_device_lux [ i ] . ch0 = = 0 ) {
2016-03-12 11:19:21 +03:00
/*
* We just printed the first " 0 " entry .
* Now get rid of the extra " , " and break .
*/
2012-04-24 20:56:49 +04:00
offset - - ;
break ;
}
i + + ;
}
2020-03-16 15:49:41 +03:00
offset + = scnprintf ( buf + offset , PAGE_SIZE - offset , " \n " ) ;
2012-04-24 20:56:49 +04:00
return offset ;
}
2017-05-19 12:37:12 +03:00
static ssize_t in_illuminance0_lux_table_store ( struct device * dev ,
2017-10-19 23:06:28 +03:00
struct device_attribute * attr ,
const char * buf , size_t len )
2012-04-24 20:56:49 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
int value [ ARRAY_SIZE ( chip - > tsl2772_device_lux ) * 2 + 1 ] ;
2017-07-07 01:56:26 +03:00
int n , ret ;
2012-04-24 20:56:49 +04:00
get_options ( buf , ARRAY_SIZE ( value ) , value ) ;
2018-04-21 03:41:52 +03:00
/*
* We now have an array of ints starting at value [ 1 ] , and
2012-04-24 20:56:49 +04:00
* enumerated by value [ 0 ] .
2018-05-04 05:53:14 +03:00
* We expect each group of two ints to be one table entry ,
2012-04-24 20:56:49 +04:00
* and the last table entry is all 0.
*/
n = value [ 0 ] ;
2018-05-04 05:53:14 +03:00
if ( ( n % 2 ) | | n < 4 | |
2018-05-11 03:12:22 +03:00
n > ( ( ARRAY_SIZE ( chip - > tsl2772_device_lux ) - 1 ) * 2 ) )
2012-04-24 20:56:49 +04:00
return - EINVAL ;
2018-05-04 05:53:14 +03:00
if ( ( value [ ( n - 1 ) ] | value [ n ] ) ! = 0 )
2012-04-24 20:56:49 +04:00
return - EINVAL ;
2018-05-11 03:12:22 +03:00
if ( chip - > tsl2772_chip_status = = TSL2772_CHIP_WORKING ) {
ret = tsl2772_chip_off ( indio_dev ) ;
2018-03-04 04:49:39 +03:00
if ( ret < 0 )
return ret ;
}
2012-04-24 20:56:49 +04:00
/* Zero out the table */
2018-05-11 03:12:22 +03:00
memset ( chip - > tsl2772_device_lux , 0 , sizeof ( chip - > tsl2772_device_lux ) ) ;
memcpy ( chip - > tsl2772_device_lux , & value [ 1 ] , ( value [ 0 ] * 4 ) ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_invoke_change ( indio_dev ) ;
2017-07-07 01:56:26 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
return len ;
}
2017-05-19 12:37:12 +03:00
static ssize_t in_proximity0_calibrate_store ( struct device * dev ,
2017-10-19 23:06:28 +03:00
struct device_attribute * attr ,
const char * buf , size_t len )
2012-04-24 20:56:49 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-04-24 20:56:49 +04:00
bool value ;
2017-07-07 01:56:26 +03:00
int ret ;
2012-04-24 20:56:49 +04:00
2018-05-04 05:53:10 +03:00
if ( kstrtobool ( buf , & value ) | | ! value )
2012-04-24 20:56:49 +04:00
return - EINVAL ;
2018-05-11 03:12:22 +03:00
ret = tsl2772_prox_cal ( indio_dev ) ;
2018-05-04 05:53:10 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
ret = tsl2772_invoke_change ( indio_dev ) ;
2017-07-07 01:56:26 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
return len ;
}
2018-05-11 03:12:22 +03:00
static int tsl2772_read_interrupt_config ( struct iio_dev * indio_dev ,
2013-10-07 18:11:00 +04:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
2013-10-07 18:11:00 +04:00
if ( chan - > type = = IIO_INTENSITY )
2018-03-21 13:29:06 +03:00
return chip - > settings . als_interrupt_en ;
2012-04-24 20:56:49 +04:00
else
2018-03-21 13:29:06 +03:00
return chip - > settings . prox_interrupt_en ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_write_interrupt_config ( struct iio_dev * indio_dev ,
2013-10-07 18:11:00 +04:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir ,
2012-04-24 20:56:49 +04:00
int val )
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
2018-03-21 13:29:06 +03:00
if ( chan - > type = = IIO_INTENSITY )
chip - > settings . als_interrupt_en = val ? true : false ;
else
chip - > settings . prox_interrupt_en = val ? true : false ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
return tsl2772_invoke_change ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_write_event_value ( struct iio_dev * indio_dev ,
2017-07-07 01:56:23 +03:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir ,
enum iio_event_info info ,
int val , int val2 )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2018-05-11 03:12:20 +03:00
int ret = - EINVAL , count , persistence ;
2017-10-19 23:06:20 +03:00
u8 time ;
2012-04-24 20:56:49 +04:00
2017-07-07 01:56:23 +03:00
switch ( info ) {
case IIO_EV_INFO_VALUE :
if ( chan - > type = = IIO_INTENSITY ) {
switch ( dir ) {
case IIO_EV_DIR_RISING :
2017-09-30 04:09:19 +03:00
chip - > settings . als_thresh_high = val ;
2017-07-07 01:56:23 +03:00
ret = 0 ;
break ;
case IIO_EV_DIR_FALLING :
2017-09-30 04:09:19 +03:00
chip - > settings . als_thresh_low = val ;
2017-07-07 01:56:23 +03:00
ret = 0 ;
break ;
default :
break ;
}
} else {
switch ( dir ) {
case IIO_EV_DIR_RISING :
2017-09-30 04:09:19 +03:00
chip - > settings . prox_thres_high = val ;
2017-07-07 01:56:23 +03:00
ret = 0 ;
break ;
case IIO_EV_DIR_FALLING :
2017-09-30 04:09:19 +03:00
chip - > settings . prox_thres_low = val ;
2017-07-07 01:56:23 +03:00
ret = 0 ;
break ;
default :
break ;
}
2012-04-24 20:56:49 +04:00
}
2017-07-07 01:56:23 +03:00
break ;
2017-10-19 23:06:20 +03:00
case IIO_EV_INFO_PERIOD :
if ( chan - > type = = IIO_INTENSITY )
time = chip - > settings . als_time ;
else
2018-04-21 03:41:50 +03:00
time = chip - > settings . prox_time ;
2017-10-19 23:06:20 +03:00
2018-05-11 03:12:20 +03:00
count = 256 - time ;
persistence = ( ( val * 1000000 ) + val2 ) /
2018-05-11 03:12:22 +03:00
( count * tsl2772_int_time_avail [ chip - > id ] [ 3 ] ) ;
2017-10-19 23:06:20 +03:00
2018-05-11 03:12:20 +03:00
if ( chan - > type = = IIO_INTENSITY ) {
/* ALS filter values are 1, 2, 3, 5, 10, 15, ..., 60 */
if ( persistence > 3 )
persistence = ( persistence / 5 ) + 3 ;
chip - > settings . als_persistence = persistence ;
} else {
chip - > settings . prox_persistence = persistence ;
}
2017-10-19 23:06:20 +03:00
ret = 0 ;
break ;
2017-07-07 01:56:23 +03:00
default :
break ;
2012-04-24 20:56:49 +04:00
}
2017-07-07 01:56:23 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
return tsl2772_invoke_change ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_read_event_value ( struct iio_dev * indio_dev ,
2017-07-07 01:56:23 +03:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir ,
enum iio_event_info info ,
int * val , int * val2 )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2018-05-11 03:12:20 +03:00
int filter_delay , persistence ;
2017-10-19 23:06:20 +03:00
u8 time ;
2012-04-24 20:56:49 +04:00
2017-07-07 01:56:23 +03:00
switch ( info ) {
case IIO_EV_INFO_VALUE :
if ( chan - > type = = IIO_INTENSITY ) {
switch ( dir ) {
case IIO_EV_DIR_RISING :
2017-09-30 04:09:19 +03:00
* val = chip - > settings . als_thresh_high ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2017-07-07 01:56:23 +03:00
case IIO_EV_DIR_FALLING :
2017-09-30 04:09:19 +03:00
* val = chip - > settings . als_thresh_low ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2017-07-07 01:56:23 +03:00
default :
2018-05-11 03:12:16 +03:00
return - EINVAL ;
2017-07-07 01:56:23 +03:00
}
} else {
switch ( dir ) {
case IIO_EV_DIR_RISING :
2017-09-30 04:09:19 +03:00
* val = chip - > settings . prox_thres_high ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2017-07-07 01:56:23 +03:00
case IIO_EV_DIR_FALLING :
2017-09-30 04:09:19 +03:00
* val = chip - > settings . prox_thres_low ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2017-07-07 01:56:23 +03:00
default :
2018-05-11 03:12:16 +03:00
return - EINVAL ;
2017-07-07 01:56:23 +03:00
}
2012-04-24 20:56:49 +04:00
}
2017-07-07 01:56:23 +03:00
break ;
2017-10-19 23:06:20 +03:00
case IIO_EV_INFO_PERIOD :
if ( chan - > type = = IIO_INTENSITY ) {
time = chip - > settings . als_time ;
2018-05-11 03:12:20 +03:00
persistence = chip - > settings . als_persistence ;
/* ALS filter values are 1, 2, 3, 5, 10, 15, ..., 60 */
if ( persistence > 3 )
persistence = ( persistence - 3 ) * 5 ;
2017-10-19 23:06:20 +03:00
} else {
2018-04-21 03:41:50 +03:00
time = chip - > settings . prox_time ;
2018-05-11 03:12:20 +03:00
persistence = chip - > settings . prox_persistence ;
2017-10-19 23:06:20 +03:00
}
2018-05-11 03:12:20 +03:00
filter_delay = persistence * ( 256 - time ) *
2018-05-11 03:12:22 +03:00
tsl2772_int_time_avail [ chip - > id ] [ 3 ] ;
2018-05-11 03:12:20 +03:00
* val = filter_delay / 1000000 ;
* val2 = filter_delay % 1000000 ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT_PLUS_MICRO ;
2017-07-07 01:56:23 +03:00
default :
2018-05-11 03:12:16 +03:00
return - EINVAL ;
2012-04-24 20:56:49 +04:00
}
}
2018-05-11 03:12:22 +03:00
static int tsl2772_read_raw ( struct iio_dev * indio_dev ,
2012-04-24 20:56:49 +04:00
struct iio_chan_spec const * chan ,
int * val ,
int * val2 ,
long mask )
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
switch ( mask ) {
2012-04-25 02:59:10 +04:00
case IIO_CHAN_INFO_PROCESSED :
2012-04-24 20:56:49 +04:00
switch ( chan - > type ) {
case IIO_LIGHT :
2018-05-11 03:12:22 +03:00
tsl2772_get_lux ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
* val = chip - > als_cur_info . lux ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2012-04-25 02:59:10 +04:00
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_RAW :
switch ( chan - > type ) {
2012-04-24 20:56:49 +04:00
case IIO_INTENSITY :
2018-05-11 03:12:22 +03:00
tsl2772_get_lux ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
if ( chan - > channel = = 0 )
* val = chip - > als_cur_info . als_ch0 ;
else
* val = chip - > als_cur_info . als_ch1 ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2012-04-24 20:56:49 +04:00
case IIO_PROXIMITY :
2018-05-11 03:12:22 +03:00
tsl2772_get_prox ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
* val = chip - > prox_data ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2012-04-24 20:56:49 +04:00
default :
return - EINVAL ;
}
break ;
case IIO_CHAN_INFO_CALIBSCALE :
if ( chan - > type = = IIO_LIGHT )
2018-05-11 03:12:22 +03:00
* val = tsl2772_als_gain [ chip - > settings . als_gain ] ;
2012-04-24 20:56:49 +04:00
else
2018-05-11 03:12:22 +03:00
* val = tsl2772_prox_gain [ chip - > settings . prox_gain ] ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2012-04-24 20:56:49 +04:00
case IIO_CHAN_INFO_CALIBBIAS :
2017-09-30 04:09:19 +03:00
* val = chip - > settings . als_gain_trim ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT ;
2017-09-30 04:09:20 +03:00
case IIO_CHAN_INFO_INT_TIME :
2018-05-04 05:53:14 +03:00
* val = 0 ;
2018-05-11 03:12:19 +03:00
* val2 = ( 256 - chip - > settings . als_time ) *
2018-05-11 03:12:22 +03:00
tsl2772_int_time_avail [ chip - > id ] [ 3 ] ;
2018-05-11 03:12:16 +03:00
return IIO_VAL_INT_PLUS_MICRO ;
2012-04-24 20:56:49 +04:00
default :
2018-05-11 03:12:16 +03:00
return - EINVAL ;
2012-04-24 20:56:49 +04:00
}
}
2018-05-11 03:12:22 +03:00
static int tsl2772_write_raw ( struct iio_dev * indio_dev ,
2016-03-12 11:19:20 +03:00
struct iio_chan_spec const * chan ,
int val ,
int val2 ,
long mask )
2012-04-24 20:56:49 +04:00
{
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
switch ( mask ) {
case IIO_CHAN_INFO_CALIBSCALE :
if ( chan - > type = = IIO_INTENSITY ) {
switch ( val ) {
case 1 :
2017-09-30 04:09:19 +03:00
chip - > settings . als_gain = 0 ;
2012-04-24 20:56:49 +04:00
break ;
case 8 :
2017-09-30 04:09:19 +03:00
chip - > settings . als_gain = 1 ;
2012-04-24 20:56:49 +04:00
break ;
case 16 :
2017-09-30 04:09:19 +03:00
chip - > settings . als_gain = 2 ;
2012-04-24 20:56:49 +04:00
break ;
case 120 :
2017-09-30 04:09:19 +03:00
chip - > settings . als_gain = 3 ;
2012-04-24 20:56:49 +04:00
break ;
default :
return - EINVAL ;
}
} else {
switch ( val ) {
case 1 :
2017-09-30 04:09:19 +03:00
chip - > settings . prox_gain = 0 ;
2012-04-24 20:56:49 +04:00
break ;
case 2 :
2017-09-30 04:09:19 +03:00
chip - > settings . prox_gain = 1 ;
2012-04-24 20:56:49 +04:00
break ;
case 4 :
2017-09-30 04:09:19 +03:00
chip - > settings . prox_gain = 2 ;
2012-04-24 20:56:49 +04:00
break ;
case 8 :
2017-09-30 04:09:19 +03:00
chip - > settings . prox_gain = 3 ;
2012-04-24 20:56:49 +04:00
break ;
default :
return - EINVAL ;
}
}
break ;
case IIO_CHAN_INFO_CALIBBIAS :
2018-05-11 03:12:22 +03:00
if ( val < TSL2772_ALS_GAIN_TRIM_MIN | |
val > TSL2772_ALS_GAIN_TRIM_MAX )
2018-05-11 03:12:21 +03:00
return - EINVAL ;
2017-09-30 04:09:19 +03:00
chip - > settings . als_gain_trim = val ;
2012-04-24 20:56:49 +04:00
break ;
2017-09-30 04:09:20 +03:00
case IIO_CHAN_INFO_INT_TIME :
2018-05-11 03:12:22 +03:00
if ( val ! = 0 | | val2 < tsl2772_int_time_avail [ chip - > id ] [ 1 ] | |
val2 > tsl2772_int_time_avail [ chip - > id ] [ 5 ] )
2018-05-11 03:12:21 +03:00
return - EINVAL ;
2018-05-11 03:12:19 +03:00
chip - > settings . als_time = 256 -
2018-05-11 03:12:22 +03:00
( val2 / tsl2772_int_time_avail [ chip - > id ] [ 3 ] ) ;
2017-09-30 04:09:20 +03:00
break ;
2012-04-24 20:56:49 +04:00
default :
return - EINVAL ;
}
2018-05-11 03:12:22 +03:00
return tsl2772_invoke_change ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
}
2017-05-19 12:37:12 +03:00
static DEVICE_ATTR_RW ( in_illuminance0_target_input ) ;
2012-04-24 20:56:49 +04:00
2017-05-19 12:37:12 +03:00
static DEVICE_ATTR_WO ( in_illuminance0_calibrate ) ;
2012-04-24 20:56:49 +04:00
2017-05-19 12:37:12 +03:00
static DEVICE_ATTR_WO ( in_proximity0_calibrate ) ;
2012-04-24 20:56:49 +04:00
2017-05-19 12:37:12 +03:00
static DEVICE_ATTR_RW ( in_illuminance0_lux_table ) ;
2012-04-24 20:56:49 +04:00
/* Use the default register values to identify the Taos device */
2018-05-11 03:12:22 +03:00
static int tsl2772_device_id_verif ( int id , int target )
2012-04-24 20:56:49 +04:00
{
switch ( target ) {
case tsl2571 :
case tsl2671 :
case tsl2771 :
2018-04-21 03:41:47 +03:00
return ( id & 0xf0 ) = = TRITON_ID ;
2012-04-24 20:56:49 +04:00
case tmd2671 :
case tmd2771 :
2018-04-21 03:41:47 +03:00
return ( id & 0xf0 ) = = HALIBUT_ID ;
2012-04-24 20:56:49 +04:00
case tsl2572 :
case tsl2672 :
case tmd2672 :
case tsl2772 :
case tmd2772 :
2018-08-03 03:18:58 +03:00
case apds9930 :
2018-04-21 03:41:47 +03:00
return ( id & 0xf0 ) = = SWORDFISH_ID ;
2012-04-24 20:56:49 +04:00
}
return - EINVAL ;
}
2018-05-11 03:12:22 +03:00
static irqreturn_t tsl2772_event_handler ( int irq , void * private )
2012-04-24 20:56:49 +04:00
{
struct iio_dev * indio_dev = private ;
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
2016-03-09 21:05:49 +03:00
s64 timestamp = iio_get_time_ns ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
int ret ;
2018-05-11 03:12:22 +03:00
ret = tsl2772_read_status ( chip ) ;
2018-03-04 04:49:33 +03:00
if ( ret < 0 )
2018-04-21 03:41:43 +03:00
return IRQ_HANDLED ;
2012-04-24 20:56:49 +04:00
/* What type of interrupt do we need to process */
2018-05-11 03:12:22 +03:00
if ( ret & TSL2772_STA_PRX_INTR ) {
2012-04-24 20:56:49 +04:00
iio_push_event ( indio_dev ,
IIO_UNMOD_EVENT_CODE ( IIO_PROXIMITY ,
0 ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_EITHER ) ,
2018-05-11 03:12:15 +03:00
timestamp ) ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
if ( ret & TSL2772_STA_ALS_INTR ) {
2012-04-24 20:56:49 +04:00
iio_push_event ( indio_dev ,
2016-03-12 11:19:20 +03:00
IIO_UNMOD_EVENT_CODE ( IIO_LIGHT ,
0 ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_EITHER ) ,
timestamp ) ;
2012-04-24 20:56:49 +04:00
}
2018-03-04 04:49:32 +03:00
2018-04-21 03:41:44 +03:00
ret = i2c_smbus_write_byte ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CMD_SPL_FN |
TSL2772_CMD_PROXALS_INT_CLR ) ;
2018-04-21 03:41:44 +03:00
if ( ret < 0 )
dev_err ( & chip - > client - > dev ,
" %s: failed to clear interrupt status: %d \n " ,
__func__ , ret ) ;
2012-04-24 20:56:49 +04:00
return IRQ_HANDLED ;
}
2018-05-11 03:12:22 +03:00
static struct attribute * tsl2772_ALS_device_attrs [ ] = {
2012-04-24 20:56:49 +04:00
& dev_attr_in_illuminance0_target_input . attr ,
& dev_attr_in_illuminance0_calibrate . attr ,
& dev_attr_in_illuminance0_lux_table . attr ,
NULL
} ;
2018-05-11 03:12:22 +03:00
static struct attribute * tsl2772_PRX_device_attrs [ ] = {
2012-04-24 20:56:49 +04:00
& dev_attr_in_proximity0_calibrate . attr ,
NULL
} ;
2018-05-11 03:12:22 +03:00
static struct attribute * tsl2772_ALSPRX_device_attrs [ ] = {
2012-04-24 20:56:49 +04:00
& dev_attr_in_illuminance0_target_input . attr ,
& dev_attr_in_illuminance0_calibrate . attr ,
& dev_attr_in_illuminance0_lux_table . attr ,
NULL
} ;
2018-05-11 03:12:22 +03:00
static struct attribute * tsl2772_PRX2_device_attrs [ ] = {
2012-04-24 20:56:49 +04:00
& dev_attr_in_proximity0_calibrate . attr ,
NULL
} ;
2018-05-11 03:12:22 +03:00
static struct attribute * tsl2772_ALSPRX2_device_attrs [ ] = {
2012-04-24 20:56:49 +04:00
& dev_attr_in_illuminance0_target_input . attr ,
& dev_attr_in_illuminance0_calibrate . attr ,
& dev_attr_in_illuminance0_lux_table . attr ,
& dev_attr_in_proximity0_calibrate . attr ,
NULL
} ;
2018-05-11 03:12:22 +03:00
static const struct attribute_group tsl2772_device_attr_group_tbl [ ] = {
2012-04-24 20:56:49 +04:00
[ ALS ] = {
2018-05-11 03:12:22 +03:00
. attrs = tsl2772_ALS_device_attrs ,
2012-04-24 20:56:49 +04:00
} ,
[ PRX ] = {
2018-05-11 03:12:22 +03:00
. attrs = tsl2772_PRX_device_attrs ,
2012-04-24 20:56:49 +04:00
} ,
[ ALSPRX ] = {
2018-05-11 03:12:22 +03:00
. attrs = tsl2772_ALSPRX_device_attrs ,
2012-04-24 20:56:49 +04:00
} ,
[ PRX2 ] = {
2018-05-11 03:12:22 +03:00
. attrs = tsl2772_PRX2_device_attrs ,
2012-04-24 20:56:49 +04:00
} ,
[ ALSPRX2 ] = {
2018-05-11 03:12:22 +03:00
. attrs = tsl2772_ALSPRX2_device_attrs ,
2012-04-24 20:56:49 +04:00
} ,
} ;
2018-05-11 03:12:22 +03:00
# define TSL2772_DEVICE_INFO(type)[type] = \
2018-05-11 03:12:18 +03:00
{ \
2018-05-11 03:12:22 +03:00
. attrs = & tsl2772_device_attr_group_tbl [ type ] , \
. read_raw = & tsl2772_read_raw , \
. read_avail = & tsl2772_read_avail , \
. write_raw = & tsl2772_write_raw , \
. read_event_value = & tsl2772_read_event_value , \
. write_event_value = & tsl2772_write_event_value , \
. read_event_config = & tsl2772_read_interrupt_config , \
. write_event_config = & tsl2772_write_interrupt_config , \
2018-05-11 03:12:18 +03:00
}
2018-05-11 03:12:22 +03:00
static const struct iio_info tsl2772_device_info [ ] = {
TSL2772_DEVICE_INFO ( ALS ) ,
TSL2772_DEVICE_INFO ( PRX ) ,
TSL2772_DEVICE_INFO ( ALSPRX ) ,
TSL2772_DEVICE_INFO ( PRX2 ) ,
TSL2772_DEVICE_INFO ( ALSPRX2 ) ,
2013-10-07 18:11:00 +04:00
} ;
2018-05-11 03:12:22 +03:00
static const struct iio_event_spec tsl2772_events [ ] = {
2013-10-07 18:11:00 +04:00
{
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_RISING ,
2018-03-24 23:05:54 +03:00
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
2013-10-07 18:11:00 +04:00
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_FALLING ,
2018-03-24 23:05:54 +03:00
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
2017-10-19 23:06:20 +03:00
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_EITHER ,
2018-03-24 23:05:54 +03:00
. mask_separate = BIT ( IIO_EV_INFO_PERIOD ) |
BIT ( IIO_EV_INFO_ENABLE ) ,
2012-04-24 20:56:49 +04:00
} ,
} ;
2018-05-11 03:12:22 +03:00
static const struct tsl2772_chip_info tsl2772_chip_info_tbl [ ] = {
2012-04-24 20:56:49 +04:00
[ ALS ] = {
2018-05-04 05:53:11 +03:00
. channel_with_events = {
2012-04-24 20:56:49 +04:00
{
. type = IIO_LIGHT ,
. indexed = 1 ,
. channel = 0 ,
2018-04-21 03:41:41 +03:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
2018-04-21 03:41:41 +03:00
BIT ( IIO_CHAN_INFO_INT_TIME ) |
2013-02-27 23:40:11 +04:00
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 1 ,
} ,
} ,
2018-05-04 05:53:11 +03:00
. channel_without_events = {
{
. type = IIO_LIGHT ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-04 05:53:11 +03:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 1 ,
} ,
} ,
. chan_table_elements = 3 ,
2018-05-11 03:12:22 +03:00
. info = & tsl2772_device_info [ ALS ] ,
2012-04-24 20:56:49 +04:00
} ,
[ PRX ] = {
2018-05-04 05:53:11 +03:00
. channel_with_events = {
2012-04-24 20:56:49 +04:00
{
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} ,
} ,
2018-05-04 05:53:11 +03:00
. channel_without_events = {
{
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
} ,
} ,
. chan_table_elements = 1 ,
2018-05-11 03:12:22 +03:00
. info = & tsl2772_device_info [ PRX ] ,
2012-04-24 20:56:49 +04:00
} ,
[ ALSPRX ] = {
2018-05-04 05:53:11 +03:00
. channel_with_events = {
2012-04-24 20:56:49 +04:00
{
. type = IIO_LIGHT ,
. indexed = 1 ,
. channel = 0 ,
2018-04-21 03:41:41 +03:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
2018-04-21 03:41:41 +03:00
BIT ( IIO_CHAN_INFO_INT_TIME ) |
2013-02-27 23:40:11 +04:00
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 1 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} ,
} ,
2018-05-04 05:53:11 +03:00
. channel_without_events = {
{
. type = IIO_LIGHT ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-04 05:53:11 +03:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 1 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
} , {
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
} ,
} ,
. chan_table_elements = 4 ,
2018-05-11 03:12:22 +03:00
. info = & tsl2772_device_info [ ALSPRX ] ,
2012-04-24 20:56:49 +04:00
} ,
[ PRX2 ] = {
2018-05-04 05:53:11 +03:00
. channel_with_events = {
2012-04-24 20:56:49 +04:00
{
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} ,
} ,
2018-05-04 05:53:11 +03:00
. channel_without_events = {
{
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-04 05:53:11 +03:00
} ,
} ,
. chan_table_elements = 1 ,
2018-05-11 03:12:22 +03:00
. info = & tsl2772_device_info [ PRX2 ] ,
2012-04-24 20:56:49 +04:00
} ,
[ ALSPRX2 ] = {
2018-05-04 05:53:11 +03:00
. channel_with_events = {
2012-04-24 20:56:49 +04:00
{
. type = IIO_LIGHT ,
. indexed = 1 ,
. channel = 0 ,
2018-04-21 03:41:41 +03:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
2018-04-21 03:41:41 +03:00
BIT ( IIO_CHAN_INFO_INT_TIME ) |
2013-02-27 23:40:11 +04:00
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 1 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2012-04-24 20:56:49 +04:00
} , {
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
2013-02-27 23:40:11 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:22 +03:00
. event_spec = tsl2772_events ,
. num_event_specs = ARRAY_SIZE ( tsl2772_events ) ,
2012-04-24 20:56:49 +04:00
} ,
} ,
2018-05-04 05:53:11 +03:00
. channel_without_events = {
{
. type = IIO_LIGHT ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-04 05:53:11 +03:00
} , {
. type = IIO_INTENSITY ,
. indexed = 1 ,
. channel = 1 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
} , {
. type = IIO_PROXIMITY ,
. indexed = 1 ,
. channel = 0 ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-11 03:12:19 +03:00
. info_mask_separate_available =
BIT ( IIO_CHAN_INFO_CALIBSCALE ) ,
2018-05-04 05:53:11 +03:00
} ,
} ,
. chan_table_elements = 4 ,
2018-05-11 03:12:22 +03:00
. info = & tsl2772_device_info [ ALSPRX2 ] ,
2012-04-24 20:56:49 +04:00
} ,
} ;
2018-05-11 03:12:22 +03:00
static int tsl2772_probe ( struct i2c_client * clientp ,
2016-03-12 11:19:20 +03:00
const struct i2c_device_id * id )
2012-04-24 20:56:49 +04:00
{
struct iio_dev * indio_dev ;
2018-05-11 03:12:22 +03:00
struct tsl2772_chip * chip ;
2018-03-21 13:29:11 +03:00
int ret ;
2012-04-24 20:56:49 +04:00
2013-09-05 13:29:00 +04:00
indio_dev = devm_iio_device_alloc ( & clientp - > dev , sizeof ( * chip ) ) ;
2012-04-24 20:56:49 +04:00
if ( ! indio_dev )
return - ENOMEM ;
chip = iio_priv ( indio_dev ) ;
chip - > client = clientp ;
i2c_set_clientdata ( clientp , indio_dev ) ;
2019-08-01 10:36:19 +03:00
chip - > supplies [ TSL2772_SUPPLY_VDD ] . supply = " vdd " ;
chip - > supplies [ TSL2772_SUPPLY_VDDIO ] . supply = " vddio " ;
2018-08-03 03:18:56 +03:00
2019-08-01 10:36:19 +03:00
ret = devm_regulator_bulk_get ( & clientp - > dev ,
ARRAY_SIZE ( chip - > supplies ) ,
chip - > supplies ) ;
2020-08-29 09:47:23 +03:00
if ( ret < 0 )
return dev_err_probe ( & clientp - > dev , ret , " Failed to get regulators \n " ) ;
2019-08-01 10:36:19 +03:00
ret = regulator_bulk_enable ( ARRAY_SIZE ( chip - > supplies ) , chip - > supplies ) ;
if ( ret < 0 ) {
dev_err ( & clientp - > dev , " Failed to enable regulators: %d \n " ,
ret ) ;
return ret ;
2018-08-03 03:18:56 +03:00
}
2019-08-01 10:35:57 +03:00
ret = devm_add_action_or_reset ( & clientp - > dev ,
tsl2772_disable_regulators_action ,
chip ) ;
2018-08-03 03:18:56 +03:00
if ( ret < 0 ) {
dev_err ( & clientp - > dev , " Failed to setup regulator cleanup action %d \n " ,
ret ) ;
return ret ;
}
usleep_range ( TSL2772_BOOT_MIN_SLEEP_TIME , TSL2772_BOOT_MAX_SLEEP_TIME ) ;
2017-07-07 01:56:21 +03:00
ret = i2c_smbus_read_byte_data ( chip - > client ,
2018-05-11 03:12:22 +03:00
TSL2772_CMD_REG | TSL2772_CHIPID ) ;
2012-04-24 20:56:49 +04:00
if ( ret < 0 )
2013-09-05 13:29:00 +04:00
return ret ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
if ( tsl2772_device_id_verif ( ret , id - > driver_data ) < = 0 ) {
2012-04-24 20:56:49 +04:00
dev_info ( & chip - > client - > dev ,
2016-03-12 11:19:20 +03:00
" %s: i2c device found does not match expected id \n " ,
2012-04-24 20:56:49 +04:00
__func__ ) ;
2013-09-05 13:29:00 +04:00
return - EINVAL ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
ret = i2c_smbus_write_byte ( clientp , TSL2772_CMD_REG | TSL2772_CNTRL ) ;
2012-04-24 20:56:49 +04:00
if ( ret < 0 ) {
2018-03-21 13:29:07 +03:00
dev_err ( & clientp - > dev ,
" %s: Failed to write to CMD register: %d \n " ,
__func__ , ret ) ;
2013-09-05 13:29:00 +04:00
return ret ;
2012-04-24 20:56:49 +04:00
}
mutex_init ( & chip - > als_mutex ) ;
mutex_init ( & chip - > prox_mutex ) ;
2018-05-11 03:12:22 +03:00
chip - > tsl2772_chip_status = TSL2772_CHIP_UNKNOWN ;
2015-11-23 20:48:50 +03:00
chip - > pdata = dev_get_platdata ( & clientp - > dev ) ;
2012-04-24 20:56:49 +04:00
chip - > id = id - > driver_data ;
chip - > chip_info =
2018-05-11 03:12:22 +03:00
& tsl2772_chip_info_tbl [ device_channel_config [ id - > driver_data ] ] ;
2012-04-24 20:56:49 +04:00
indio_dev - > info = chip - > chip_info - > info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > name = chip - > client - > name ;
indio_dev - > num_channels = chip - > chip_info - > chan_table_elements ;
if ( clientp - > irq ) {
2018-05-04 05:53:11 +03:00
indio_dev - > channels = chip - > chip_info - > channel_with_events ;
2013-09-05 13:29:00 +04:00
ret = devm_request_threaded_irq ( & clientp - > dev , clientp - > irq ,
NULL ,
2018-05-11 03:12:22 +03:00
& tsl2772_event_handler ,
staging: iio: tsl2x7x: correct interrupt handler trigger
tsl2x7x_event_handler() was not called as expected when the device was
asserting a hardware interrupt. This patch changes the interrupt line
trigger from rising to falling.
The driver was tested on a TSL2772 hooked up to a Raspberry Pi 2. The
interrupt pin also had a 10K pull-up resistor per the requirements from
the datasheet. The relevant device tree binding:
&i2c1 {
tsl2772@39 {
compatible = "amstaos,tsl2772";
reg = <0x39>;
interrupt-parent = <&gpio>;
interrupts = <22 0x2>;
};
};
With this patch, iio_event_monitor now shows the events when the
channels are outside the defined interrupt thresholds.
$ sudo ./iio_event_monitor tsl2772
Found IIO device with name tsl2772 with device number 0
Event: time: 1478193460053760446, type: proximity, channel: 0, evtype:
thresh, direction: either
...
Event: time: 1478193463020270185, type: illuminance, channel: 0, evtype:
thresh, direction: either
...
Signed-off-by: Brian Masney <masneyb@onstation.org>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2018-03-21 13:29:03 +03:00
IRQF_TRIGGER_FALLING |
2013-09-05 13:29:00 +04:00
IRQF_ONESHOT ,
2018-05-11 03:12:22 +03:00
" TSL2772_event " ,
2013-09-05 13:29:00 +04:00
indio_dev ) ;
2012-04-24 20:56:49 +04:00
if ( ret ) {
dev_err ( & clientp - > dev ,
2018-03-21 13:29:07 +03:00
" %s: irq request failed \n " , __func__ ) ;
2013-09-05 13:29:00 +04:00
return ret ;
2012-04-24 20:56:49 +04:00
}
2018-05-04 05:53:11 +03:00
} else {
indio_dev - > channels = chip - > chip_info - > channel_without_events ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
tsl2772_defaults ( chip ) ;
ret = tsl2772_chip_on ( indio_dev ) ;
2018-05-11 03:12:17 +03:00
if ( ret < 0 )
return ret ;
2012-04-24 20:56:49 +04:00
2019-08-01 10:36:05 +03:00
ret = devm_add_action_or_reset ( & clientp - > dev ,
tsl2772_chip_off_action ,
indio_dev ) ;
if ( ret < 0 )
return ret ;
2019-08-01 10:36:12 +03:00
return devm_iio_device_register ( & clientp - > dev , indio_dev ) ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_suspend ( struct device * dev )
2012-04-24 20:56:49 +04:00
{
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2018-08-03 03:18:56 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
int ret ;
2012-04-24 20:56:49 +04:00
2018-08-03 03:18:56 +03:00
ret = tsl2772_chip_off ( indio_dev ) ;
2019-08-01 10:36:19 +03:00
regulator_bulk_disable ( ARRAY_SIZE ( chip - > supplies ) , chip - > supplies ) ;
2018-08-03 03:18:56 +03:00
return ret ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static int tsl2772_resume ( struct device * dev )
2012-04-24 20:56:49 +04:00
{
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2018-08-03 03:18:56 +03:00
struct tsl2772_chip * chip = iio_priv ( indio_dev ) ;
int ret ;
2019-08-01 10:36:19 +03:00
ret = regulator_bulk_enable ( ARRAY_SIZE ( chip - > supplies ) , chip - > supplies ) ;
2018-08-03 03:18:56 +03:00
if ( ret < 0 )
return ret ;
usleep_range ( TSL2772_BOOT_MIN_SLEEP_TIME , TSL2772_BOOT_MAX_SLEEP_TIME ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
return tsl2772_chip_on ( indio_dev ) ;
2012-04-24 20:56:49 +04:00
}
2018-05-11 03:12:22 +03:00
static const struct i2c_device_id tsl2772_idtable [ ] = {
2012-04-24 20:56:49 +04:00
{ " tsl2571 " , tsl2571 } ,
{ " tsl2671 " , tsl2671 } ,
{ " tmd2671 " , tmd2671 } ,
{ " tsl2771 " , tsl2771 } ,
{ " tmd2771 " , tmd2771 } ,
{ " tsl2572 " , tsl2572 } ,
{ " tsl2672 " , tsl2672 } ,
{ " tmd2672 " , tmd2672 } ,
{ " tsl2772 " , tsl2772 } ,
{ " tmd2772 " , tmd2772 } ,
2018-08-03 03:18:58 +03:00
{ " apds9930 " , apds9930 } ,
2012-04-24 20:56:49 +04:00
{ }
} ;
2018-05-11 03:12:22 +03:00
MODULE_DEVICE_TABLE ( i2c , tsl2772_idtable ) ;
2012-04-24 20:56:49 +04:00
2018-05-11 03:12:22 +03:00
static const struct of_device_id tsl2772_of_match [ ] = {
2017-07-07 01:56:18 +03:00
{ . compatible = " amstaos,tsl2571 " } ,
{ . compatible = " amstaos,tsl2671 " } ,
{ . compatible = " amstaos,tmd2671 " } ,
{ . compatible = " amstaos,tsl2771 " } ,
{ . compatible = " amstaos,tmd2771 " } ,
{ . compatible = " amstaos,tsl2572 " } ,
{ . compatible = " amstaos,tsl2672 " } ,
{ . compatible = " amstaos,tmd2672 " } ,
{ . compatible = " amstaos,tsl2772 " } ,
{ . compatible = " amstaos,tmd2772 " } ,
2018-08-03 03:18:58 +03:00
{ . compatible = " avago,apds9930 " } ,
2017-07-07 01:56:18 +03:00
{ }
} ;
2018-05-11 03:12:22 +03:00
MODULE_DEVICE_TABLE ( of , tsl2772_of_match ) ;
2017-07-07 01:56:18 +03:00
2018-05-11 03:12:22 +03:00
static const struct dev_pm_ops tsl2772_pm_ops = {
. suspend = tsl2772_suspend ,
. resume = tsl2772_resume ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
static struct i2c_driver tsl2772_driver = {
2012-04-24 20:56:49 +04:00
. driver = {
2018-05-11 03:12:22 +03:00
. name = " tsl2772 " ,
. of_match_table = tsl2772_of_match ,
. pm = & tsl2772_pm_ops ,
2012-04-24 20:56:49 +04:00
} ,
2018-05-11 03:12:22 +03:00
. id_table = tsl2772_idtable ,
. probe = tsl2772_probe ,
2012-04-24 20:56:49 +04:00
} ;
2018-05-11 03:12:22 +03:00
module_i2c_driver ( tsl2772_driver ) ;
2012-04-24 20:56:49 +04:00
2018-03-21 13:29:12 +03:00
MODULE_AUTHOR ( " J. August Brenner <Jon.Brenner@ams.com> " ) ;
MODULE_AUTHOR ( " Brian Masney <masneyb@onstation.org> " ) ;
2018-05-11 03:12:22 +03:00
MODULE_DESCRIPTION ( " TAOS tsl2772 ambient and proximity light sensor driver " ) ;
2012-04-24 20:56:49 +04:00
MODULE_LICENSE ( " GPL " ) ;