2014-12-03 16:31:48 +03:00
/*
* KMX61 - Kionix 6 - axis Accelerometer / Magnetometer
*
* Copyright ( c ) 2014 , Intel Corporation .
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License . See the file COPYING in the main
* directory of this archive for more details .
*
* IIO driver for KMX61 ( 7 - bit I2C slave address 0x0E or 0x0F ) .
*
*/
# include <linux/module.h>
# include <linux/i2c.h>
2014-12-03 16:31:49 +03:00
# include <linux/acpi.h>
# include <linux/gpio/consumer.h>
2014-12-03 16:31:50 +03:00
# include <linux/interrupt.h>
2014-12-03 16:31:51 +03:00
# include <linux/pm.h>
2014-12-03 16:31:50 +03:00
# include <linux/pm_runtime.h>
2014-12-03 16:31:48 +03:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2014-12-03 16:31:53 +03:00
# include <linux/iio/events.h>
2014-12-03 16:31:52 +03:00
# include <linux/iio/trigger.h>
# include <linux/iio/buffer.h>
# include <linux/iio/triggered_buffer.h>
# include <linux/iio/trigger_consumer.h>
2014-12-03 16:31:48 +03:00
# define KMX61_DRV_NAME "kmx61"
2014-12-03 16:31:49 +03:00
# define KMX61_GPIO_NAME "kmx61_int"
2014-12-03 16:31:52 +03:00
# define KMX61_IRQ_NAME "kmx61_event"
2014-12-03 16:31:48 +03:00
# define KMX61_REG_WHO_AM_I 0x00
2014-12-03 16:31:53 +03:00
# define KMX61_REG_INS1 0x01
# define KMX61_REG_INS2 0x02
2014-12-03 16:31:48 +03:00
/*
* three 16 - bit accelerometer output registers for X / Y / Z axis
* we use only XOUT_L as a base register , all other addresses
* can be obtained by applying an offset and are provided here
* only for clarity .
*/
# define KMX61_ACC_XOUT_L 0x0A
# define KMX61_ACC_XOUT_H 0x0B
# define KMX61_ACC_YOUT_L 0x0C
# define KMX61_ACC_YOUT_H 0x0D
# define KMX61_ACC_ZOUT_L 0x0E
# define KMX61_ACC_ZOUT_H 0x0F
/*
* one 16 - bit temperature output register
*/
# define KMX61_TEMP_L 0x10
# define KMX61_TEMP_H 0x11
/*
* three 16 - bit magnetometer output registers for X / Y / Z axis
*/
# define KMX61_MAG_XOUT_L 0x12
# define KMX61_MAG_XOUT_H 0x13
# define KMX61_MAG_YOUT_L 0x14
# define KMX61_MAG_YOUT_H 0x15
# define KMX61_MAG_ZOUT_L 0x16
# define KMX61_MAG_ZOUT_H 0x17
2014-12-03 16:31:52 +03:00
# define KMX61_REG_INL 0x28
2014-12-03 16:31:48 +03:00
# define KMX61_REG_STBY 0x29
# define KMX61_REG_CTRL1 0x2A
2014-12-03 16:31:53 +03:00
# define KMX61_REG_CTRL2 0x2B
2014-12-03 16:31:48 +03:00
# define KMX61_REG_ODCNTL 0x2C
2014-12-03 16:31:52 +03:00
# define KMX61_REG_INC1 0x2D
2014-12-03 16:31:48 +03:00
2014-12-03 16:31:53 +03:00
# define KMX61_REG_WUF_THRESH 0x3D
# define KMX61_REG_WUF_TIMER 0x3E
2014-12-03 16:31:48 +03:00
# define KMX61_ACC_STBY_BIT BIT(0)
# define KMX61_MAG_STBY_BIT BIT(1)
# define KMX61_ACT_STBY_BIT BIT(7)
# define KMX61_ALL_STBY (KMX61_ACC_STBY_BIT | KMX61_MAG_STBY_BIT)
2014-12-03 16:31:53 +03:00
# define KMX61_REG_INS1_BIT_WUFS BIT(1)
# define KMX61_REG_INS2_BIT_ZP BIT(0)
# define KMX61_REG_INS2_BIT_ZN BIT(1)
# define KMX61_REG_INS2_BIT_YP BIT(2)
# define KMX61_REG_INS2_BIT_YN BIT(3)
# define KMX61_REG_INS2_BIT_XP BIT(4)
# define KMX61_REG_INS2_BIT_XN BIT(5)
2014-12-03 16:31:48 +03:00
# define KMX61_REG_CTRL1_GSEL_MASK 0x03
2014-12-03 16:31:52 +03:00
# define KMX61_REG_CTRL1_BIT_RES BIT(4)
# define KMX61_REG_CTRL1_BIT_DRDYE BIT(5)
2014-12-03 16:31:53 +03:00
# define KMX61_REG_CTRL1_BIT_WUFE BIT(6)
# define KMX61_REG_CTRL1_BIT_BTSE BIT(7)
2014-12-03 16:31:52 +03:00
2014-12-03 16:31:53 +03:00
# define KMX61_REG_INC1_BIT_WUFS BIT(0)
2014-12-03 16:31:52 +03:00
# define KMX61_REG_INC1_BIT_DRDYM BIT(1)
# define KMX61_REG_INC1_BIT_DRDYA BIT(2)
# define KMX61_REG_INC1_BIT_IEN BIT(5)
2014-12-03 16:31:48 +03:00
# define KMX61_ACC_ODR_SHIFT 0
# define KMX61_MAG_ODR_SHIFT 4
# define KMX61_ACC_ODR_MASK 0x0F
# define KMX61_MAG_ODR_MASK 0xF0
2014-12-03 16:31:53 +03:00
# define KMX61_OWUF_MASK 0x7
# define KMX61_DEFAULT_WAKE_THRESH 1
# define KMX61_DEFAULT_WAKE_DURATION 1
2014-12-03 16:31:50 +03:00
# define KMX61_SLEEP_DELAY_MS 2000
2014-12-03 16:31:48 +03:00
# define KMX61_CHIP_ID 0x12
/* KMX61 devices */
# define KMX61_ACC 0x01
# define KMX61_MAG 0x02
struct kmx61_data {
struct i2c_client * client ;
/* serialize access to non-atomic ops, e.g set_mode */
struct mutex lock ;
/* standby state */
bool acc_stby ;
bool mag_stby ;
2014-12-03 16:31:50 +03:00
/* power state */
bool acc_ps ;
bool mag_ps ;
2014-12-03 16:31:48 +03:00
/* config bits */
u8 range ;
u8 odr_bits ;
2014-12-03 16:31:53 +03:00
u8 wake_thresh ;
u8 wake_duration ;
2014-12-03 16:31:48 +03:00
/* accelerometer specific data */
struct iio_dev * acc_indio_dev ;
2014-12-03 16:31:52 +03:00
struct iio_trigger * acc_dready_trig ;
2014-12-03 16:31:53 +03:00
struct iio_trigger * motion_trig ;
2014-12-03 16:31:52 +03:00
bool acc_dready_trig_on ;
2014-12-03 16:31:53 +03:00
bool motion_trig_on ;
bool ev_enable_state ;
2014-12-03 16:31:48 +03:00
/* magnetometer specific data */
struct iio_dev * mag_indio_dev ;
2014-12-03 16:31:52 +03:00
struct iio_trigger * mag_dready_trig ;
bool mag_dready_trig_on ;
2014-12-03 16:31:48 +03:00
} ;
enum kmx61_range {
KMX61_RANGE_2G ,
KMX61_RANGE_4G ,
KMX61_RANGE_8G ,
} ;
enum kmx61_axis {
KMX61_AXIS_X ,
KMX61_AXIS_Y ,
KMX61_AXIS_Z ,
} ;
static const u16 kmx61_uscale_table [ ] = { 9582 , 19163 , 38326 } ;
static const struct {
int val ;
int val2 ;
u8 odr_bits ;
} kmx61_samp_freq_table [ ] = { { 12 , 500000 , 0x00 } ,
{ 25 , 0 , 0x01 } ,
{ 50 , 0 , 0x02 } ,
{ 100 , 0 , 0x03 } ,
{ 200 , 0 , 0x04 } ,
{ 400 , 0 , 0x05 } ,
{ 800 , 0 , 0x06 } ,
{ 1600 , 0 , 0x07 } ,
{ 0 , 781000 , 0x08 } ,
{ 1 , 563000 , 0x09 } ,
{ 3 , 125000 , 0x0A } ,
{ 6 , 250000 , 0x0B } } ;
2014-12-03 16:31:53 +03:00
static const struct {
int val ;
int val2 ;
int odr_bits ;
} kmx61_wake_up_odr_table [ ] = { { 0 , 781000 , 0x00 } ,
{ 1 , 563000 , 0x01 } ,
{ 3 , 125000 , 0x02 } ,
{ 6 , 250000 , 0x03 } ,
{ 12 , 500000 , 0x04 } ,
{ 25 , 0 , 0x05 } ,
{ 50 , 0 , 0x06 } ,
{ 100 , 0 , 0x06 } ,
{ 200 , 0 , 0x06 } ,
{ 400 , 0 , 0x06 } ,
{ 800 , 0 , 0x06 } ,
{ 1600 , 0 , 0x06 } } ;
2014-12-03 16:31:48 +03:00
static IIO_CONST_ATTR ( accel_scale_available , " 0.009582 0.019163 0.038326 " ) ;
static IIO_CONST_ATTR ( magn_scale_available , " 0.001465 " ) ;
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL (
" 0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 " ) ;
static struct attribute * kmx61_acc_attributes [ ] = {
& iio_const_attr_accel_scale_available . dev_attr . attr ,
& iio_const_attr_sampling_frequency_available . dev_attr . attr ,
NULL ,
} ;
static struct attribute * kmx61_mag_attributes [ ] = {
& iio_const_attr_magn_scale_available . dev_attr . attr ,
& iio_const_attr_sampling_frequency_available . dev_attr . attr ,
NULL ,
} ;
static const struct attribute_group kmx61_acc_attribute_group = {
. attrs = kmx61_acc_attributes ,
} ;
static const struct attribute_group kmx61_mag_attribute_group = {
. attrs = kmx61_mag_attributes ,
} ;
2014-12-03 16:31:53 +03:00
static const struct iio_event_spec kmx61_event = {
. type = IIO_EV_TYPE_THRESH ,
. dir = IIO_EV_DIR_EITHER ,
. mask_separate = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_ENABLE ) |
BIT ( IIO_EV_INFO_PERIOD ) ,
} ;
2014-12-03 16:31:48 +03:00
# define KMX61_ACC_CHAN(_axis) { \
. type = IIO_ACCEL , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # _axis , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. address = KMX61_ACC , \
. scan_index = KMX61_AXIS_ # # _axis , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 12 , \
. storagebits = 16 , \
. shift = 4 , \
. endianness = IIO_LE , \
} , \
2014-12-03 16:31:53 +03:00
. event_spec = & kmx61_event , \
. num_event_specs = 1 \
2014-12-03 16:31:48 +03:00
}
# define KMX61_MAG_CHAN(_axis) { \
. type = IIO_MAGN , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # _axis , \
. address = KMX61_MAG , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. scan_index = KMX61_AXIS_ # # _axis , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 14 , \
. storagebits = 16 , \
. shift = 2 , \
. endianness = IIO_LE , \
} , \
}
static const struct iio_chan_spec kmx61_acc_channels [ ] = {
KMX61_ACC_CHAN ( X ) ,
KMX61_ACC_CHAN ( Y ) ,
KMX61_ACC_CHAN ( Z ) ,
} ;
static const struct iio_chan_spec kmx61_mag_channels [ ] = {
KMX61_MAG_CHAN ( X ) ,
KMX61_MAG_CHAN ( Y ) ,
KMX61_MAG_CHAN ( Z ) ,
} ;
static void kmx61_set_data ( struct iio_dev * indio_dev , struct kmx61_data * data )
{
struct kmx61_data * * priv = iio_priv ( indio_dev ) ;
* priv = data ;
}
static struct kmx61_data * kmx61_get_data ( struct iio_dev * indio_dev )
{
return * ( struct kmx61_data * * ) iio_priv ( indio_dev ) ;
}
static int kmx61_convert_freq_to_bit ( int val , int val2 )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( kmx61_samp_freq_table ) ; i + + )
if ( val = = kmx61_samp_freq_table [ i ] . val & &
val2 = = kmx61_samp_freq_table [ i ] . val2 )
return kmx61_samp_freq_table [ i ] . odr_bits ;
return - EINVAL ;
}
2014-12-03 16:31:53 +03:00
static int kmx61_convert_bit_to_freq ( u8 odr_bits , int * val , int * val2 )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( kmx61_samp_freq_table ) ; i + + )
if ( odr_bits = = kmx61_samp_freq_table [ i ] . odr_bits ) {
* val = kmx61_samp_freq_table [ i ] . val ;
* val2 = kmx61_samp_freq_table [ i ] . val2 ;
return 0 ;
}
return - EINVAL ;
}
static int kmx61_convert_wake_up_odr_to_bit ( int val , int val2 )
{
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( kmx61_wake_up_odr_table ) ; + + i )
if ( kmx61_wake_up_odr_table [ i ] . val = = val & &
kmx61_wake_up_odr_table [ i ] . val2 = = val2 )
return kmx61_wake_up_odr_table [ i ] . odr_bits ;
return - EINVAL ;
}
2014-12-03 16:31:48 +03:00
/**
* kmx61_set_mode ( ) - set KMX61 device operating mode
* @ data - kmx61 device private data pointer
* @ mode - bitmask , indicating operating mode for @ device
* @ device - bitmask , indicating device for which @ mode needs to be set
* @ update - update stby bits stored in device ' s private @ data
*
* For each sensor ( accelerometer / magnetometer ) there are two operating modes
* STANDBY and OPERATION . Neither accel nor magn can be disabled independently
* if they are both enabled . Internal sensors state is saved in acc_stby and
* mag_stby members of driver ' s private @ data .
*/
static int kmx61_set_mode ( struct kmx61_data * data , u8 mode , u8 device ,
bool update )
{
int ret ;
int acc_stby = - 1 , mag_stby = - 1 ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_STBY ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_stby \n " ) ;
return ret ;
}
if ( device & KMX61_ACC ) {
if ( mode & KMX61_ACC_STBY_BIT ) {
ret | = KMX61_ACC_STBY_BIT ;
acc_stby = 1 ;
} else {
ret & = ~ KMX61_ACC_STBY_BIT ;
acc_stby = 0 ;
}
}
if ( device & KMX61_MAG ) {
if ( mode & KMX61_MAG_STBY_BIT ) {
ret | = KMX61_MAG_STBY_BIT ;
mag_stby = 1 ;
} else {
ret & = ~ KMX61_MAG_STBY_BIT ;
mag_stby = 0 ;
}
}
if ( mode & KMX61_ACT_STBY_BIT )
ret | = KMX61_ACT_STBY_BIT ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_STBY , ret ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error writing reg_stby \n " ) ;
return ret ;
}
if ( acc_stby ! = - 1 & & update )
data - > acc_stby = acc_stby ;
if ( mag_stby ! = - 1 & & update )
data - > mag_stby = mag_stby ;
return 0 ;
}
static int kmx61_get_mode ( struct kmx61_data * data , u8 * mode , u8 device )
{
int ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_STBY ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_stby \n " ) ;
return ret ;
}
* mode = 0 ;
if ( device & KMX61_ACC ) {
if ( ret & KMX61_ACC_STBY_BIT )
* mode | = KMX61_ACC_STBY_BIT ;
else
* mode & = ~ KMX61_ACC_STBY_BIT ;
}
if ( device & KMX61_MAG ) {
if ( ret & KMX61_MAG_STBY_BIT )
* mode | = KMX61_MAG_STBY_BIT ;
else
* mode & = ~ KMX61_MAG_STBY_BIT ;
}
return 0 ;
}
2014-12-12 19:28:52 +03:00
static int kmx61_set_wake_up_odr ( struct kmx61_data * data , int val , int val2 )
2014-12-03 16:31:53 +03:00
{
int ret , odr_bits ;
odr_bits = kmx61_convert_wake_up_odr_to_bit ( val , val2 ) ;
if ( odr_bits < 0 )
return odr_bits ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_CTRL2 ,
odr_bits ) ;
if ( ret < 0 )
dev_err ( & data - > client - > dev , " Error writing reg_ctrl2 \n " ) ;
return ret ;
}
2014-12-03 16:31:48 +03:00
static int kmx61_set_odr ( struct kmx61_data * data , int val , int val2 , u8 device )
{
int ret ;
u8 mode ;
int lodr_bits , odr_bits ;
ret = kmx61_get_mode ( data , & mode , KMX61_ACC | KMX61_MAG ) ;
if ( ret < 0 )
return ret ;
lodr_bits = kmx61_convert_freq_to_bit ( val , val2 ) ;
if ( lodr_bits < 0 )
return lodr_bits ;
/* To change ODR, accel and magn must be in STDBY */
ret = kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG ,
true ) ;
if ( ret < 0 )
return ret ;
odr_bits = 0 ;
if ( device & KMX61_ACC )
odr_bits | = lodr_bits < < KMX61_ACC_ODR_SHIFT ;
if ( device & KMX61_MAG )
odr_bits | = lodr_bits < < KMX61_MAG_ODR_SHIFT ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_ODCNTL ,
odr_bits ) ;
if ( ret < 0 )
return ret ;
2014-12-23 16:22:24 +03:00
data - > odr_bits = odr_bits ;
2014-12-03 16:31:53 +03:00
if ( device & KMX61_ACC ) {
ret = kmx61_set_wake_up_odr ( data , val , val2 ) ;
if ( ret )
return ret ;
}
2014-12-03 16:31:48 +03:00
return kmx61_set_mode ( data , mode , KMX61_ACC | KMX61_MAG , true ) ;
}
static int kmx61_get_odr ( struct kmx61_data * data , int * val , int * val2 ,
u8 device )
{ int i ;
u8 lodr_bits ;
if ( device & KMX61_ACC )
lodr_bits = ( data - > odr_bits > > KMX61_ACC_ODR_SHIFT ) &
KMX61_ACC_ODR_MASK ;
else if ( device & KMX61_MAG )
lodr_bits = ( data - > odr_bits > > KMX61_MAG_ODR_SHIFT ) &
KMX61_MAG_ODR_MASK ;
else
return - EINVAL ;
for ( i = 0 ; i < ARRAY_SIZE ( kmx61_samp_freq_table ) ; i + + )
if ( lodr_bits = = kmx61_samp_freq_table [ i ] . odr_bits ) {
* val = kmx61_samp_freq_table [ i ] . val ;
* val2 = kmx61_samp_freq_table [ i ] . val2 ;
return 0 ;
}
return - EINVAL ;
}
static int kmx61_set_range ( struct kmx61_data * data , u8 range )
{
int ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_CTRL1 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_ctrl1 \n " ) ;
return ret ;
}
ret & = ~ KMX61_REG_CTRL1_GSEL_MASK ;
ret | = range & KMX61_REG_CTRL1_GSEL_MASK ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_CTRL1 , ret ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error writing reg_ctrl1 \n " ) ;
return ret ;
}
data - > range = range ;
return 0 ;
}
static int kmx61_set_scale ( struct kmx61_data * data , u16 uscale )
{
int ret , i ;
u8 mode ;
for ( i = 0 ; i < ARRAY_SIZE ( kmx61_uscale_table ) ; i + + ) {
if ( kmx61_uscale_table [ i ] = = uscale ) {
ret = kmx61_get_mode ( data , & mode ,
KMX61_ACC | KMX61_MAG ) ;
if ( ret < 0 )
return ret ;
ret = kmx61_set_mode ( data , KMX61_ALL_STBY ,
KMX61_ACC | KMX61_MAG , true ) ;
if ( ret < 0 )
return ret ;
ret = kmx61_set_range ( data , i ) ;
if ( ret < 0 )
return ret ;
return kmx61_set_mode ( data , mode ,
KMX61_ACC | KMX61_MAG , true ) ;
}
}
return - EINVAL ;
}
static int kmx61_chip_init ( struct kmx61_data * data )
{
2014-12-03 16:31:53 +03:00
int ret , val , val2 ;
2014-12-03 16:31:48 +03:00
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_WHO_AM_I ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading who_am_i \n " ) ;
return ret ;
}
if ( ret ! = KMX61_CHIP_ID ) {
dev_err ( & data - > client - > dev ,
" Wrong chip id, got %x expected %x \n " ,
ret , KMX61_CHIP_ID ) ;
return - EINVAL ;
}
/* set accel 12bit, 4g range */
ret = kmx61_set_range ( data , KMX61_RANGE_4G ) ;
if ( ret < 0 )
return ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_ODCNTL ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_odcntl \n " ) ;
return ret ;
}
data - > odr_bits = ret ;
2014-12-03 16:31:53 +03:00
/* set output data rate for wake up (motion detection) function */
ret = kmx61_convert_bit_to_freq ( data - > odr_bits , & val , & val2 ) ;
if ( ret < 0 )
return ret ;
ret = kmx61_set_wake_up_odr ( data , val , val2 ) ;
if ( ret < 0 )
return ret ;
2014-12-03 16:31:48 +03:00
/* set acc/magn to OPERATION mode */
ret = kmx61_set_mode ( data , 0 , KMX61_ACC | KMX61_MAG , true ) ;
if ( ret < 0 )
return ret ;
2014-12-03 16:31:53 +03:00
data - > wake_thresh = KMX61_DEFAULT_WAKE_THRESH ;
data - > wake_duration = KMX61_DEFAULT_WAKE_DURATION ;
2014-12-03 16:31:48 +03:00
return 0 ;
}
2014-12-03 16:31:52 +03:00
static int kmx61_setup_new_data_interrupt ( struct kmx61_data * data ,
bool status , u8 device )
{
u8 mode ;
int ret ;
ret = kmx61_get_mode ( data , & mode , KMX61_ACC | KMX61_MAG ) ;
if ( ret < 0 )
return ret ;
ret = kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG , true ) ;
if ( ret < 0 )
return ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_INC1 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_ctrl1 \n " ) ;
return ret ;
}
if ( status ) {
ret | = KMX61_REG_INC1_BIT_IEN ;
if ( device & KMX61_ACC )
ret | = KMX61_REG_INC1_BIT_DRDYA ;
if ( device & KMX61_MAG )
ret | = KMX61_REG_INC1_BIT_DRDYM ;
} else {
ret & = ~ KMX61_REG_INC1_BIT_IEN ;
if ( device & KMX61_ACC )
ret & = ~ KMX61_REG_INC1_BIT_DRDYA ;
if ( device & KMX61_MAG )
ret & = ~ KMX61_REG_INC1_BIT_DRDYM ;
}
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_INC1 , ret ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error writing reg_int_ctrl1 \n " ) ;
return ret ;
}
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_CTRL1 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_ctrl1 \n " ) ;
return ret ;
}
if ( status )
ret | = KMX61_REG_CTRL1_BIT_DRDYE ;
else
ret & = ~ KMX61_REG_CTRL1_BIT_DRDYE ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_CTRL1 , ret ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error writing reg_ctrl1 \n " ) ;
return ret ;
}
2014-12-23 16:22:26 +03:00
return kmx61_set_mode ( data , mode , KMX61_ACC | KMX61_MAG , true ) ;
2014-12-03 16:31:52 +03:00
}
2014-12-03 16:31:53 +03:00
static int kmx61_chip_update_thresholds ( struct kmx61_data * data )
{
int ret ;
ret = i2c_smbus_write_byte_data ( data - > client ,
KMX61_REG_WUF_TIMER ,
data - > wake_duration ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Errow writing reg_wuf_timer \n " ) ;
return ret ;
}
ret = i2c_smbus_write_byte_data ( data - > client ,
KMX61_REG_WUF_THRESH ,
data - > wake_thresh ) ;
2014-12-23 16:22:26 +03:00
if ( ret < 0 )
2014-12-03 16:31:53 +03:00
dev_err ( & data - > client - > dev , " Error writing reg_wuf_thresh \n " ) ;
2014-12-23 16:22:26 +03:00
return ret ;
2014-12-03 16:31:53 +03:00
}
static int kmx61_setup_any_motion_interrupt ( struct kmx61_data * data ,
2014-12-23 16:22:28 +03:00
bool status )
2014-12-03 16:31:53 +03:00
{
u8 mode ;
int ret ;
ret = kmx61_get_mode ( data , & mode , KMX61_ACC | KMX61_MAG ) ;
if ( ret < 0 )
return ret ;
ret = kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG , true ) ;
if ( ret < 0 )
return ret ;
ret = kmx61_chip_update_thresholds ( data ) ;
if ( ret < 0 )
return ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_INC1 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_inc1 \n " ) ;
return ret ;
}
if ( status )
ret | = ( KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS ) ;
else
ret & = ~ ( KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS ) ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_INC1 , ret ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error writing reg_inc1 \n " ) ;
return ret ;
}
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_CTRL1 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_ctrl1 \n " ) ;
return ret ;
}
if ( status )
ret | = KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE ;
else
ret & = ~ ( KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE ) ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_CTRL1 , ret ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error writing reg_ctrl1 \n " ) ;
return ret ;
}
mode | = KMX61_ACT_STBY_BIT ;
2014-12-23 16:22:26 +03:00
return kmx61_set_mode ( data , mode , KMX61_ACC | KMX61_MAG , true ) ;
2014-12-03 16:31:53 +03:00
}
2014-12-03 16:31:50 +03:00
/**
* kmx61_set_power_state ( ) - set power state for kmx61 @ device
* @ data - kmx61 device private pointer
* @ on - power state to be set for @ device
* @ device - bitmask indicating device for which @ on state needs to be set
*
* Notice that when ACC power state needs to be set to ON and MAG is in
* OPERATION then we know that kmx61_runtime_resume was already called
* so we must set ACC OPERATION mode here . The same happens when MAG power
* state needs to be set to ON and ACC is in OPERATION .
*/
static int kmx61_set_power_state ( struct kmx61_data * data , bool on , u8 device )
{
2015-01-09 12:39:30 +03:00
# ifdef CONFIG_PM
2014-12-03 16:31:50 +03:00
int ret ;
if ( device & KMX61_ACC ) {
if ( on & & ! data - > acc_ps & & ! data - > mag_stby ) {
ret = kmx61_set_mode ( data , 0 , KMX61_ACC , true ) ;
if ( ret < 0 )
return ret ;
}
data - > acc_ps = on ;
}
if ( device & KMX61_MAG ) {
if ( on & & ! data - > mag_ps & & ! data - > acc_stby ) {
ret = kmx61_set_mode ( data , 0 , KMX61_MAG , true ) ;
if ( ret < 0 )
return ret ;
}
data - > mag_ps = on ;
}
if ( on ) {
ret = pm_runtime_get_sync ( & data - > client - > dev ) ;
} else {
pm_runtime_mark_last_busy ( & data - > client - > dev ) ;
ret = pm_runtime_put_autosuspend ( & data - > client - > dev ) ;
}
if ( ret < 0 ) {
dev_err ( & data - > client - > dev ,
" Failed: kmx61_set_power_state for %d, ret %d \n " ,
on , ret ) ;
if ( on )
pm_runtime_put_noidle ( & data - > client - > dev ) ;
return ret ;
}
# endif
return 0 ;
}
2014-12-03 16:31:48 +03:00
static int kmx61_read_measurement ( struct kmx61_data * data , u8 base , u8 offset )
{
int ret ;
u8 reg = base + offset * 2 ;
ret = i2c_smbus_read_word_data ( data - > client , reg ) ;
if ( ret < 0 )
dev_err ( & data - > client - > dev , " failed to read reg at %x \n " , reg ) ;
return ret ;
}
static int kmx61_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
{
int ret ;
u8 base_reg ;
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
switch ( chan - > type ) {
case IIO_ACCEL :
base_reg = KMX61_ACC_XOUT_L ;
break ;
case IIO_MAGN :
base_reg = KMX61_MAG_XOUT_L ;
break ;
default :
return - EINVAL ;
}
mutex_lock ( & data - > lock ) ;
2014-12-23 16:22:25 +03:00
ret = kmx61_set_power_state ( data , true , chan - > address ) ;
if ( ret ) {
mutex_unlock ( & data - > lock ) ;
return ret ;
}
2014-12-03 16:31:48 +03:00
ret = kmx61_read_measurement ( data , base_reg , chan - > scan_index ) ;
if ( ret < 0 ) {
2014-12-03 16:31:50 +03:00
kmx61_set_power_state ( data , false , chan - > address ) ;
2014-12-03 16:31:48 +03:00
mutex_unlock ( & data - > lock ) ;
return ret ;
}
* val = sign_extend32 ( ret > > chan - > scan_type . shift ,
chan - > scan_type . realbits - 1 ) ;
2014-12-23 16:22:25 +03:00
ret = kmx61_set_power_state ( data , false , chan - > address ) ;
2014-12-03 16:31:48 +03:00
mutex_unlock ( & data - > lock ) ;
2014-12-23 16:22:25 +03:00
if ( ret )
return ret ;
2014-12-03 16:31:48 +03:00
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_ACCEL :
* val = 0 ;
* val2 = kmx61_uscale_table [ data - > range ] ;
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_MAGN :
/* 14 bits res, 1465 microGauss per magn count */
* val = 0 ;
* val2 = 1465 ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_SAMP_FREQ :
if ( chan - > type ! = IIO_ACCEL & & chan - > type ! = IIO_MAGN )
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
ret = kmx61_get_odr ( data , val , val2 , chan - > address ) ;
mutex_unlock ( & data - > lock ) ;
if ( ret )
return - EINVAL ;
return IIO_VAL_INT_PLUS_MICRO ;
}
return - EINVAL ;
}
static int kmx61_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int val ,
int val2 , long mask )
{
int ret ;
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
if ( chan - > type ! = IIO_ACCEL & & chan - > type ! = IIO_MAGN )
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
ret = kmx61_set_odr ( data , val , val2 , chan - > address ) ;
mutex_unlock ( & data - > lock ) ;
return ret ;
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_ACCEL :
if ( val ! = 0 )
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
ret = kmx61_set_scale ( data , val2 ) ;
mutex_unlock ( & data - > lock ) ;
return ret ;
default :
return - EINVAL ;
}
default :
return - EINVAL ;
}
}
2014-12-03 16:31:53 +03:00
static int kmx61_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 )
{
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
* val2 = 0 ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
* val = data - > wake_thresh ;
2014-12-23 16:22:26 +03:00
return IIO_VAL_INT ;
2014-12-03 16:31:53 +03:00
case IIO_EV_INFO_PERIOD :
* val = data - > wake_duration ;
2014-12-23 16:22:26 +03:00
return IIO_VAL_INT ;
2014-12-03 16:31:53 +03:00
default :
return - EINVAL ;
}
}
static int kmx61_write_event ( struct iio_dev * indio_dev ,
2014-12-23 16:22:27 +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 )
2014-12-03 16:31:53 +03:00
{
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
if ( data - > ev_enable_state )
return - EBUSY ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
data - > wake_thresh = val ;
2014-12-23 16:22:26 +03:00
return IIO_VAL_INT ;
2014-12-03 16:31:53 +03:00
case IIO_EV_INFO_PERIOD :
data - > wake_duration = val ;
2014-12-23 16:22:26 +03:00
return IIO_VAL_INT ;
2014-12-03 16:31:53 +03:00
default :
return - EINVAL ;
}
}
static int kmx61_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 kmx61_data * data = kmx61_get_data ( indio_dev ) ;
return data - > ev_enable_state ;
}
static int kmx61_write_event_config ( struct iio_dev * indio_dev ,
2014-12-23 16:22:27 +03:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir ,
int state )
2014-12-03 16:31:53 +03:00
{
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
2014-12-23 16:22:26 +03:00
int ret = 0 ;
2014-12-03 16:31:53 +03:00
if ( state & & data - > ev_enable_state )
return 0 ;
mutex_lock ( & data - > lock ) ;
if ( ! state & & data - > motion_trig_on ) {
2014-12-23 16:22:29 +03:00
data - > ev_enable_state = false ;
2014-12-23 16:22:26 +03:00
goto err_unlock ;
2014-12-03 16:31:53 +03:00
}
ret = kmx61_set_power_state ( data , state , KMX61_ACC ) ;
2014-12-23 16:22:26 +03:00
if ( ret < 0 )
goto err_unlock ;
2014-12-03 16:31:53 +03:00
2014-12-23 16:22:28 +03:00
ret = kmx61_setup_any_motion_interrupt ( data , state ) ;
2014-12-03 16:31:53 +03:00
if ( ret < 0 ) {
kmx61_set_power_state ( data , false , KMX61_ACC ) ;
2014-12-23 16:22:26 +03:00
goto err_unlock ;
2014-12-03 16:31:53 +03:00
}
data - > ev_enable_state = state ;
2014-12-23 16:22:26 +03:00
err_unlock :
2014-12-03 16:31:53 +03:00
mutex_unlock ( & data - > lock ) ;
2014-12-23 16:22:26 +03:00
return ret ;
2014-12-03 16:31:53 +03:00
}
2014-12-03 16:31:52 +03:00
static int kmx61_acc_validate_trigger ( struct iio_dev * indio_dev ,
struct iio_trigger * trig )
{
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
2014-12-03 16:31:53 +03:00
if ( data - > acc_dready_trig ! = trig & & data - > motion_trig ! = trig )
2014-12-03 16:31:52 +03:00
return - EINVAL ;
return 0 ;
}
static int kmx61_mag_validate_trigger ( struct iio_dev * indio_dev ,
struct iio_trigger * trig )
{
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
if ( data - > mag_dready_trig ! = trig )
return - EINVAL ;
return 0 ;
}
2014-12-03 16:31:48 +03:00
static const struct iio_info kmx61_acc_info = {
. driver_module = THIS_MODULE ,
. read_raw = kmx61_read_raw ,
. write_raw = kmx61_write_raw ,
. attrs = & kmx61_acc_attribute_group ,
2014-12-03 16:31:53 +03:00
. read_event_value = kmx61_read_event ,
. write_event_value = kmx61_write_event ,
. read_event_config = kmx61_read_event_config ,
. write_event_config = kmx61_write_event_config ,
2014-12-03 16:31:52 +03:00
. validate_trigger = kmx61_acc_validate_trigger ,
2014-12-03 16:31:48 +03:00
} ;
static const struct iio_info kmx61_mag_info = {
. driver_module = THIS_MODULE ,
. read_raw = kmx61_read_raw ,
. write_raw = kmx61_write_raw ,
. attrs = & kmx61_mag_attribute_group ,
2014-12-03 16:31:52 +03:00
. validate_trigger = kmx61_mag_validate_trigger ,
2014-12-03 16:31:48 +03:00
} ;
2014-12-03 16:31:52 +03:00
static int kmx61_data_rdy_trigger_set_state ( struct iio_trigger * trig ,
bool state )
{
int ret = 0 ;
u8 device ;
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
2014-12-03 16:31:53 +03:00
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
2014-12-03 16:31:52 +03:00
mutex_lock ( & data - > lock ) ;
2014-12-03 16:31:53 +03:00
if ( ! state & & data - > ev_enable_state & & data - > motion_trig_on ) {
data - > motion_trig_on = false ;
2014-12-23 16:22:26 +03:00
goto err_unlock ;
2014-12-03 16:31:53 +03:00
}
2014-12-23 16:22:30 +03:00
if ( data - > acc_dready_trig = = trig | | data - > motion_trig = = trig )
2014-12-03 16:31:52 +03:00
device = KMX61_ACC ;
else
device = KMX61_MAG ;
ret = kmx61_set_power_state ( data , state , device ) ;
2014-12-23 16:22:26 +03:00
if ( ret < 0 )
goto err_unlock ;
2014-12-03 16:31:52 +03:00
2014-12-03 16:31:53 +03:00
if ( data - > acc_dready_trig = = trig | | data - > mag_dready_trig = = trig )
ret = kmx61_setup_new_data_interrupt ( data , state , device ) ;
else
2014-12-23 16:22:28 +03:00
ret = kmx61_setup_any_motion_interrupt ( data , state ) ;
2014-12-03 16:31:52 +03:00
if ( ret < 0 ) {
kmx61_set_power_state ( data , false , device ) ;
2014-12-23 16:22:26 +03:00
goto err_unlock ;
2014-12-03 16:31:52 +03:00
}
if ( data - > acc_dready_trig = = trig )
data - > acc_dready_trig_on = state ;
2014-12-03 16:31:53 +03:00
else if ( data - > mag_dready_trig = = trig )
2014-12-03 16:31:52 +03:00
data - > mag_dready_trig_on = state ;
2014-12-03 16:31:53 +03:00
else
data - > motion_trig_on = state ;
2014-12-23 16:22:26 +03:00
err_unlock :
2014-12-03 16:31:52 +03:00
mutex_unlock ( & data - > lock ) ;
2014-12-23 16:22:26 +03:00
return ret ;
2014-12-03 16:31:52 +03:00
}
static int kmx61_trig_try_reenable ( struct iio_trigger * trig )
{
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
int ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_INL ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_inl \n " ) ;
return ret ;
}
return 0 ;
}
static const struct iio_trigger_ops kmx61_trigger_ops = {
. set_trigger_state = kmx61_data_rdy_trigger_set_state ,
. try_reenable = kmx61_trig_try_reenable ,
. owner = THIS_MODULE ,
} ;
2014-12-03 16:31:53 +03:00
static irqreturn_t kmx61_event_handler ( int irq , void * private )
{
struct kmx61_data * data = private ;
struct iio_dev * indio_dev = data - > acc_indio_dev ;
int ret ;
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_INS1 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_ins1 \n " ) ;
goto ack_intr ;
}
if ( ret & KMX61_REG_INS1_BIT_WUFS ) {
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_INS2 ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " Error reading reg_ins2 \n " ) ;
goto ack_intr ;
}
if ( ret & KMX61_REG_INS2_BIT_XN )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL ,
0 ,
IIO_MOD_X ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_FALLING ) ,
0 ) ;
if ( ret & KMX61_REG_INS2_BIT_XP )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL ,
0 ,
IIO_MOD_X ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_RISING ) ,
0 ) ;
if ( ret & KMX61_REG_INS2_BIT_YN )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL ,
0 ,
IIO_MOD_Y ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_FALLING ) ,
0 ) ;
if ( ret & KMX61_REG_INS2_BIT_YP )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL ,
0 ,
IIO_MOD_Y ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_RISING ) ,
0 ) ;
if ( ret & KMX61_REG_INS2_BIT_ZN )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL ,
0 ,
IIO_MOD_Z ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_FALLING ) ,
0 ) ;
if ( ret & KMX61_REG_INS2_BIT_ZP )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL ,
0 ,
IIO_MOD_Z ,
IIO_EV_TYPE_THRESH ,
IIO_EV_DIR_RISING ) ,
0 ) ;
}
ack_intr :
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_CTRL1 ) ;
if ( ret < 0 )
dev_err ( & data - > client - > dev , " Error reading reg_ctrl1 \n " ) ;
ret | = KMX61_REG_CTRL1_BIT_RES ;
ret = i2c_smbus_write_byte_data ( data - > client , KMX61_REG_CTRL1 , ret ) ;
if ( ret < 0 )
2014-12-23 16:22:26 +03:00
dev_err ( & data - > client - > dev , " Error writing reg_ctrl1 \n " ) ;
2014-12-03 16:31:53 +03:00
ret = i2c_smbus_read_byte_data ( data - > client , KMX61_REG_INL ) ;
if ( ret < 0 )
dev_err ( & data - > client - > dev , " Error reading reg_inl \n " ) ;
return IRQ_HANDLED ;
}
2014-12-03 16:31:52 +03:00
static irqreturn_t kmx61_data_rdy_trig_poll ( int irq , void * private )
{
struct kmx61_data * data = private ;
if ( data - > acc_dready_trig_on )
iio_trigger_poll ( data - > acc_dready_trig ) ;
if ( data - > mag_dready_trig_on )
iio_trigger_poll ( data - > mag_dready_trig ) ;
2014-12-03 16:31:53 +03:00
if ( data - > motion_trig_on )
iio_trigger_poll ( data - > motion_trig ) ;
if ( data - > ev_enable_state )
return IRQ_WAKE_THREAD ;
2014-12-03 16:31:52 +03:00
return IRQ_HANDLED ;
}
static irqreturn_t kmx61_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct kmx61_data * data = kmx61_get_data ( indio_dev ) ;
int bit , ret , i = 0 ;
2014-12-23 16:22:33 +03:00
u8 base ;
2014-12-03 16:31:52 +03:00
s16 buffer [ 8 ] ;
2014-12-23 16:22:33 +03:00
if ( indio_dev = = data - > acc_indio_dev )
base = KMX61_ACC_XOUT_L ;
else
base = KMX61_MAG_XOUT_L ;
2014-12-03 16:31:52 +03:00
mutex_lock ( & data - > lock ) ;
for_each_set_bit ( bit , indio_dev - > buffer - > scan_mask ,
indio_dev - > masklength ) {
2014-12-23 16:22:33 +03:00
ret = kmx61_read_measurement ( data , base , bit ) ;
2014-12-03 16:31:52 +03:00
if ( ret < 0 ) {
mutex_unlock ( & data - > lock ) ;
goto err ;
}
buffer [ i + + ] = ret ;
}
mutex_unlock ( & data - > lock ) ;
iio_push_to_buffers ( indio_dev , buffer ) ;
err :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
2014-12-03 16:31:49 +03:00
static const char * kmx61_match_acpi_device ( struct device * dev )
{
const struct acpi_device_id * id ;
id = acpi_match_device ( dev - > driver - > acpi_match_table , dev ) ;
if ( ! id )
return NULL ;
return dev_name ( dev ) ;
}
static int kmx61_gpio_probe ( struct i2c_client * client , struct kmx61_data * data )
{
struct device * dev ;
struct gpio_desc * gpio ;
int ret ;
if ( ! client )
return - EINVAL ;
dev = & client - > dev ;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index ( dev , KMX61_GPIO_NAME , 0 ) ;
if ( IS_ERR ( gpio ) ) {
dev_err ( dev , " acpi gpio get index failed \n " ) ;
return PTR_ERR ( gpio ) ;
}
ret = gpiod_direction_input ( gpio ) ;
if ( ret )
return ret ;
ret = gpiod_to_irq ( gpio ) ;
dev_dbg ( dev , " GPIO resource, no:%d irq:%d \n " , desc_to_gpio ( gpio ) , ret ) ;
return ret ;
}
2014-12-03 16:31:48 +03:00
static struct iio_dev * kmx61_indiodev_setup ( struct kmx61_data * data ,
const struct iio_info * info ,
const struct iio_chan_spec * chan ,
int num_channels ,
const char * name )
{
struct iio_dev * indio_dev ;
indio_dev = devm_iio_device_alloc ( & data - > client - > dev , sizeof ( data ) ) ;
if ( ! indio_dev )
return ERR_PTR ( - ENOMEM ) ;
kmx61_set_data ( indio_dev , data ) ;
indio_dev - > dev . parent = & data - > client - > dev ;
indio_dev - > channels = chan ;
indio_dev - > num_channels = num_channels ;
indio_dev - > name = name ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = info ;
return indio_dev ;
}
2014-12-03 16:31:52 +03:00
static struct iio_trigger * kmx61_trigger_setup ( struct kmx61_data * data ,
struct iio_dev * indio_dev ,
const char * tag )
{
struct iio_trigger * trig ;
int ret ;
trig = devm_iio_trigger_alloc ( & data - > client - > dev ,
" %s-%s-dev%d " ,
indio_dev - > name ,
tag ,
indio_dev - > id ) ;
if ( ! trig )
return ERR_PTR ( - ENOMEM ) ;
trig - > dev . parent = & data - > client - > dev ;
trig - > ops = & kmx61_trigger_ops ;
iio_trigger_set_drvdata ( trig , indio_dev ) ;
ret = iio_trigger_register ( trig ) ;
if ( ret )
return ERR_PTR ( ret ) ;
return trig ;
}
2014-12-03 16:31:48 +03:00
static int kmx61_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
int ret ;
struct kmx61_data * data ;
const char * name = NULL ;
data = devm_kzalloc ( & client - > dev , sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
i2c_set_clientdata ( client , data ) ;
data - > client = client ;
mutex_init ( & data - > lock ) ;
2014-12-03 16:31:49 +03:00
if ( id )
name = id - > name ;
else if ( ACPI_HANDLE ( & client - > dev ) )
name = kmx61_match_acpi_device ( & client - > dev ) ;
else
return - ENODEV ;
2014-12-03 16:31:48 +03:00
data - > acc_indio_dev =
kmx61_indiodev_setup ( data , & kmx61_acc_info ,
kmx61_acc_channels ,
ARRAY_SIZE ( kmx61_acc_channels ) ,
name ) ;
if ( IS_ERR ( data - > acc_indio_dev ) )
return PTR_ERR ( data - > acc_indio_dev ) ;
data - > mag_indio_dev =
kmx61_indiodev_setup ( data , & kmx61_mag_info ,
kmx61_mag_channels ,
ARRAY_SIZE ( kmx61_mag_channels ) ,
name ) ;
if ( IS_ERR ( data - > mag_indio_dev ) )
return PTR_ERR ( data - > mag_indio_dev ) ;
ret = kmx61_chip_init ( data ) ;
if ( ret < 0 )
return ret ;
2014-12-03 16:31:49 +03:00
if ( client - > irq < 0 )
client - > irq = kmx61_gpio_probe ( client , data ) ;
2014-12-03 16:31:52 +03:00
if ( client - > irq > = 0 ) {
ret = devm_request_threaded_irq ( & client - > dev , client - > irq ,
kmx61_data_rdy_trig_poll ,
2014-12-03 16:31:53 +03:00
kmx61_event_handler ,
2014-12-03 16:31:52 +03:00
IRQF_TRIGGER_RISING ,
KMX61_IRQ_NAME ,
data ) ;
if ( ret )
goto err_chip_uninit ;
data - > acc_dready_trig =
kmx61_trigger_setup ( data , data - > acc_indio_dev ,
" dready " ) ;
2014-12-23 16:22:26 +03:00
if ( IS_ERR ( data - > acc_dready_trig ) ) {
ret = PTR_ERR ( data - > acc_dready_trig ) ;
goto err_chip_uninit ;
}
2014-12-03 16:31:52 +03:00
data - > mag_dready_trig =
kmx61_trigger_setup ( data , data - > mag_indio_dev ,
" dready " ) ;
if ( IS_ERR ( data - > mag_dready_trig ) ) {
ret = PTR_ERR ( data - > mag_dready_trig ) ;
2014-12-23 16:22:26 +03:00
goto err_trigger_unregister_acc_dready ;
2014-12-03 16:31:52 +03:00
}
2014-12-03 16:31:53 +03:00
data - > motion_trig =
kmx61_trigger_setup ( data , data - > acc_indio_dev ,
" any-motion " ) ;
if ( IS_ERR ( data - > motion_trig ) ) {
ret = PTR_ERR ( data - > motion_trig ) ;
2014-12-23 16:22:26 +03:00
goto err_trigger_unregister_mag_dready ;
2014-12-03 16:31:53 +03:00
}
2014-12-03 16:31:52 +03:00
ret = iio_triggered_buffer_setup ( data - > acc_indio_dev ,
& iio_pollfunc_store_time ,
kmx61_trigger_handler ,
NULL ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev ,
" Failed to setup acc triggered buffer \n " ) ;
2014-12-23 16:22:26 +03:00
goto err_trigger_unregister_motion ;
2014-12-03 16:31:52 +03:00
}
ret = iio_triggered_buffer_setup ( data - > mag_indio_dev ,
& iio_pollfunc_store_time ,
kmx61_trigger_handler ,
NULL ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev ,
" Failed to setup mag triggered buffer \n " ) ;
2014-12-23 16:22:26 +03:00
goto err_buffer_cleanup_acc ;
2014-12-03 16:31:52 +03:00
}
}
2014-12-03 16:31:48 +03:00
ret = iio_device_register ( data - > acc_indio_dev ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to register acc iio device \n " ) ;
2014-12-23 16:22:26 +03:00
goto err_buffer_cleanup_mag ;
2014-12-03 16:31:48 +03:00
}
ret = iio_device_register ( data - > mag_indio_dev ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to register mag iio device \n " ) ;
2014-12-03 16:31:50 +03:00
goto err_iio_unregister_acc ;
2014-12-03 16:31:48 +03:00
}
2014-12-03 16:31:50 +03:00
ret = pm_runtime_set_active ( & client - > dev ) ;
if ( ret < 0 )
goto err_iio_unregister_mag ;
pm_runtime_enable ( & client - > dev ) ;
pm_runtime_set_autosuspend_delay ( & client - > dev , KMX61_SLEEP_DELAY_MS ) ;
pm_runtime_use_autosuspend ( & client - > dev ) ;
2014-12-03 16:31:48 +03:00
return 0 ;
2014-12-03 16:31:50 +03:00
err_iio_unregister_mag :
iio_device_unregister ( data - > mag_indio_dev ) ;
err_iio_unregister_acc :
2014-12-03 16:31:48 +03:00
iio_device_unregister ( data - > acc_indio_dev ) ;
2014-12-23 16:22:26 +03:00
err_buffer_cleanup_mag :
if ( client - > irq > = 0 )
2014-12-03 16:31:52 +03:00
iio_triggered_buffer_cleanup ( data - > mag_indio_dev ) ;
2014-12-23 16:22:26 +03:00
err_buffer_cleanup_acc :
if ( client - > irq > = 0 )
iio_triggered_buffer_cleanup ( data - > acc_indio_dev ) ;
err_trigger_unregister_motion :
iio_trigger_unregister ( data - > motion_trig ) ;
err_trigger_unregister_mag_dready :
iio_trigger_unregister ( data - > mag_dready_trig ) ;
err_trigger_unregister_acc_dready :
iio_trigger_unregister ( data - > acc_dready_trig ) ;
2014-12-03 16:31:48 +03:00
err_chip_uninit :
kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG , true ) ;
return ret ;
}
static int kmx61_remove ( struct i2c_client * client )
{
struct kmx61_data * data = i2c_get_clientdata ( client ) ;
2014-12-03 16:31:50 +03:00
pm_runtime_disable ( & client - > dev ) ;
pm_runtime_set_suspended ( & client - > dev ) ;
pm_runtime_put_noidle ( & client - > dev ) ;
2014-12-03 16:31:48 +03:00
iio_device_unregister ( data - > acc_indio_dev ) ;
iio_device_unregister ( data - > mag_indio_dev ) ;
2014-12-03 16:31:52 +03:00
if ( client - > irq > = 0 ) {
iio_triggered_buffer_cleanup ( data - > acc_indio_dev ) ;
iio_triggered_buffer_cleanup ( data - > mag_indio_dev ) ;
iio_trigger_unregister ( data - > acc_dready_trig ) ;
iio_trigger_unregister ( data - > mag_dready_trig ) ;
2014-12-03 16:31:53 +03:00
iio_trigger_unregister ( data - > motion_trig ) ;
2014-12-03 16:31:52 +03:00
}
2014-12-03 16:31:48 +03:00
mutex_lock ( & data - > lock ) ;
kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG , true ) ;
mutex_unlock ( & data - > lock ) ;
return 0 ;
}
2014-12-03 16:31:51 +03:00
# ifdef CONFIG_PM_SLEEP
static int kmx61_suspend ( struct device * dev )
{
int ret ;
struct kmx61_data * data = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
mutex_lock ( & data - > lock ) ;
ret = kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG ,
false ) ;
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int kmx61_resume ( struct device * dev )
{
u8 stby = 0 ;
struct kmx61_data * data = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
if ( data - > acc_stby )
stby | = KMX61_ACC_STBY_BIT ;
if ( data - > mag_stby )
stby | = KMX61_MAG_STBY_BIT ;
return kmx61_set_mode ( data , stby , KMX61_ACC | KMX61_MAG , true ) ;
}
# endif
2014-12-03 16:31:50 +03:00
2015-01-09 12:39:30 +03:00
# ifdef CONFIG_PM
2014-12-03 16:31:50 +03:00
static int kmx61_runtime_suspend ( struct device * dev )
{
struct kmx61_data * data = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
int ret ;
mutex_lock ( & data - > lock ) ;
ret = kmx61_set_mode ( data , KMX61_ALL_STBY , KMX61_ACC | KMX61_MAG , true ) ;
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int kmx61_runtime_resume ( struct device * dev )
{
struct kmx61_data * data = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
u8 stby = 0 ;
if ( ! data - > acc_ps )
stby | = KMX61_ACC_STBY_BIT ;
if ( ! data - > mag_ps )
stby | = KMX61_MAG_STBY_BIT ;
return kmx61_set_mode ( data , stby , KMX61_ACC | KMX61_MAG , true ) ;
}
# endif
static const struct dev_pm_ops kmx61_pm_ops = {
2014-12-03 16:31:51 +03:00
SET_SYSTEM_SLEEP_PM_OPS ( kmx61_suspend , kmx61_resume )
2014-12-03 16:31:50 +03:00
SET_RUNTIME_PM_OPS ( kmx61_runtime_suspend , kmx61_runtime_resume , NULL )
} ;
2014-12-03 16:31:49 +03:00
static const struct acpi_device_id kmx61_acpi_match [ ] = {
{ " KMX61021 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , kmx61_acpi_match ) ;
2014-12-03 16:31:48 +03:00
static const struct i2c_device_id kmx61_id [ ] = {
{ " kmx611021 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , kmx61_id ) ;
static struct i2c_driver kmx61_driver = {
. driver = {
. name = KMX61_DRV_NAME ,
2014-12-03 16:31:49 +03:00
. acpi_match_table = ACPI_PTR ( kmx61_acpi_match ) ,
2014-12-03 16:31:50 +03:00
. pm = & kmx61_pm_ops ,
2014-12-03 16:31:48 +03:00
} ,
. probe = kmx61_probe ,
. remove = kmx61_remove ,
. id_table = kmx61_id ,
} ;
module_i2c_driver ( kmx61_driver ) ;
MODULE_AUTHOR ( " Daniel Baluta <daniel.baluta@intel.com> " ) ;
MODULE_DESCRIPTION ( " KMX61 accelerometer/magnetometer driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;