2011-08-09 00:06:37 -07:00
/*
* Copyright ( c ) 2011 Bosch Sensortec GmbH
* Copyright ( c ) 2011 Unixphere
*
* This driver adds support for Bosch Sensortec ' s digital acceleration
* sensors BMA150 and SMB380 .
* The SMB380 is fully compatible with BMA150 and only differs in packaging .
*
* The datasheet for the BMA150 chip can be found here :
* http : //www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/i2c.h>
# include <linux/input.h>
# include <linux/input-polldev.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/pm.h>
# include <linux/pm_runtime.h>
# include <linux/bma150.h>
# define ABSMAX_ACC_VAL 0x01FF
# define ABSMIN_ACC_VAL -(ABSMAX_ACC_VAL)
/* Each axis is represented by a 2-byte data word */
# define BMA150_XYZ_DATA_SIZE 6
/* Input poll interval in milliseconds */
# define BMA150_POLL_INTERVAL 10
# define BMA150_POLL_MAX 200
# define BMA150_POLL_MIN 0
# define BMA150_MODE_NORMAL 0
# define BMA150_MODE_SLEEP 2
# define BMA150_MODE_WAKE_UP 3
/* Data register addresses */
# define BMA150_DATA_0_REG 0x00
# define BMA150_DATA_1_REG 0x01
# define BMA150_DATA_2_REG 0x02
/* Control register addresses */
# define BMA150_CTRL_0_REG 0x0A
# define BMA150_CTRL_1_REG 0x0B
# define BMA150_CTRL_2_REG 0x14
# define BMA150_CTRL_3_REG 0x15
/* Configuration/Setting register addresses */
# define BMA150_CFG_0_REG 0x0C
# define BMA150_CFG_1_REG 0x0D
# define BMA150_CFG_2_REG 0x0E
# define BMA150_CFG_3_REG 0x0F
# define BMA150_CFG_4_REG 0x10
# define BMA150_CFG_5_REG 0x11
# define BMA150_CHIP_ID 2
# define BMA150_CHIP_ID_REG BMA150_DATA_0_REG
# define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG
# define BMA150_SLEEP_POS 0
# define BMA150_SLEEP_MSK 0x01
# define BMA150_SLEEP_REG BMA150_CTRL_0_REG
# define BMA150_BANDWIDTH_POS 0
# define BMA150_BANDWIDTH_MSK 0x07
# define BMA150_BANDWIDTH_REG BMA150_CTRL_2_REG
# define BMA150_RANGE_POS 3
# define BMA150_RANGE_MSK 0x18
# define BMA150_RANGE_REG BMA150_CTRL_2_REG
# define BMA150_WAKE_UP_POS 0
# define BMA150_WAKE_UP_MSK 0x01
# define BMA150_WAKE_UP_REG BMA150_CTRL_3_REG
# define BMA150_SW_RES_POS 1
# define BMA150_SW_RES_MSK 0x02
# define BMA150_SW_RES_REG BMA150_CTRL_0_REG
/* Any-motion interrupt register fields */
# define BMA150_ANY_MOTION_EN_POS 6
# define BMA150_ANY_MOTION_EN_MSK 0x40
# define BMA150_ANY_MOTION_EN_REG BMA150_CTRL_1_REG
# define BMA150_ANY_MOTION_DUR_POS 6
# define BMA150_ANY_MOTION_DUR_MSK 0xC0
# define BMA150_ANY_MOTION_DUR_REG BMA150_CFG_5_REG
# define BMA150_ANY_MOTION_THRES_REG BMA150_CFG_4_REG
/* Advanced interrupt register fields */
# define BMA150_ADV_INT_EN_POS 6
# define BMA150_ADV_INT_EN_MSK 0x40
# define BMA150_ADV_INT_EN_REG BMA150_CTRL_3_REG
/* High-G interrupt register fields */
# define BMA150_HIGH_G_EN_POS 1
# define BMA150_HIGH_G_EN_MSK 0x02
# define BMA150_HIGH_G_EN_REG BMA150_CTRL_1_REG
# define BMA150_HIGH_G_HYST_POS 3
# define BMA150_HIGH_G_HYST_MSK 0x38
# define BMA150_HIGH_G_HYST_REG BMA150_CFG_5_REG
# define BMA150_HIGH_G_DUR_REG BMA150_CFG_3_REG
# define BMA150_HIGH_G_THRES_REG BMA150_CFG_2_REG
/* Low-G interrupt register fields */
# define BMA150_LOW_G_EN_POS 0
# define BMA150_LOW_G_EN_MSK 0x01
# define BMA150_LOW_G_EN_REG BMA150_CTRL_1_REG
# define BMA150_LOW_G_HYST_POS 0
# define BMA150_LOW_G_HYST_MSK 0x07
# define BMA150_LOW_G_HYST_REG BMA150_CFG_5_REG
# define BMA150_LOW_G_DUR_REG BMA150_CFG_1_REG
# define BMA150_LOW_G_THRES_REG BMA150_CFG_0_REG
struct bma150_data {
struct i2c_client * client ;
struct input_polled_dev * input_polled ;
struct input_dev * input ;
u8 mode ;
} ;
/*
* The settings for the given range , bandwidth and interrupt features
* are stated and verified by Bosch Sensortec where they are configured
* to provide a generic sensitivity performance .
*/
2016-01-02 21:04:30 -08:00
static const struct bma150_cfg default_cfg = {
2011-08-09 00:06:37 -07:00
. any_motion_int = 1 ,
. hg_int = 1 ,
. lg_int = 1 ,
. any_motion_dur = 0 ,
. any_motion_thres = 0 ,
. hg_hyst = 0 ,
. hg_dur = 150 ,
. hg_thres = 160 ,
. lg_hyst = 0 ,
. lg_dur = 150 ,
. lg_thres = 20 ,
. range = BMA150_RANGE_2G ,
. bandwidth = BMA150_BW_50HZ
} ;
static int bma150_write_byte ( struct i2c_client * client , u8 reg , u8 val )
{
s32 ret ;
/* As per specification, disable irq in between register writes */
if ( client - > irq )
disable_irq_nosync ( client - > irq ) ;
ret = i2c_smbus_write_byte_data ( client , reg , val ) ;
if ( client - > irq )
enable_irq ( client - > irq ) ;
return ret ;
}
static int bma150_set_reg_bits ( struct i2c_client * client ,
int val , int shift , u8 mask , u8 reg )
{
int data ;
data = i2c_smbus_read_byte_data ( client , reg ) ;
if ( data < 0 )
return data ;
data = ( data & ~ mask ) | ( ( val < < shift ) & mask ) ;
return bma150_write_byte ( client , reg , data ) ;
}
static int bma150_set_mode ( struct bma150_data * bma150 , u8 mode )
{
int error ;
error = bma150_set_reg_bits ( bma150 - > client , mode , BMA150_WAKE_UP_POS ,
BMA150_WAKE_UP_MSK , BMA150_WAKE_UP_REG ) ;
if ( error )
return error ;
error = bma150_set_reg_bits ( bma150 - > client , mode , BMA150_SLEEP_POS ,
BMA150_SLEEP_MSK , BMA150_SLEEP_REG ) ;
if ( error )
return error ;
if ( mode = = BMA150_MODE_NORMAL )
2016-12-27 13:22:42 -08:00
usleep_range ( 2000 , 2100 ) ;
2011-08-09 00:06:37 -07:00
bma150 - > mode = mode ;
return 0 ;
}
2012-11-23 21:38:25 -08:00
static int bma150_soft_reset ( struct bma150_data * bma150 )
2011-08-09 00:06:37 -07:00
{
int error ;
error = bma150_set_reg_bits ( bma150 - > client , 1 , BMA150_SW_RES_POS ,
BMA150_SW_RES_MSK , BMA150_SW_RES_REG ) ;
if ( error )
return error ;
2016-12-27 13:22:42 -08:00
usleep_range ( 2000 , 2100 ) ;
2011-08-09 00:06:37 -07:00
return 0 ;
}
2012-11-23 21:38:25 -08:00
static int bma150_set_range ( struct bma150_data * bma150 , u8 range )
2011-08-09 00:06:37 -07:00
{
return bma150_set_reg_bits ( bma150 - > client , range , BMA150_RANGE_POS ,
BMA150_RANGE_MSK , BMA150_RANGE_REG ) ;
}
2012-11-23 21:38:25 -08:00
static int bma150_set_bandwidth ( struct bma150_data * bma150 , u8 bw )
2011-08-09 00:06:37 -07:00
{
return bma150_set_reg_bits ( bma150 - > client , bw , BMA150_BANDWIDTH_POS ,
BMA150_BANDWIDTH_MSK , BMA150_BANDWIDTH_REG ) ;
}
2012-11-23 21:38:25 -08:00
static int bma150_set_low_g_interrupt ( struct bma150_data * bma150 ,
2011-08-09 00:06:37 -07:00
u8 enable , u8 hyst , u8 dur , u8 thres )
{
int error ;
error = bma150_set_reg_bits ( bma150 - > client , hyst ,
BMA150_LOW_G_HYST_POS , BMA150_LOW_G_HYST_MSK ,
BMA150_LOW_G_HYST_REG ) ;
if ( error )
return error ;
error = bma150_write_byte ( bma150 - > client , BMA150_LOW_G_DUR_REG , dur ) ;
if ( error )
return error ;
error = bma150_write_byte ( bma150 - > client , BMA150_LOW_G_THRES_REG , thres ) ;
if ( error )
return error ;
return bma150_set_reg_bits ( bma150 - > client , ! ! enable ,
BMA150_LOW_G_EN_POS , BMA150_LOW_G_EN_MSK ,
BMA150_LOW_G_EN_REG ) ;
}
2012-11-23 21:38:25 -08:00
static int bma150_set_high_g_interrupt ( struct bma150_data * bma150 ,
2011-08-09 00:06:37 -07:00
u8 enable , u8 hyst , u8 dur , u8 thres )
{
int error ;
error = bma150_set_reg_bits ( bma150 - > client , hyst ,
BMA150_HIGH_G_HYST_POS , BMA150_HIGH_G_HYST_MSK ,
BMA150_HIGH_G_HYST_REG ) ;
if ( error )
return error ;
error = bma150_write_byte ( bma150 - > client ,
BMA150_HIGH_G_DUR_REG , dur ) ;
if ( error )
return error ;
error = bma150_write_byte ( bma150 - > client ,
BMA150_HIGH_G_THRES_REG , thres ) ;
if ( error )
return error ;
return bma150_set_reg_bits ( bma150 - > client , ! ! enable ,
BMA150_HIGH_G_EN_POS , BMA150_HIGH_G_EN_MSK ,
BMA150_HIGH_G_EN_REG ) ;
}
2012-11-23 21:38:25 -08:00
static int bma150_set_any_motion_interrupt ( struct bma150_data * bma150 ,
2011-08-09 00:06:37 -07:00
u8 enable , u8 dur , u8 thres )
{
int error ;
error = bma150_set_reg_bits ( bma150 - > client , dur ,
BMA150_ANY_MOTION_DUR_POS ,
BMA150_ANY_MOTION_DUR_MSK ,
BMA150_ANY_MOTION_DUR_REG ) ;
if ( error )
return error ;
error = bma150_write_byte ( bma150 - > client ,
BMA150_ANY_MOTION_THRES_REG , thres ) ;
if ( error )
return error ;
error = bma150_set_reg_bits ( bma150 - > client , ! ! enable ,
BMA150_ADV_INT_EN_POS , BMA150_ADV_INT_EN_MSK ,
BMA150_ADV_INT_EN_REG ) ;
if ( error )
return error ;
return bma150_set_reg_bits ( bma150 - > client , ! ! enable ,
BMA150_ANY_MOTION_EN_POS ,
BMA150_ANY_MOTION_EN_MSK ,
BMA150_ANY_MOTION_EN_REG ) ;
}
static void bma150_report_xyz ( struct bma150_data * bma150 )
{
u8 data [ BMA150_XYZ_DATA_SIZE ] ;
s16 x , y , z ;
s32 ret ;
ret = i2c_smbus_read_i2c_block_data ( bma150 - > client ,
BMA150_ACC_X_LSB_REG , BMA150_XYZ_DATA_SIZE , data ) ;
if ( ret ! = BMA150_XYZ_DATA_SIZE )
return ;
x = ( ( 0xc0 & data [ 0 ] ) > > 6 ) | ( data [ 1 ] < < 2 ) ;
y = ( ( 0xc0 & data [ 2 ] ) > > 6 ) | ( data [ 3 ] < < 2 ) ;
z = ( ( 0xc0 & data [ 4 ] ) > > 6 ) | ( data [ 5 ] < < 2 ) ;
2015-07-06 15:52:21 -07:00
x = sign_extend32 ( x , 9 ) ;
y = sign_extend32 ( y , 9 ) ;
z = sign_extend32 ( z , 9 ) ;
2011-08-09 00:06:37 -07:00
input_report_abs ( bma150 - > input , ABS_X , x ) ;
input_report_abs ( bma150 - > input , ABS_Y , y ) ;
input_report_abs ( bma150 - > input , ABS_Z , z ) ;
input_sync ( bma150 - > input ) ;
}
static irqreturn_t bma150_irq_thread ( int irq , void * dev )
{
bma150_report_xyz ( dev ) ;
return IRQ_HANDLED ;
}
static void bma150_poll ( struct input_polled_dev * dev )
{
bma150_report_xyz ( dev - > private ) ;
}
static int bma150_open ( struct bma150_data * bma150 )
{
int error ;
error = pm_runtime_get_sync ( & bma150 - > client - > dev ) ;
2013-02-15 14:42:51 -08:00
if ( error < 0 & & error ! = - ENOSYS )
2011-08-09 00:06:37 -07:00
return error ;
/*
* See if runtime PM woke up the device . If runtime PM
* is disabled we need to do it ourselves .
*/
if ( bma150 - > mode ! = BMA150_MODE_NORMAL ) {
error = bma150_set_mode ( bma150 , BMA150_MODE_NORMAL ) ;
if ( error )
return error ;
}
return 0 ;
}
static void bma150_close ( struct bma150_data * bma150 )
{
pm_runtime_put_sync ( & bma150 - > client - > dev ) ;
if ( bma150 - > mode ! = BMA150_MODE_SLEEP )
bma150_set_mode ( bma150 , BMA150_MODE_SLEEP ) ;
}
static int bma150_irq_open ( struct input_dev * input )
{
struct bma150_data * bma150 = input_get_drvdata ( input ) ;
return bma150_open ( bma150 ) ;
}
static void bma150_irq_close ( struct input_dev * input )
{
struct bma150_data * bma150 = input_get_drvdata ( input ) ;
bma150_close ( bma150 ) ;
}
static void bma150_poll_open ( struct input_polled_dev * ipoll_dev )
{
struct bma150_data * bma150 = ipoll_dev - > private ;
bma150_open ( bma150 ) ;
}
static void bma150_poll_close ( struct input_polled_dev * ipoll_dev )
{
struct bma150_data * bma150 = ipoll_dev - > private ;
bma150_close ( bma150 ) ;
}
2012-11-23 21:38:25 -08:00
static int bma150_initialize ( struct bma150_data * bma150 ,
2011-08-09 00:06:37 -07:00
const struct bma150_cfg * cfg )
{
int error ;
error = bma150_soft_reset ( bma150 ) ;
if ( error )
return error ;
error = bma150_set_bandwidth ( bma150 , cfg - > bandwidth ) ;
if ( error )
return error ;
error = bma150_set_range ( bma150 , cfg - > range ) ;
if ( error )
return error ;
if ( bma150 - > client - > irq ) {
error = bma150_set_any_motion_interrupt ( bma150 ,
cfg - > any_motion_int ,
cfg - > any_motion_dur ,
cfg - > any_motion_thres ) ;
if ( error )
return error ;
error = bma150_set_high_g_interrupt ( bma150 ,
cfg - > hg_int , cfg - > hg_hyst ,
cfg - > hg_dur , cfg - > hg_thres ) ;
if ( error )
return error ;
error = bma150_set_low_g_interrupt ( bma150 ,
cfg - > lg_int , cfg - > lg_hyst ,
cfg - > lg_dur , cfg - > lg_thres ) ;
if ( error )
return error ;
}
return bma150_set_mode ( bma150 , BMA150_MODE_SLEEP ) ;
}
2012-11-23 21:38:25 -08:00
static void bma150_init_input_device ( struct bma150_data * bma150 ,
2011-08-09 00:06:37 -07:00
struct input_dev * idev )
{
idev - > name = BMA150_DRIVER ;
idev - > phys = BMA150_DRIVER " /input0 " ;
idev - > id . bustype = BUS_I2C ;
idev - > dev . parent = & bma150 - > client - > dev ;
idev - > evbit [ 0 ] = BIT_MASK ( EV_ABS ) ;
input_set_abs_params ( idev , ABS_X , ABSMIN_ACC_VAL , ABSMAX_ACC_VAL , 0 , 0 ) ;
input_set_abs_params ( idev , ABS_Y , ABSMIN_ACC_VAL , ABSMAX_ACC_VAL , 0 , 0 ) ;
input_set_abs_params ( idev , ABS_Z , ABSMIN_ACC_VAL , ABSMAX_ACC_VAL , 0 , 0 ) ;
}
2012-11-23 21:38:25 -08:00
static int bma150_register_input_device ( struct bma150_data * bma150 )
2011-08-09 00:06:37 -07:00
{
struct input_dev * idev ;
int error ;
idev = input_allocate_device ( ) ;
if ( ! idev )
return - ENOMEM ;
bma150_init_input_device ( bma150 , idev ) ;
idev - > open = bma150_irq_open ;
idev - > close = bma150_irq_close ;
input_set_drvdata ( idev , bma150 ) ;
error = input_register_device ( idev ) ;
if ( error ) {
input_free_device ( idev ) ;
return error ;
}
bma150 - > input = idev ;
return 0 ;
}
2012-11-23 21:38:25 -08:00
static int bma150_register_polled_device ( struct bma150_data * bma150 )
2011-08-09 00:06:37 -07:00
{
struct input_polled_dev * ipoll_dev ;
int error ;
ipoll_dev = input_allocate_polled_device ( ) ;
if ( ! ipoll_dev )
return - ENOMEM ;
ipoll_dev - > private = bma150 ;
ipoll_dev - > open = bma150_poll_open ;
ipoll_dev - > close = bma150_poll_close ;
ipoll_dev - > poll = bma150_poll ;
ipoll_dev - > poll_interval = BMA150_POLL_INTERVAL ;
ipoll_dev - > poll_interval_min = BMA150_POLL_MIN ;
ipoll_dev - > poll_interval_max = BMA150_POLL_MAX ;
bma150_init_input_device ( bma150 , ipoll_dev - > input ) ;
error = input_register_polled_device ( ipoll_dev ) ;
if ( error ) {
input_free_polled_device ( ipoll_dev ) ;
return error ;
}
bma150 - > input_polled = ipoll_dev ;
bma150 - > input = ipoll_dev - > input ;
return 0 ;
}
2012-11-23 21:38:25 -08:00
static int bma150_probe ( struct i2c_client * client ,
2011-08-09 00:06:37 -07:00
const struct i2c_device_id * id )
{
2013-12-05 19:21:10 -08:00
const struct bma150_platform_data * pdata =
dev_get_platdata ( & client - > dev ) ;
2011-08-09 00:06:37 -07:00
const struct bma150_cfg * cfg ;
struct bma150_data * bma150 ;
int chip_id ;
int error ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
dev_err ( & client - > dev , " i2c_check_functionality error \n " ) ;
return - EIO ;
}
chip_id = i2c_smbus_read_byte_data ( client , BMA150_CHIP_ID_REG ) ;
2017-04-01 09:43:47 -07:00
if ( chip_id ! = BMA150_CHIP_ID ) {
2011-08-09 00:06:37 -07:00
dev_err ( & client - > dev , " BMA150 chip id error: %d \n " , chip_id ) ;
return - EINVAL ;
}
bma150 = kzalloc ( sizeof ( struct bma150_data ) , GFP_KERNEL ) ;
if ( ! bma150 )
return - ENOMEM ;
bma150 - > client = client ;
if ( pdata ) {
if ( pdata - > irq_gpio_cfg ) {
error = pdata - > irq_gpio_cfg ( ) ;
if ( error ) {
dev_err ( & client - > dev ,
" IRQ GPIO conf. error %d, error %d \n " ,
client - > irq , error ) ;
goto err_free_mem ;
}
}
cfg = & pdata - > cfg ;
} else {
cfg = & default_cfg ;
}
error = bma150_initialize ( bma150 , cfg ) ;
if ( error )
goto err_free_mem ;
if ( client - > irq > 0 ) {
error = bma150_register_input_device ( bma150 ) ;
if ( error )
goto err_free_mem ;
error = request_threaded_irq ( client - > irq ,
NULL , bma150_irq_thread ,
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
BMA150_DRIVER , bma150 ) ;
if ( error ) {
dev_err ( & client - > dev ,
" irq request failed %d, error %d \n " ,
client - > irq , error ) ;
input_unregister_device ( bma150 - > input ) ;
goto err_free_mem ;
}
} else {
error = bma150_register_polled_device ( bma150 ) ;
if ( error )
goto err_free_mem ;
}
i2c_set_clientdata ( client , bma150 ) ;
pm_runtime_enable ( & client - > dev ) ;
return 0 ;
err_free_mem :
kfree ( bma150 ) ;
return error ;
}
2012-11-23 21:50:47 -08:00
static int bma150_remove ( struct i2c_client * client )
2011-08-09 00:06:37 -07:00
{
struct bma150_data * bma150 = i2c_get_clientdata ( client ) ;
pm_runtime_disable ( & client - > dev ) ;
if ( client - > irq > 0 ) {
free_irq ( client - > irq , bma150 ) ;
input_unregister_device ( bma150 - > input ) ;
} else {
input_unregister_polled_device ( bma150 - > input_polled ) ;
input_free_polled_device ( bma150 - > input_polled ) ;
}
kfree ( bma150 ) ;
return 0 ;
}
# ifdef CONFIG_PM
static int bma150_suspend ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct bma150_data * bma150 = i2c_get_clientdata ( client ) ;
return bma150_set_mode ( bma150 , BMA150_MODE_SLEEP ) ;
}
static int bma150_resume ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct bma150_data * bma150 = i2c_get_clientdata ( client ) ;
return bma150_set_mode ( bma150 , BMA150_MODE_NORMAL ) ;
}
# endif
static UNIVERSAL_DEV_PM_OPS ( bma150_pm , bma150_suspend , bma150_resume , NULL ) ;
static const struct i2c_device_id bma150_id [ ] = {
{ " bma150 " , 0 } ,
{ " smb380 " , 0 } ,
{ " bma023 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , bma150_id ) ;
static struct i2c_driver bma150_driver = {
. driver = {
. name = BMA150_DRIVER ,
. pm = & bma150_pm ,
} ,
. class = I2C_CLASS_HWMON ,
. id_table = bma150_id ,
. probe = bma150_probe ,
2012-11-23 21:27:39 -08:00
. remove = bma150_remove ,
2011-08-09 00:06:37 -07:00
} ;
2012-03-16 23:05:41 -07:00
module_i2c_driver ( bma150_driver ) ;
2011-08-09 00:06:37 -07:00
MODULE_AUTHOR ( " Albert Zhang <xu.zhang@bosch-sensortec.com> " ) ;
MODULE_DESCRIPTION ( " BMA150 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;