2019-02-02 13:55:56 -08:00
// SPDX-License-Identifier: GPL-2.0
2016-04-15 18:06:56 +03:00
/*
* BMI160 - Bosch IMU ( accel , gyro plus external magnetometer )
*
* Copyright ( c ) 2016 , Intel Corporation .
2019-02-02 13:55:57 -08:00
* Copyright ( c ) 2019 , Martin Kelly .
2016-04-15 18:06:56 +03:00
*
* IIO core driver for BMI160 , with support for I2C / SPI busses
*
2019-02-02 13:55:57 -08:00
* TODO : magnetometer , hardware FIFO
2016-04-15 18:06:56 +03:00
*/
# include <linux/module.h>
# include <linux/regmap.h>
# include <linux/acpi.h>
# include <linux/delay.h>
2019-02-02 13:55:57 -08:00
# include <linux/irq.h>
# include <linux/of_irq.h>
2020-05-25 18:46:03 +02:00
# include <linux/regulator/consumer.h>
2016-04-15 18:06:56 +03:00
# include <linux/iio/iio.h>
# include <linux/iio/triggered_buffer.h>
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/buffer.h>
2016-04-29 14:42:35 +03:00
# include <linux/iio/sysfs.h>
2019-02-02 13:55:57 -08:00
# include <linux/iio/trigger.h>
2016-04-15 18:06:56 +03:00
# include "bmi160.h"
# define BMI160_REG_CHIP_ID 0x00
# define BMI160_CHIP_ID_VAL 0xD1
# define BMI160_REG_PMU_STATUS 0x03
/* X axis data low byte address, the rest can be obtained using axis offset */
# define BMI160_REG_DATA_MAGN_XOUT_L 0x04
# define BMI160_REG_DATA_GYRO_XOUT_L 0x0C
# define BMI160_REG_DATA_ACCEL_XOUT_L 0x12
# define BMI160_REG_ACCEL_CONFIG 0x40
# define BMI160_ACCEL_CONFIG_ODR_MASK GENMASK(3, 0)
# define BMI160_ACCEL_CONFIG_BWP_MASK GENMASK(6, 4)
# define BMI160_REG_ACCEL_RANGE 0x41
# define BMI160_ACCEL_RANGE_2G 0x03
# define BMI160_ACCEL_RANGE_4G 0x05
# define BMI160_ACCEL_RANGE_8G 0x08
# define BMI160_ACCEL_RANGE_16G 0x0C
# define BMI160_REG_GYRO_CONFIG 0x42
# define BMI160_GYRO_CONFIG_ODR_MASK GENMASK(3, 0)
# define BMI160_GYRO_CONFIG_BWP_MASK GENMASK(5, 4)
# define BMI160_REG_GYRO_RANGE 0x43
# define BMI160_GYRO_RANGE_2000DPS 0x00
# define BMI160_GYRO_RANGE_1000DPS 0x01
# define BMI160_GYRO_RANGE_500DPS 0x02
# define BMI160_GYRO_RANGE_250DPS 0x03
# define BMI160_GYRO_RANGE_125DPS 0x04
# define BMI160_REG_CMD 0x7E
# define BMI160_CMD_ACCEL_PM_SUSPEND 0x10
# define BMI160_CMD_ACCEL_PM_NORMAL 0x11
# define BMI160_CMD_ACCEL_PM_LOW_POWER 0x12
# define BMI160_CMD_GYRO_PM_SUSPEND 0x14
# define BMI160_CMD_GYRO_PM_NORMAL 0x15
# define BMI160_CMD_GYRO_PM_FAST_STARTUP 0x17
# define BMI160_CMD_SOFTRESET 0xB6
2019-02-02 13:55:57 -08:00
# define BMI160_REG_INT_EN 0x51
# define BMI160_DRDY_INT_EN BIT(4)
# define BMI160_REG_INT_OUT_CTRL 0x53
# define BMI160_INT_OUT_CTRL_MASK 0x0f
# define BMI160_INT1_OUT_CTRL_SHIFT 0
# define BMI160_INT2_OUT_CTRL_SHIFT 4
# define BMI160_EDGE_TRIGGERED BIT(0)
# define BMI160_ACTIVE_HIGH BIT(1)
# define BMI160_OPEN_DRAIN BIT(2)
# define BMI160_OUTPUT_EN BIT(3)
# define BMI160_REG_INT_LATCH 0x54
# define BMI160_INT1_LATCH_MASK BIT(4)
# define BMI160_INT2_LATCH_MASK BIT(5)
/* INT1 and INT2 are in the opposite order as in INT_OUT_CTRL! */
# define BMI160_REG_INT_MAP 0x56
# define BMI160_INT1_MAP_DRDY_EN 0x80
# define BMI160_INT2_MAP_DRDY_EN 0x08
2016-04-15 18:06:56 +03:00
# define BMI160_REG_DUMMY 0x7F
2019-02-02 13:55:57 -08:00
# define BMI160_NORMAL_WRITE_USLEEP 2
# define BMI160_SUSPENDED_WRITE_USLEEP 450
2016-12-08 15:22:58 +01:00
# define BMI160_ACCEL_PMU_MIN_USLEEP 3800
# define BMI160_GYRO_PMU_MIN_USLEEP 80000
2016-04-15 18:06:56 +03:00
# define BMI160_SOFTRESET_USLEEP 1000
# define BMI160_CHANNEL(_type, _axis, _index) { \
. type = _type , \
. 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 ) , \
. scan_index = _index , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 16 , \
. storagebits = 16 , \
. endianness = IIO_LE , \
} , \
2020-05-25 18:46:04 +02:00
. ext_info = bmi160_ext_info , \
2016-04-15 18:06:56 +03:00
}
/* scan indexes follow DATA register order */
enum bmi160_scan_axis {
BMI160_SCAN_EXT_MAGN_X = 0 ,
BMI160_SCAN_EXT_MAGN_Y ,
BMI160_SCAN_EXT_MAGN_Z ,
BMI160_SCAN_RHALL ,
BMI160_SCAN_GYRO_X ,
BMI160_SCAN_GYRO_Y ,
BMI160_SCAN_GYRO_Z ,
BMI160_SCAN_ACCEL_X ,
BMI160_SCAN_ACCEL_Y ,
BMI160_SCAN_ACCEL_Z ,
BMI160_SCAN_TIMESTAMP ,
} ;
enum bmi160_sensor_type {
BMI160_ACCEL = 0 ,
BMI160_GYRO ,
BMI160_EXT_MAGN ,
BMI160_NUM_SENSORS /* must be last */
} ;
2019-02-02 13:55:57 -08:00
enum bmi160_int_pin {
BMI160_PIN_INT1 ,
BMI160_PIN_INT2
2016-04-15 18:06:56 +03:00
} ;
const struct regmap_config bmi160_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
EXPORT_SYMBOL ( bmi160_regmap_config ) ;
struct bmi160_regs {
u8 data ; /* LSB byte register for X-axis */
u8 config ;
u8 config_odr_mask ;
u8 config_bwp_mask ;
u8 range ;
u8 pmu_cmd_normal ;
u8 pmu_cmd_suspend ;
} ;
static struct bmi160_regs bmi160_regs [ ] = {
[ BMI160_ACCEL ] = {
. data = BMI160_REG_DATA_ACCEL_XOUT_L ,
. config = BMI160_REG_ACCEL_CONFIG ,
. config_odr_mask = BMI160_ACCEL_CONFIG_ODR_MASK ,
. config_bwp_mask = BMI160_ACCEL_CONFIG_BWP_MASK ,
. range = BMI160_REG_ACCEL_RANGE ,
. pmu_cmd_normal = BMI160_CMD_ACCEL_PM_NORMAL ,
. pmu_cmd_suspend = BMI160_CMD_ACCEL_PM_SUSPEND ,
} ,
[ BMI160_GYRO ] = {
. data = BMI160_REG_DATA_GYRO_XOUT_L ,
. config = BMI160_REG_GYRO_CONFIG ,
. config_odr_mask = BMI160_GYRO_CONFIG_ODR_MASK ,
. config_bwp_mask = BMI160_GYRO_CONFIG_BWP_MASK ,
. range = BMI160_REG_GYRO_RANGE ,
. pmu_cmd_normal = BMI160_CMD_GYRO_PM_NORMAL ,
. pmu_cmd_suspend = BMI160_CMD_GYRO_PM_SUSPEND ,
} ,
} ;
2016-12-08 15:22:58 +01:00
static unsigned long bmi160_pmu_time [ ] = {
[ BMI160_ACCEL ] = BMI160_ACCEL_PMU_MIN_USLEEP ,
[ BMI160_GYRO ] = BMI160_GYRO_PMU_MIN_USLEEP ,
2016-04-15 18:06:56 +03:00
} ;
struct bmi160_scale {
u8 bits ;
int uscale ;
} ;
struct bmi160_odr {
u8 bits ;
int odr ;
int uodr ;
} ;
static const struct bmi160_scale bmi160_accel_scale [ ] = {
{ BMI160_ACCEL_RANGE_2G , 598 } ,
{ BMI160_ACCEL_RANGE_4G , 1197 } ,
{ BMI160_ACCEL_RANGE_8G , 2394 } ,
{ BMI160_ACCEL_RANGE_16G , 4788 } ,
} ;
static const struct bmi160_scale bmi160_gyro_scale [ ] = {
{ BMI160_GYRO_RANGE_2000DPS , 1065 } ,
{ BMI160_GYRO_RANGE_1000DPS , 532 } ,
{ BMI160_GYRO_RANGE_500DPS , 266 } ,
{ BMI160_GYRO_RANGE_250DPS , 133 } ,
{ BMI160_GYRO_RANGE_125DPS , 66 } ,
} ;
struct bmi160_scale_item {
const struct bmi160_scale * tbl ;
int num ;
} ;
static const struct bmi160_scale_item bmi160_scale_table [ ] = {
[ BMI160_ACCEL ] = {
. tbl = bmi160_accel_scale ,
. num = ARRAY_SIZE ( bmi160_accel_scale ) ,
} ,
[ BMI160_GYRO ] = {
. tbl = bmi160_gyro_scale ,
. num = ARRAY_SIZE ( bmi160_gyro_scale ) ,
} ,
} ;
static const struct bmi160_odr bmi160_accel_odr [ ] = {
2016-04-29 14:42:33 +03:00
{ 0x01 , 0 , 781250 } ,
{ 0x02 , 1 , 562500 } ,
{ 0x03 , 3 , 125000 } ,
{ 0x04 , 6 , 250000 } ,
{ 0x05 , 12 , 500000 } ,
2016-04-15 18:06:56 +03:00
{ 0x06 , 25 , 0 } ,
{ 0x07 , 50 , 0 } ,
{ 0x08 , 100 , 0 } ,
{ 0x09 , 200 , 0 } ,
{ 0x0A , 400 , 0 } ,
{ 0x0B , 800 , 0 } ,
{ 0x0C , 1600 , 0 } ,
} ;
static const struct bmi160_odr bmi160_gyro_odr [ ] = {
{ 0x06 , 25 , 0 } ,
{ 0x07 , 50 , 0 } ,
{ 0x08 , 100 , 0 } ,
{ 0x09 , 200 , 0 } ,
{ 0x0A , 400 , 0 } ,
2016-04-29 14:42:33 +03:00
{ 0x0B , 800 , 0 } ,
2016-04-15 18:06:56 +03:00
{ 0x0C , 1600 , 0 } ,
{ 0x0D , 3200 , 0 } ,
} ;
struct bmi160_odr_item {
const struct bmi160_odr * tbl ;
int num ;
} ;
static const struct bmi160_odr_item bmi160_odr_table [ ] = {
[ BMI160_ACCEL ] = {
. tbl = bmi160_accel_odr ,
. num = ARRAY_SIZE ( bmi160_accel_odr ) ,
} ,
[ BMI160_GYRO ] = {
. tbl = bmi160_gyro_odr ,
. num = ARRAY_SIZE ( bmi160_gyro_odr ) ,
} ,
} ;
2020-05-25 18:46:04 +02:00
static const struct iio_mount_matrix *
bmi160_get_mount_matrix ( const struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct bmi160_data * data = iio_priv ( indio_dev ) ;
return & data - > orientation ;
}
static const struct iio_chan_spec_ext_info bmi160_ext_info [ ] = {
IIO_MOUNT_MATRIX ( IIO_SHARED_BY_DIR , bmi160_get_mount_matrix ) ,
{ }
} ;
2016-04-15 18:06:56 +03:00
static const struct iio_chan_spec bmi160_channels [ ] = {
BMI160_CHANNEL ( IIO_ACCEL , X , BMI160_SCAN_ACCEL_X ) ,
BMI160_CHANNEL ( IIO_ACCEL , Y , BMI160_SCAN_ACCEL_Y ) ,
BMI160_CHANNEL ( IIO_ACCEL , Z , BMI160_SCAN_ACCEL_Z ) ,
BMI160_CHANNEL ( IIO_ANGL_VEL , X , BMI160_SCAN_GYRO_X ) ,
BMI160_CHANNEL ( IIO_ANGL_VEL , Y , BMI160_SCAN_GYRO_Y ) ,
BMI160_CHANNEL ( IIO_ANGL_VEL , Z , BMI160_SCAN_GYRO_Z ) ,
IIO_CHAN_SOFT_TIMESTAMP ( BMI160_SCAN_TIMESTAMP ) ,
} ;
static enum bmi160_sensor_type bmi160_to_sensor ( enum iio_chan_type iio_type )
{
switch ( iio_type ) {
case IIO_ACCEL :
return BMI160_ACCEL ;
case IIO_ANGL_VEL :
return BMI160_GYRO ;
default :
return - EINVAL ;
}
}
static
int bmi160_set_mode ( struct bmi160_data * data , enum bmi160_sensor_type t ,
bool mode )
{
int ret ;
u8 cmd ;
if ( mode )
cmd = bmi160_regs [ t ] . pmu_cmd_normal ;
else
cmd = bmi160_regs [ t ] . pmu_cmd_suspend ;
ret = regmap_write ( data - > regmap , BMI160_REG_CMD , cmd ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
2016-12-08 15:22:58 +01:00
usleep_range ( bmi160_pmu_time [ t ] , bmi160_pmu_time [ t ] + 1000 ) ;
2016-04-15 18:06:56 +03:00
return 0 ;
}
static
int bmi160_set_scale ( struct bmi160_data * data , enum bmi160_sensor_type t ,
int uscale )
{
int i ;
for ( i = 0 ; i < bmi160_scale_table [ t ] . num ; i + + )
if ( bmi160_scale_table [ t ] . tbl [ i ] . uscale = = uscale )
break ;
if ( i = = bmi160_scale_table [ t ] . num )
return - EINVAL ;
return regmap_write ( data - > regmap , bmi160_regs [ t ] . range ,
bmi160_scale_table [ t ] . tbl [ i ] . bits ) ;
}
static
int bmi160_get_scale ( struct bmi160_data * data , enum bmi160_sensor_type t ,
int * uscale )
{
int i , ret , val ;
ret = regmap_read ( data - > regmap , bmi160_regs [ t ] . range , & val ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
for ( i = 0 ; i < bmi160_scale_table [ t ] . num ; i + + )
if ( bmi160_scale_table [ t ] . tbl [ i ] . bits = = val ) {
* uscale = bmi160_scale_table [ t ] . tbl [ i ] . uscale ;
return 0 ;
}
return - EINVAL ;
}
static int bmi160_get_data ( struct bmi160_data * data , int chan_type ,
int axis , int * val )
{
u8 reg ;
int ret ;
__le16 sample ;
enum bmi160_sensor_type t = bmi160_to_sensor ( chan_type ) ;
2017-01-15 21:01:10 -08:00
reg = bmi160_regs [ t ] . data + ( axis - IIO_MOD_X ) * sizeof ( sample ) ;
2016-04-15 18:06:56 +03:00
2017-01-15 21:01:10 -08:00
ret = regmap_bulk_read ( data - > regmap , reg , & sample , sizeof ( sample ) ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
* val = sign_extend32 ( le16_to_cpu ( sample ) , 15 ) ;
return 0 ;
}
static
int bmi160_set_odr ( struct bmi160_data * data , enum bmi160_sensor_type t ,
int odr , int uodr )
{
int i ;
for ( i = 0 ; i < bmi160_odr_table [ t ] . num ; i + + )
if ( bmi160_odr_table [ t ] . tbl [ i ] . odr = = odr & &
bmi160_odr_table [ t ] . tbl [ i ] . uodr = = uodr )
break ;
if ( i > = bmi160_odr_table [ t ] . num )
return - EINVAL ;
return regmap_update_bits ( data - > regmap ,
bmi160_regs [ t ] . config ,
2016-04-29 14:42:34 +03:00
bmi160_regs [ t ] . config_odr_mask ,
bmi160_odr_table [ t ] . tbl [ i ] . bits ) ;
2016-04-15 18:06:56 +03:00
}
static int bmi160_get_odr ( struct bmi160_data * data , enum bmi160_sensor_type t ,
int * odr , int * uodr )
{
int i , val , ret ;
ret = regmap_read ( data - > regmap , bmi160_regs [ t ] . config , & val ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
val & = bmi160_regs [ t ] . config_odr_mask ;
for ( i = 0 ; i < bmi160_odr_table [ t ] . num ; i + + )
if ( val = = bmi160_odr_table [ t ] . tbl [ i ] . bits )
break ;
if ( i > = bmi160_odr_table [ t ] . num )
return - EINVAL ;
* odr = bmi160_odr_table [ t ] . tbl [ i ] . odr ;
* uodr = bmi160_odr_table [ t ] . tbl [ i ] . uodr ;
return 0 ;
}
static irqreturn_t bmi160_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct bmi160_data * data = iio_priv ( indio_dev ) ;
int i , ret , j = 0 , base = BMI160_REG_DATA_MAGN_XOUT_L ;
__le16 sample ;
for_each_set_bit ( i , indio_dev - > active_scan_mask ,
indio_dev - > masklength ) {
2017-01-15 21:01:10 -08:00
ret = regmap_bulk_read ( data - > regmap , base + i * sizeof ( sample ) ,
& sample , sizeof ( sample ) ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
goto done ;
2020-09-20 12:27:39 +01:00
data - > buf [ j + + ] = sample ;
2016-04-15 18:06:56 +03:00
}
2020-09-20 12:27:39 +01:00
iio_push_to_buffers_with_timestamp ( indio_dev , data - > buf , pf - > timestamp ) ;
2016-04-15 18:06:56 +03:00
done :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
static int bmi160_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
int ret ;
struct bmi160_data * data = iio_priv ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = bmi160_get_data ( data , chan - > type , chan - > channel2 , val ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
* val = 0 ;
ret = bmi160_get_scale ( data ,
bmi160_to_sensor ( chan - > type ) , val2 ) ;
2019-02-02 13:56:01 -08:00
return ret ? ret : IIO_VAL_INT_PLUS_MICRO ;
2016-04-15 18:06:56 +03:00
case IIO_CHAN_INFO_SAMP_FREQ :
ret = bmi160_get_odr ( data , bmi160_to_sensor ( chan - > type ) ,
val , val2 ) ;
2019-02-02 13:56:01 -08:00
return ret ? ret : IIO_VAL_INT_PLUS_MICRO ;
2016-04-15 18:06:56 +03:00
default :
return - EINVAL ;
}
return 0 ;
}
static int bmi160_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
{
struct bmi160_data * data = iio_priv ( indio_dev ) ;
switch ( mask ) {
case IIO_CHAN_INFO_SCALE :
return bmi160_set_scale ( data ,
bmi160_to_sensor ( chan - > type ) , val2 ) ;
case IIO_CHAN_INFO_SAMP_FREQ :
return bmi160_set_odr ( data , bmi160_to_sensor ( chan - > type ) ,
val , val2 ) ;
default :
return - EINVAL ;
}
return 0 ;
}
2016-04-29 14:42:35 +03:00
static
IIO_CONST_ATTR ( in_accel_sampling_frequency_available ,
" 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 " ) ;
static
IIO_CONST_ATTR ( in_anglvel_sampling_frequency_available ,
" 25 50 100 200 400 800 1600 3200 " ) ;
static
IIO_CONST_ATTR ( in_accel_scale_available ,
" 0.000598 0.001197 0.002394 0.004788 " ) ;
static
IIO_CONST_ATTR ( in_anglvel_scale_available ,
" 0.001065 0.000532 0.000266 0.000133 0.000066 " ) ;
static struct attribute * bmi160_attrs [ ] = {
& iio_const_attr_in_accel_sampling_frequency_available . dev_attr . attr ,
& iio_const_attr_in_anglvel_sampling_frequency_available . dev_attr . attr ,
& iio_const_attr_in_accel_scale_available . dev_attr . attr ,
& iio_const_attr_in_anglvel_scale_available . dev_attr . attr ,
NULL ,
} ;
static const struct attribute_group bmi160_attrs_group = {
. attrs = bmi160_attrs ,
} ;
2016-04-15 18:06:56 +03:00
static const struct iio_info bmi160_info = {
. read_raw = bmi160_read_raw ,
. write_raw = bmi160_write_raw ,
2016-04-29 14:42:35 +03:00
. attrs = & bmi160_attrs_group ,
2016-04-15 18:06:56 +03:00
} ;
static const char * bmi160_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 ) ;
}
2019-02-02 13:55:57 -08:00
static int bmi160_write_conf_reg ( struct regmap * regmap , unsigned int reg ,
unsigned int mask , unsigned int bits ,
unsigned int write_usleep )
{
int ret ;
unsigned int val ;
ret = regmap_read ( regmap , reg , & val ) ;
if ( ret )
return ret ;
val = ( val & ~ mask ) | bits ;
ret = regmap_write ( regmap , reg , val ) ;
if ( ret )
return ret ;
/*
* We need to wait after writing before we can write again . See the
* datasheet , page 93.
*/
usleep_range ( write_usleep , write_usleep + 1000 ) ;
return 0 ;
}
static int bmi160_config_pin ( struct regmap * regmap , enum bmi160_int_pin pin ,
bool open_drain , u8 irq_mask ,
unsigned long write_usleep )
{
int ret ;
struct device * dev = regmap_get_device ( regmap ) ;
u8 int_out_ctrl_shift ;
u8 int_latch_mask ;
u8 int_map_mask ;
u8 int_out_ctrl_mask ;
u8 int_out_ctrl_bits ;
const char * pin_name ;
switch ( pin ) {
case BMI160_PIN_INT1 :
int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT ;
int_latch_mask = BMI160_INT1_LATCH_MASK ;
int_map_mask = BMI160_INT1_MAP_DRDY_EN ;
break ;
case BMI160_PIN_INT2 :
int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT ;
int_latch_mask = BMI160_INT2_LATCH_MASK ;
int_map_mask = BMI160_INT2_MAP_DRDY_EN ;
break ;
}
int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK < < int_out_ctrl_shift ;
/*
* Enable the requested pin with the right settings :
* - Push - pull / open - drain
* - Active low / high
* - Edge / level triggered
*/
int_out_ctrl_bits = BMI160_OUTPUT_EN ;
if ( open_drain )
/* Default is push-pull. */
int_out_ctrl_bits | = BMI160_OPEN_DRAIN ;
int_out_ctrl_bits | = irq_mask ;
int_out_ctrl_bits < < = int_out_ctrl_shift ;
ret = bmi160_write_conf_reg ( regmap , BMI160_REG_INT_OUT_CTRL ,
int_out_ctrl_mask , int_out_ctrl_bits ,
write_usleep ) ;
if ( ret )
return ret ;
/* Set the pin to input mode with no latching. */
ret = bmi160_write_conf_reg ( regmap , BMI160_REG_INT_LATCH ,
int_latch_mask , int_latch_mask ,
write_usleep ) ;
if ( ret )
return ret ;
/* Map interrupts to the requested pin. */
ret = bmi160_write_conf_reg ( regmap , BMI160_REG_INT_MAP ,
int_map_mask , int_map_mask ,
write_usleep ) ;
if ( ret ) {
switch ( pin ) {
case BMI160_PIN_INT1 :
pin_name = " INT1 " ;
break ;
case BMI160_PIN_INT2 :
pin_name = " INT2 " ;
break ;
}
dev_err ( dev , " Failed to configure %s IRQ pin " , pin_name ) ;
}
return ret ;
}
int bmi160_enable_irq ( struct regmap * regmap , bool enable )
{
unsigned int enable_bit = 0 ;
if ( enable )
enable_bit = BMI160_DRDY_INT_EN ;
return bmi160_write_conf_reg ( regmap , BMI160_REG_INT_EN ,
BMI160_DRDY_INT_EN , enable_bit ,
BMI160_NORMAL_WRITE_USLEEP ) ;
}
EXPORT_SYMBOL ( bmi160_enable_irq ) ;
static int bmi160_get_irq ( struct device_node * of_node , enum bmi160_int_pin * pin )
{
int irq ;
/* Use INT1 if possible, otherwise fall back to INT2. */
irq = of_irq_get_byname ( of_node , " INT1 " ) ;
if ( irq > 0 ) {
* pin = BMI160_PIN_INT1 ;
return irq ;
}
irq = of_irq_get_byname ( of_node , " INT2 " ) ;
if ( irq > 0 )
* pin = BMI160_PIN_INT2 ;
return irq ;
}
static int bmi160_config_device_irq ( struct iio_dev * indio_dev , int irq_type ,
enum bmi160_int_pin pin )
{
bool open_drain ;
u8 irq_mask ;
struct bmi160_data * data = iio_priv ( indio_dev ) ;
struct device * dev = regmap_get_device ( data - > regmap ) ;
/* Level-triggered, active-low is the default if we set all zeroes. */
if ( irq_type = = IRQF_TRIGGER_RISING )
irq_mask = BMI160_ACTIVE_HIGH | BMI160_EDGE_TRIGGERED ;
else if ( irq_type = = IRQF_TRIGGER_FALLING )
irq_mask = BMI160_EDGE_TRIGGERED ;
else if ( irq_type = = IRQF_TRIGGER_HIGH )
irq_mask = BMI160_ACTIVE_HIGH ;
else if ( irq_type = = IRQF_TRIGGER_LOW )
irq_mask = 0 ;
else {
dev_err ( & indio_dev - > dev ,
" Invalid interrupt type 0x%x specified \n " , irq_type ) ;
return - EINVAL ;
}
open_drain = of_property_read_bool ( dev - > of_node , " drive-open-drain " ) ;
return bmi160_config_pin ( data - > regmap , pin , open_drain , irq_mask ,
BMI160_NORMAL_WRITE_USLEEP ) ;
}
static int bmi160_setup_irq ( struct iio_dev * indio_dev , int irq ,
enum bmi160_int_pin pin )
{
struct irq_data * desc ;
u32 irq_type ;
int ret ;
desc = irq_get_irq_data ( irq ) ;
if ( ! desc ) {
dev_err ( & indio_dev - > dev , " Could not find IRQ %d \n " , irq ) ;
return - EINVAL ;
}
irq_type = irqd_get_trigger_type ( desc ) ;
ret = bmi160_config_device_irq ( indio_dev , irq_type , pin ) ;
if ( ret )
return ret ;
return bmi160_probe_trigger ( indio_dev , irq , irq_type ) ;
}
2016-04-15 18:06:56 +03:00
static int bmi160_chip_init ( struct bmi160_data * data , bool use_spi )
{
int ret ;
unsigned int val ;
struct device * dev = regmap_get_device ( data - > regmap ) ;
2020-05-25 18:46:03 +02:00
ret = regulator_bulk_enable ( ARRAY_SIZE ( data - > supplies ) , data - > supplies ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable regulators: %d \n " , ret ) ;
return ret ;
}
2016-04-15 18:06:56 +03:00
ret = regmap_write ( data - > regmap , BMI160_REG_CMD , BMI160_CMD_SOFTRESET ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
usleep_range ( BMI160_SOFTRESET_USLEEP , BMI160_SOFTRESET_USLEEP + 1 ) ;
/*
* CS rising edge is needed before starting SPI , so do a dummy read
* See Section 3.2 .1 , page 86 of the datasheet
*/
if ( use_spi ) {
ret = regmap_read ( data - > regmap , BMI160_REG_DUMMY , & val ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
}
ret = regmap_read ( data - > regmap , BMI160_REG_CHIP_ID , & val ) ;
2019-02-02 13:56:01 -08:00
if ( ret ) {
2016-04-15 18:06:56 +03:00
dev_err ( dev , " Error reading chip id \n " ) ;
return ret ;
}
if ( val ! = BMI160_CHIP_ID_VAL ) {
dev_err ( dev , " Wrong chip id, got %x expected %x \n " ,
val , BMI160_CHIP_ID_VAL ) ;
return - ENODEV ;
}
ret = bmi160_set_mode ( data , BMI160_ACCEL , true ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
ret = bmi160_set_mode ( data , BMI160_GYRO , true ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
return 0 ;
}
2019-02-02 13:55:57 -08:00
static int bmi160_data_rdy_trigger_set_state ( struct iio_trigger * trig ,
bool enable )
{
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
struct bmi160_data * data = iio_priv ( indio_dev ) ;
return bmi160_enable_irq ( data - > regmap , enable ) ;
}
static const struct iio_trigger_ops bmi160_trigger_ops = {
. set_trigger_state = & bmi160_data_rdy_trigger_set_state ,
} ;
int bmi160_probe_trigger ( struct iio_dev * indio_dev , int irq , u32 irq_type )
{
struct bmi160_data * data = iio_priv ( indio_dev ) ;
int ret ;
data - > trig = devm_iio_trigger_alloc ( & indio_dev - > dev , " %s-dev%d " ,
indio_dev - > name , indio_dev - > id ) ;
if ( data - > trig = = NULL )
return - ENOMEM ;
ret = devm_request_irq ( & indio_dev - > dev , irq ,
& iio_trigger_generic_data_rdy_poll ,
irq_type , " bmi160 " , data - > trig ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2019-02-02 13:55:57 -08:00
return ret ;
data - > trig - > dev . parent = regmap_get_device ( data - > regmap ) ;
data - > trig - > ops = & bmi160_trigger_ops ;
iio_trigger_set_drvdata ( data - > trig , indio_dev ) ;
ret = devm_iio_trigger_register ( & indio_dev - > dev , data - > trig ) ;
if ( ret )
return ret ;
indio_dev - > trig = iio_trigger_get ( data - > trig ) ;
return 0 ;
}
2018-12-09 19:14:55 -08:00
static void bmi160_chip_uninit ( void * data )
2016-04-15 18:06:56 +03:00
{
2018-12-09 19:14:55 -08:00
struct bmi160_data * bmi_data = data ;
2020-05-25 18:46:03 +02:00
struct device * dev = regmap_get_device ( bmi_data - > regmap ) ;
int ret ;
2018-12-09 19:14:55 -08:00
bmi160_set_mode ( bmi_data , BMI160_GYRO , false ) ;
bmi160_set_mode ( bmi_data , BMI160_ACCEL , false ) ;
2020-05-25 18:46:03 +02:00
ret = regulator_bulk_disable ( ARRAY_SIZE ( bmi_data - > supplies ) ,
bmi_data - > supplies ) ;
if ( ret )
dev_err ( dev , " Failed to disable regulators: %d \n " , ret ) ;
2016-04-15 18:06:56 +03:00
}
int bmi160_core_probe ( struct device * dev , struct regmap * regmap ,
const char * name , bool use_spi )
{
struct iio_dev * indio_dev ;
struct bmi160_data * data ;
2019-02-02 13:55:57 -08:00
int irq ;
enum bmi160_int_pin int_pin ;
2016-04-15 18:06:56 +03:00
int ret ;
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
dev_set_drvdata ( dev , indio_dev ) ;
data - > regmap = regmap ;
2020-05-25 18:46:03 +02:00
data - > supplies [ 0 ] . supply = " vdd " ;
data - > supplies [ 1 ] . supply = " vddio " ;
ret = devm_regulator_bulk_get ( dev ,
ARRAY_SIZE ( data - > supplies ) ,
data - > supplies ) ;
if ( ret ) {
dev_err ( dev , " Failed to get regulators: %d \n " , ret ) ;
return ret ;
}
2020-05-25 18:46:04 +02:00
ret = iio_read_mount_matrix ( dev , " mount-matrix " ,
& data - > orientation ) ;
if ( ret )
return ret ;
2016-04-15 18:06:56 +03:00
ret = bmi160_chip_init ( data , use_spi ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2016-04-15 18:06:56 +03:00
return ret ;
2018-12-09 19:14:55 -08:00
ret = devm_add_action_or_reset ( dev , bmi160_chip_uninit , data ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2018-12-09 19:14:55 -08:00
return ret ;
2016-04-15 18:06:56 +03:00
if ( ! name & & ACPI_HANDLE ( dev ) )
name = bmi160_match_acpi_device ( dev ) ;
indio_dev - > channels = bmi160_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( bmi160_channels ) ;
indio_dev - > name = name ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & bmi160_info ;
2019-02-02 13:56:00 -08:00
ret = devm_iio_triggered_buffer_setup ( dev , indio_dev ,
iio_pollfunc_store_time ,
2018-12-09 19:14:55 -08:00
bmi160_trigger_handler , NULL ) ;
2019-02-02 13:56:01 -08:00
if ( ret )
2018-12-09 19:14:55 -08:00
return ret ;
2016-04-15 18:06:56 +03:00
2019-02-02 13:55:57 -08:00
irq = bmi160_get_irq ( dev - > of_node , & int_pin ) ;
if ( irq > 0 ) {
ret = bmi160_setup_irq ( indio_dev , irq , int_pin ) ;
if ( ret )
dev_err ( & indio_dev - > dev , " Failed to setup IRQ %d \n " ,
irq ) ;
} else {
dev_info ( & indio_dev - > dev , " Not setting up IRQ trigger \n " ) ;
}
2019-02-02 13:56:01 -08:00
return devm_iio_device_register ( dev , indio_dev ) ;
2016-04-15 18:06:56 +03:00
}
EXPORT_SYMBOL_GPL ( bmi160_core_probe ) ;
2020-05-25 18:46:02 +02:00
MODULE_AUTHOR ( " Daniel Baluta <daniel.baluta@intel.com> " ) ;
2016-04-15 18:06:56 +03:00
MODULE_DESCRIPTION ( " Bosch BMI160 driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;