2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-04-15 21:38:43 +04:00
/*
* Device driver for monitoring ambient light intensity ( lux )
2016-11-12 21:19:35 +03:00
* within the TAOS tsl258x family of devices ( tsl2580 , tsl2581 , tsl2583 ) .
2011-04-15 21:38:43 +04:00
*
* Copyright ( c ) 2011 , TAOS Corporation .
2017-04-25 11:06:33 +03:00
* Copyright ( c ) 2016 - 2017 Brian Masney < masneyb @ onstation . org >
2011-04-15 21:38:43 +04:00
*/
# include <linux/kernel.h>
# include <linux/i2c.h>
# include <linux/errno.h>
# include <linux/delay.h>
# include <linux/string.h>
# include <linux/mutex.h>
# include <linux/unistd.h>
# include <linux/slab.h>
2011-07-03 23:49:50 +04:00
# include <linux/module.h>
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
2016-10-28 13:00:19 +03:00
# include <linux/iio/sysfs.h>
2017-04-25 11:06:33 +03:00
# include <linux/pm_runtime.h>
2011-04-15 21:38:43 +04:00
/* Device Registers and Masks */
2016-11-12 21:19:23 +03:00
# define TSL2583_CNTRL 0x00
# define TSL2583_ALS_TIME 0X01
# define TSL2583_INTERRUPT 0x02
# define TSL2583_GAIN 0x07
# define TSL2583_REVID 0x11
# define TSL2583_CHIPID 0x12
# define TSL2583_ALS_CHAN0LO 0x14
# define TSL2583_ALS_CHAN0HI 0x15
# define TSL2583_ALS_CHAN1LO 0x16
# define TSL2583_ALS_CHAN1HI 0x17
# define TSL2583_TMR_LO 0x18
# define TSL2583_TMR_HI 0x19
2011-04-15 21:38:43 +04:00
/* tsl2583 cmd reg masks */
2016-11-12 21:19:23 +03:00
# define TSL2583_CMD_REG 0x80
# define TSL2583_CMD_SPL_FN 0x60
2016-11-12 21:19:24 +03:00
# define TSL2583_CMD_ALS_INT_CLR 0x01
2011-04-15 21:38:43 +04:00
/* tsl2583 cntrl reg masks */
2016-11-12 21:19:24 +03:00
# define TSL2583_CNTL_ADC_ENBL 0x02
2016-11-12 21:19:23 +03:00
# define TSL2583_CNTL_PWR_OFF 0x00
# define TSL2583_CNTL_PWR_ON 0x01
2011-04-15 21:38:43 +04:00
/* tsl2583 status reg masks */
2016-11-12 21:19:24 +03:00
# define TSL2583_STA_ADC_VALID 0x01
# define TSL2583_STA_ADC_INTR 0x10
2011-04-15 21:38:43 +04:00
/* Lux calculation constants */
2016-11-12 21:19:24 +03:00
# define TSL2583_LUX_CALC_OVER_FLOW 65535
2011-04-15 21:38:43 +04:00
2016-11-10 12:25:37 +03:00
# define TSL2583_INTERRUPT_DISABLED 0x00
2016-11-03 15:56:13 +03:00
# define TSL2583_CHIP_ID 0x90
# define TSL2583_CHIP_ID_MASK 0xf0
2017-04-25 11:06:33 +03:00
# define TSL2583_POWER_OFF_DELAY_MS 2000
2011-04-15 21:38:43 +04:00
/* Per-device data */
2016-11-12 21:19:23 +03:00
struct tsl2583_als_info {
2011-04-15 21:38:43 +04:00
u16 als_ch0 ;
u16 als_ch1 ;
u16 lux ;
} ;
2016-11-12 21:19:34 +03:00
struct tsl2583_lux {
unsigned int ratio ;
unsigned int ch0 ;
unsigned int ch1 ;
} ;
static const struct tsl2583_lux tsl2583_default_lux [ ] = {
{ 9830 , 8520 , 15729 } ,
{ 12452 , 10807 , 23344 } ,
{ 14746 , 6383 , 11705 } ,
{ 17695 , 4063 , 6554 } ,
{ 0 , 0 , 0 } /* Termination segment */
} ;
# define TSL2583_MAX_LUX_TABLE_ENTRIES 11
2016-11-12 21:19:23 +03:00
struct tsl2583_settings {
2011-04-15 21:38:43 +04:00
int als_time ;
int als_gain ;
int als_gain_trim ;
int als_cal_target ;
2016-11-12 21:19:34 +03:00
/*
* This structure is intentionally large to accommodate updates via
* sysfs . Sized to 11 = max 10 segments + 1 termination segment .
* Assumption is that one and only one type of glass used .
*/
struct tsl2583_lux als_device_lux [ TSL2583_MAX_LUX_TABLE_ENTRIES ] ;
2011-04-15 21:38:43 +04:00
} ;
struct tsl2583_chip {
struct mutex als_mutex ;
struct i2c_client * client ;
2016-11-12 21:19:23 +03:00
struct tsl2583_als_info als_cur_info ;
struct tsl2583_settings als_settings ;
2011-04-15 21:38:43 +04:00
int als_time_scale ;
int als_saturation ;
} ;
struct gainadj {
s16 ch0 ;
s16 ch1 ;
2016-10-28 13:00:18 +03:00
s16 mean ;
2011-04-15 21:38:43 +04:00
} ;
/* Index = (0 - 3) Used to validate the gain selection index */
static const struct gainadj gainadj [ ] = {
2016-10-28 13:00:18 +03:00
{ 1 , 1 , 1 } ,
{ 8 , 8 , 8 } ,
{ 16 , 16 , 16 } ,
{ 107 , 115 , 111 }
2011-04-15 21:38:43 +04:00
} ;
/*
* Provides initial operational parameter defaults .
* These defaults may be changed through the device ' s sysfs files .
*/
2016-11-12 21:19:23 +03:00
static void tsl2583_defaults ( struct tsl2583_chip * chip )
2011-04-15 21:38:43 +04:00
{
2016-11-03 15:56:14 +03:00
/*
* The integration time must be a multiple of 50 ms and within the
* range [ 50 , 600 ] ms .
*/
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_time = 100 ;
2016-11-03 15:56:14 +03:00
/*
* This is an index into the gainadj table . Assume clear glass as the
* default .
*/
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_gain = 0 ;
2016-11-03 15:56:14 +03:00
/* Default gain trim to account for aperture effects */
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_gain_trim = 1000 ;
2016-11-03 15:56:14 +03:00
2011-04-15 21:38:43 +04:00
/* Known external ALS reading used for calibration */
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_cal_target = 130 ;
2016-11-12 21:19:34 +03:00
/* Default lux table. */
memcpy ( chip - > als_settings . als_device_lux , tsl2583_default_lux ,
sizeof ( tsl2583_default_lux ) ) ;
2011-04-15 21:38:43 +04:00
}
/*
* Reads and calculates current lux value .
* 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
2016-11-12 21:19:34 +03:00
* of ch1 value , to the ch0 value , is calculated . The array als_device_lux [ ]
2011-04-15 21:38:43 +04:00
* declared above 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 .
*/
2016-11-12 21:19:23 +03:00
static int tsl2583_get_lux ( struct iio_dev * indio_dev )
2011-04-15 21:38:43 +04:00
{
u16 ch0 , ch1 ; /* separated ch0/ch1 data from device */
u32 lux ; /* raw lux calculated from device data */
2011-12-03 02:19:30 +04:00
u64 lux64 ;
2011-04-15 21:38:43 +04:00
u32 ratio ;
u8 buf [ 5 ] ;
2016-11-12 21:19:23 +03:00
struct tsl2583_lux * p ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2011-04-15 21:38:43 +04:00
int i , ret ;
2016-11-12 21:19:23 +03:00
ret = i2c_smbus_read_byte_data ( chip - > client , TSL2583_CMD_REG ) ;
2011-04-15 21:38:43 +04:00
if ( ret < 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev , " %s: failed to read CMD_REG register \n " ,
__func__ ) ;
2016-10-28 13:00:17 +03:00
goto done ;
2011-04-15 21:38:43 +04:00
}
2016-11-03 15:56:12 +03:00
2011-04-15 21:38:43 +04:00
/* is data new & valid */
2016-11-12 21:19:23 +03:00
if ( ! ( ret & TSL2583_STA_ADC_INTR ) ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev , " %s: data not valid; returning last value \n " ,
__func__ ) ;
2011-04-15 21:38:43 +04:00
ret = chip - > als_cur_info . lux ; /* return LAST VALUE */
2016-10-28 13:00:17 +03:00
goto done ;
2011-04-15 21:38:43 +04:00
}
for ( i = 0 ; i < 4 ; i + + ) {
2016-11-12 21:19:23 +03:00
int reg = TSL2583_CMD_REG | ( TSL2583_ALS_CHAN0LO + i ) ;
2014-09-25 00:13:21 +04:00
2016-11-03 15:56:12 +03:00
ret = i2c_smbus_read_byte_data ( chip - > client , reg ) ;
2011-04-15 21:38:43 +04:00
if ( ret < 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev , " %s: failed to read register %x \n " ,
__func__ , reg ) ;
2016-10-28 13:00:17 +03:00
goto done ;
2011-04-15 21:38:43 +04:00
}
2016-11-03 15:56:12 +03:00
buf [ i ] = ret ;
2011-04-15 21:38:43 +04:00
}
2016-02-18 10:35:38 +03:00
/*
2016-11-12 21:19:36 +03:00
* Clear the pending interrupt status bit on the chip to allow the next
* integration cycle to start . This has to be done even though this
* driver currently does not support interrupts .
2016-02-18 10:35:38 +03:00
*/
2011-08-12 20:08:52 +04:00
ret = i2c_smbus_write_byte ( chip - > client ,
2016-11-12 21:19:23 +03:00
( TSL2583_CMD_REG | TSL2583_CMD_SPL_FN |
TSL2583_CMD_ALS_INT_CLR ) ) ;
2011-04-15 21:38:43 +04:00
if ( ret < 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev , " %s: failed to clear the interrupt bit \n " ,
__func__ ) ;
2016-10-28 13:00:17 +03:00
goto done ; /* have no data, so return failure */
2011-04-15 21:38:43 +04:00
}
/* extract ALS/lux data */
ch0 = le16_to_cpup ( ( const __le16 * ) & buf [ 0 ] ) ;
ch1 = le16_to_cpup ( ( const __le16 * ) & buf [ 2 ] ) ;
chip - > als_cur_info . als_ch0 = ch0 ;
chip - > als_cur_info . als_ch1 = ch1 ;
if ( ( ch0 > = chip - > als_saturation ) | | ( ch1 > = chip - > als_saturation ) )
goto return_max ;
2015-10-20 22:55:40 +03:00
if ( ! ch0 ) {
2016-11-12 21:19:29 +03:00
/*
* The sensor appears to be in total darkness so set the
* calculated lux to 0 and return early to avoid a division by
* zero below when calculating the ratio .
*/
2016-02-18 10:35:40 +03:00
ret = 0 ;
chip - > als_cur_info . lux = 0 ;
2016-10-28 13:00:17 +03:00
goto done ;
2011-04-15 21:38:43 +04:00
}
2016-11-12 21:19:26 +03:00
2011-04-15 21:38:43 +04:00
/* calculate ratio */
ratio = ( ch1 < < 15 ) / ch0 ;
2016-11-12 21:19:26 +03:00
2011-04-15 21:38:43 +04:00
/* convert to unscaled lux using the pointer to the table */
2016-11-12 21:19:34 +03:00
for ( p = ( struct tsl2583_lux * ) chip - > als_settings . als_device_lux ;
2011-04-15 21:38:43 +04:00
p - > ratio ! = 0 & & p - > ratio < ratio ; p + + )
;
if ( p - > ratio = = 0 ) {
lux = 0 ;
} else {
2016-11-12 21:19:30 +03:00
u32 ch0lux , ch1lux ;
2011-04-15 21:38:43 +04:00
ch0lux = ( ( ch0 * p - > ch0 ) +
2016-11-12 21:19:23 +03:00
( gainadj [ chip - > als_settings . als_gain ] . ch0 > > 1 ) )
/ gainadj [ chip - > als_settings . als_gain ] . ch0 ;
2011-04-15 21:38:43 +04:00
ch1lux = ( ( ch1 * p - > ch1 ) +
2016-11-12 21:19:23 +03:00
( gainadj [ chip - > als_settings . als_gain ] . ch1 > > 1 ) )
/ gainadj [ chip - > als_settings . als_gain ] . ch1 ;
2011-04-15 21:38:43 +04:00
2016-11-12 21:19:30 +03:00
/* note: lux is 31 bit max at this point */
if ( ch1lux > ch0lux ) {
dev_dbg ( & chip - > client - > dev , " %s: No Data - Returning 0 \n " ,
__func__ ) ;
ret = 0 ;
chip - > als_cur_info . lux = 0 ;
goto done ;
}
lux = ch0lux - ch1lux ;
2011-04-15 21:38:43 +04:00
}
/* 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 ;
2016-11-12 21:19:28 +03:00
/*
* Adjust for active gain scale .
2016-11-12 21:19:34 +03:00
* The tsl2583_default_lux tables above have a factor of 8192 built in ,
2011-12-03 02:19:30 +04:00
* so we need to shift right .
* 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 ;
2016-11-12 21:19:23 +03:00
lux64 = lux64 * chip - > als_settings . als_gain_trim ;
2011-12-03 02:19:30 +04:00
lux64 > > = 13 ;
lux = lux64 ;
2020-12-27 20:11:26 +03:00
lux = DIV_ROUND_CLOSEST ( lux , 1000 ) ;
2016-11-12 21:19:26 +03:00
2016-11-12 21:19:23 +03:00
if ( lux > TSL2583_LUX_CALC_OVER_FLOW ) { /* check for overflow */
2011-04-15 21:38:43 +04:00
return_max :
2016-11-12 21:19:23 +03:00
lux = TSL2583_LUX_CALC_OVER_FLOW ;
2011-04-15 21:38:43 +04:00
}
/* Update the structure with the latest VALID lux. */
chip - > als_cur_info . lux = lux ;
ret = lux ;
2016-10-28 13:00:17 +03:00
done :
2011-04-15 21:38:43 +04:00
return ret ;
}
/*
* Obtain single reading and calculate the als_gain_trim ( later used
* to derive actual lux ) .
* Return updated gain_trim value .
*/
2016-11-12 21:19:23 +03:00
static int tsl2583_als_calibrate ( struct iio_dev * indio_dev )
2011-04-15 21:38:43 +04:00
{
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2011-04-15 21:38:43 +04:00
unsigned int gain_trim_val ;
int ret ;
int lux_val ;
2016-11-03 15:56:12 +03:00
ret = i2c_smbus_read_byte_data ( chip - > client ,
2016-11-12 21:19:23 +03:00
TSL2583_CMD_REG | TSL2583_CNTRL ) ;
2011-04-15 21:38:43 +04:00
if ( ret < 0 ) {
2011-08-12 20:08:52 +04:00
dev_err ( & chip - > client - > dev ,
2016-11-12 21:19:22 +03:00
" %s: failed to read from the CNTRL register \n " ,
2016-10-28 13:00:13 +03:00
__func__ ) ;
return ret ;
}
2016-11-12 21:19:23 +03:00
if ( ( ret & ( TSL2583_CNTL_ADC_ENBL | TSL2583_CNTL_PWR_ON ) )
! = ( TSL2583_CNTL_ADC_ENBL | TSL2583_CNTL_PWR_ON ) ) {
2011-08-12 20:08:52 +04:00
dev_err ( & chip - > client - > dev ,
2016-11-12 21:19:22 +03:00
" %s: Device is not powered on and/or ADC is not enabled \n " ,
__func__ ) ;
2016-10-28 13:00:14 +03:00
return - EINVAL ;
2016-11-12 21:19:23 +03:00
} else if ( ( ret & TSL2583_STA_ADC_VALID ) ! = TSL2583_STA_ADC_VALID ) {
2011-08-12 20:08:52 +04:00
dev_err ( & chip - > client - > dev ,
2016-11-12 21:19:22 +03:00
" %s: The two ADC channels have not completed an integration cycle \n " ,
__func__ ) ;
2011-04-15 21:38:43 +04:00
return - ENODATA ;
}
2016-11-12 21:19:26 +03:00
2016-11-12 21:19:23 +03:00
lux_val = tsl2583_get_lux ( indio_dev ) ;
2011-04-15 21:38:43 +04:00
if ( lux_val < 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev , " %s: failed to get lux \n " ,
__func__ ) ;
2011-04-15 21:38:43 +04:00
return lux_val ;
}
2016-11-12 21:19:26 +03:00
2021-05-07 21:30:41 +03:00
/* Avoid division by zero of lux_value later on */
if ( lux_val = = 0 ) {
dev_err ( & chip - > client - > dev ,
" %s: lux_val of 0 will produce out of range trim_value \n " ,
__func__ ) ;
return - ENODATA ;
}
2016-11-12 21:19:23 +03:00
gain_trim_val = ( unsigned int ) ( ( ( chip - > als_settings . als_cal_target )
* chip - > als_settings . als_gain_trim ) / lux_val ) ;
2011-04-15 21:38:43 +04:00
if ( ( gain_trim_val < 250 ) | | ( gain_trim_val > 4000 ) ) {
2011-08-12 20:08:52 +04:00
dev_err ( & chip - > client - > dev ,
2016-11-12 21:19:22 +03:00
" %s: trim_val of %d is not within the range [250, 4000] \n " ,
__func__ , gain_trim_val ) ;
2011-04-15 21:38:43 +04:00
return - ENODATA ;
}
2016-11-12 21:19:26 +03:00
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_gain_trim = ( int ) gain_trim_val ;
2011-04-15 21:38:43 +04:00
2016-11-12 21:19:31 +03:00
return 0 ;
2011-04-15 21:38:43 +04:00
}
2016-11-10 12:25:38 +03:00
static int tsl2583_set_als_time ( struct tsl2583_chip * chip )
{
int als_count , als_time , ret ;
u8 val ;
/* determine als integration register */
2020-12-27 20:11:26 +03:00
als_count = DIV_ROUND_CLOSEST ( chip - > als_settings . als_time * 100 , 270 ) ;
2016-11-10 12:25:38 +03:00
if ( ! als_count )
als_count = 1 ; /* ensure at least one cycle */
/* convert back to time (encompasses overrides) */
2020-12-27 20:11:26 +03:00
als_time = DIV_ROUND_CLOSEST ( als_count * 27 , 10 ) ;
2016-11-10 12:25:38 +03:00
val = 256 - als_count ;
ret = i2c_smbus_write_byte_data ( chip - > client ,
2016-11-12 21:19:23 +03:00
TSL2583_CMD_REG | TSL2583_ALS_TIME ,
2016-11-10 12:25:38 +03:00
val ) ;
if ( ret < 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev , " %s: failed to set the als time to %d \n " ,
2016-11-10 12:25:38 +03:00
__func__ , val ) ;
return ret ;
}
/* set chip struct re scaling and saturation */
chip - > als_saturation = als_count * 922 ; /* 90% of full scale */
2020-12-27 20:11:26 +03:00
chip - > als_time_scale = DIV_ROUND_CLOSEST ( als_time , 50 ) ;
2016-11-10 12:25:38 +03:00
return ret ;
}
static int tsl2583_set_als_gain ( struct tsl2583_chip * chip )
{
int ret ;
2016-11-12 21:19:23 +03:00
/* Set the gain based on als_settings struct */
2016-11-10 12:25:38 +03:00
ret = i2c_smbus_write_byte_data ( chip - > client ,
2016-11-12 21:19:23 +03:00
TSL2583_CMD_REG | TSL2583_GAIN ,
chip - > als_settings . als_gain ) ;
2016-11-10 12:25:38 +03:00
if ( ret < 0 )
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev ,
" %s: failed to set the gain to %d \n " , __func__ ,
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_gain ) ;
2016-11-10 12:25:38 +03:00
return ret ;
}
2016-11-10 12:25:37 +03:00
static int tsl2583_set_power_state ( struct tsl2583_chip * chip , u8 state )
{
int ret ;
ret = i2c_smbus_write_byte_data ( chip - > client ,
2016-11-12 21:19:23 +03:00
TSL2583_CMD_REG | TSL2583_CNTRL , state ) ;
2016-11-10 12:25:37 +03:00
if ( ret < 0 )
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev ,
" %s: failed to set the power state to %d \n " , __func__ ,
state ) ;
2016-11-10 12:25:37 +03:00
return ret ;
}
2011-04-15 21:38:43 +04:00
/*
* Turn the device on .
* Configuration must be set before calling this function .
*/
2016-11-10 12:25:37 +03:00
static int tsl2583_chip_init_and_power_on ( struct iio_dev * indio_dev )
2011-04-15 21:38:43 +04:00
{
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-11-10 12:25:38 +03:00
int ret ;
2011-04-15 21:38:43 +04:00
2016-11-10 12:25:37 +03:00
/* Power on the device; ADC off. */
2016-11-12 21:19:23 +03:00
ret = tsl2583_set_power_state ( chip , TSL2583_CNTL_PWR_ON ) ;
2016-11-10 12:25:37 +03:00
if ( ret < 0 )
return ret ;
ret = i2c_smbus_write_byte_data ( chip - > client ,
2016-11-12 21:19:23 +03:00
TSL2583_CMD_REG | TSL2583_INTERRUPT ,
2016-11-10 12:25:37 +03:00
TSL2583_INTERRUPT_DISABLED ) ;
if ( ret < 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( & chip - > client - > dev ,
" %s: failed to disable interrupts \n " , __func__ ) ;
2016-11-10 12:25:37 +03:00
return ret ;
}
2016-11-10 12:25:38 +03:00
ret = tsl2583_set_als_time ( chip ) ;
if ( ret < 0 )
2016-11-10 12:25:37 +03:00
return ret ;
2011-04-15 21:38:43 +04:00
2016-11-10 12:25:38 +03:00
ret = tsl2583_set_als_gain ( chip ) ;
if ( ret < 0 )
2016-11-10 12:25:37 +03:00
return ret ;
2011-04-15 21:38:43 +04:00
2014-04-10 06:26:45 +04:00
usleep_range ( 3000 , 3500 ) ;
2016-11-10 12:25:37 +03:00
2016-11-12 21:19:23 +03:00
ret = tsl2583_set_power_state ( chip , TSL2583_CNTL_PWR_ON |
TSL2583_CNTL_ADC_ENBL ) ;
2016-11-10 12:25:37 +03:00
if ( ret < 0 )
2014-03-09 09:28:40 +04:00
return ret ;
2016-11-10 12:25:37 +03:00
2011-04-15 21:38:43 +04:00
return ret ;
}
/* Sysfs Interface Functions */
2016-10-28 13:00:19 +03:00
static ssize_t in_illuminance_input_target_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2011-04-15 21:38:43 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-10-28 13:00:21 +03:00
int ret ;
mutex_lock ( & chip - > als_mutex ) ;
2016-11-12 21:19:23 +03:00
ret = sprintf ( buf , " %d \n " , chip - > als_settings . als_cal_target ) ;
2016-10-28 13:00:21 +03:00
mutex_unlock ( & chip - > als_mutex ) ;
2011-04-15 21:38:43 +04:00
2016-10-28 13:00:21 +03:00
return ret ;
2011-04-15 21:38:43 +04:00
}
2016-10-28 13:00:19 +03:00
static ssize_t in_illuminance_input_target_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
2011-04-15 21:38:43 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
staging: iio: replace strict_strto*() with kstrto*()
The usage of strict_strto*() is not preferred, because
strict_strto*() is obsolete. Thus, kstrto*() should be
used.
Previously, there were only strict_strtol(), strict_strtoul(),
strict_strtoull(), and strict_strtoll(). Thus, when converting
to the variables, only long, unsigned long, unsigned long long,
and long long can be used.
However, kstrto*() provides various functions handling all types
of variables. Therefore, the types of variables can be changed
properly.
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
2013-08-20 06:31:00 +04:00
int value ;
2011-04-15 21:38:43 +04:00
2016-10-28 13:00:20 +03:00
if ( kstrtoint ( buf , 0 , & value ) | | ! value )
2011-04-15 21:38:43 +04:00
return - EINVAL ;
2016-10-28 13:00:21 +03:00
mutex_lock ( & chip - > als_mutex ) ;
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_cal_target = value ;
2016-10-28 13:00:21 +03:00
mutex_unlock ( & chip - > als_mutex ) ;
2011-04-15 21:38:43 +04:00
return len ;
}
2016-10-28 13:00:19 +03:00
static ssize_t in_illuminance_calibrate_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
2011-04-15 21:38:43 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2016-10-28 13:00:21 +03:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-11-12 21:19:16 +03:00
int value , ret ;
2011-04-15 21:38:43 +04:00
2016-10-28 13:00:20 +03:00
if ( kstrtoint ( buf , 0 , & value ) | | value ! = 1 )
2011-04-15 21:38:43 +04:00
return - EINVAL ;
2016-10-28 13:00:21 +03:00
mutex_lock ( & chip - > als_mutex ) ;
2016-11-12 21:19:16 +03:00
2016-11-12 21:19:23 +03:00
ret = tsl2583_als_calibrate ( indio_dev ) ;
2016-11-12 21:19:16 +03:00
if ( ret < 0 )
goto done ;
ret = len ;
done :
2016-10-28 13:00:21 +03:00
mutex_unlock ( & chip - > als_mutex ) ;
2011-04-15 21:38:43 +04:00
2016-11-12 21:19:16 +03:00
return ret ;
2011-04-15 21:38:43 +04:00
}
2016-10-28 13:00:19 +03:00
static ssize_t in_illuminance_lux_table_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2011-04-15 21:38:43 +04:00
{
2016-11-12 21:19:34 +03:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-11-12 21:19:25 +03:00
unsigned int i ;
2011-04-15 21:38:43 +04:00
int offset = 0 ;
2016-11-12 21:19:34 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( chip - > als_settings . als_device_lux ) ; i + + ) {
2015-01-20 13:43:38 +03:00
offset + = sprintf ( buf + offset , " %u,%u,%u, " ,
2016-11-12 21:19:34 +03:00
chip - > als_settings . als_device_lux [ i ] . ratio ,
chip - > als_settings . als_device_lux [ i ] . ch0 ,
chip - > als_settings . als_device_lux [ i ] . ch1 ) ;
if ( chip - > als_settings . als_device_lux [ i ] . ratio = = 0 ) {
2016-02-18 10:35:38 +03:00
/*
* We just printed the first " 0 " entry .
* Now get rid of the extra " , " and break .
*/
2011-04-15 21:38:43 +04:00
offset - - ;
break ;
}
}
offset + = sprintf ( buf + offset , " \n " ) ;
2016-11-12 21:19:26 +03:00
2011-04-15 21:38:43 +04:00
return offset ;
}
2016-10-28 13:00:19 +03:00
static ssize_t in_illuminance_lux_table_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
2011-04-15 21:38:43 +04:00
{
2012-05-12 17:39:51 +04:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-11-12 21:19:34 +03:00
const unsigned int max_ints = TSL2583_MAX_LUX_TABLE_ENTRIES * 3 ;
2016-11-24 16:38:07 +03:00
int value [ TSL2583_MAX_LUX_TABLE_ENTRIES * 3 + 1 ] ;
2016-11-12 21:19:25 +03:00
int ret = - EINVAL ;
unsigned int n ;
2011-04-15 21:38:43 +04:00
2016-10-28 13:00:21 +03:00
mutex_lock ( & chip - > als_mutex ) ;
2011-04-15 21:38:43 +04:00
get_options ( buf , ARRAY_SIZE ( value ) , value ) ;
2016-11-12 21:19:28 +03:00
/*
* We now have an array of ints starting at value [ 1 ] , and
2011-04-15 21:38:43 +04:00
* enumerated by value [ 0 ] .
* We expect each group of three ints is one table entry ,
* and the last table entry is all 0.
*/
n = value [ 0 ] ;
2016-11-12 21:19:34 +03:00
if ( ( n % 3 ) | | n < 6 | | n > max_ints ) {
2016-11-12 21:19:22 +03:00
dev_err ( dev ,
2016-11-12 21:19:34 +03:00
" %s: The number of entries in the lux table must be a multiple of 3 and within the range [6, %d] \n " ,
__func__ , max_ints ) ;
2016-10-28 13:00:16 +03:00
goto done ;
2011-04-15 21:38:43 +04:00
}
2016-11-12 21:19:32 +03:00
if ( ( value [ n - 2 ] | value [ n - 1 ] | value [ n ] ) ! = 0 ) {
2016-11-12 21:19:22 +03:00
dev_err ( dev , " %s: The last 3 entries in the lux table must be zeros. \n " ,
__func__ ) ;
2016-10-28 13:00:16 +03:00
goto done ;
2011-04-15 21:38:43 +04:00
}
2016-11-12 21:19:34 +03:00
memcpy ( chip - > als_settings . als_device_lux , & value [ 1 ] ,
value [ 0 ] * sizeof ( value [ 1 ] ) ) ;
2011-04-15 21:38:43 +04:00
2016-10-28 13:00:16 +03:00
ret = len ;
done :
2016-10-28 13:00:21 +03:00
mutex_unlock ( & chip - > als_mutex ) ;
2016-10-28 13:00:16 +03:00
return ret ;
2011-04-15 21:38:43 +04:00
}
2016-10-28 13:00:19 +03:00
static IIO_CONST_ATTR ( in_illuminance_calibscale_available , " 1 8 16 111 " ) ;
static IIO_CONST_ATTR ( in_illuminance_integration_time_available ,
2018-05-13 03:20:39 +03:00
" 0.050 0.100 0.150 0.200 0.250 0.300 0.350 0.400 0.450 0.500 0.550 0.600 0.650 " ) ;
2016-10-28 13:00:19 +03:00
static IIO_DEVICE_ATTR_RW ( in_illuminance_input_target , 0 ) ;
static IIO_DEVICE_ATTR_WO ( in_illuminance_calibrate , 0 ) ;
static IIO_DEVICE_ATTR_RW ( in_illuminance_lux_table , 0 ) ;
2011-04-15 21:38:43 +04:00
static struct attribute * sysfs_attrs_ctrl [ ] = {
2016-10-28 13:00:19 +03:00
& iio_const_attr_in_illuminance_calibscale_available . dev_attr . attr ,
& iio_const_attr_in_illuminance_integration_time_available . dev_attr . attr ,
& iio_dev_attr_in_illuminance_input_target . dev_attr . attr ,
& iio_dev_attr_in_illuminance_calibrate . dev_attr . attr ,
& iio_dev_attr_in_illuminance_lux_table . dev_attr . attr ,
2011-04-15 21:38:43 +04:00
NULL
} ;
2016-09-26 08:01:39 +03:00
static const struct attribute_group tsl2583_attribute_group = {
2011-04-15 21:38:43 +04:00
. attrs = sysfs_attrs_ctrl ,
} ;
2016-10-28 13:00:17 +03:00
static const struct iio_chan_spec tsl2583_channels [ ] = {
{
. type = IIO_LIGHT ,
. modified = 1 ,
. channel2 = IIO_MOD_LIGHT_IR ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
} ,
{
. type = IIO_LIGHT ,
. modified = 1 ,
. channel2 = IIO_MOD_LIGHT_BOTH ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
} ,
{
. type = IIO_LIGHT ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) |
BIT ( IIO_CHAN_INFO_CALIBBIAS ) |
2016-10-28 13:00:18 +03:00
BIT ( IIO_CHAN_INFO_CALIBSCALE ) |
2016-10-28 13:00:17 +03:00
BIT ( IIO_CHAN_INFO_INT_TIME ) ,
} ,
} ;
2017-04-25 11:06:33 +03:00
static int tsl2583_set_pm_runtime_busy ( struct tsl2583_chip * chip , bool on )
{
int ret ;
if ( on ) {
2021-05-09 14:33:29 +03:00
ret = pm_runtime_resume_and_get ( & chip - > client - > dev ) ;
2017-04-25 11:06:33 +03:00
} else {
pm_runtime_mark_last_busy ( & chip - > client - > dev ) ;
ret = pm_runtime_put_autosuspend ( & chip - > client - > dev ) ;
}
return ret ;
}
2016-10-28 13:00:17 +03:00
static int tsl2583_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2017-04-25 11:06:33 +03:00
int ret , pm_ret ;
2016-10-28 13:00:17 +03:00
2017-04-25 11:06:33 +03:00
ret = tsl2583_set_pm_runtime_busy ( chip , true ) ;
if ( ret < 0 )
return ret ;
2016-10-28 13:00:17 +03:00
2017-04-25 11:06:33 +03:00
mutex_lock ( & chip - > als_mutex ) ;
2016-10-28 13:00:17 +03:00
2017-04-25 11:06:33 +03:00
ret = - EINVAL ;
2016-10-28 13:00:17 +03:00
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
if ( chan - > type = = IIO_LIGHT ) {
2016-11-12 21:19:23 +03:00
ret = tsl2583_get_lux ( indio_dev ) ;
2016-10-28 13:00:17 +03:00
if ( ret < 0 )
goto read_done ;
/*
* From page 20 of the TSL2581 , TSL2583 data
* sheet ( TAOS134 − MARCH 2011 ) :
*
* One of the photodiodes ( channel 0 ) is
* sensitive to both visible and infrared light ,
* while the second photodiode ( channel 1 ) is
* sensitive primarily to infrared light .
*/
if ( chan - > channel2 = = IIO_MOD_LIGHT_BOTH )
* val = chip - > als_cur_info . als_ch0 ;
else
* val = chip - > als_cur_info . als_ch1 ;
ret = IIO_VAL_INT ;
}
break ;
case IIO_CHAN_INFO_PROCESSED :
if ( chan - > type = = IIO_LIGHT ) {
2016-11-12 21:19:23 +03:00
ret = tsl2583_get_lux ( indio_dev ) ;
2016-10-28 13:00:17 +03:00
if ( ret < 0 )
goto read_done ;
* val = ret ;
ret = IIO_VAL_INT ;
}
break ;
case IIO_CHAN_INFO_CALIBBIAS :
if ( chan - > type = = IIO_LIGHT ) {
2016-11-12 21:19:23 +03:00
* val = chip - > als_settings . als_gain_trim ;
2016-10-28 13:00:17 +03:00
ret = IIO_VAL_INT ;
}
break ;
2016-10-28 13:00:18 +03:00
case IIO_CHAN_INFO_CALIBSCALE :
if ( chan - > type = = IIO_LIGHT ) {
2016-11-12 21:19:23 +03:00
* val = gainadj [ chip - > als_settings . als_gain ] . mean ;
2016-10-28 13:00:18 +03:00
ret = IIO_VAL_INT ;
}
break ;
2016-10-28 13:00:17 +03:00
case IIO_CHAN_INFO_INT_TIME :
if ( chan - > type = = IIO_LIGHT ) {
* val = 0 ;
2016-11-12 21:19:23 +03:00
* val2 = chip - > als_settings . als_time ;
2016-10-28 13:00:17 +03:00
ret = IIO_VAL_INT_PLUS_MICRO ;
}
break ;
default :
break ;
}
read_done :
mutex_unlock ( & chip - > als_mutex ) ;
2021-05-09 14:33:29 +03:00
if ( ret < 0 ) {
tsl2583_set_pm_runtime_busy ( chip , false ) ;
2017-04-25 11:06:33 +03:00
return ret ;
2021-05-09 14:33:29 +03:00
}
2017-04-25 11:06:33 +03:00
/*
* Preserve the ret variable if the call to
* tsl2583_set_pm_runtime_busy ( ) is successful so the reading
* ( if applicable ) is returned to user space .
*/
pm_ret = tsl2583_set_pm_runtime_busy ( chip , false ) ;
if ( pm_ret < 0 )
return pm_ret ;
2016-10-28 13:00:17 +03:00
return ret ;
}
static int tsl2583_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
{
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2017-04-25 11:06:33 +03:00
int ret ;
2016-10-28 13:00:17 +03:00
2017-04-25 11:06:33 +03:00
ret = tsl2583_set_pm_runtime_busy ( chip , true ) ;
if ( ret < 0 )
return ret ;
2016-10-28 13:00:17 +03:00
2017-04-25 11:06:33 +03:00
mutex_lock ( & chip - > als_mutex ) ;
2016-10-28 13:00:17 +03:00
2017-04-25 11:06:33 +03:00
ret = - EINVAL ;
2016-10-28 13:00:17 +03:00
switch ( mask ) {
case IIO_CHAN_INFO_CALIBBIAS :
if ( chan - > type = = IIO_LIGHT ) {
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_gain_trim = val ;
2016-10-28 13:00:17 +03:00
ret = 0 ;
}
break ;
2016-10-28 13:00:18 +03:00
case IIO_CHAN_INFO_CALIBSCALE :
if ( chan - > type = = IIO_LIGHT ) {
2016-11-12 21:19:25 +03:00
unsigned int i ;
2016-10-28 13:00:18 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( gainadj ) ; i + + ) {
if ( gainadj [ i ] . mean = = val ) {
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_gain = i ;
2016-11-10 12:25:38 +03:00
ret = tsl2583_set_als_gain ( chip ) ;
2016-10-28 13:00:18 +03:00
break ;
}
}
}
break ;
2016-10-28 13:00:17 +03:00
case IIO_CHAN_INFO_INT_TIME :
if ( chan - > type = = IIO_LIGHT & & ! val & & val2 > = 50 & &
val2 < = 650 & & ! ( val2 % 50 ) ) {
2016-11-12 21:19:23 +03:00
chip - > als_settings . als_time = val2 ;
2016-11-10 12:25:38 +03:00
ret = tsl2583_set_als_time ( chip ) ;
2016-10-28 13:00:17 +03:00
}
break ;
default :
break ;
}
mutex_unlock ( & chip - > als_mutex ) ;
2021-05-09 14:33:29 +03:00
if ( ret < 0 ) {
tsl2583_set_pm_runtime_busy ( chip , false ) ;
2017-04-25 11:06:33 +03:00
return ret ;
2021-05-09 14:33:29 +03:00
}
2017-04-25 11:06:33 +03:00
ret = tsl2583_set_pm_runtime_busy ( chip , false ) ;
if ( ret < 0 )
return ret ;
2016-10-28 13:00:17 +03:00
return ret ;
}
2011-05-18 17:42:37 +04:00
static const struct iio_info tsl2583_info = {
. attrs = & tsl2583_attribute_group ,
2016-10-28 13:00:17 +03:00
. read_raw = tsl2583_read_raw ,
. write_raw = tsl2583_write_raw ,
2011-05-18 17:42:37 +04:00
} ;
2016-11-12 21:19:23 +03:00
static int tsl2583_probe ( struct i2c_client * clientp ,
const struct i2c_device_id * idp )
2011-04-15 21:38:43 +04:00
{
2016-11-03 15:56:13 +03:00
int ret ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip ;
struct iio_dev * indio_dev ;
2011-04-15 21:38:43 +04:00
if ( ! i2c_check_functionality ( clientp - > adapter ,
2016-02-18 10:35:36 +03:00
I2C_FUNC_SMBUS_BYTE_DATA ) ) {
2016-11-12 21:19:22 +03:00
dev_err ( & clientp - > dev , " %s: i2c smbus byte data functionality is unsupported \n " ,
__func__ ) ;
2011-04-15 21:38:43 +04:00
return - EOPNOTSUPP ;
}
2013-09-05 13:29:00 +04:00
indio_dev = devm_iio_device_alloc ( & clientp - > dev , sizeof ( * chip ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2016-11-12 21:19:26 +03:00
2011-08-12 20:08:52 +04:00
chip = iio_priv ( indio_dev ) ;
2011-04-15 21:38:43 +04:00
chip - > client = clientp ;
2011-08-12 20:08:52 +04:00
i2c_set_clientdata ( clientp , indio_dev ) ;
2011-04-15 21:38:43 +04:00
mutex_init ( & chip - > als_mutex ) ;
2016-11-03 15:56:13 +03:00
ret = i2c_smbus_read_byte_data ( clientp ,
2016-11-12 21:19:23 +03:00
TSL2583_CMD_REG | TSL2583_CHIPID ) ;
2016-11-03 15:56:13 +03:00
if ( ret < 0 ) {
dev_err ( & clientp - > dev ,
2016-11-12 21:19:22 +03:00
" %s: failed to read the chip ID register \n " , __func__ ) ;
2016-11-03 15:56:13 +03:00
return ret ;
2011-04-15 21:38:43 +04:00
}
2016-11-03 15:56:13 +03:00
if ( ( ret & TSL2583_CHIP_ID_MASK ) ! = TSL2583_CHIP_ID ) {
2016-11-12 21:19:22 +03:00
dev_err ( & clientp - > dev , " %s: received an unknown chip ID %x \n " ,
__func__ , ret ) ;
2013-09-05 13:29:00 +04:00
return - EINVAL ;
2011-04-15 21:38:43 +04:00
}
2011-08-12 20:08:52 +04:00
indio_dev - > info = & tsl2583_info ;
2016-10-28 13:00:17 +03:00
indio_dev - > channels = tsl2583_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( tsl2583_channels ) ;
2011-08-12 20:08:52 +04:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > name = chip - > client - > name ;
2016-11-12 21:19:26 +03:00
2017-04-25 11:06:33 +03:00
pm_runtime_enable ( & clientp - > dev ) ;
pm_runtime_set_autosuspend_delay ( & clientp - > dev ,
TSL2583_POWER_OFF_DELAY_MS ) ;
pm_runtime_use_autosuspend ( & clientp - > dev ) ;
2015-10-02 13:37:49 +03:00
ret = devm_iio_device_register ( indio_dev - > dev . parent , indio_dev ) ;
2011-04-15 21:38:43 +04:00
if ( ret ) {
2016-11-12 21:19:22 +03:00
dev_err ( & clientp - > dev , " %s: iio registration failed \n " ,
__func__ ) ;
2013-09-05 13:29:00 +04:00
return ret ;
2011-04-15 21:38:43 +04:00
}
/* Load up the V2 defaults (these are hard coded defaults for now) */
2016-11-12 21:19:23 +03:00
tsl2583_defaults ( chip ) ;
2011-04-15 21:38:43 +04:00
dev_info ( & clientp - > dev , " Light sensor found. \n " ) ;
2016-11-12 21:19:26 +03:00
2011-04-15 21:38:43 +04:00
return 0 ;
}
2017-04-25 11:06:33 +03:00
static int tsl2583_remove ( struct i2c_client * client )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
iio_device_unregister ( indio_dev ) ;
pm_runtime_disable ( & client - > dev ) ;
pm_runtime_set_suspended ( & client - > dev ) ;
2022-04-30 11:16:07 +03:00
tsl2583_set_power_state ( chip , TSL2583_CNTL_PWR_OFF ) ;
return 0 ;
2017-04-25 11:06:33 +03:00
}
2022-06-21 23:27:13 +03:00
static int tsl2583_suspend ( struct device * dev )
2011-04-15 21:38:43 +04:00
{
2012-02-20 22:37:05 +04:00
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-11-12 21:19:39 +03:00
int ret ;
2011-04-15 21:38:43 +04:00
mutex_lock ( & chip - > als_mutex ) ;
2016-11-12 21:19:23 +03:00
ret = tsl2583_set_power_state ( chip , TSL2583_CNTL_PWR_OFF ) ;
2011-04-15 21:38:43 +04:00
mutex_unlock ( & chip - > als_mutex ) ;
2016-11-12 21:19:26 +03:00
2011-04-15 21:38:43 +04:00
return ret ;
}
2022-06-21 23:27:13 +03:00
static int tsl2583_resume ( struct device * dev )
2011-04-15 21:38:43 +04:00
{
2012-02-20 22:37:05 +04:00
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
2011-08-12 20:08:52 +04:00
struct tsl2583_chip * chip = iio_priv ( indio_dev ) ;
2016-11-12 21:19:39 +03:00
int ret ;
2011-04-15 21:38:43 +04:00
mutex_lock ( & chip - > als_mutex ) ;
2016-11-12 21:19:18 +03:00
ret = tsl2583_chip_init_and_power_on ( indio_dev ) ;
2011-04-15 21:38:43 +04:00
mutex_unlock ( & chip - > als_mutex ) ;
2016-11-12 21:19:26 +03:00
2011-04-15 21:38:43 +04:00
return ret ;
}
2022-06-21 23:27:13 +03:00
static DEFINE_RUNTIME_DEV_PM_OPS ( tsl2583_pm_ops , tsl2583_suspend ,
tsl2583_resume , NULL ) ;
2011-04-15 21:38:43 +04:00
2017-08-19 21:47:38 +03:00
static const struct i2c_device_id tsl2583_idtable [ ] = {
2011-04-15 21:38:43 +04:00
{ " tsl2580 " , 0 } ,
{ " tsl2581 " , 1 } ,
{ " tsl2583 " , 2 } ,
{ }
} ;
2016-11-12 21:19:23 +03:00
MODULE_DEVICE_TABLE ( i2c , tsl2583_idtable ) ;
2011-04-15 21:38:43 +04:00
2016-11-12 21:19:23 +03:00
static const struct of_device_id tsl2583_of_match [ ] = {
2016-10-28 13:00:12 +03:00
{ . compatible = " amstaos,tsl2580 " , } ,
{ . compatible = " amstaos,tsl2581 " , } ,
{ . compatible = " amstaos,tsl2583 " , } ,
{ } ,
} ;
2016-11-12 21:19:23 +03:00
MODULE_DEVICE_TABLE ( of , tsl2583_of_match ) ;
2016-10-28 13:00:12 +03:00
2011-04-15 21:38:43 +04:00
/* Driver definition */
2016-11-12 21:19:23 +03:00
static struct i2c_driver tsl2583_driver = {
2011-04-15 21:38:43 +04:00
. driver = {
. name = " tsl2583 " ,
2022-06-21 23:27:13 +03:00
. pm = pm_ptr ( & tsl2583_pm_ops ) ,
2016-11-12 21:19:23 +03:00
. of_match_table = tsl2583_of_match ,
2011-04-15 21:38:43 +04:00
} ,
2016-11-12 21:19:23 +03:00
. id_table = tsl2583_idtable ,
. probe = tsl2583_probe ,
2017-04-25 11:06:33 +03:00
. remove = tsl2583_remove ,
2011-04-15 21:38:43 +04:00
} ;
2016-11-12 21:19:23 +03:00
module_i2c_driver ( tsl2583_driver ) ;
2011-04-15 21:38:43 +04:00
2016-11-12 21:19:40 +03:00
MODULE_AUTHOR ( " J. August Brenner <jbrenner@taosinc.com> " ) ;
MODULE_AUTHOR ( " Brian Masney <masneyb@onstation.org> " ) ;
2011-04-15 21:38:43 +04:00
MODULE_DESCRIPTION ( " TAOS tsl2583 ambient light sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;