2019-05-29 16:57:44 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-10-01 22:01:00 +01:00
/*
2021-11-06 18:41:37 +01:00
* Support for Lite - On LTR501 and similar ambient light and proximity sensors .
2014-10-01 22:01:00 +01:00
*
* Copyright 2014 Peter Meerwald < pmeerw @ pmeerw . net >
*
* 7 - bit I2C slave address 0x23
*
2015-04-19 02:10:03 -07:00
* TODO : IR LED characteristics
2014-10-01 22:01:00 +01:00
*/
# include <linux/module.h>
# include <linux/i2c.h>
# include <linux/err.h>
# include <linux/delay.h>
2015-04-17 22:15:10 -07:00
# include <linux/regmap.h>
2015-04-19 02:10:04 -07:00
# include <linux/acpi.h>
2021-10-06 21:30:57 +05:00
# include <linux/regulator/consumer.h>
2014-10-01 22:01:00 +01:00
# include <linux/iio/iio.h>
2015-04-19 02:10:02 -07:00
# include <linux/iio/events.h>
2014-10-01 22:01:00 +01:00
# include <linux/iio/sysfs.h>
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/buffer.h>
# include <linux/iio/triggered_buffer.h>
# define LTR501_DRV_NAME "ltr501"
# define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */
# define LTR501_PS_CONTR 0x81 /* PS operation mode */
2015-04-19 02:10:03 -07:00
# define LTR501_PS_MEAS_RATE 0x84 /* measurement rate*/
2015-04-19 02:10:01 -07:00
# define LTR501_ALS_MEAS_RATE 0x85 /* ALS integ time, measurement rate*/
2014-10-01 22:01:00 +01:00
# define LTR501_PART_ID 0x86
# define LTR501_MANUFAC_ID 0x87
# define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */
2021-06-10 15:46:16 +02:00
# define LTR501_ALS_DATA1_UPPER 0x89 /* upper 8 bits of LTR501_ALS_DATA1 */
2014-10-01 22:01:00 +01:00
# define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */
2021-06-10 15:46:16 +02:00
# define LTR501_ALS_DATA0_UPPER 0x8b /* upper 8 bits of LTR501_ALS_DATA0 */
2014-10-01 22:01:00 +01:00
# define LTR501_ALS_PS_STATUS 0x8c
# define LTR501_PS_DATA 0x8d /* 16-bit, little endian */
2021-06-10 15:46:16 +02:00
# define LTR501_PS_DATA_UPPER 0x8e /* upper 8 bits of LTR501_PS_DATA */
2015-04-19 02:10:02 -07:00
# define LTR501_INTR 0x8f /* output mode, polarity, mode */
# define LTR501_PS_THRESH_UP 0x90 /* 11 bit, ps upper threshold */
# define LTR501_PS_THRESH_LOW 0x92 /* 11 bit, ps lower threshold */
# define LTR501_ALS_THRESH_UP 0x97 /* 16 bit, ALS upper threshold */
# define LTR501_ALS_THRESH_LOW 0x99 /* 16 bit, ALS lower threshold */
2015-04-19 02:10:03 -07:00
# define LTR501_INTR_PRST 0x9e /* ps thresh, als thresh */
2015-04-17 22:15:10 -07:00
# define LTR501_MAX_REG 0x9f
2014-10-01 22:01:00 +01:00
# define LTR501_ALS_CONTR_SW_RESET BIT(2)
# define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2))
# define LTR501_CONTR_PS_GAIN_SHIFT 2
# define LTR501_CONTR_ALS_GAIN_MASK BIT(3)
# define LTR501_CONTR_ACTIVE BIT(1)
2015-04-19 02:10:02 -07:00
# define LTR501_STATUS_ALS_INTR BIT(3)
2014-10-01 22:01:00 +01:00
# define LTR501_STATUS_ALS_RDY BIT(2)
2015-04-19 02:10:02 -07:00
# define LTR501_STATUS_PS_INTR BIT(1)
2014-10-01 22:01:00 +01:00
# define LTR501_STATUS_PS_RDY BIT(0)
# define LTR501_PS_DATA_MASK 0x7ff
2015-04-19 02:10:02 -07:00
# define LTR501_PS_THRESH_MASK 0x7ff
# define LTR501_ALS_THRESH_MASK 0xffff
2014-10-01 22:01:00 +01:00
2015-04-19 02:10:03 -07:00
# define LTR501_ALS_DEF_PERIOD 500000
# define LTR501_PS_DEF_PERIOD 100000
2015-04-17 22:15:10 -07:00
# define LTR501_REGMAP_NAME "ltr501_regmap"
2015-05-15 18:23:21 -07:00
# define LTR501_LUX_CONV(vis_coeff, vis_data, ir_coeff, ir_data) \
( ( vis_coeff * vis_data ) - ( ir_coeff * ir_data ) )
2015-04-19 02:10:01 -07:00
static const int int_time_mapping [ ] = { 100000 , 50000 , 200000 , 400000 } ;
static const struct reg_field reg_field_it =
REG_FIELD ( LTR501_ALS_MEAS_RATE , 3 , 4 ) ;
2015-04-19 02:10:02 -07:00
static const struct reg_field reg_field_als_intr =
REG_FIELD ( LTR501_INTR , 1 , 1 ) ;
2017-05-17 12:41:19 +02:00
static const struct reg_field reg_field_ps_intr =
REG_FIELD ( LTR501_INTR , 0 , 0 ) ;
2015-04-19 02:10:03 -07:00
static const struct reg_field reg_field_als_rate =
REG_FIELD ( LTR501_ALS_MEAS_RATE , 0 , 2 ) ;
static const struct reg_field reg_field_ps_rate =
REG_FIELD ( LTR501_PS_MEAS_RATE , 0 , 3 ) ;
static const struct reg_field reg_field_als_prst =
REG_FIELD ( LTR501_INTR_PRST , 0 , 3 ) ;
static const struct reg_field reg_field_ps_prst =
REG_FIELD ( LTR501_INTR_PRST , 4 , 7 ) ;
struct ltr501_samp_table {
int freq_val ; /* repetition frequency in micro HZ*/
int time_val ; /* repetition rate in micro seconds */
} ;
2015-04-19 02:10:01 -07:00
2015-04-21 19:10:59 +03:00
# define LTR501_RESERVED_GAIN -1
enum {
ltr501 = 0 ,
ltr559 ,
2015-04-21 19:11:00 +03:00
ltr301 ,
2021-11-06 18:41:37 +01:00
ltr303 ,
2015-04-21 19:10:59 +03:00
} ;
struct ltr501_gain {
int scale ;
int uscale ;
} ;
2020-05-02 11:52:37 +02:00
static const struct ltr501_gain ltr501_als_gain_tbl [ ] = {
2015-04-21 19:10:59 +03:00
{ 1 , 0 } ,
{ 0 , 5000 } ,
} ;
2020-05-02 11:52:37 +02:00
static const struct ltr501_gain ltr559_als_gain_tbl [ ] = {
2015-04-21 19:10:59 +03:00
{ 1 , 0 } ,
{ 0 , 500000 } ,
{ 0 , 250000 } ,
{ 0 , 125000 } ,
{ LTR501_RESERVED_GAIN , LTR501_RESERVED_GAIN } ,
{ LTR501_RESERVED_GAIN , LTR501_RESERVED_GAIN } ,
{ 0 , 20000 } ,
{ 0 , 10000 } ,
} ;
2020-05-02 11:52:37 +02:00
static const struct ltr501_gain ltr501_ps_gain_tbl [ ] = {
2015-04-21 19:10:59 +03:00
{ 1 , 0 } ,
{ 0 , 250000 } ,
{ 0 , 125000 } ,
{ 0 , 62500 } ,
} ;
2020-05-02 11:52:37 +02:00
static const struct ltr501_gain ltr559_ps_gain_tbl [ ] = {
2015-04-21 19:10:59 +03:00
{ 0 , 62500 } , /* x16 gain */
{ 0 , 31250 } , /* x32 gain */
{ 0 , 15625 } , /* bits X1 are for x64 gain */
{ 0 , 15624 } ,
} ;
struct ltr501_chip_info {
u8 partid ;
2020-05-02 11:52:37 +02:00
const struct ltr501_gain * als_gain ;
2015-04-21 19:10:59 +03:00
int als_gain_tbl_size ;
2020-05-02 11:52:37 +02:00
const struct ltr501_gain * ps_gain ;
2015-04-21 19:10:59 +03:00
int ps_gain_tbl_size ;
u8 als_mode_active ;
u8 als_gain_mask ;
u8 als_gain_shift ;
2015-04-21 19:11:00 +03:00
struct iio_chan_spec const * channels ;
const int no_channels ;
const struct iio_info * info ;
const struct iio_info * info_no_irq ;
2015-04-21 19:10:59 +03:00
} ;
2014-10-01 22:01:00 +01:00
struct ltr501_data {
struct i2c_client * client ;
struct mutex lock_als , lock_ps ;
2021-06-10 15:46:19 +02:00
const struct ltr501_chip_info * chip_info ;
2014-10-01 22:01:00 +01:00
u8 als_contr , ps_contr ;
2015-04-19 02:10:03 -07:00
int als_period , ps_period ; /* period in micro seconds */
2015-04-17 22:15:10 -07:00
struct regmap * regmap ;
2015-04-19 02:10:01 -07:00
struct regmap_field * reg_it ;
2015-04-19 02:10:02 -07:00
struct regmap_field * reg_als_intr ;
struct regmap_field * reg_ps_intr ;
2015-04-19 02:10:03 -07:00
struct regmap_field * reg_als_rate ;
struct regmap_field * reg_ps_rate ;
struct regmap_field * reg_als_prst ;
struct regmap_field * reg_ps_prst ;
2021-11-25 17:56:46 +05:00
uint32_t near_level ;
2015-04-19 02:10:03 -07:00
} ;
static const struct ltr501_samp_table ltr501_als_samp_table [ ] = {
{ 20000000 , 50000 } , { 10000000 , 100000 } ,
{ 5000000 , 200000 } , { 2000000 , 500000 } ,
{ 1000000 , 1000000 } , { 500000 , 2000000 } ,
{ 500000 , 2000000 } , { 500000 , 2000000 }
2014-10-01 22:01:00 +01:00
} ;
2015-04-19 02:10:03 -07:00
static const struct ltr501_samp_table ltr501_ps_samp_table [ ] = {
{ 20000000 , 50000 } , { 14285714 , 70000 } ,
{ 10000000 , 100000 } , { 5000000 , 200000 } ,
{ 2000000 , 500000 } , { 1000000 , 1000000 } ,
{ 500000 , 2000000 } , { 500000 , 2000000 } ,
{ 500000 , 2000000 }
} ;
2015-12-19 14:14:54 +01:00
static int ltr501_match_samp_freq ( const struct ltr501_samp_table * tab ,
2015-04-19 02:10:03 -07:00
int len , int val , int val2 )
{
int i , freq ;
freq = val * 1000000 + val2 ;
for ( i = 0 ; i < len ; i + + ) {
if ( tab [ i ] . freq_val = = freq )
return i ;
}
return - EINVAL ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_als_read_samp_freq ( const struct ltr501_data * data ,
2015-04-19 02:10:03 -07:00
int * val , int * val2 )
{
int ret , i ;
ret = regmap_field_read ( data - > reg_als_rate , & i ) ;
if ( ret < 0 )
return ret ;
if ( i < 0 | | i > = ARRAY_SIZE ( ltr501_als_samp_table ) )
return - EINVAL ;
* val = ltr501_als_samp_table [ i ] . freq_val / 1000000 ;
* val2 = ltr501_als_samp_table [ i ] . freq_val % 1000000 ;
return IIO_VAL_INT_PLUS_MICRO ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_ps_read_samp_freq ( const struct ltr501_data * data ,
2015-04-19 02:10:03 -07:00
int * val , int * val2 )
{
int ret , i ;
ret = regmap_field_read ( data - > reg_ps_rate , & i ) ;
if ( ret < 0 )
return ret ;
if ( i < 0 | | i > = ARRAY_SIZE ( ltr501_ps_samp_table ) )
return - EINVAL ;
* val = ltr501_ps_samp_table [ i ] . freq_val / 1000000 ;
* val2 = ltr501_ps_samp_table [ i ] . freq_val % 1000000 ;
return IIO_VAL_INT_PLUS_MICRO ;
}
static int ltr501_als_write_samp_freq ( struct ltr501_data * data ,
int val , int val2 )
{
int i , ret ;
i = ltr501_match_samp_freq ( ltr501_als_samp_table ,
ARRAY_SIZE ( ltr501_als_samp_table ) ,
val , val2 ) ;
if ( i < 0 )
return i ;
mutex_lock ( & data - > lock_als ) ;
ret = regmap_field_write ( data - > reg_als_rate , i ) ;
mutex_unlock ( & data - > lock_als ) ;
return ret ;
}
static int ltr501_ps_write_samp_freq ( struct ltr501_data * data ,
int val , int val2 )
{
int i , ret ;
i = ltr501_match_samp_freq ( ltr501_ps_samp_table ,
ARRAY_SIZE ( ltr501_ps_samp_table ) ,
val , val2 ) ;
if ( i < 0 )
return i ;
mutex_lock ( & data - > lock_ps ) ;
ret = regmap_field_write ( data - > reg_ps_rate , i ) ;
mutex_unlock ( & data - > lock_ps ) ;
return ret ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_als_read_samp_period ( const struct ltr501_data * data , int * val )
2015-04-19 02:10:03 -07:00
{
int ret , i ;
ret = regmap_field_read ( data - > reg_als_rate , & i ) ;
if ( ret < 0 )
return ret ;
if ( i < 0 | | i > = ARRAY_SIZE ( ltr501_als_samp_table ) )
return - EINVAL ;
* val = ltr501_als_samp_table [ i ] . time_val ;
return IIO_VAL_INT ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_ps_read_samp_period ( const struct ltr501_data * data , int * val )
2015-04-19 02:10:03 -07:00
{
int ret , i ;
ret = regmap_field_read ( data - > reg_ps_rate , & i ) ;
if ( ret < 0 )
return ret ;
if ( i < 0 | | i > = ARRAY_SIZE ( ltr501_ps_samp_table ) )
return - EINVAL ;
* val = ltr501_ps_samp_table [ i ] . time_val ;
return IIO_VAL_INT ;
}
2015-05-15 18:23:21 -07:00
/* IR and visible spectrum coeff's are given in data sheet */
static unsigned long ltr501_calculate_lux ( u16 vis_data , u16 ir_data )
{
unsigned long ratio , lux ;
if ( vis_data = = 0 )
return 0 ;
/* multiply numerator by 100 to avoid handling ratio < 1 */
ratio = DIV_ROUND_UP ( ir_data * 100 , ir_data + vis_data ) ;
if ( ratio < 45 )
lux = LTR501_LUX_CONV ( 1774 , vis_data , - 1105 , ir_data ) ;
else if ( ratio > = 45 & & ratio < 64 )
lux = LTR501_LUX_CONV ( 3772 , vis_data , 1336 , ir_data ) ;
else if ( ratio > = 64 & & ratio < 85 )
lux = LTR501_LUX_CONV ( 1690 , vis_data , 169 , ir_data ) ;
else
lux = 0 ;
return lux / 1000 ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_drdy ( const struct ltr501_data * data , u8 drdy_mask )
2014-10-01 22:01:00 +01:00
{
int tries = 100 ;
2015-04-17 22:15:10 -07:00
int ret , status ;
2014-10-01 22:01:00 +01:00
while ( tries - - ) {
2015-04-17 22:15:10 -07:00
ret = regmap_read ( data - > regmap , LTR501_ALS_PS_STATUS , & status ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
2015-04-17 22:15:10 -07:00
if ( ( status & drdy_mask ) = = drdy_mask )
2014-10-01 22:01:00 +01:00
return 0 ;
msleep ( 25 ) ;
}
dev_err ( & data - > client - > dev , " ltr501_drdy() failed, data not ready \n " ) ;
return - EIO ;
}
2015-04-19 02:10:01 -07:00
static int ltr501_set_it_time ( struct ltr501_data * data , int it )
{
int ret , i , index = - 1 , status ;
for ( i = 0 ; i < ARRAY_SIZE ( int_time_mapping ) ; i + + ) {
if ( int_time_mapping [ i ] = = it ) {
index = i ;
break ;
}
}
/* Make sure integ time index is valid */
if ( index < 0 )
return - EINVAL ;
ret = regmap_read ( data - > regmap , LTR501_ALS_CONTR , & status ) ;
if ( ret < 0 )
return ret ;
if ( status & LTR501_CONTR_ALS_GAIN_MASK ) {
/*
* 200 ms and 400 ms integ time can only be
* used in dynamic range 1
*/
if ( index > 1 )
return - EINVAL ;
} else
/* 50 ms integ time can only be used in dynamic range 2 */
if ( index = = 1 )
return - EINVAL ;
return regmap_field_write ( data - > reg_it , index ) ;
}
/* read int time in micro seconds */
2020-05-02 11:52:37 +02:00
static int ltr501_read_it_time ( const struct ltr501_data * data ,
int * val , int * val2 )
2015-04-19 02:10:01 -07:00
{
int ret , index ;
ret = regmap_field_read ( data - > reg_it , & index ) ;
if ( ret < 0 )
return ret ;
/* Make sure integ time index is valid */
if ( index < 0 | | index > = ARRAY_SIZE ( int_time_mapping ) )
return - EINVAL ;
* val2 = int_time_mapping [ index ] ;
* val = 0 ;
return IIO_VAL_INT_PLUS_MICRO ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_read_als ( const struct ltr501_data * data , __le16 buf [ 2 ] )
2014-10-01 22:01:00 +01:00
{
2015-04-17 22:15:10 -07:00
int ret ;
ret = ltr501_drdy ( data , LTR501_STATUS_ALS_RDY ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
/* always read both ALS channels in given order */
2015-04-17 22:15:10 -07:00
return regmap_bulk_read ( data - > regmap , LTR501_ALS_DATA1 ,
buf , 2 * sizeof ( __le16 ) ) ;
2014-10-01 22:01:00 +01:00
}
2020-05-02 11:52:37 +02:00
static int ltr501_read_ps ( const struct ltr501_data * data )
2014-10-01 22:01:00 +01:00
{
2021-06-10 15:46:18 +02:00
__le16 status ;
int ret ;
2015-04-17 22:15:10 -07:00
ret = ltr501_drdy ( data , LTR501_STATUS_PS_RDY ) ;
if ( ret < 0 )
return ret ;
ret = regmap_bulk_read ( data - > regmap , LTR501_PS_DATA ,
2021-06-10 15:46:18 +02:00
& status , sizeof ( status ) ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
2015-04-17 22:15:10 -07:00
2021-06-10 15:46:18 +02:00
return le16_to_cpu ( status ) ;
2014-10-01 22:01:00 +01:00
}
2020-05-02 11:52:37 +02:00
static int ltr501_read_intr_prst ( const struct ltr501_data * data ,
2015-04-19 02:10:03 -07:00
enum iio_chan_type type ,
int * val2 )
{
int ret , samp_period , prst ;
switch ( type ) {
case IIO_INTENSITY :
ret = regmap_field_read ( data - > reg_als_prst , & prst ) ;
if ( ret < 0 )
return ret ;
ret = ltr501_als_read_samp_period ( data , & samp_period ) ;
if ( ret < 0 )
return ret ;
* val2 = samp_period * prst ;
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_PROXIMITY :
ret = regmap_field_read ( data - > reg_ps_prst , & prst ) ;
if ( ret < 0 )
return ret ;
ret = ltr501_ps_read_samp_period ( data , & samp_period ) ;
if ( ret < 0 )
return ret ;
* val2 = samp_period * prst ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
static int ltr501_write_intr_prst ( struct ltr501_data * data ,
enum iio_chan_type type ,
int val , int val2 )
{
int ret , samp_period , new_val ;
unsigned long period ;
if ( val < 0 | | val2 < 0 )
return - EINVAL ;
/* period in microseconds */
period = ( ( val * 1000000 ) + val2 ) ;
switch ( type ) {
case IIO_INTENSITY :
ret = ltr501_als_read_samp_period ( data , & samp_period ) ;
if ( ret < 0 )
return ret ;
/* period should be atleast equal to sampling period */
if ( period < samp_period )
return - EINVAL ;
new_val = DIV_ROUND_UP ( period , samp_period ) ;
if ( new_val < 0 | | new_val > 0x0f )
return - EINVAL ;
mutex_lock ( & data - > lock_als ) ;
ret = regmap_field_write ( data - > reg_als_prst , new_val ) ;
mutex_unlock ( & data - > lock_als ) ;
if ( ret > = 0 )
data - > als_period = period ;
return ret ;
case IIO_PROXIMITY :
ret = ltr501_ps_read_samp_period ( data , & samp_period ) ;
if ( ret < 0 )
return ret ;
/* period should be atleast equal to rate */
if ( period < samp_period )
return - EINVAL ;
new_val = DIV_ROUND_UP ( period , samp_period ) ;
if ( new_val < 0 | | new_val > 0x0f )
return - EINVAL ;
mutex_lock ( & data - > lock_ps ) ;
ret = regmap_field_write ( data - > reg_ps_prst , new_val ) ;
mutex_unlock ( & data - > lock_ps ) ;
if ( ret > = 0 )
data - > ps_period = period ;
return ret ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
2021-11-25 17:56:46 +05:00
static ssize_t ltr501_read_near_level ( struct iio_dev * indio_dev ,
uintptr_t priv ,
const struct iio_chan_spec * chan ,
char * buf )
{
struct ltr501_data * data = iio_priv ( indio_dev ) ;
return sprintf ( buf , " %u \n " , data - > near_level ) ;
}
static const struct iio_chan_spec_ext_info ltr501_ext_info [ ] = {
{
. name = " nearlevel " ,
. shared = IIO_SEPARATE ,
. read = ltr501_read_near_level ,
} ,
{ /* sentinel */ }
} ;
2015-04-19 02:10:02 -07:00
static const struct iio_event_spec ltr501_als_event_spec [ ] = {
{
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_RISING ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_FALLING ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_EITHER ,
2015-04-19 02:10:03 -07:00
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) |
BIT ( IIO_EV_INFO_PERIOD ) ,
2015-04-19 02:10:02 -07:00
} ,
} ;
static const struct iio_event_spec ltr501_pxs_event_spec [ ] = {
{
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_RISING ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_FALLING ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) ,
} , {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_EITHER ,
2015-04-19 02:10:03 -07:00
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) |
BIT ( IIO_EV_INFO_PERIOD ) ,
2015-04-19 02:10:02 -07:00
} ,
} ;
# define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared, \
_evspec , _evsize ) { \
2014-10-01 22:01:00 +01:00
. type = IIO_INTENSITY , \
. modified = 1 , \
. address = ( _addr ) , \
. channel2 = ( _mod ) , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = ( _shared ) , \
. scan_index = ( _idx ) , \
. scan_type = { \
. sign = ' u ' , \
. realbits = 16 , \
. storagebits = 16 , \
. endianness = IIO_CPU , \
2015-04-19 02:10:02 -07:00
} , \
. event_spec = _evspec , \
. num_event_specs = _evsize , \
2014-10-01 22:01:00 +01:00
}
2015-05-15 18:23:21 -07:00
# define LTR501_LIGHT_CHANNEL() { \
. type = IIO_LIGHT , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) , \
. scan_index = - 1 , \
}
2014-10-01 22:01:00 +01:00
static const struct iio_chan_spec ltr501_channels [ ] = {
2015-05-15 18:23:21 -07:00
LTR501_LIGHT_CHANNEL ( ) ,
2015-04-19 02:10:02 -07:00
LTR501_INTENSITY_CHANNEL ( 0 , LTR501_ALS_DATA0 , IIO_MOD_LIGHT_BOTH , 0 ,
ltr501_als_event_spec ,
ARRAY_SIZE ( ltr501_als_event_spec ) ) ,
2014-10-01 22:01:00 +01:00
LTR501_INTENSITY_CHANNEL ( 1 , LTR501_ALS_DATA1 , IIO_MOD_LIGHT_IR ,
2015-04-19 02:10:01 -07:00
BIT ( IIO_CHAN_INFO_SCALE ) |
2015-04-19 02:10:03 -07:00
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2015-04-19 02:10:02 -07:00
NULL , 0 ) ,
2014-10-01 22:01:00 +01:00
{
. type = IIO_PROXIMITY ,
. address = LTR501_PS_DATA ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) ,
. scan_index = 2 ,
. scan_type = {
. sign = ' u ' ,
. realbits = 11 ,
. storagebits = 16 ,
. endianness = IIO_CPU ,
} ,
2015-04-19 02:10:02 -07:00
. event_spec = ltr501_pxs_event_spec ,
. num_event_specs = ARRAY_SIZE ( ltr501_pxs_event_spec ) ,
2021-11-25 17:56:46 +05:00
. ext_info = ltr501_ext_info ,
2014-10-01 22:01:00 +01:00
} ,
IIO_CHAN_SOFT_TIMESTAMP ( 3 ) ,
} ;
2015-04-21 19:11:00 +03:00
static const struct iio_chan_spec ltr301_channels [ ] = {
2015-05-15 18:23:21 -07:00
LTR501_LIGHT_CHANNEL ( ) ,
2015-04-21 19:11:00 +03:00
LTR501_INTENSITY_CHANNEL ( 0 , LTR501_ALS_DATA0 , IIO_MOD_LIGHT_BOTH , 0 ,
ltr501_als_event_spec ,
ARRAY_SIZE ( ltr501_als_event_spec ) ) ,
LTR501_INTENSITY_CHANNEL ( 1 , LTR501_ALS_DATA1 , IIO_MOD_LIGHT_IR ,
BIT ( IIO_CHAN_INFO_SCALE ) |
BIT ( IIO_CHAN_INFO_INT_TIME ) |
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
NULL , 0 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( 2 ) ,
} ;
2014-10-01 22:01:00 +01:00
static int ltr501_read_raw ( struct iio_dev * indio_dev ,
2015-04-09 17:17:47 +03:00
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
2014-10-01 22:01:00 +01:00
{
struct ltr501_data * data = iio_priv ( indio_dev ) ;
__le16 buf [ 2 ] ;
int ret , i ;
switch ( mask ) {
2015-05-15 18:23:21 -07:00
case IIO_CHAN_INFO_PROCESSED :
switch ( chan - > type ) {
case IIO_LIGHT :
2016-10-15 22:00:53 -07:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
return ret ;
2015-05-15 18:23:21 -07:00
mutex_lock ( & data - > lock_als ) ;
ret = ltr501_read_als ( data , buf ) ;
mutex_unlock ( & data - > lock_als ) ;
2016-10-15 22:00:53 -07:00
iio_device_release_direct_mode ( indio_dev ) ;
2015-05-15 18:23:21 -07:00
if ( ret < 0 )
return ret ;
* val = ltr501_calculate_lux ( le16_to_cpu ( buf [ 1 ] ) ,
le16_to_cpu ( buf [ 0 ] ) ) ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
2014-10-01 22:01:00 +01:00
case IIO_CHAN_INFO_RAW :
2016-10-15 22:00:53 -07:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
return ret ;
2014-10-01 22:01:00 +01:00
switch ( chan - > type ) {
case IIO_INTENSITY :
mutex_lock ( & data - > lock_als ) ;
ret = ltr501_read_als ( data , buf ) ;
mutex_unlock ( & data - > lock_als ) ;
if ( ret < 0 )
2016-10-15 22:00:53 -07:00
break ;
2014-10-01 22:01:00 +01:00
* val = le16_to_cpu ( chan - > address = = LTR501_ALS_DATA1 ?
2015-04-09 17:17:47 +03:00
buf [ 0 ] : buf [ 1 ] ) ;
2016-10-15 22:00:53 -07:00
ret = IIO_VAL_INT ;
break ;
2014-10-01 22:01:00 +01:00
case IIO_PROXIMITY :
mutex_lock ( & data - > lock_ps ) ;
ret = ltr501_read_ps ( data ) ;
mutex_unlock ( & data - > lock_ps ) ;
if ( ret < 0 )
2016-10-15 22:00:53 -07:00
break ;
2014-10-01 22:01:00 +01:00
* val = ret & LTR501_PS_DATA_MASK ;
2016-10-15 22:00:53 -07:00
ret = IIO_VAL_INT ;
break ;
2014-10-01 22:01:00 +01:00
default :
2016-10-15 22:00:53 -07:00
ret = - EINVAL ;
break ;
2014-10-01 22:01:00 +01:00
}
2016-10-15 22:00:53 -07:00
iio_device_release_direct_mode ( indio_dev ) ;
return ret ;
2014-10-01 22:01:00 +01:00
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_INTENSITY :
2015-04-21 19:10:59 +03:00
i = ( data - > als_contr & data - > chip_info - > als_gain_mask )
> > data - > chip_info - > als_gain_shift ;
* val = data - > chip_info - > als_gain [ i ] . scale ;
* val2 = data - > chip_info - > als_gain [ i ] . uscale ;
return IIO_VAL_INT_PLUS_MICRO ;
2014-10-01 22:01:00 +01:00
case IIO_PROXIMITY :
i = ( data - > ps_contr & LTR501_CONTR_PS_GAIN_MASK ) > >
LTR501_CONTR_PS_GAIN_SHIFT ;
2015-04-21 19:10:59 +03:00
* val = data - > chip_info - > ps_gain [ i ] . scale ;
* val2 = data - > chip_info - > ps_gain [ i ] . uscale ;
2014-10-01 22:01:00 +01:00
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
2015-04-19 02:10:01 -07:00
case IIO_CHAN_INFO_INT_TIME :
switch ( chan - > type ) {
case IIO_INTENSITY :
return ltr501_read_it_time ( data , val , val2 ) ;
default :
return - EINVAL ;
}
2015-04-19 02:10:03 -07:00
case IIO_CHAN_INFO_SAMP_FREQ :
switch ( chan - > type ) {
case IIO_INTENSITY :
return ltr501_als_read_samp_freq ( data , val , val2 ) ;
case IIO_PROXIMITY :
return ltr501_ps_read_samp_freq ( data , val , val2 ) ;
default :
return - EINVAL ;
}
2014-10-01 22:01:00 +01:00
}
return - EINVAL ;
}
2020-05-02 11:52:37 +02:00
static int ltr501_get_gain_index ( const struct ltr501_gain * gain , int size ,
2015-04-21 19:10:59 +03:00
int val , int val2 )
2014-10-01 22:01:00 +01:00
{
int i ;
2015-04-21 19:10:59 +03:00
for ( i = 0 ; i < size ; i + + )
if ( val = = gain [ i ] . scale & & val2 = = gain [ i ] . uscale )
2014-10-01 22:01:00 +01:00
return i ;
return - 1 ;
}
static int ltr501_write_raw ( struct iio_dev * indio_dev ,
2015-04-09 17:17:47 +03:00
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
2014-10-01 22:01:00 +01:00
{
struct ltr501_data * data = iio_priv ( indio_dev ) ;
2015-04-19 02:10:03 -07:00
int i , ret , freq_val , freq_val2 ;
2021-06-10 15:46:19 +02:00
const struct ltr501_chip_info * info = data - > chip_info ;
2014-10-01 22:01:00 +01:00
2016-10-15 22:02:19 -07:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
return ret ;
2014-10-01 22:01:00 +01:00
switch ( mask ) {
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_INTENSITY :
2015-04-21 19:10:59 +03:00
i = ltr501_get_gain_index ( info - > als_gain ,
info - > als_gain_tbl_size ,
val , val2 ) ;
2016-10-15 22:02:19 -07:00
if ( i < 0 ) {
ret = - EINVAL ;
break ;
}
2015-04-17 22:15:10 -07:00
2015-04-21 19:10:59 +03:00
data - > als_contr & = ~ info - > als_gain_mask ;
data - > als_contr | = i < < info - > als_gain_shift ;
2016-10-15 22:02:19 -07:00
ret = regmap_write ( data - > regmap , LTR501_ALS_CONTR ,
data - > als_contr ) ;
break ;
2014-10-01 22:01:00 +01:00
case IIO_PROXIMITY :
2015-04-21 19:10:59 +03:00
i = ltr501_get_gain_index ( info - > ps_gain ,
info - > ps_gain_tbl_size ,
val , val2 ) ;
2016-10-15 22:02:19 -07:00
if ( i < 0 ) {
ret = - EINVAL ;
break ;
}
2014-10-01 22:01:00 +01:00
data - > ps_contr & = ~ LTR501_CONTR_PS_GAIN_MASK ;
data - > ps_contr | = i < < LTR501_CONTR_PS_GAIN_SHIFT ;
2015-04-17 22:15:10 -07:00
2016-10-15 22:02:19 -07:00
ret = regmap_write ( data - > regmap , LTR501_PS_CONTR ,
data - > ps_contr ) ;
break ;
2014-10-01 22:01:00 +01:00
default :
2016-10-15 22:02:19 -07:00
ret = - EINVAL ;
break ;
2014-10-01 22:01:00 +01:00
}
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:01 -07:00
case IIO_CHAN_INFO_INT_TIME :
switch ( chan - > type ) {
case IIO_INTENSITY :
2016-10-15 22:02:19 -07:00
if ( val ! = 0 ) {
ret = - EINVAL ;
break ;
}
2015-04-19 02:10:01 -07:00
mutex_lock ( & data - > lock_als ) ;
2016-10-15 22:02:19 -07:00
ret = ltr501_set_it_time ( data , val2 ) ;
2015-04-19 02:10:01 -07:00
mutex_unlock ( & data - > lock_als ) ;
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:01 -07:00
default :
2016-10-15 22:02:19 -07:00
ret = - EINVAL ;
break ;
2015-04-19 02:10:01 -07:00
}
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:03 -07:00
case IIO_CHAN_INFO_SAMP_FREQ :
switch ( chan - > type ) {
case IIO_INTENSITY :
ret = ltr501_als_read_samp_freq ( data , & freq_val ,
& freq_val2 ) ;
if ( ret < 0 )
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:03 -07:00
ret = ltr501_als_write_samp_freq ( data , val , val2 ) ;
if ( ret < 0 )
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:03 -07:00
/* update persistence count when changing frequency */
ret = ltr501_write_intr_prst ( data , chan - > type ,
0 , data - > als_period ) ;
if ( ret < 0 )
2016-10-15 22:02:19 -07:00
ret = ltr501_als_write_samp_freq ( data , freq_val ,
freq_val2 ) ;
break ;
2015-04-19 02:10:03 -07:00
case IIO_PROXIMITY :
ret = ltr501_ps_read_samp_freq ( data , & freq_val ,
& freq_val2 ) ;
if ( ret < 0 )
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:03 -07:00
ret = ltr501_ps_write_samp_freq ( data , val , val2 ) ;
if ( ret < 0 )
2016-10-15 22:02:19 -07:00
break ;
2015-04-19 02:10:03 -07:00
/* update persistence count when changing frequency */
ret = ltr501_write_intr_prst ( data , chan - > type ,
0 , data - > ps_period ) ;
if ( ret < 0 )
2016-10-15 22:02:19 -07:00
ret = ltr501_ps_write_samp_freq ( data , freq_val ,
freq_val2 ) ;
break ;
2015-04-19 02:10:03 -07:00
default :
2016-10-15 22:02:19 -07:00
ret = - EINVAL ;
break ;
2015-04-19 02:10:03 -07:00
}
2016-10-15 22:02:19 -07:00
break ;
default :
ret = - EINVAL ;
break ;
2014-10-01 22:01:00 +01:00
}
2016-10-15 22:02:19 -07:00
iio_device_release_direct_mode ( indio_dev ) ;
return ret ;
2014-10-01 22:01:00 +01:00
}
2020-05-02 11:52:37 +02:00
static int ltr501_read_thresh ( const struct iio_dev * indio_dev ,
2015-04-19 02:10:02 -07: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 )
{
2020-05-02 11:52:37 +02:00
const struct ltr501_data * data = iio_priv ( indio_dev ) ;
2015-04-19 02:10:02 -07:00
int ret , thresh_data ;
switch ( chan - > type ) {
case IIO_INTENSITY :
switch ( dir ) {
case IIO_EV_DIR_RISING :
ret = regmap_bulk_read ( data - > regmap ,
LTR501_ALS_THRESH_UP ,
& thresh_data , 2 ) ;
if ( ret < 0 )
return ret ;
* val = thresh_data & LTR501_ALS_THRESH_MASK ;
return IIO_VAL_INT ;
case IIO_EV_DIR_FALLING :
ret = regmap_bulk_read ( data - > regmap ,
LTR501_ALS_THRESH_LOW ,
& thresh_data , 2 ) ;
if ( ret < 0 )
return ret ;
* val = thresh_data & LTR501_ALS_THRESH_MASK ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
case IIO_PROXIMITY :
switch ( dir ) {
case IIO_EV_DIR_RISING :
ret = regmap_bulk_read ( data - > regmap ,
LTR501_PS_THRESH_UP ,
& thresh_data , 2 ) ;
if ( ret < 0 )
return ret ;
* val = thresh_data & LTR501_PS_THRESH_MASK ;
return IIO_VAL_INT ;
case IIO_EV_DIR_FALLING :
ret = regmap_bulk_read ( data - > regmap ,
LTR501_PS_THRESH_LOW ,
& thresh_data , 2 ) ;
if ( ret < 0 )
return ret ;
* val = thresh_data & LTR501_PS_THRESH_MASK ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
default :
return - EINVAL ;
}
return - EINVAL ;
}
static int ltr501_write_thresh ( struct iio_dev * indio_dev ,
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 )
{
struct ltr501_data * data = iio_priv ( indio_dev ) ;
int ret ;
if ( val < 0 )
return - EINVAL ;
switch ( chan - > type ) {
case IIO_INTENSITY :
if ( val > LTR501_ALS_THRESH_MASK )
return - EINVAL ;
switch ( dir ) {
case IIO_EV_DIR_RISING :
mutex_lock ( & data - > lock_als ) ;
ret = regmap_bulk_write ( data - > regmap ,
LTR501_ALS_THRESH_UP ,
& val , 2 ) ;
mutex_unlock ( & data - > lock_als ) ;
return ret ;
case IIO_EV_DIR_FALLING :
mutex_lock ( & data - > lock_als ) ;
ret = regmap_bulk_write ( data - > regmap ,
LTR501_ALS_THRESH_LOW ,
& val , 2 ) ;
mutex_unlock ( & data - > lock_als ) ;
return ret ;
default :
return - EINVAL ;
}
case IIO_PROXIMITY :
if ( val > LTR501_PS_THRESH_MASK )
return - EINVAL ;
2015-05-15 16:42:56 -07:00
switch ( dir ) {
2015-04-19 02:10:02 -07:00
case IIO_EV_DIR_RISING :
mutex_lock ( & data - > lock_ps ) ;
ret = regmap_bulk_write ( data - > regmap ,
LTR501_PS_THRESH_UP ,
& val , 2 ) ;
mutex_unlock ( & data - > lock_ps ) ;
return ret ;
case IIO_EV_DIR_FALLING :
mutex_lock ( & data - > lock_ps ) ;
ret = regmap_bulk_write ( data - > regmap ,
LTR501_PS_THRESH_LOW ,
& val , 2 ) ;
mutex_unlock ( & data - > lock_ps ) ;
return ret ;
default :
return - EINVAL ;
}
default :
return - EINVAL ;
}
return - EINVAL ;
}
2015-04-19 02:10:03 -07:00
static int ltr501_read_event ( struct iio_dev * indio_dev ,
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 )
{
int ret ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
return ltr501_read_thresh ( indio_dev , chan , type , dir ,
info , val , val2 ) ;
case IIO_EV_INFO_PERIOD :
ret = ltr501_read_intr_prst ( iio_priv ( indio_dev ) ,
chan - > type , val2 ) ;
* val = * val2 / 1000000 ;
* val2 = * val2 % 1000000 ;
return ret ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
static int ltr501_write_event ( struct iio_dev * indio_dev ,
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 )
{
switch ( info ) {
case IIO_EV_INFO_VALUE :
if ( val2 ! = 0 )
return - EINVAL ;
return ltr501_write_thresh ( indio_dev , chan , type , dir ,
info , val , val2 ) ;
case IIO_EV_INFO_PERIOD :
return ltr501_write_intr_prst ( iio_priv ( indio_dev ) , chan - > type ,
val , val2 ) ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
2015-04-19 02:10:02 -07:00
static int ltr501_read_event_config ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir )
{
struct ltr501_data * data = iio_priv ( indio_dev ) ;
int ret , status ;
switch ( chan - > type ) {
case IIO_INTENSITY :
ret = regmap_field_read ( data - > reg_als_intr , & status ) ;
if ( ret < 0 )
return ret ;
return status ;
case IIO_PROXIMITY :
ret = regmap_field_read ( data - > reg_ps_intr , & status ) ;
if ( ret < 0 )
return ret ;
return status ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
static int ltr501_write_event_config ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir , int state )
{
struct ltr501_data * data = iio_priv ( indio_dev ) ;
int ret ;
/* only 1 and 0 are valid inputs */
2015-05-02 11:25:48 +01:00
if ( state ! = 1 & & state ! = 0 )
2015-04-19 02:10:02 -07:00
return - EINVAL ;
switch ( chan - > type ) {
case IIO_INTENSITY :
mutex_lock ( & data - > lock_als ) ;
ret = regmap_field_write ( data - > reg_als_intr , state ) ;
mutex_unlock ( & data - > lock_als ) ;
return ret ;
case IIO_PROXIMITY :
mutex_lock ( & data - > lock_ps ) ;
ret = regmap_field_write ( data - > reg_ps_intr , state ) ;
mutex_unlock ( & data - > lock_ps ) ;
return ret ;
default :
return - EINVAL ;
}
return - EINVAL ;
}
2015-04-21 19:10:59 +03:00
static ssize_t ltr501_show_proximity_scale_avail ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct ltr501_data * data = iio_priv ( dev_to_iio_dev ( dev ) ) ;
2021-06-10 15:46:19 +02:00
const struct ltr501_chip_info * info = data - > chip_info ;
2015-04-21 19:10:59 +03:00
ssize_t len = 0 ;
int i ;
for ( i = 0 ; i < info - > ps_gain_tbl_size ; i + + ) {
if ( info - > ps_gain [ i ] . scale = = LTR501_RESERVED_GAIN )
continue ;
len + = scnprintf ( buf + len , PAGE_SIZE - len , " %d.%06d " ,
info - > ps_gain [ i ] . scale ,
info - > ps_gain [ i ] . uscale ) ;
}
buf [ len - 1 ] = ' \n ' ;
return len ;
}
static ssize_t ltr501_show_intensity_scale_avail ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct ltr501_data * data = iio_priv ( dev_to_iio_dev ( dev ) ) ;
2021-06-10 15:46:19 +02:00
const struct ltr501_chip_info * info = data - > chip_info ;
2015-04-21 19:10:59 +03:00
ssize_t len = 0 ;
int i ;
for ( i = 0 ; i < info - > als_gain_tbl_size ; i + + ) {
if ( info - > als_gain [ i ] . scale = = LTR501_RESERVED_GAIN )
continue ;
len + = scnprintf ( buf + len , PAGE_SIZE - len , " %d.%06d " ,
info - > als_gain [ i ] . scale ,
info - > als_gain [ i ] . uscale ) ;
}
buf [ len - 1 ] = ' \n ' ;
return len ;
}
2015-04-19 02:10:01 -07:00
static IIO_CONST_ATTR_INT_TIME_AVAIL ( " 0.05 0.1 0.2 0.4 " ) ;
2015-04-19 02:10:03 -07:00
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL ( " 20 10 5 2 1 0.5 " ) ;
2014-10-01 22:01:00 +01:00
2015-04-21 19:10:59 +03:00
static IIO_DEVICE_ATTR ( in_proximity_scale_available , S_IRUGO ,
ltr501_show_proximity_scale_avail , NULL , 0 ) ;
static IIO_DEVICE_ATTR ( in_intensity_scale_available , S_IRUGO ,
ltr501_show_intensity_scale_avail , NULL , 0 ) ;
2014-10-01 22:01:00 +01:00
static struct attribute * ltr501_attributes [ ] = {
2015-04-21 19:10:59 +03:00
& iio_dev_attr_in_proximity_scale_available . dev_attr . attr ,
& iio_dev_attr_in_intensity_scale_available . dev_attr . attr ,
2015-04-19 02:10:01 -07:00
& iio_const_attr_integration_time_available . dev_attr . attr ,
2015-04-19 02:10:03 -07:00
& iio_const_attr_sampling_frequency_available . dev_attr . attr ,
2014-10-01 22:01:00 +01:00
NULL
} ;
2015-04-21 19:11:00 +03:00
static struct attribute * ltr301_attributes [ ] = {
& iio_dev_attr_in_intensity_scale_available . dev_attr . attr ,
& iio_const_attr_integration_time_available . dev_attr . attr ,
& iio_const_attr_sampling_frequency_available . dev_attr . attr ,
NULL
} ;
2014-10-01 22:01:00 +01:00
static const struct attribute_group ltr501_attribute_group = {
. attrs = ltr501_attributes ,
} ;
2015-04-21 19:11:00 +03:00
static const struct attribute_group ltr301_attribute_group = {
. attrs = ltr301_attributes ,
} ;
2015-04-19 02:10:02 -07:00
static const struct iio_info ltr501_info_no_irq = {
. read_raw = ltr501_read_raw ,
. write_raw = ltr501_write_raw ,
. attrs = & ltr501_attribute_group ,
} ;
2014-10-01 22:01:00 +01:00
static const struct iio_info ltr501_info = {
. read_raw = ltr501_read_raw ,
. write_raw = ltr501_write_raw ,
. attrs = & ltr501_attribute_group ,
2015-04-19 02:10:03 -07:00
. read_event_value = & ltr501_read_event ,
. write_event_value = & ltr501_write_event ,
2015-04-19 02:10:02 -07:00
. read_event_config = & ltr501_read_event_config ,
. write_event_config = & ltr501_write_event_config ,
2014-10-01 22:01:00 +01:00
} ;
2015-04-21 19:11:00 +03:00
static const struct iio_info ltr301_info_no_irq = {
. read_raw = ltr501_read_raw ,
. write_raw = ltr501_write_raw ,
. attrs = & ltr301_attribute_group ,
} ;
static const struct iio_info ltr301_info = {
. read_raw = ltr501_read_raw ,
. write_raw = ltr501_write_raw ,
. attrs = & ltr301_attribute_group ,
. read_event_value = & ltr501_read_event ,
. write_event_value = & ltr501_write_event ,
. read_event_config = & ltr501_read_event_config ,
. write_event_config = & ltr501_write_event_config ,
} ;
2021-06-10 15:46:19 +02:00
static const struct ltr501_chip_info ltr501_chip_info_tbl [ ] = {
2015-04-21 19:10:59 +03:00
[ ltr501 ] = {
. partid = 0x08 ,
. als_gain = ltr501_als_gain_tbl ,
. als_gain_tbl_size = ARRAY_SIZE ( ltr501_als_gain_tbl ) ,
. ps_gain = ltr501_ps_gain_tbl ,
. ps_gain_tbl_size = ARRAY_SIZE ( ltr501_ps_gain_tbl ) ,
. als_mode_active = BIT ( 0 ) | BIT ( 1 ) ,
. als_gain_mask = BIT ( 3 ) ,
. als_gain_shift = 3 ,
2015-04-21 19:11:00 +03:00
. info = & ltr501_info ,
. info_no_irq = & ltr501_info_no_irq ,
. channels = ltr501_channels ,
. no_channels = ARRAY_SIZE ( ltr501_channels ) ,
2015-04-21 19:10:59 +03:00
} ,
[ ltr559 ] = {
. partid = 0x09 ,
. als_gain = ltr559_als_gain_tbl ,
. als_gain_tbl_size = ARRAY_SIZE ( ltr559_als_gain_tbl ) ,
. ps_gain = ltr559_ps_gain_tbl ,
. ps_gain_tbl_size = ARRAY_SIZE ( ltr559_ps_gain_tbl ) ,
2021-06-10 15:46:17 +02:00
. als_mode_active = BIT ( 0 ) ,
2015-04-21 19:10:59 +03:00
. als_gain_mask = BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) ,
. als_gain_shift = 2 ,
2015-04-21 19:11:00 +03:00
. info = & ltr501_info ,
. info_no_irq = & ltr501_info_no_irq ,
. channels = ltr501_channels ,
. no_channels = ARRAY_SIZE ( ltr501_channels ) ,
} ,
[ ltr301 ] = {
. partid = 0x08 ,
. als_gain = ltr501_als_gain_tbl ,
. als_gain_tbl_size = ARRAY_SIZE ( ltr501_als_gain_tbl ) ,
. als_mode_active = BIT ( 0 ) | BIT ( 1 ) ,
. als_gain_mask = BIT ( 3 ) ,
. als_gain_shift = 3 ,
. info = & ltr301_info ,
. info_no_irq = & ltr301_info_no_irq ,
. channels = ltr301_channels ,
. no_channels = ARRAY_SIZE ( ltr301_channels ) ,
2015-04-21 19:10:59 +03:00
} ,
2021-11-06 18:41:37 +01:00
[ ltr303 ] = {
. partid = 0x0A ,
. als_gain = ltr559_als_gain_tbl ,
. als_gain_tbl_size = ARRAY_SIZE ( ltr559_als_gain_tbl ) ,
. als_mode_active = BIT ( 0 ) ,
. als_gain_mask = BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) ,
. als_gain_shift = 2 ,
. info = & ltr301_info ,
. info_no_irq = & ltr301_info_no_irq ,
. channels = ltr301_channels ,
. no_channels = ARRAY_SIZE ( ltr301_channels ) ,
} ,
2015-04-21 19:10:59 +03:00
} ;
2015-04-17 22:15:10 -07:00
static int ltr501_write_contr ( struct ltr501_data * data , u8 als_val , u8 ps_val )
2014-10-01 22:01:00 +01:00
{
2015-04-17 22:15:10 -07:00
int ret ;
ret = regmap_write ( data - > regmap , LTR501_ALS_CONTR , als_val ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
2015-04-17 22:15:10 -07:00
return regmap_write ( data - > regmap , LTR501_PS_CONTR , ps_val ) ;
2014-10-01 22:01:00 +01:00
}
static irqreturn_t ltr501_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct ltr501_data * data = iio_priv ( indio_dev ) ;
2020-07-22 16:50:48 +01:00
struct {
u16 channels [ 3 ] ;
s64 ts __aligned ( 8 ) ;
} scan ;
2014-10-01 22:01:00 +01:00
__le16 als_buf [ 2 ] ;
u8 mask = 0 ;
int j = 0 ;
2015-04-17 22:15:10 -07:00
int ret , psdata ;
2014-10-01 22:01:00 +01:00
2020-07-22 16:50:48 +01:00
memset ( & scan , 0 , sizeof ( scan ) ) ;
2014-10-01 22:01:00 +01:00
/* figure out which data needs to be ready */
if ( test_bit ( 0 , indio_dev - > active_scan_mask ) | |
2015-04-09 17:17:47 +03:00
test_bit ( 1 , indio_dev - > active_scan_mask ) )
2014-10-01 22:01:00 +01:00
mask | = LTR501_STATUS_ALS_RDY ;
if ( test_bit ( 2 , indio_dev - > active_scan_mask ) )
mask | = LTR501_STATUS_PS_RDY ;
ret = ltr501_drdy ( data , mask ) ;
if ( ret < 0 )
goto done ;
if ( mask & LTR501_STATUS_ALS_RDY ) {
2015-04-17 22:15:10 -07:00
ret = regmap_bulk_read ( data - > regmap , LTR501_ALS_DATA1 ,
2020-04-05 19:03:21 +01:00
als_buf , sizeof ( als_buf ) ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
2021-10-24 19:12:49 +02:00
goto done ;
2014-10-01 22:01:00 +01:00
if ( test_bit ( 0 , indio_dev - > active_scan_mask ) )
2020-07-22 16:50:48 +01:00
scan . channels [ j + + ] = le16_to_cpu ( als_buf [ 1 ] ) ;
2014-10-01 22:01:00 +01:00
if ( test_bit ( 1 , indio_dev - > active_scan_mask ) )
2020-07-22 16:50:48 +01:00
scan . channels [ j + + ] = le16_to_cpu ( als_buf [ 0 ] ) ;
2014-10-01 22:01:00 +01:00
}
if ( mask & LTR501_STATUS_PS_RDY ) {
2015-04-17 22:15:10 -07:00
ret = regmap_bulk_read ( data - > regmap , LTR501_PS_DATA ,
& psdata , 2 ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
goto done ;
2020-07-22 16:50:48 +01:00
scan . channels [ j + + ] = psdata & LTR501_PS_DATA_MASK ;
2014-10-01 22:01:00 +01:00
}
2020-07-22 16:50:48 +01:00
iio_push_to_buffers_with_timestamp ( indio_dev , & scan ,
2016-03-09 19:05:49 +01:00
iio_get_time_ns ( indio_dev ) ) ;
2014-10-01 22:01:00 +01:00
done :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
2015-04-19 02:10:02 -07:00
static irqreturn_t ltr501_interrupt_handler ( int irq , void * private )
{
struct iio_dev * indio_dev = private ;
struct ltr501_data * data = iio_priv ( indio_dev ) ;
int ret , status ;
ret = regmap_read ( data - > regmap , LTR501_ALS_PS_STATUS , & status ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev ,
" irq read int reg failed \n " ) ;
return IRQ_HANDLED ;
}
if ( status & LTR501_STATUS_ALS_INTR )
iio_push_event ( indio_dev ,
IIO_UNMOD_EVENT_CODE ( IIO_INTENSITY , 0 ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_EITHER ) ,
2016-03-09 19:05:49 +01:00
iio_get_time_ns ( indio_dev ) ) ;
2015-04-19 02:10:02 -07:00
if ( status & LTR501_STATUS_PS_INTR )
iio_push_event ( indio_dev ,
IIO_UNMOD_EVENT_CODE ( IIO_PROXIMITY , 0 ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_EITHER ) ,
2016-03-09 19:05:49 +01:00
iio_get_time_ns ( indio_dev ) ) ;
2015-04-19 02:10:02 -07:00
return IRQ_HANDLED ;
}
2014-10-01 22:01:00 +01:00
static int ltr501_init ( struct ltr501_data * data )
{
2015-04-17 22:15:10 -07:00
int ret , status ;
2014-10-01 22:01:00 +01:00
2015-04-17 22:15:10 -07:00
ret = regmap_read ( data - > regmap , LTR501_ALS_CONTR , & status ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
2015-06-28 12:31:53 +02:00
data - > als_contr = status | data - > chip_info - > als_mode_active ;
2015-04-17 22:15:10 -07:00
ret = regmap_read ( data - > regmap , LTR501_PS_CONTR , & status ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
2015-04-17 22:15:10 -07:00
data - > ps_contr = status | LTR501_CONTR_ACTIVE ;
2015-04-19 02:10:03 -07:00
ret = ltr501_read_intr_prst ( data , IIO_INTENSITY , & data - > als_period ) ;
if ( ret < 0 )
return ret ;
ret = ltr501_read_intr_prst ( data , IIO_PROXIMITY , & data - > ps_period ) ;
if ( ret < 0 )
return ret ;
2015-04-17 22:15:10 -07:00
return ltr501_write_contr ( data , data - > als_contr , data - > ps_contr ) ;
2014-10-01 22:01:00 +01:00
}
2015-04-17 22:15:10 -07:00
static bool ltr501_is_volatile_reg ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case LTR501_ALS_DATA1 :
2021-06-10 15:46:16 +02:00
case LTR501_ALS_DATA1_UPPER :
2015-04-17 22:15:10 -07:00
case LTR501_ALS_DATA0 :
2021-06-10 15:46:16 +02:00
case LTR501_ALS_DATA0_UPPER :
2015-04-17 22:15:10 -07:00
case LTR501_ALS_PS_STATUS :
case LTR501_PS_DATA :
2021-06-10 15:46:16 +02:00
case LTR501_PS_DATA_UPPER :
2015-04-17 22:15:10 -07:00
return true ;
default :
return false ;
}
}
2020-05-02 11:52:37 +02:00
static const struct regmap_config ltr501_regmap_config = {
2015-04-17 22:15:10 -07:00
. name = LTR501_REGMAP_NAME ,
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = LTR501_MAX_REG ,
. cache_type = REGCACHE_RBTREE ,
. volatile_reg = ltr501_is_volatile_reg ,
} ;
2015-04-01 18:50:17 +03:00
static int ltr501_powerdown ( struct ltr501_data * data )
{
2015-04-21 19:10:59 +03:00
return ltr501_write_contr ( data , data - > als_contr &
~ data - > chip_info - > als_mode_active ,
2015-04-01 18:50:17 +03:00
data - > ps_contr & ~ LTR501_CONTR_ACTIVE ) ;
}
2015-04-21 19:10:59 +03:00
static const char * ltr501_match_acpi_device ( struct device * dev , int * chip_idx )
{
const struct acpi_device_id * id ;
id = acpi_match_device ( dev - > driver - > acpi_match_table , dev ) ;
if ( ! id )
return NULL ;
* chip_idx = id - > driver_data ;
return dev_name ( dev ) ;
}
2022-11-18 23:37:43 +01:00
static int ltr501_probe ( struct i2c_client * client )
2014-10-01 22:01:00 +01:00
{
2022-11-18 23:37:43 +01:00
const struct i2c_device_id * id = i2c_client_get_device_id ( client ) ;
2022-10-16 17:34:05 +01:00
static const char * const regulator_names [ ] = { " vdd " , " vddio " } ;
2014-10-01 22:01:00 +01:00
struct ltr501_data * data ;
struct iio_dev * indio_dev ;
2015-04-17 22:15:10 -07:00
struct regmap * regmap ;
2015-04-21 19:10:59 +03:00
int ret , partid , chip_idx = 0 ;
const char * name = NULL ;
2014-10-01 22:01:00 +01:00
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
2015-04-17 22:15:10 -07:00
regmap = devm_regmap_init_i2c ( client , & ltr501_regmap_config ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( & client - > dev , " Regmap initialization failed. \n " ) ;
return PTR_ERR ( regmap ) ;
}
2014-10-01 22:01:00 +01:00
data = iio_priv ( indio_dev ) ;
i2c_set_clientdata ( client , indio_dev ) ;
data - > client = client ;
2015-04-17 22:15:10 -07:00
data - > regmap = regmap ;
2014-10-01 22:01:00 +01:00
mutex_init ( & data - > lock_als ) ;
mutex_init ( & data - > lock_ps ) ;
2022-10-16 17:34:05 +01:00
ret = devm_regulator_bulk_get_enable ( & client - > dev ,
ARRAY_SIZE ( regulator_names ) ,
regulator_names ) ;
2021-10-06 21:30:57 +05:00
if ( ret )
return dev_err_probe ( & client - > dev , ret ,
" Failed to get regulators \n " ) ;
2015-04-19 02:10:01 -07:00
data - > reg_it = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_it ) ;
if ( IS_ERR ( data - > reg_it ) ) {
dev_err ( & client - > dev , " Integ time reg field init failed. \n " ) ;
return PTR_ERR ( data - > reg_it ) ;
}
2015-04-19 02:10:02 -07:00
data - > reg_als_intr = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_als_intr ) ;
if ( IS_ERR ( data - > reg_als_intr ) ) {
dev_err ( & client - > dev , " ALS intr mode reg field init failed \n " ) ;
return PTR_ERR ( data - > reg_als_intr ) ;
}
data - > reg_ps_intr = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_ps_intr ) ;
if ( IS_ERR ( data - > reg_ps_intr ) ) {
dev_err ( & client - > dev , " PS intr mode reg field init failed. \n " ) ;
return PTR_ERR ( data - > reg_ps_intr ) ;
}
2015-04-19 02:10:03 -07:00
data - > reg_als_rate = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_als_rate ) ;
if ( IS_ERR ( data - > reg_als_rate ) ) {
dev_err ( & client - > dev , " ALS samp rate field init failed. \n " ) ;
return PTR_ERR ( data - > reg_als_rate ) ;
}
data - > reg_ps_rate = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_ps_rate ) ;
if ( IS_ERR ( data - > reg_ps_rate ) ) {
dev_err ( & client - > dev , " PS samp rate field init failed. \n " ) ;
return PTR_ERR ( data - > reg_ps_rate ) ;
}
data - > reg_als_prst = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_als_prst ) ;
if ( IS_ERR ( data - > reg_als_prst ) ) {
dev_err ( & client - > dev , " ALS prst reg field init failed \n " ) ;
return PTR_ERR ( data - > reg_als_prst ) ;
}
data - > reg_ps_prst = devm_regmap_field_alloc ( & client - > dev , regmap ,
reg_field_ps_prst ) ;
if ( IS_ERR ( data - > reg_ps_prst ) ) {
dev_err ( & client - > dev , " PS prst reg field init failed. \n " ) ;
return PTR_ERR ( data - > reg_ps_prst ) ;
}
2015-04-17 22:15:10 -07:00
ret = regmap_read ( data - > regmap , LTR501_PART_ID , & partid ) ;
2014-10-01 22:01:00 +01:00
if ( ret < 0 )
return ret ;
2015-04-21 19:10:59 +03:00
if ( id ) {
name = id - > name ;
chip_idx = id - > driver_data ;
} else if ( ACPI_HANDLE ( & client - > dev ) ) {
name = ltr501_match_acpi_device ( & client - > dev , & chip_idx ) ;
} else {
return - ENODEV ;
}
data - > chip_info = & ltr501_chip_info_tbl [ chip_idx ] ;
if ( ( partid > > 4 ) ! = data - > chip_info - > partid )
2014-10-01 22:01:00 +01:00
return - ENODEV ;
2021-11-25 17:56:46 +05:00
if ( device_property_read_u32 ( & client - > dev , " proximity-near-level " ,
& data - > near_level ) )
data - > near_level = 0 ;
2015-04-21 19:11:00 +03:00
indio_dev - > info = data - > chip_info - > info ;
indio_dev - > channels = data - > chip_info - > channels ;
indio_dev - > num_channels = data - > chip_info - > no_channels ;
2015-04-21 19:10:59 +03:00
indio_dev - > name = name ;
2014-10-01 22:01:00 +01:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
ret = ltr501_init ( data ) ;
if ( ret < 0 )
return ret ;
2015-04-19 02:10:02 -07:00
if ( client - > irq > 0 ) {
ret = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , ltr501_interrupt_handler ,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT ,
" ltr501_thresh_event " ,
indio_dev ) ;
if ( ret ) {
dev_err ( & client - > dev , " request irq (%d) failed \n " ,
client - > irq ) ;
return ret ;
}
} else {
2015-04-21 19:11:00 +03:00
indio_dev - > info = data - > chip_info - > info_no_irq ;
2015-04-19 02:10:02 -07:00
}
2014-10-01 22:01:00 +01:00
ret = iio_triggered_buffer_setup ( indio_dev , NULL ,
2015-04-09 17:17:47 +03:00
ltr501_trigger_handler , NULL ) ;
2014-10-01 22:01:00 +01:00
if ( ret )
2015-04-01 18:50:17 +03:00
goto powerdown_on_error ;
2014-10-01 22:01:00 +01:00
ret = iio_device_register ( indio_dev ) ;
if ( ret )
goto error_unreg_buffer ;
return 0 ;
error_unreg_buffer :
iio_triggered_buffer_cleanup ( indio_dev ) ;
2015-04-01 18:50:17 +03:00
powerdown_on_error :
ltr501_powerdown ( data ) ;
2014-10-01 22:01:00 +01:00
return ret ;
}
2022-08-15 10:02:30 +02:00
static void ltr501_remove ( struct i2c_client * client )
2014-10-01 22:01:00 +01:00
{
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
iio_device_unregister ( indio_dev ) ;
iio_triggered_buffer_cleanup ( indio_dev ) ;
ltr501_powerdown ( iio_priv ( indio_dev ) ) ;
}
static int ltr501_suspend ( struct device * dev )
{
struct ltr501_data * data = iio_priv ( i2c_get_clientdata (
2015-04-09 17:17:47 +03:00
to_i2c_client ( dev ) ) ) ;
2014-10-01 22:01:00 +01:00
return ltr501_powerdown ( data ) ;
}
static int ltr501_resume ( struct device * dev )
{
struct ltr501_data * data = iio_priv ( i2c_get_clientdata (
2015-04-09 17:17:47 +03:00
to_i2c_client ( dev ) ) ) ;
2014-10-01 22:01:00 +01:00
2015-04-17 22:15:10 -07:00
return ltr501_write_contr ( data , data - > als_contr ,
2014-10-01 22:01:00 +01:00
data - > ps_contr ) ;
}
2022-01-30 19:31:20 +00:00
static DEFINE_SIMPLE_DEV_PM_OPS ( ltr501_pm_ops , ltr501_suspend , ltr501_resume ) ;
2014-10-01 22:01:00 +01:00
2015-04-19 02:10:04 -07:00
static const struct acpi_device_id ltr_acpi_match [ ] = {
2021-12-30 17:49:00 +00:00
{ " LTER0501 " , ltr501 } ,
{ " LTER0559 " , ltr559 } ,
{ " LTER0301 " , ltr301 } ,
2015-04-19 02:10:04 -07:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( acpi , ltr_acpi_match ) ;
2014-10-01 22:01:00 +01:00
static const struct i2c_device_id ltr501_id [ ] = {
2021-12-30 17:49:00 +00:00
{ " ltr501 " , ltr501 } ,
{ " ltr559 " , ltr559 } ,
{ " ltr301 " , ltr301 } ,
{ " ltr303 " , ltr303 } ,
2014-10-01 22:01:00 +01:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ltr501_id ) ;
2021-10-06 21:30:58 +05:00
static const struct of_device_id ltr501_of_match [ ] = {
{ . compatible = " liteon,ltr501 " , } ,
{ . compatible = " liteon,ltr559 " , } ,
{ . compatible = " liteon,ltr301 " , } ,
2021-11-06 18:41:37 +01:00
{ . compatible = " liteon,ltr303 " , } ,
2021-10-06 21:30:58 +05:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , ltr501_of_match ) ;
2014-10-01 22:01:00 +01:00
static struct i2c_driver ltr501_driver = {
. driver = {
. name = LTR501_DRV_NAME ,
2021-10-06 21:30:58 +05:00
. of_match_table = ltr501_of_match ,
2022-01-30 19:31:20 +00:00
. pm = pm_sleep_ptr ( & ltr501_pm_ops ) ,
2015-04-19 02:10:04 -07:00
. acpi_match_table = ACPI_PTR ( ltr_acpi_match ) ,
2014-10-01 22:01:00 +01:00
} ,
2022-11-18 23:37:43 +01:00
. probe_new = ltr501_probe ,
2014-10-01 22:01:00 +01:00
. remove = ltr501_remove ,
. id_table = ltr501_id ,
} ;
module_i2c_driver ( ltr501_driver ) ;
MODULE_AUTHOR ( " Peter Meerwald <pmeerw@pmeerw.net> " ) ;
MODULE_DESCRIPTION ( " Lite-On LTR501 ambient light and proximity sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;