2019-12-20 16:00:50 +00:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Core IIO driver for Bosch BMA400 triaxial acceleration sensor .
*
* Copyright 2019 Dan Robertson < dan @ dlrobertson . com >
*
* TODO :
* - Support for power management
* - Support events and interrupts
* - Create channel for step count
* - Create channel for sensor time
*/
2022-05-05 19:00:15 +05:30
# include <linux/bitfield.h>
2019-12-20 16:00:50 +00:00
# include <linux/bitops.h>
# include <linux/device.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/regmap.h>
2019-12-20 16:00:51 +00:00
# include <linux/regulator/consumer.h>
2022-05-05 19:00:16 +05:30
# include <linux/slab.h>
# include <asm/unaligned.h>
2019-12-20 16:00:50 +00:00
2022-05-05 19:00:13 +05:30
# include <linux/iio/iio.h>
2022-05-05 19:00:15 +05:30
# include <linux/iio/buffer.h>
2022-05-05 19:00:17 +05:30
# include <linux/iio/events.h>
2022-08-31 12:01:17 +05:30
# include <linux/iio/sysfs.h>
2022-05-05 19:00:15 +05:30
# include <linux/iio/trigger.h>
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/triggered_buffer.h>
2022-05-05 19:00:13 +05:30
2019-12-20 16:00:50 +00:00
# include "bma400.h"
/*
* The G - range selection may be one of 2 g , 4 g , 8 , or 16 g . The scale may
* be selected with the acc_range bits of the ACC_CONFIG1 register .
* NB : This buffer is populated in the device init .
*/
static int bma400_scales [ 8 ] ;
/*
* See the ACC_CONFIG1 section of the datasheet .
* NB : This buffer is populated in the device init .
*/
static int bma400_sample_freqs [ 14 ] ;
static const int bma400_osr_range [ ] = { 0 , 1 , 3 } ;
2022-08-31 12:01:17 +05:30
static int tap_reset_timeout [ BMA400_TAP_TIM_LIST_LEN ] = {
300000 ,
400000 ,
500000 ,
600000
} ;
static int tap_max2min_time [ BMA400_TAP_TIM_LIST_LEN ] = {
30000 ,
45000 ,
60000 ,
90000
} ;
static int double_tap2_min_delay [ BMA400_TAP_TIM_LIST_LEN ] = {
20000 ,
40000 ,
60000 ,
80000
} ;
2019-12-20 16:00:50 +00:00
/* See the ACC_CONFIG0 section of the datasheet */
enum bma400_power_mode {
POWER_MODE_SLEEP = 0x00 ,
POWER_MODE_LOW = 0x01 ,
POWER_MODE_NORMAL = 0x02 ,
POWER_MODE_INVALID = 0x03 ,
} ;
2022-05-05 19:00:15 +05:30
enum bma400_scan {
BMA400_ACCL_X ,
BMA400_ACCL_Y ,
BMA400_ACCL_Z ,
BMA400_TEMP ,
} ;
2019-12-20 16:00:50 +00:00
struct bma400_sample_freq {
int hz ;
int uhz ;
} ;
2022-05-05 19:00:18 +05:30
enum bma400_activity {
BMA400_STILL ,
BMA400_WALKING ,
BMA400_RUNNING ,
} ;
2019-12-20 16:00:50 +00:00
struct bma400_data {
struct device * dev ;
struct regmap * regmap ;
2019-12-20 16:00:51 +00:00
struct regulator_bulk_data regulators [ BMA400_NUM_REGULATORS ] ;
2019-12-20 16:00:50 +00:00
struct mutex mutex ; /* data register lock */
struct iio_mount_matrix orientation ;
enum bma400_power_mode power_mode ;
struct bma400_sample_freq sample_freq ;
int oversampling_ratio ;
int scale ;
2022-05-05 19:00:15 +05:30
struct iio_trigger * trig ;
2022-05-05 19:00:16 +05:30
int steps_enabled ;
2022-05-05 19:00:17 +05:30
bool step_event_en ;
2022-05-05 19:00:18 +05:30
bool activity_event_en ;
2022-05-05 19:00:19 +05:30
unsigned int generic_event_en ;
2022-08-31 12:01:17 +05:30
unsigned int tap_event_en_bitmask ;
2022-05-05 19:00:15 +05:30
/* Correct time stamp alignment */
struct {
__le16 buff [ 3 ] ;
u8 temperature ;
s64 ts __aligned ( 8 ) ;
2022-05-08 18:55:41 +01:00
} buffer __aligned ( IIO_DMA_MINALIGN ) ;
2022-05-05 19:00:15 +05:30
__le16 status ;
2022-05-05 19:00:19 +05:30
__be16 duration ;
2019-12-20 16:00:50 +00:00
} ;
static bool bma400_is_writable_reg ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case BMA400_CHIP_ID_REG :
case BMA400_ERR_REG :
case BMA400_STATUS_REG :
case BMA400_X_AXIS_LSB_REG :
case BMA400_X_AXIS_MSB_REG :
case BMA400_Y_AXIS_LSB_REG :
case BMA400_Y_AXIS_MSB_REG :
case BMA400_Z_AXIS_LSB_REG :
case BMA400_Z_AXIS_MSB_REG :
case BMA400_SENSOR_TIME0 :
case BMA400_SENSOR_TIME1 :
case BMA400_SENSOR_TIME2 :
case BMA400_EVENT_REG :
case BMA400_INT_STAT0_REG :
case BMA400_INT_STAT1_REG :
case BMA400_INT_STAT2_REG :
case BMA400_TEMP_DATA_REG :
case BMA400_FIFO_LENGTH0_REG :
case BMA400_FIFO_LENGTH1_REG :
case BMA400_FIFO_DATA_REG :
case BMA400_STEP_CNT0_REG :
case BMA400_STEP_CNT1_REG :
case BMA400_STEP_CNT3_REG :
case BMA400_STEP_STAT_REG :
return false ;
default :
return true ;
}
}
static bool bma400_is_volatile_reg ( struct device * dev , unsigned int reg )
{
switch ( reg ) {
case BMA400_ERR_REG :
case BMA400_STATUS_REG :
case BMA400_X_AXIS_LSB_REG :
case BMA400_X_AXIS_MSB_REG :
case BMA400_Y_AXIS_LSB_REG :
case BMA400_Y_AXIS_MSB_REG :
case BMA400_Z_AXIS_LSB_REG :
case BMA400_Z_AXIS_MSB_REG :
case BMA400_SENSOR_TIME0 :
case BMA400_SENSOR_TIME1 :
case BMA400_SENSOR_TIME2 :
case BMA400_EVENT_REG :
case BMA400_INT_STAT0_REG :
case BMA400_INT_STAT1_REG :
case BMA400_INT_STAT2_REG :
case BMA400_TEMP_DATA_REG :
case BMA400_FIFO_LENGTH0_REG :
case BMA400_FIFO_LENGTH1_REG :
case BMA400_FIFO_DATA_REG :
case BMA400_STEP_CNT0_REG :
case BMA400_STEP_CNT1_REG :
case BMA400_STEP_CNT3_REG :
case BMA400_STEP_STAT_REG :
return true ;
default :
return false ;
}
}
const struct regmap_config bma400_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = BMA400_CMD_REG ,
. cache_type = REGCACHE_RBTREE ,
. writeable_reg = bma400_is_writable_reg ,
. volatile_reg = bma400_is_volatile_reg ,
} ;
2022-01-16 18:05:26 +00:00
EXPORT_SYMBOL_NS ( bma400_regmap_config , IIO_BMA400 ) ;
2019-12-20 16:00:50 +00:00
static const struct iio_mount_matrix *
bma400_accel_get_mount_matrix ( const struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct bma400_data * data = iio_priv ( indio_dev ) ;
return & data - > orientation ;
}
static const struct iio_chan_spec_ext_info bma400_ext_info [ ] = {
IIO_MOUNT_MATRIX ( IIO_SHARED_BY_DIR , bma400_accel_get_mount_matrix ) ,
{ }
} ;
2022-05-05 19:00:17 +05:30
static const struct iio_event_spec bma400_step_detect_event = {
. type = IIO_EV_TYPE_CHANGE ,
. dir = IIO_EV_DIR_NONE ,
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) ,
} ;
2022-05-05 19:00:18 +05:30
static const struct iio_event_spec bma400_activity_event = {
. type = IIO_EV_TYPE_CHANGE ,
. dir = IIO_EV_DIR_NONE ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_ENABLE ) ,
} ;
2022-05-05 19:00:19 +05:30
static const struct iio_event_spec bma400_accel_event [ ] = {
{
. type = IIO_EV_TYPE_MAG ,
. dir = IIO_EV_DIR_FALLING ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_PERIOD ) |
BIT ( IIO_EV_INFO_HYSTERESIS ) |
BIT ( IIO_EV_INFO_ENABLE ) ,
} ,
{
. type = IIO_EV_TYPE_MAG ,
. dir = IIO_EV_DIR_RISING ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_PERIOD ) |
BIT ( IIO_EV_INFO_HYSTERESIS ) |
BIT ( IIO_EV_INFO_ENABLE ) ,
} ,
2022-08-31 12:01:17 +05:30
{
. type = IIO_EV_TYPE_GESTURE ,
. dir = IIO_EV_DIR_SINGLETAP ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_ENABLE ) |
BIT ( IIO_EV_INFO_RESET_TIMEOUT ) ,
} ,
{
. type = IIO_EV_TYPE_GESTURE ,
. dir = IIO_EV_DIR_DOUBLETAP ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_ENABLE ) |
BIT ( IIO_EV_INFO_RESET_TIMEOUT ) |
BIT ( IIO_EV_INFO_TAP2_MIN_DELAY ) ,
} ,
} ;
static int usec_to_tapreg_raw ( int usec , const int * time_list )
{
int index ;
for ( index = 0 ; index < BMA400_TAP_TIM_LIST_LEN ; index + + ) {
if ( usec = = time_list [ index ] )
return index ;
}
return - EINVAL ;
}
static ssize_t in_accel_gesture_tap_maxtomin_time_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct bma400_data * data = iio_priv ( indio_dev ) ;
int ret , reg_val , raw , vals [ 2 ] ;
ret = regmap_read ( data - > regmap , BMA400_TAP_CONFIG1 , & reg_val ) ;
if ( ret )
return ret ;
raw = FIELD_GET ( BMA400_TAP_TICSTH_MSK , reg_val ) ;
vals [ 0 ] = 0 ;
vals [ 1 ] = tap_max2min_time [ raw ] ;
return iio_format_value ( buf , IIO_VAL_INT_PLUS_MICRO , 2 , vals ) ;
}
static ssize_t in_accel_gesture_tap_maxtomin_time_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct bma400_data * data = iio_priv ( indio_dev ) ;
int ret , val_int , val_fract , raw ;
ret = iio_str_to_fixpoint ( buf , 100000 , & val_int , & val_fract ) ;
if ( ret )
return ret ;
raw = usec_to_tapreg_raw ( val_fract , tap_max2min_time ) ;
if ( raw < 0 )
return - EINVAL ;
ret = regmap_update_bits ( data - > regmap , BMA400_TAP_CONFIG1 ,
BMA400_TAP_TICSTH_MSK ,
FIELD_PREP ( BMA400_TAP_TICSTH_MSK , raw ) ) ;
if ( ret )
return ret ;
return len ;
}
static IIO_DEVICE_ATTR_RW ( in_accel_gesture_tap_maxtomin_time , 0 ) ;
/*
* Tap interrupts works with 200 Hz input data rate and the time based tap
* controls are in the terms of data samples so the below calculation is
* used to convert the configuration values into seconds .
* e . g . :
* 60 data samples * 0.005 ms = 0.3 seconds .
* 80 data samples * 0.005 ms = 0.4 seconds .
*/
/* quiet configuration values in seconds */
static IIO_CONST_ATTR ( in_accel_gesture_tap_reset_timeout_available ,
" 0.3 0.4 0.5 0.6 " ) ;
/* tics_th configuration values in seconds */
static IIO_CONST_ATTR ( in_accel_gesture_tap_maxtomin_time_available ,
" 0.03 0.045 0.06 0.09 " ) ;
/* quiet_dt configuration values in seconds */
static IIO_CONST_ATTR ( in_accel_gesture_doubletap_tap2_min_delay_available ,
" 0.02 0.04 0.06 0.08 " ) ;
/* List of sensitivity values available to configure tap interrupts */
static IIO_CONST_ATTR ( in_accel_gesture_tap_value_available , " 0 1 2 3 4 5 6 7 " ) ;
static struct attribute * bma400_event_attributes [ ] = {
& iio_const_attr_in_accel_gesture_tap_value_available . dev_attr . attr ,
& iio_const_attr_in_accel_gesture_tap_reset_timeout_available . dev_attr . attr ,
& iio_const_attr_in_accel_gesture_tap_maxtomin_time_available . dev_attr . attr ,
& iio_const_attr_in_accel_gesture_doubletap_tap2_min_delay_available . dev_attr . attr ,
& iio_dev_attr_in_accel_gesture_tap_maxtomin_time . dev_attr . attr ,
NULL
} ;
static const struct attribute_group bma400_event_attribute_group = {
. attrs = bma400_event_attributes ,
2022-05-05 19:00:19 +05:30
} ;
2022-05-05 19:00:15 +05:30
# define BMA400_ACC_CHANNEL(_index, _axis) { \
2019-12-20 16:00:50 +00:00
. 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_SAMP_FREQ ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_OVERSAMPLING_RATIO ) , \
. info_mask_shared_by_type_available = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) | \
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_OVERSAMPLING_RATIO ) , \
. ext_info = bma400_ext_info , \
2022-05-05 19:00:15 +05:30
. scan_index = _index , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 12 , \
. storagebits = 16 , \
. endianness = IIO_LE , \
} , \
2022-05-05 19:00:19 +05:30
. event_spec = bma400_accel_event , \
. num_event_specs = ARRAY_SIZE ( bma400_accel_event ) \
2019-12-20 16:00:50 +00:00
}
2022-05-05 19:00:18 +05:30
# define BMA400_ACTIVITY_CHANNEL(_chan2) { \
. type = IIO_ACTIVITY , \
. modified = 1 , \
. channel2 = _chan2 , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) , \
. scan_index = - 1 , /* No buffer support */ \
. event_spec = & bma400_activity_event , \
. num_event_specs = 1 , \
}
2019-12-20 16:00:50 +00:00
static const struct iio_chan_spec bma400_channels [ ] = {
2022-05-05 19:00:15 +05:30
BMA400_ACC_CHANNEL ( 0 , X ) ,
BMA400_ACC_CHANNEL ( 1 , Y ) ,
BMA400_ACC_CHANNEL ( 2 , Z ) ,
2019-12-20 16:00:50 +00:00
{
. type = IIO_TEMP ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) ,
2022-05-05 19:00:15 +05:30
. scan_index = 3 ,
. scan_type = {
. sign = ' s ' ,
. realbits = 8 ,
. storagebits = 8 ,
. endianness = IIO_LE ,
} ,
2019-12-20 16:00:50 +00:00
} ,
2022-05-05 19:00:16 +05:30
{
. type = IIO_STEPS ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) |
BIT ( IIO_CHAN_INFO_ENABLE ) ,
. scan_index = - 1 , /* No buffer support */
2022-05-05 19:00:17 +05:30
. event_spec = & bma400_step_detect_event ,
. num_event_specs = 1 ,
2022-05-05 19:00:16 +05:30
} ,
2022-05-05 19:00:18 +05:30
BMA400_ACTIVITY_CHANNEL ( IIO_MOD_STILL ) ,
BMA400_ACTIVITY_CHANNEL ( IIO_MOD_WALKING ) ,
BMA400_ACTIVITY_CHANNEL ( IIO_MOD_RUNNING ) ,
2022-05-05 19:00:15 +05:30
IIO_CHAN_SOFT_TIMESTAMP ( 4 ) ,
2019-12-20 16:00:50 +00:00
} ;
static int bma400_get_temp_reg ( struct bma400_data * data , int * val , int * val2 )
{
unsigned int raw_temp ;
int host_temp ;
int ret ;
if ( data - > power_mode = = POWER_MODE_SLEEP )
return - EBUSY ;
ret = regmap_read ( data - > regmap , BMA400_TEMP_DATA_REG , & raw_temp ) ;
if ( ret )
return ret ;
host_temp = sign_extend32 ( raw_temp , 7 ) ;
/*
* The formula for the TEMP_DATA register in the datasheet
* is : x * 0.5 + 23
*/
* val = ( host_temp > > 1 ) + 23 ;
* val2 = ( host_temp & 0x1 ) * 500000 ;
return IIO_VAL_INT_PLUS_MICRO ;
}
static int bma400_get_accel_reg ( struct bma400_data * data ,
const struct iio_chan_spec * chan ,
int * val )
{
__le16 raw_accel ;
int lsb_reg ;
int ret ;
if ( data - > power_mode = = POWER_MODE_SLEEP )
return - EBUSY ;
switch ( chan - > channel2 ) {
case IIO_MOD_X :
lsb_reg = BMA400_X_AXIS_LSB_REG ;
break ;
case IIO_MOD_Y :
lsb_reg = BMA400_Y_AXIS_LSB_REG ;
break ;
case IIO_MOD_Z :
lsb_reg = BMA400_Z_AXIS_LSB_REG ;
break ;
default :
dev_err ( data - > dev , " invalid axis channel modifier \n " ) ;
return - EINVAL ;
}
/* bulk read two registers, with the base being the LSB register */
ret = regmap_bulk_read ( data - > regmap , lsb_reg , & raw_accel ,
sizeof ( raw_accel ) ) ;
if ( ret )
return ret ;
* val = sign_extend32 ( le16_to_cpu ( raw_accel ) , 11 ) ;
return IIO_VAL_INT ;
}
static void bma400_output_data_rate_from_raw ( int raw , unsigned int * val ,
unsigned int * val2 )
{
* val = BMA400_ACC_ODR_MAX_HZ > > ( BMA400_ACC_ODR_MAX_RAW - raw ) ;
if ( raw > BMA400_ACC_ODR_MIN_RAW )
* val2 = 0 ;
else
* val2 = 500000 ;
}
static int bma400_get_accel_output_data_rate ( struct bma400_data * data )
{
unsigned int val ;
unsigned int odr ;
int ret ;
switch ( data - > power_mode ) {
case POWER_MODE_LOW :
/*
* Runs at a fixed rate in low - power mode . See section 4.3
* in the datasheet .
*/
bma400_output_data_rate_from_raw ( BMA400_ACC_ODR_LP_RAW ,
& data - > sample_freq . hz ,
& data - > sample_freq . uhz ) ;
return 0 ;
case POWER_MODE_NORMAL :
/*
* In normal mode the ODR can be found in the ACC_CONFIG1
* register .
*/
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG1_REG , & val ) ;
if ( ret )
goto error ;
odr = val & BMA400_ACC_ODR_MASK ;
if ( odr < BMA400_ACC_ODR_MIN_RAW | |
odr > BMA400_ACC_ODR_MAX_RAW ) {
ret = - EINVAL ;
goto error ;
}
bma400_output_data_rate_from_raw ( odr , & data - > sample_freq . hz ,
& data - > sample_freq . uhz ) ;
return 0 ;
case POWER_MODE_SLEEP :
data - > sample_freq . hz = 0 ;
data - > sample_freq . uhz = 0 ;
return 0 ;
default :
ret = 0 ;
goto error ;
}
error :
data - > sample_freq . hz = - 1 ;
data - > sample_freq . uhz = - 1 ;
return ret ;
}
static int bma400_set_accel_output_data_rate ( struct bma400_data * data ,
int hz , int uhz )
{
unsigned int idx ;
unsigned int odr ;
unsigned int val ;
int ret ;
if ( hz > = BMA400_ACC_ODR_MIN_WHOLE_HZ ) {
if ( uhz | | hz > BMA400_ACC_ODR_MAX_HZ )
return - EINVAL ;
/* Note this works because MIN_WHOLE_HZ is odd */
idx = __ffs ( hz ) ;
if ( hz > > idx ! = BMA400_ACC_ODR_MIN_WHOLE_HZ )
return - EINVAL ;
idx + = BMA400_ACC_ODR_MIN_RAW + 1 ;
} else if ( hz = = BMA400_ACC_ODR_MIN_HZ & & uhz = = 500000 ) {
idx = BMA400_ACC_ODR_MIN_RAW ;
} else {
return - EINVAL ;
}
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG1_REG , & val ) ;
if ( ret )
return ret ;
/* preserve the range and normal mode osr */
odr = ( ~ BMA400_ACC_ODR_MASK & val ) | idx ;
ret = regmap_write ( data - > regmap , BMA400_ACC_CONFIG1_REG , odr ) ;
if ( ret )
return ret ;
bma400_output_data_rate_from_raw ( idx , & data - > sample_freq . hz ,
& data - > sample_freq . uhz ) ;
return 0 ;
}
static int bma400_get_accel_oversampling_ratio ( struct bma400_data * data )
{
unsigned int val ;
unsigned int osr ;
int ret ;
/*
* The oversampling ratio is stored in a different register
* based on the power - mode . In normal mode the OSR is stored
* in ACC_CONFIG1 . In low - power mode it is stored in
* ACC_CONFIG0 .
*/
switch ( data - > power_mode ) {
case POWER_MODE_LOW :
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG0_REG , & val ) ;
if ( ret ) {
data - > oversampling_ratio = - 1 ;
return ret ;
}
osr = ( val & BMA400_LP_OSR_MASK ) > > BMA400_LP_OSR_SHIFT ;
data - > oversampling_ratio = osr ;
return 0 ;
case POWER_MODE_NORMAL :
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG1_REG , & val ) ;
if ( ret ) {
data - > oversampling_ratio = - 1 ;
return ret ;
}
osr = ( val & BMA400_NP_OSR_MASK ) > > BMA400_NP_OSR_SHIFT ;
data - > oversampling_ratio = osr ;
return 0 ;
case POWER_MODE_SLEEP :
data - > oversampling_ratio = 0 ;
return 0 ;
default :
data - > oversampling_ratio = - 1 ;
return - EINVAL ;
}
}
static int bma400_set_accel_oversampling_ratio ( struct bma400_data * data ,
int val )
{
unsigned int acc_config ;
int ret ;
if ( val & ~ BMA400_TWO_BITS_MASK )
return - EINVAL ;
/*
* The oversampling ratio is stored in a different register
* based on the power - mode .
*/
switch ( data - > power_mode ) {
case POWER_MODE_LOW :
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG0_REG ,
& acc_config ) ;
if ( ret )
return ret ;
ret = regmap_write ( data - > regmap , BMA400_ACC_CONFIG0_REG ,
( acc_config & ~ BMA400_LP_OSR_MASK ) |
( val < < BMA400_LP_OSR_SHIFT ) ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to write out OSR \n " ) ;
return ret ;
}
data - > oversampling_ratio = val ;
return 0 ;
case POWER_MODE_NORMAL :
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG1_REG ,
& acc_config ) ;
if ( ret )
return ret ;
ret = regmap_write ( data - > regmap , BMA400_ACC_CONFIG1_REG ,
( acc_config & ~ BMA400_NP_OSR_MASK ) |
( val < < BMA400_NP_OSR_SHIFT ) ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to write out OSR \n " ) ;
return ret ;
}
data - > oversampling_ratio = val ;
return 0 ;
default :
return - EINVAL ;
}
return ret ;
}
static int bma400_accel_scale_to_raw ( struct bma400_data * data ,
unsigned int val )
{
int raw ;
if ( val = = 0 )
return - EINVAL ;
/* Note this works because BMA400_SCALE_MIN is odd */
raw = __ffs ( val ) ;
if ( val > > raw ! = BMA400_SCALE_MIN )
return - EINVAL ;
return raw ;
}
static int bma400_get_accel_scale ( struct bma400_data * data )
{
unsigned int raw_scale ;
unsigned int val ;
int ret ;
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG1_REG , & val ) ;
if ( ret )
return ret ;
raw_scale = ( val & BMA400_ACC_SCALE_MASK ) > > BMA400_SCALE_SHIFT ;
if ( raw_scale > BMA400_TWO_BITS_MASK )
return - EINVAL ;
data - > scale = BMA400_SCALE_MIN < < raw_scale ;
return 0 ;
}
static int bma400_set_accel_scale ( struct bma400_data * data , unsigned int val )
{
unsigned int acc_config ;
int raw ;
int ret ;
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG1_REG , & acc_config ) ;
if ( ret )
return ret ;
raw = bma400_accel_scale_to_raw ( data , val ) ;
if ( raw < 0 )
return raw ;
ret = regmap_write ( data - > regmap , BMA400_ACC_CONFIG1_REG ,
( acc_config & ~ BMA400_ACC_SCALE_MASK ) |
( raw < < BMA400_SCALE_SHIFT ) ) ;
if ( ret )
return ret ;
data - > scale = val ;
return 0 ;
}
static int bma400_get_power_mode ( struct bma400_data * data )
{
unsigned int val ;
int ret ;
ret = regmap_read ( data - > regmap , BMA400_STATUS_REG , & val ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to read status register \n " ) ;
return ret ;
}
data - > power_mode = ( val > > 1 ) & BMA400_TWO_BITS_MASK ;
return 0 ;
}
static int bma400_set_power_mode ( struct bma400_data * data ,
enum bma400_power_mode mode )
{
unsigned int val ;
int ret ;
ret = regmap_read ( data - > regmap , BMA400_ACC_CONFIG0_REG , & val ) ;
if ( ret )
return ret ;
if ( data - > power_mode = = mode )
return 0 ;
if ( mode = = POWER_MODE_INVALID )
return - EINVAL ;
/* Preserve the low-power oversample ratio etc */
ret = regmap_write ( data - > regmap , BMA400_ACC_CONFIG0_REG ,
mode | ( val & ~ BMA400_TWO_BITS_MASK ) ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to write to power-mode \n " ) ;
return ret ;
}
data - > power_mode = mode ;
/*
* Update our cached osr and odr based on the new
* power - mode .
*/
bma400_get_accel_output_data_rate ( data ) ;
bma400_get_accel_oversampling_ratio ( data ) ;
return 0 ;
}
2022-05-05 19:00:16 +05:30
static int bma400_enable_steps ( struct bma400_data * data , int val )
{
int ret ;
if ( data - > steps_enabled = = val )
return 0 ;
ret = regmap_update_bits ( data - > regmap , BMA400_INT_CONFIG1_REG ,
BMA400_STEP_INT_MSK ,
FIELD_PREP ( BMA400_STEP_INT_MSK , val ? 1 : 0 ) ) ;
if ( ret )
return ret ;
data - > steps_enabled = val ;
return ret ;
}
static int bma400_get_steps_reg ( struct bma400_data * data , int * val )
{
u8 * steps_raw ;
int ret ;
steps_raw = kmalloc ( BMA400_STEP_RAW_LEN , GFP_KERNEL ) ;
if ( ! steps_raw )
return - ENOMEM ;
ret = regmap_bulk_read ( data - > regmap , BMA400_STEP_CNT0_REG ,
steps_raw , BMA400_STEP_RAW_LEN ) ;
if ( ret )
return ret ;
* val = get_unaligned_le24 ( steps_raw ) ;
kfree ( steps_raw ) ;
return IIO_VAL_INT ;
}
2019-12-20 16:00:50 +00:00
static void bma400_init_tables ( void )
{
int raw ;
int i ;
for ( i = 0 ; i + 1 < ARRAY_SIZE ( bma400_sample_freqs ) ; i + = 2 ) {
raw = ( i / 2 ) + 5 ;
bma400_output_data_rate_from_raw ( raw , & bma400_sample_freqs [ i ] ,
& bma400_sample_freqs [ i + 1 ] ) ;
}
for ( i = 0 ; i + 1 < ARRAY_SIZE ( bma400_scales ) ; i + = 2 ) {
raw = i / 2 ;
bma400_scales [ i ] = 0 ;
bma400_scales [ i + 1 ] = BMA400_SCALE_MIN < < raw ;
}
}
2022-05-05 19:00:14 +05:30
static void bma400_regulators_disable ( void * data_ptr )
{
struct bma400_data * data = data_ptr ;
regulator_bulk_disable ( ARRAY_SIZE ( data - > regulators ) , data - > regulators ) ;
}
static void bma400_power_disable ( void * data_ptr )
{
struct bma400_data * data = data_ptr ;
int ret ;
mutex_lock ( & data - > mutex ) ;
ret = bma400_set_power_mode ( data , POWER_MODE_SLEEP ) ;
mutex_unlock ( & data - > mutex ) ;
if ( ret )
dev_warn ( data - > dev , " Failed to put device into sleep mode (%pe) \n " ,
ERR_PTR ( ret ) ) ;
}
2022-05-05 19:00:18 +05:30
static enum iio_modifier bma400_act_to_mod ( enum bma400_activity activity )
{
switch ( activity ) {
case BMA400_STILL :
return IIO_MOD_STILL ;
case BMA400_WALKING :
return IIO_MOD_WALKING ;
case BMA400_RUNNING :
return IIO_MOD_RUNNING ;
default :
return IIO_NO_MOD ;
}
}
2019-12-20 16:00:50 +00:00
static int bma400_init ( struct bma400_data * data )
{
unsigned int val ;
int ret ;
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read ( data - > regmap , BMA400_CHIP_ID_REG , & val ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to read chip id register \n " ) ;
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:50 +00:00
}
if ( val ! = BMA400_ID_REG_VAL ) {
dev_err ( data - > dev , " Chip ID mismatch \n " ) ;
2022-05-05 19:00:14 +05:30
return - ENODEV ;
2019-12-20 16:00:50 +00:00
}
2019-12-20 16:00:51 +00:00
data - > regulators [ BMA400_VDD_REGULATOR ] . supply = " vdd " ;
data - > regulators [ BMA400_VDDIO_REGULATOR ] . supply = " vddio " ;
ret = devm_regulator_bulk_get ( data - > dev ,
ARRAY_SIZE ( data - > regulators ) ,
data - > regulators ) ;
2022-09-21 02:39:15 +00:00
if ( ret )
return dev_err_probe ( data - > dev , ret , " Failed to get regulators: %d \n " ,
ret ) ;
2019-12-20 16:00:51 +00:00
ret = regulator_bulk_enable ( ARRAY_SIZE ( data - > regulators ) ,
data - > regulators ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to enable regulators: %d \n " ,
ret ) ;
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:51 +00:00
}
2022-05-05 19:00:14 +05:30
ret = devm_add_action_or_reset ( data - > dev , bma400_regulators_disable , data ) ;
if ( ret )
return ret ;
2019-12-20 16:00:50 +00:00
ret = bma400_get_power_mode ( data ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to get the initial power-mode \n " ) ;
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:50 +00:00
}
if ( data - > power_mode ! = POWER_MODE_NORMAL ) {
ret = bma400_set_power_mode ( data , POWER_MODE_NORMAL ) ;
if ( ret ) {
dev_err ( data - > dev , " Failed to wake up the device \n " ) ;
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:50 +00:00
}
/*
* TODO : The datasheet waits 1500u s here in the example , but
* lists 2 / ODR as the wakeup time .
*/
usleep_range ( 1500 , 2000 ) ;
}
2022-05-05 19:00:14 +05:30
ret = devm_add_action_or_reset ( data - > dev , bma400_power_disable , data ) ;
if ( ret )
return ret ;
2019-12-20 16:00:50 +00:00
bma400_init_tables ( ) ;
ret = bma400_get_accel_output_data_rate ( data ) ;
if ( ret )
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:50 +00:00
ret = bma400_get_accel_oversampling_ratio ( data ) ;
if ( ret )
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:50 +00:00
ret = bma400_get_accel_scale ( data ) ;
if ( ret )
2022-05-05 19:00:14 +05:30
return ret ;
2019-12-20 16:00:50 +00:00
2022-05-05 19:00:15 +05:30
/* Configure INT1 pin to open drain */
ret = regmap_write ( data - > regmap , BMA400_INT_IO_CTRL_REG , 0x06 ) ;
if ( ret )
return ret ;
2019-12-20 16:00:50 +00:00
/*
* Once the interrupt engine is supported we might use the
* data_src_reg , but for now ensure this is set to the
* variable ODR filter selectable by the sample frequency
* channel .
*/
return regmap_write ( data - > regmap , BMA400_ACC_CONFIG2_REG , 0x00 ) ;
}
static int bma400_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
{
struct bma400_data * data = iio_priv ( indio_dev ) ;
2022-05-05 19:00:18 +05:30
unsigned int activity ;
2019-12-20 16:00:50 +00:00
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_PROCESSED :
2022-05-05 19:00:16 +05:30
switch ( chan - > type ) {
case IIO_TEMP :
mutex_lock ( & data - > mutex ) ;
ret = bma400_get_temp_reg ( data , val , val2 ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
case IIO_STEPS :
return bma400_get_steps_reg ( data , val ) ;
2022-05-05 19:00:18 +05:30
case IIO_ACTIVITY :
ret = regmap_read ( data - > regmap , BMA400_STEP_STAT_REG ,
& activity ) ;
if ( ret )
return ret ;
/*
* The device does not support confidence value levels ,
* so we will always have 100 % for current activity and
* 0 % for the others .
*/
if ( chan - > channel2 = = bma400_act_to_mod ( activity ) )
* val = 100 ;
else
* val = 0 ;
return IIO_VAL_INT ;
2022-05-05 19:00:16 +05:30
default :
return - EINVAL ;
}
2019-12-20 16:00:50 +00:00
case IIO_CHAN_INFO_RAW :
mutex_lock ( & data - > mutex ) ;
ret = bma400_get_accel_reg ( data , chan , val ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
case IIO_CHAN_INFO_SAMP_FREQ :
switch ( chan - > type ) {
case IIO_ACCEL :
if ( data - > sample_freq . hz < 0 )
return - EINVAL ;
* val = data - > sample_freq . hz ;
* val2 = data - > sample_freq . uhz ;
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_TEMP :
/*
* Runs at a fixed sampling frequency . See Section 4.4
* of the datasheet .
*/
* val = 6 ;
* val2 = 250000 ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_SCALE :
* val = 0 ;
* val2 = data - > scale ;
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO :
/*
* TODO : We could avoid this logic and returning - EINVAL here if
* we set both the low - power and normal mode OSR registers when
* we configure the device .
*/
if ( data - > oversampling_ratio < 0 )
return - EINVAL ;
* val = data - > oversampling_ratio ;
return IIO_VAL_INT ;
2022-05-05 19:00:16 +05:30
case IIO_CHAN_INFO_ENABLE :
* val = data - > steps_enabled ;
return IIO_VAL_INT ;
2019-12-20 16:00:50 +00:00
default :
return - EINVAL ;
}
}
static int bma400_read_avail ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
const int * * vals , int * type , int * length ,
long mask )
{
switch ( mask ) {
case IIO_CHAN_INFO_SCALE :
* type = IIO_VAL_INT_PLUS_MICRO ;
* vals = bma400_scales ;
* length = ARRAY_SIZE ( bma400_scales ) ;
return IIO_AVAIL_LIST ;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO :
* type = IIO_VAL_INT ;
* vals = bma400_osr_range ;
* length = ARRAY_SIZE ( bma400_osr_range ) ;
return IIO_AVAIL_RANGE ;
case IIO_CHAN_INFO_SAMP_FREQ :
* type = IIO_VAL_INT_PLUS_MICRO ;
* vals = bma400_sample_freqs ;
* length = ARRAY_SIZE ( bma400_sample_freqs ) ;
return IIO_AVAIL_LIST ;
default :
return - EINVAL ;
}
}
static int bma400_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int val , int val2 ,
long mask )
{
struct bma400_data * data = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
/*
* The sample frequency is readonly for the temperature
* register and a fixed value in low - power mode .
*/
if ( chan - > type ! = IIO_ACCEL )
return - EINVAL ;
mutex_lock ( & data - > mutex ) ;
ret = bma400_set_accel_output_data_rate ( data , val , val2 ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
case IIO_CHAN_INFO_SCALE :
2020-01-16 13:08:29 +03:00
if ( val ! = 0 | |
val2 < BMA400_SCALE_MIN | | val2 > BMA400_SCALE_MAX )
2019-12-20 16:00:50 +00:00
return - EINVAL ;
mutex_lock ( & data - > mutex ) ;
ret = bma400_set_accel_scale ( data , val2 ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO :
mutex_lock ( & data - > mutex ) ;
ret = bma400_set_accel_oversampling_ratio ( data , val ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
2022-05-05 19:00:16 +05:30
case IIO_CHAN_INFO_ENABLE :
mutex_lock ( & data - > mutex ) ;
ret = bma400_enable_steps ( data , val ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
2019-12-20 16:00:50 +00:00
default :
return - EINVAL ;
}
}
static int bma400_write_raw_get_fmt ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
long mask )
{
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_SCALE :
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO :
return IIO_VAL_INT ;
2022-05-05 19:00:16 +05:30
case IIO_CHAN_INFO_ENABLE :
return IIO_VAL_INT ;
2019-12-20 16:00:50 +00:00
default :
return - EINVAL ;
}
}
2022-05-05 19:00:17 +05:30
static int bma400_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 bma400_data * data = iio_priv ( indio_dev ) ;
switch ( chan - > type ) {
2022-05-05 19:00:19 +05:30
case IIO_ACCEL :
switch ( dir ) {
case IIO_EV_DIR_RISING :
return FIELD_GET ( BMA400_INT_GEN1_MSK ,
data - > generic_event_en ) ;
case IIO_EV_DIR_FALLING :
return FIELD_GET ( BMA400_INT_GEN2_MSK ,
data - > generic_event_en ) ;
2022-08-31 12:01:17 +05:30
case IIO_EV_DIR_SINGLETAP :
return FIELD_GET ( BMA400_S_TAP_MSK ,
data - > tap_event_en_bitmask ) ;
case IIO_EV_DIR_DOUBLETAP :
return FIELD_GET ( BMA400_D_TAP_MSK ,
data - > tap_event_en_bitmask ) ;
2022-05-05 19:00:19 +05:30
default :
return - EINVAL ;
}
2022-05-05 19:00:17 +05:30
case IIO_STEPS :
return data - > step_event_en ;
2022-05-05 19:00:18 +05:30
case IIO_ACTIVITY :
return data - > activity_event_en ;
2022-05-05 19:00:17 +05:30
default :
return - EINVAL ;
}
}
static int bma400_steps_event_enable ( struct bma400_data * data , int state )
{
int ret ;
ret = bma400_enable_steps ( data , 1 ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( data - > regmap , BMA400_INT12_MAP_REG ,
BMA400_STEP_INT_MSK ,
FIELD_PREP ( BMA400_STEP_INT_MSK ,
state ) ) ;
if ( ret )
return ret ;
data - > step_event_en = state ;
return 0 ;
}
2022-05-05 19:00:19 +05:30
static int bma400_activity_event_en ( struct bma400_data * data ,
enum iio_event_direction dir ,
int state )
{
2022-09-17 14:14:01 +01:00
int ret , reg , msk , value ;
int field_value = 0 ;
2022-05-05 19:00:19 +05:30
switch ( dir ) {
case IIO_EV_DIR_RISING :
reg = BMA400_GEN1INT_CONFIG0 ;
msk = BMA400_INT_GEN1_MSK ;
value = 2 ;
set_mask_bits ( & field_value , BMA400_INT_GEN1_MSK ,
FIELD_PREP ( BMA400_INT_GEN1_MSK , state ) ) ;
break ;
case IIO_EV_DIR_FALLING :
reg = BMA400_GEN2INT_CONFIG0 ;
msk = BMA400_INT_GEN2_MSK ;
value = 0 ;
set_mask_bits ( & field_value , BMA400_INT_GEN2_MSK ,
FIELD_PREP ( BMA400_INT_GEN2_MSK , state ) ) ;
break ;
default :
return - EINVAL ;
}
/* Enabling all axis for interrupt evaluation */
ret = regmap_write ( data - > regmap , reg , 0xF8 ) ;
if ( ret )
return ret ;
/* OR combination of all axis for interrupt evaluation */
ret = regmap_write ( data - > regmap , reg + BMA400_GEN_CONFIG1_OFF , value ) ;
if ( ret )
return ret ;
/* Initial value to avoid interrupts while enabling*/
ret = regmap_write ( data - > regmap , reg + BMA400_GEN_CONFIG2_OFF , 0x0A ) ;
if ( ret )
return ret ;
/* Initial duration value to avoid interrupts while enabling*/
ret = regmap_write ( data - > regmap , reg + BMA400_GEN_CONFIG31_OFF , 0x0F ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( data - > regmap , BMA400_INT1_MAP_REG , msk ,
field_value ) ;
if ( ret )
return ret ;
ret = regmap_update_bits ( data - > regmap , BMA400_INT_CONFIG0_REG , msk ,
field_value ) ;
if ( ret )
return ret ;
set_mask_bits ( & data - > generic_event_en , msk , field_value ) ;
return 0 ;
}
2022-08-31 12:01:17 +05:30
static int bma400_tap_event_en ( struct bma400_data * data ,
enum iio_event_direction dir , int state )
{
unsigned int mask , field_value ;
int ret ;
/*
* Tap interrupts can be configured only in normal mode .
* See table in section 4.3 " Power modes - performance modes " of
* datasheet v1 .2 .
*/
if ( data - > power_mode ! = POWER_MODE_NORMAL )
return - EINVAL ;
/*
* Tap interrupts are operating with a data rate of 200 Hz .
* See section 4.7 " Tap sensing interrupt " in datasheet v1 .2 .
*/
if ( data - > sample_freq . hz ! = 200 & & state ) {
dev_err ( data - > dev , " Invalid data rate for tap interrupts. \n " ) ;
return - EINVAL ;
}
ret = regmap_update_bits ( data - > regmap , BMA400_INT12_MAP_REG ,
BMA400_S_TAP_MSK ,
FIELD_PREP ( BMA400_S_TAP_MSK , state ) ) ;
if ( ret )
return ret ;
switch ( dir ) {
case IIO_EV_DIR_SINGLETAP :
mask = BMA400_S_TAP_MSK ;
set_mask_bits ( & field_value , BMA400_S_TAP_MSK ,
FIELD_PREP ( BMA400_S_TAP_MSK , state ) ) ;
break ;
case IIO_EV_DIR_DOUBLETAP :
mask = BMA400_D_TAP_MSK ;
set_mask_bits ( & field_value , BMA400_D_TAP_MSK ,
FIELD_PREP ( BMA400_D_TAP_MSK , state ) ) ;
break ;
default :
return - EINVAL ;
}
ret = regmap_update_bits ( data - > regmap , BMA400_INT_CONFIG1_REG , mask ,
field_value ) ;
if ( ret )
return ret ;
set_mask_bits ( & data - > tap_event_en_bitmask , mask , field_value ) ;
return 0 ;
}
static int bma400_disable_adv_interrupt ( struct bma400_data * data )
{
int ret ;
ret = regmap_write ( data - > regmap , BMA400_INT_CONFIG0_REG , 0 ) ;
if ( ret )
return ret ;
ret = regmap_write ( data - > regmap , BMA400_INT_CONFIG1_REG , 0 ) ;
if ( ret )
return ret ;
data - > tap_event_en_bitmask = 0 ;
data - > generic_event_en = 0 ;
data - > step_event_en = false ;
data - > activity_event_en = false ;
return 0 ;
}
2022-05-05 19:00:17 +05:30
static int bma400_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 bma400_data * data = iio_priv ( indio_dev ) ;
int ret ;
switch ( chan - > type ) {
2022-05-05 19:00:19 +05:30
case IIO_ACCEL :
2022-08-31 12:01:17 +05:30
switch ( type ) {
case IIO_EV_TYPE_MAG :
mutex_lock ( & data - > mutex ) ;
ret = bma400_activity_event_en ( data , dir , state ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
case IIO_EV_TYPE_GESTURE :
mutex_lock ( & data - > mutex ) ;
ret = bma400_tap_event_en ( data , dir , state ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
default :
return - EINVAL ;
}
2022-05-05 19:00:17 +05:30
case IIO_STEPS :
mutex_lock ( & data - > mutex ) ;
ret = bma400_steps_event_enable ( data , state ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
2022-05-05 19:00:18 +05:30
case IIO_ACTIVITY :
mutex_lock ( & data - > mutex ) ;
if ( ! data - > step_event_en ) {
ret = bma400_steps_event_enable ( data , true ) ;
if ( ret ) {
mutex_unlock ( & data - > mutex ) ;
return ret ;
}
}
data - > activity_event_en = state ;
mutex_unlock ( & data - > mutex ) ;
return 0 ;
2022-05-05 19:00:17 +05:30
default :
return - EINVAL ;
}
}
2022-05-05 19:00:19 +05:30
static int get_gen_config_reg ( enum iio_event_direction dir )
{
switch ( dir ) {
case IIO_EV_DIR_FALLING :
return BMA400_GEN2INT_CONFIG0 ;
case IIO_EV_DIR_RISING :
return BMA400_GEN1INT_CONFIG0 ;
default :
return - EINVAL ;
}
}
static int bma400_read_event_value ( 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 bma400_data * data = iio_priv ( indio_dev ) ;
2022-08-31 12:01:17 +05:30
int ret , reg , reg_val , raw ;
2022-05-05 19:00:19 +05:30
2022-08-31 12:01:17 +05:30
if ( chan - > type ! = IIO_ACCEL )
return - EINVAL ;
switch ( type ) {
case IIO_EV_TYPE_MAG :
2022-05-05 19:00:19 +05:30
reg = get_gen_config_reg ( dir ) ;
if ( reg < 0 )
return - EINVAL ;
* val2 = 0 ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
ret = regmap_read ( data - > regmap ,
reg + BMA400_GEN_CONFIG2_OFF ,
val ) ;
if ( ret )
return ret ;
return IIO_VAL_INT ;
case IIO_EV_INFO_PERIOD :
mutex_lock ( & data - > mutex ) ;
ret = regmap_bulk_read ( data - > regmap ,
reg + BMA400_GEN_CONFIG3_OFF ,
& data - > duration ,
sizeof ( data - > duration ) ) ;
if ( ret ) {
mutex_unlock ( & data - > mutex ) ;
return ret ;
}
* val = be16_to_cpu ( data - > duration ) ;
mutex_unlock ( & data - > mutex ) ;
return IIO_VAL_INT ;
case IIO_EV_INFO_HYSTERESIS :
ret = regmap_read ( data - > regmap , reg , val ) ;
if ( ret )
return ret ;
* val = FIELD_GET ( BMA400_GEN_HYST_MSK , * val ) ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
2022-08-31 12:01:17 +05:30
case IIO_EV_TYPE_GESTURE :
switch ( info ) {
case IIO_EV_INFO_VALUE :
ret = regmap_read ( data - > regmap , BMA400_TAP_CONFIG ,
& reg_val ) ;
if ( ret )
return ret ;
* val = FIELD_GET ( BMA400_TAP_SEN_MSK , reg_val ) ;
return IIO_VAL_INT ;
case IIO_EV_INFO_RESET_TIMEOUT :
ret = regmap_read ( data - > regmap , BMA400_TAP_CONFIG1 ,
& reg_val ) ;
if ( ret )
return ret ;
raw = FIELD_GET ( BMA400_TAP_QUIET_MSK , reg_val ) ;
* val = 0 ;
* val2 = tap_reset_timeout [ raw ] ;
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_EV_INFO_TAP2_MIN_DELAY :
ret = regmap_read ( data - > regmap , BMA400_TAP_CONFIG1 ,
& reg_val ) ;
if ( ret )
return ret ;
raw = FIELD_GET ( BMA400_TAP_QUIETDT_MSK , reg_val ) ;
* val = 0 ;
* val2 = double_tap2_min_delay [ raw ] ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
2022-05-05 19:00:19 +05:30
default :
return - EINVAL ;
}
}
static int bma400_write_event_value ( 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 bma400_data * data = iio_priv ( indio_dev ) ;
2022-08-31 12:01:17 +05:30
int reg , ret , raw ;
2022-05-05 19:00:19 +05:30
2022-08-31 12:01:17 +05:30
if ( chan - > type ! = IIO_ACCEL )
return - EINVAL ;
switch ( type ) {
case IIO_EV_TYPE_MAG :
2022-05-05 19:00:19 +05:30
reg = get_gen_config_reg ( dir ) ;
if ( reg < 0 )
return - EINVAL ;
switch ( info ) {
case IIO_EV_INFO_VALUE :
if ( val < 1 | | val > 255 )
return - EINVAL ;
return regmap_write ( data - > regmap ,
reg + BMA400_GEN_CONFIG2_OFF ,
val ) ;
case IIO_EV_INFO_PERIOD :
if ( val < 1 | | val > 65535 )
return - EINVAL ;
mutex_lock ( & data - > mutex ) ;
put_unaligned_be16 ( val , & data - > duration ) ;
ret = regmap_bulk_write ( data - > regmap ,
reg + BMA400_GEN_CONFIG3_OFF ,
& data - > duration ,
sizeof ( data - > duration ) ) ;
mutex_unlock ( & data - > mutex ) ;
return ret ;
case IIO_EV_INFO_HYSTERESIS :
if ( val < 0 | | val > 3 )
return - EINVAL ;
return regmap_update_bits ( data - > regmap , reg ,
BMA400_GEN_HYST_MSK ,
FIELD_PREP ( BMA400_GEN_HYST_MSK ,
val ) ) ;
default :
return - EINVAL ;
}
2022-08-31 12:01:17 +05:30
case IIO_EV_TYPE_GESTURE :
switch ( info ) {
case IIO_EV_INFO_VALUE :
if ( val < 0 | | val > 7 )
return - EINVAL ;
return regmap_update_bits ( data - > regmap ,
BMA400_TAP_CONFIG ,
BMA400_TAP_SEN_MSK ,
FIELD_PREP ( BMA400_TAP_SEN_MSK ,
val ) ) ;
case IIO_EV_INFO_RESET_TIMEOUT :
raw = usec_to_tapreg_raw ( val2 , tap_reset_timeout ) ;
if ( raw < 0 )
return - EINVAL ;
return regmap_update_bits ( data - > regmap ,
BMA400_TAP_CONFIG1 ,
BMA400_TAP_QUIET_MSK ,
FIELD_PREP ( BMA400_TAP_QUIET_MSK ,
raw ) ) ;
case IIO_EV_INFO_TAP2_MIN_DELAY :
raw = usec_to_tapreg_raw ( val2 , double_tap2_min_delay ) ;
if ( raw < 0 )
return - EINVAL ;
return regmap_update_bits ( data - > regmap ,
BMA400_TAP_CONFIG1 ,
BMA400_TAP_QUIETDT_MSK ,
FIELD_PREP ( BMA400_TAP_QUIETDT_MSK ,
raw ) ) ;
default :
return - EINVAL ;
}
2022-05-05 19:00:19 +05:30
default :
return - EINVAL ;
}
}
2022-05-05 19:00:15 +05:30
static int bma400_data_rdy_trigger_set_state ( struct iio_trigger * trig ,
bool state )
{
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
struct bma400_data * data = iio_priv ( indio_dev ) ;
int ret ;
ret = regmap_update_bits ( data - > regmap , BMA400_INT_CONFIG0_REG ,
BMA400_INT_DRDY_MSK ,
FIELD_PREP ( BMA400_INT_DRDY_MSK , state ) ) ;
if ( ret )
return ret ;
return regmap_update_bits ( data - > regmap , BMA400_INT1_MAP_REG ,
BMA400_INT_DRDY_MSK ,
FIELD_PREP ( BMA400_INT_DRDY_MSK , state ) ) ;
}
static const unsigned long bma400_avail_scan_masks [ ] = {
BIT ( BMA400_ACCL_X ) | BIT ( BMA400_ACCL_Y ) | BIT ( BMA400_ACCL_Z ) ,
BIT ( BMA400_ACCL_X ) | BIT ( BMA400_ACCL_Y ) | BIT ( BMA400_ACCL_Z )
| BIT ( BMA400_TEMP ) ,
0
} ;
2019-12-20 16:00:50 +00:00
static const struct iio_info bma400_info = {
. read_raw = bma400_read_raw ,
. read_avail = bma400_read_avail ,
. write_raw = bma400_write_raw ,
. write_raw_get_fmt = bma400_write_raw_get_fmt ,
2022-05-05 19:00:17 +05:30
. read_event_config = bma400_read_event_config ,
. write_event_config = bma400_write_event_config ,
2022-05-05 19:00:19 +05:30
. write_event_value = bma400_write_event_value ,
. read_event_value = bma400_read_event_value ,
2022-08-31 12:01:17 +05:30
. event_attrs = & bma400_event_attribute_group ,
2019-12-20 16:00:50 +00:00
} ;
2022-05-05 19:00:15 +05:30
static const struct iio_trigger_ops bma400_trigger_ops = {
. set_trigger_state = & bma400_data_rdy_trigger_set_state ,
. validate_device = & iio_trigger_validate_own_device ,
} ;
static irqreturn_t bma400_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct bma400_data * data = iio_priv ( indio_dev ) ;
int ret , temp ;
/* Lock to protect the data->buffer */
mutex_lock ( & data - > mutex ) ;
/* bulk read six registers, with the base being the LSB register */
ret = regmap_bulk_read ( data - > regmap , BMA400_X_AXIS_LSB_REG ,
& data - > buffer . buff , sizeof ( data - > buffer . buff ) ) ;
if ( ret )
goto unlock_err ;
if ( test_bit ( BMA400_TEMP , indio_dev - > active_scan_mask ) ) {
ret = regmap_read ( data - > regmap , BMA400_TEMP_DATA_REG , & temp ) ;
if ( ret )
goto unlock_err ;
data - > buffer . temperature = temp ;
}
iio_push_to_buffers_with_timestamp ( indio_dev , & data - > buffer ,
iio_get_time_ns ( indio_dev ) ) ;
mutex_unlock ( & data - > mutex ) ;
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
unlock_err :
mutex_unlock ( & data - > mutex ) ;
return IRQ_NONE ;
}
static irqreturn_t bma400_interrupt ( int irq , void * private )
{
struct iio_dev * indio_dev = private ;
struct bma400_data * data = iio_priv ( indio_dev ) ;
2022-05-05 19:00:17 +05:30
s64 timestamp = iio_get_time_ns ( indio_dev ) ;
2022-05-05 19:00:19 +05:30
unsigned int act , ev_dir = IIO_EV_DIR_NONE ;
2022-05-05 19:00:15 +05:30
int ret ;
/* Lock to protect the data->status */
mutex_lock ( & data - > mutex ) ;
ret = regmap_bulk_read ( data - > regmap , BMA400_INT_STAT0_REG ,
& data - > status ,
sizeof ( data - > status ) ) ;
/*
* if none of the bit is set in the status register then it is
* spurious interrupt .
*/
if ( ret | | ! data - > status )
goto unlock_err ;
2022-08-31 12:01:17 +05:30
/*
* Disable all advance interrupts if interrupt engine overrun occurs .
* See section 4.7 " Interrupt engine overrun " in datasheet v1 .2 .
*/
if ( FIELD_GET ( BMA400_INT_ENG_OVRUN_MSK , le16_to_cpu ( data - > status ) ) ) {
bma400_disable_adv_interrupt ( data ) ;
dev_err ( data - > dev , " Interrupt engine overrun \n " ) ;
goto unlock_err ;
}
if ( FIELD_GET ( BMA400_INT_S_TAP_MSK , le16_to_cpu ( data - > status ) ) )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 ,
IIO_MOD_X_OR_Y_OR_Z ,
IIO_EV_TYPE_GESTURE ,
IIO_EV_DIR_SINGLETAP ) ,
timestamp ) ;
if ( FIELD_GET ( BMA400_INT_D_TAP_MSK , le16_to_cpu ( data - > status ) ) )
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 ,
IIO_MOD_X_OR_Y_OR_Z ,
IIO_EV_TYPE_GESTURE ,
IIO_EV_DIR_DOUBLETAP ) ,
timestamp ) ;
2022-05-05 19:00:19 +05:30
if ( FIELD_GET ( BMA400_INT_GEN1_MSK , le16_to_cpu ( data - > status ) ) )
ev_dir = IIO_EV_DIR_RISING ;
if ( FIELD_GET ( BMA400_INT_GEN2_MSK , le16_to_cpu ( data - > status ) ) )
ev_dir = IIO_EV_DIR_FALLING ;
if ( ev_dir ! = IIO_EV_DIR_NONE ) {
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 ,
IIO_MOD_X_OR_Y_OR_Z ,
IIO_EV_TYPE_MAG , ev_dir ) ,
timestamp ) ;
}
2022-05-05 19:00:17 +05:30
if ( FIELD_GET ( BMA400_STEP_STAT_MASK , le16_to_cpu ( data - > status ) ) ) {
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_STEPS , 0 , IIO_NO_MOD ,
IIO_EV_TYPE_CHANGE ,
IIO_EV_DIR_NONE ) ,
timestamp ) ;
2022-05-05 19:00:18 +05:30
if ( data - > activity_event_en ) {
ret = regmap_read ( data - > regmap , BMA400_STEP_STAT_REG ,
& act ) ;
if ( ret )
goto unlock_err ;
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACTIVITY , 0 ,
bma400_act_to_mod ( act ) ,
IIO_EV_TYPE_CHANGE ,
IIO_EV_DIR_NONE ) ,
timestamp ) ;
}
2022-05-05 19:00:17 +05:30
}
2022-05-05 19:00:15 +05:30
if ( FIELD_GET ( BMA400_INT_DRDY_MSK , le16_to_cpu ( data - > status ) ) ) {
mutex_unlock ( & data - > mutex ) ;
iio_trigger_poll_chained ( data - > trig ) ;
return IRQ_HANDLED ;
}
2022-05-05 19:00:17 +05:30
mutex_unlock ( & data - > mutex ) ;
return IRQ_HANDLED ;
2022-05-05 19:00:15 +05:30
unlock_err :
mutex_unlock ( & data - > mutex ) ;
return IRQ_NONE ;
}
int bma400_probe ( struct device * dev , struct regmap * regmap , int irq ,
const char * name )
2019-12-20 16:00:50 +00:00
{
struct iio_dev * indio_dev ;
struct bma400_data * data ;
int ret ;
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
data - > regmap = regmap ;
data - > dev = dev ;
ret = bma400_init ( data ) ;
if ( ret )
return ret ;
2021-05-18 14:25:46 +03:00
ret = iio_read_mount_matrix ( dev , & data - > orientation ) ;
2019-12-20 16:00:50 +00:00
if ( ret )
return ret ;
mutex_init ( & data - > mutex ) ;
indio_dev - > name = name ;
indio_dev - > info = & bma400_info ;
indio_dev - > channels = bma400_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( bma400_channels ) ;
2022-05-05 19:00:15 +05:30
indio_dev - > available_scan_masks = bma400_avail_scan_masks ;
2019-12-20 16:00:50 +00:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2022-05-05 19:00:15 +05:30
if ( irq > 0 ) {
data - > trig = devm_iio_trigger_alloc ( dev , " %s-dev%d " ,
indio_dev - > name ,
iio_device_id ( indio_dev ) ) ;
if ( ! data - > trig )
return - ENOMEM ;
data - > trig - > ops = & bma400_trigger_ops ;
iio_trigger_set_drvdata ( data - > trig , indio_dev ) ;
ret = devm_iio_trigger_register ( data - > dev , data - > trig ) ;
if ( ret )
return dev_err_probe ( data - > dev , ret ,
" iio trigger register fail \n " ) ;
indio_dev - > trig = iio_trigger_get ( data - > trig ) ;
ret = devm_request_threaded_irq ( dev , irq , NULL ,
& bma400_interrupt ,
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
indio_dev - > name , indio_dev ) ;
if ( ret )
return dev_err_probe ( data - > dev , ret ,
" request irq %d failed \n " , irq ) ;
}
ret = devm_iio_triggered_buffer_setup ( dev , indio_dev , NULL ,
& bma400_trigger_handler , NULL ) ;
if ( ret )
return dev_err_probe ( data - > dev , ret ,
" iio triggered buffer setup failed \n " ) ;
2022-05-05 19:00:14 +05:30
return devm_iio_device_register ( dev , indio_dev ) ;
2019-12-20 16:00:50 +00:00
}
2022-01-16 18:05:26 +00:00
EXPORT_SYMBOL_NS ( bma400_probe , IIO_BMA400 ) ;
2019-12-20 16:00:50 +00:00
MODULE_AUTHOR ( " Dan Robertson <dan@dlrobertson.com> " ) ;
2022-08-31 12:01:17 +05:30
MODULE_AUTHOR ( " Jagath Jog J <jagathjog1996@gmail.com> " ) ;
2019-12-20 16:00:50 +00:00
MODULE_DESCRIPTION ( " Bosch BMA400 triaxial acceleration sensor core " ) ;
MODULE_LICENSE ( " GPL " ) ;