2017-11-18 10:10:11 +01:00
// SPDX-License-Identifier: GPL-2.0
2014-02-05 09:51:00 +00:00
/*
2016-06-03 14:51:52 +02:00
* mma8452 . c - Support for following Freescale / NXP 3 - axis accelerometers :
2015-09-01 13:45:09 +02:00
*
2016-06-03 14:51:51 +02:00
* device name digital output 7 - bit I2C slave address ( pin selectable )
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* MMA8451Q 14 bit 0x1c / 0x1d
* MMA8452Q 12 bit 0x1c / 0x1d
* MMA8453Q 10 bit 0x1c / 0x1d
* MMA8652FC 12 bit 0x1d
* MMA8653FC 10 bit 0x1d
* FXLS8471Q 14 bit 0x1e / 0x1d / 0x1c / 0x1f
2014-02-05 09:51:00 +00:00
*
2016-06-03 14:51:50 +02:00
* Copyright 2015 Martin Kepplinger < martink @ posteo . de >
2014-02-05 09:51:00 +00:00
* Copyright 2014 Peter Meerwald < pmeerw @ pmeerw . net >
*
*
2016-03-14 12:26:29 +01:00
* TODO : orientation events
2014-02-05 09:51:00 +00:00
*/
# include <linux/module.h>
# include <linux/i2c.h>
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# include <linux/iio/buffer.h>
2015-06-01 15:39:58 +02:00
# include <linux/iio/trigger.h>
# include <linux/iio/trigger_consumer.h>
2014-02-05 09:51:00 +00:00
# include <linux/iio/triggered_buffer.h>
2015-06-01 15:39:52 +02:00
# include <linux/iio/events.h>
2014-02-05 09:51:00 +00:00
# include <linux/delay.h>
2015-09-01 13:45:08 +02:00
# include <linux/of_device.h>
2015-10-15 15:10:32 +02:00
# include <linux/of_irq.h>
2016-03-03 09:24:03 +01:00
# include <linux/pm_runtime.h>
2019-01-08 09:14:06 +00:00
# include <linux/regulator/consumer.h>
2014-02-05 09:51:00 +00:00
2015-08-02 22:43:50 +02:00
# define MMA8452_STATUS 0x00
# define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
2015-09-01 13:45:09 +02:00
# define MMA8452_OUT_X 0x01 /* MSB first */
2015-08-02 22:43:50 +02:00
# define MMA8452_OUT_Y 0x03
# define MMA8452_OUT_Z 0x05
# define MMA8452_INT_SRC 0x0c
# define MMA8452_WHO_AM_I 0x0d
# define MMA8452_DATA_CFG 0x0e
# define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0)
# define MMA8452_DATA_CFG_FS_2G 0
# define MMA8452_DATA_CFG_FS_4G 1
# define MMA8452_DATA_CFG_FS_8G 2
# define MMA8452_DATA_CFG_HPF_MASK BIT(4)
# define MMA8452_HP_FILTER_CUTOFF 0x0f
# define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0)
2015-09-01 13:45:10 +02:00
# define MMA8452_FF_MT_CFG 0x15
# define MMA8452_FF_MT_CFG_OAE BIT(6)
# define MMA8452_FF_MT_CFG_ELE BIT(7)
# define MMA8452_FF_MT_SRC 0x16
# define MMA8452_FF_MT_SRC_XHE BIT(1)
# define MMA8452_FF_MT_SRC_YHE BIT(3)
# define MMA8452_FF_MT_SRC_ZHE BIT(5)
# define MMA8452_FF_MT_THS 0x17
# define MMA8452_FF_MT_THS_MASK 0x7f
# define MMA8452_FF_MT_COUNT 0x18
2021-03-01 09:00:28 +01:00
# define MMA8452_FF_MT_CHAN_SHIFT 3
2015-08-02 22:43:50 +02:00
# define MMA8452_TRANSIENT_CFG 0x1d
2017-09-09 15:56:58 -04:00
# define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1)
2015-08-02 22:43:50 +02:00
# define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0)
# define MMA8452_TRANSIENT_CFG_ELE BIT(4)
# define MMA8452_TRANSIENT_SRC 0x1e
# define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1)
# define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3)
# define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5)
# define MMA8452_TRANSIENT_THS 0x1f
# define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0)
# define MMA8452_TRANSIENT_COUNT 0x20
2021-03-01 09:00:28 +01:00
# define MMA8452_TRANSIENT_CHAN_SHIFT 1
2015-08-02 22:43:50 +02:00
# define MMA8452_CTRL_REG1 0x2a
# define MMA8452_CTRL_ACTIVE BIT(0)
# define MMA8452_CTRL_DR_MASK GENMASK(5, 3)
# define MMA8452_CTRL_DR_SHIFT 3
# define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */
# define MMA8452_CTRL_REG2 0x2b
# define MMA8452_CTRL_REG2_RST BIT(6)
2016-04-25 14:08:25 +02:00
# define MMA8452_CTRL_REG2_MODS_SHIFT 3
# define MMA8452_CTRL_REG2_MODS_MASK 0x1b
2015-08-02 22:43:50 +02:00
# define MMA8452_CTRL_REG4 0x2d
# define MMA8452_CTRL_REG5 0x2e
# define MMA8452_OFF_X 0x2f
# define MMA8452_OFF_Y 0x30
# define MMA8452_OFF_Z 0x31
2014-02-05 09:51:00 +00:00
2015-08-02 22:43:50 +02:00
# define MMA8452_MAX_REG 0x31
2015-05-13 12:26:40 +02:00
2015-08-02 22:43:50 +02:00
# define MMA8452_INT_DRDY BIT(0)
2015-09-01 13:45:10 +02:00
# define MMA8452_INT_FF_MT BIT(2)
2015-08-02 22:43:50 +02:00
# define MMA8452_INT_TRANS BIT(5)
2014-02-05 09:51:00 +00:00
2016-01-16 15:35:22 +01:00
# define MMA8451_DEVICE_ID 0x1a
2016-01-16 15:35:21 +01:00
# define MMA8452_DEVICE_ID 0x2a
# define MMA8453_DEVICE_ID 0x3a
2015-09-01 13:45:11 +02:00
# define MMA8652_DEVICE_ID 0x4a
# define MMA8653_DEVICE_ID 0x5a
2016-03-09 12:01:29 +01:00
# define FXLS8471_DEVICE_ID 0x6a
2014-02-05 09:51:00 +00:00
2016-03-03 09:24:03 +01:00
# define MMA8452_AUTO_SUSPEND_DELAY_MS 2000
2014-02-05 09:51:00 +00:00
struct mma8452_data {
struct i2c_client * client ;
struct mutex lock ;
2022-02-08 13:43:36 +01:00
struct iio_mount_matrix orientation ;
2014-02-05 09:51:00 +00:00
u8 ctrl_reg1 ;
u8 data_cfg ;
2015-09-01 13:45:08 +02:00
const struct mma_chip_info * chip_info ;
2018-05-11 16:54:59 +08:00
int sleep_val ;
2019-01-08 09:14:06 +00:00
struct regulator * vdd_reg ;
struct regulator * vddio_reg ;
2020-07-22 16:50:38 +01:00
/* Ensure correct alignment of time stamp when present */
struct {
__be16 channels [ 3 ] ;
s64 ts __aligned ( 8 ) ;
} buffer ;
2015-09-01 13:45:08 +02:00
} ;
2017-09-09 15:56:58 -04:00
/**
* struct mma8452_event_regs - chip specific data related to events
* @ ev_cfg : event config register address
* @ ev_cfg_ele : latch bit in event config register
* @ ev_cfg_chan_shift : number of the bit to enable events in X
* direction ; in event config register
* @ ev_src : event source register address
* @ ev_ths : event threshold register address
* @ ev_ths_mask : mask for the threshold value
* @ ev_count : event count ( period ) register address
*
* Since not all chips supported by the driver support comparing high pass
* filtered data for events ( interrupts ) , different interrupt sources are
* used for different chips and the relevant registers are included here .
*/
struct mma8452_event_regs {
2021-03-01 09:00:28 +01:00
u8 ev_cfg ;
u8 ev_cfg_ele ;
u8 ev_cfg_chan_shift ;
u8 ev_src ;
u8 ev_ths ;
u8 ev_ths_mask ;
u8 ev_count ;
2017-09-09 15:56:58 -04:00
} ;
2017-11-05 13:00:03 -05:00
static const struct mma8452_event_regs ff_mt_ev_regs = {
2021-03-01 09:00:28 +01:00
. ev_cfg = MMA8452_FF_MT_CFG ,
. ev_cfg_ele = MMA8452_FF_MT_CFG_ELE ,
. ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT ,
. ev_src = MMA8452_FF_MT_SRC ,
. ev_ths = MMA8452_FF_MT_THS ,
. ev_ths_mask = MMA8452_FF_MT_THS_MASK ,
. ev_count = MMA8452_FF_MT_COUNT
2017-09-09 15:56:58 -04:00
} ;
2017-11-05 13:00:03 -05:00
static const struct mma8452_event_regs trans_ev_regs = {
2021-03-01 09:00:28 +01:00
. ev_cfg = MMA8452_TRANSIENT_CFG ,
. ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE ,
. ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT ,
. ev_src = MMA8452_TRANSIENT_SRC ,
. ev_ths = MMA8452_TRANSIENT_THS ,
. ev_ths_mask = MMA8452_TRANSIENT_THS_MASK ,
. ev_count = MMA8452_TRANSIENT_COUNT ,
2017-09-09 15:56:58 -04:00
} ;
2015-09-01 13:45:08 +02:00
/**
2016-06-03 14:51:52 +02:00
* struct mma_chip_info - chip specific data
2022-04-10 16:33:17 +01:00
* @ name : part number of device reported via ' name ' attr
2015-09-01 13:45:08 +02:00
* @ chip_id : WHO_AM_I register ' s value
* @ channels : struct iio_chan_spec matching the device ' s
* capabilities
* @ num_channels : number of channels
* @ mma_scales : scale factors for converting register values
* to m / s ^ 2 ; 3 modes : 2 g , 4 g , 8 g ; 2 integers
* per mode : m / s ^ 2 and micro m / s ^ 2
2017-09-09 15:56:58 -04:00
* @ all_events : all events supported by this chip
* @ enabled_events : event flags enabled and handled by this driver
2015-09-01 13:45:08 +02:00
*/
struct mma_chip_info {
2022-02-08 13:43:35 +01:00
const char * name ;
2015-09-01 13:45:08 +02:00
u8 chip_id ;
const struct iio_chan_spec * channels ;
int num_channels ;
const int mma_scales [ 3 ] [ 2 ] ;
2017-09-09 15:56:58 -04:00
int all_events ;
int enabled_events ;
2014-02-05 09:51:00 +00:00
} ;
2015-12-15 17:45:00 +01:00
enum {
idx_x ,
idx_y ,
idx_z ,
idx_ts ,
} ;
2014-02-05 09:51:00 +00:00
static int mma8452_drdy ( struct mma8452_data * data )
{
int tries = 150 ;
while ( tries - - > 0 ) {
int ret = i2c_smbus_read_byte_data ( data - > client ,
MMA8452_STATUS ) ;
if ( ret < 0 )
return ret ;
if ( ( ret & MMA8452_STATUS_DRDY ) = = MMA8452_STATUS_DRDY )
return 0 ;
2015-08-02 22:43:51 +02:00
2018-05-11 16:54:59 +08:00
if ( data - > sleep_val < = 20 )
usleep_range ( data - > sleep_val * 250 ,
data - > sleep_val * 500 ) ;
else
msleep ( 20 ) ;
2014-02-05 09:51:00 +00:00
}
dev_err ( & data - > client - > dev , " data not ready \n " ) ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return - EIO ;
}
2016-03-03 09:24:03 +01:00
static int mma8452_set_runtime_pm_state ( struct i2c_client * client , bool on )
{
# ifdef CONFIG_PM
int ret ;
if ( on ) {
2021-05-09 12:33:31 +01:00
ret = pm_runtime_resume_and_get ( & client - > dev ) ;
2016-03-03 09:24:03 +01:00
} else {
pm_runtime_mark_last_busy ( & client - > dev ) ;
ret = pm_runtime_put_autosuspend ( & client - > dev ) ;
}
if ( ret < 0 ) {
dev_err ( & client - > dev ,
" failed to change power state to %d \n " , on ) ;
return ret ;
}
# endif
return 0 ;
}
2014-02-05 09:51:00 +00:00
static int mma8452_read ( struct mma8452_data * data , __be16 buf [ 3 ] )
{
int ret = mma8452_drdy ( data ) ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
return ret ;
2015-08-02 22:43:51 +02:00
2016-03-03 09:24:03 +01:00
ret = mma8452_set_runtime_pm_state ( data - > client , true ) ;
if ( ret )
return ret ;
ret = i2c_smbus_read_i2c_block_data ( data - > client , MMA8452_OUT_X ,
3 * sizeof ( __be16 ) , ( u8 * ) buf ) ;
ret = mma8452_set_runtime_pm_state ( data - > client , false ) ;
return ret ;
2014-02-05 09:51:00 +00:00
}
2015-08-02 22:43:51 +02:00
static ssize_t mma8452_show_int_plus_micros ( char * buf , const int ( * vals ) [ 2 ] ,
int n )
2014-02-05 09:51:00 +00:00
{
size_t len = 0 ;
while ( n - - > 0 )
2015-08-02 22:43:51 +02:00
len + = scnprintf ( buf + len , PAGE_SIZE - len , " %d.%06d " ,
vals [ n ] [ 0 ] , vals [ n ] [ 1 ] ) ;
2014-02-05 09:51:00 +00:00
/* replace trailing space by newline */
buf [ len - 1 ] = ' \n ' ;
return len ;
}
static int mma8452_get_int_plus_micros_index ( const int ( * vals ) [ 2 ] , int n ,
2015-08-02 22:43:51 +02:00
int val , int val2 )
2014-02-05 09:51:00 +00:00
{
while ( n - - > 0 )
if ( val = = vals [ n ] [ 0 ] & & val2 = = vals [ n ] [ 1 ] )
return n ;
return - EINVAL ;
}
2016-11-21 20:53:54 +01:00
static unsigned int mma8452_get_odr_index ( struct mma8452_data * data )
2015-06-01 15:39:54 +02:00
{
return ( data - > ctrl_reg1 & MMA8452_CTRL_DR_MASK ) > >
MMA8452_CTRL_DR_SHIFT ;
}
2014-02-05 09:51:00 +00:00
static const int mma8452_samp_freq [ 8 ] [ 2 ] = {
{ 800 , 0 } , { 400 , 0 } , { 200 , 0 } , { 100 , 0 } , { 50 , 0 } , { 12 , 500000 } ,
{ 6 , 250000 } , { 1 , 560000 }
} ;
2016-04-25 14:08:25 +02:00
/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
2017-11-05 13:00:02 -05:00
static const unsigned int mma8452_time_step_us [ 4 ] [ 8 ] = {
2016-04-25 14:08:25 +02:00
{ 1250 , 2500 , 5000 , 10000 , 20000 , 20000 , 20000 , 20000 } , /* normal */
{ 1250 , 2500 , 5000 , 10000 , 20000 , 80000 , 80000 , 80000 } , /* l p l n */
{ 1250 , 2500 , 2500 , 2500 , 2500 , 2500 , 2500 , 2500 } , /* high res*/
{ 1250 , 2500 , 5000 , 10000 , 20000 , 80000 , 160000 , 160000 } /* l p */
2015-06-01 15:39:54 +02:00
} ;
2016-04-25 14:08:25 +02:00
/* Datasheet table "High-Pass Filter Cutoff Options" */
static const int mma8452_hp_filter_cutoff [ 4 ] [ 8 ] [ 4 ] [ 2 ] = {
{ /* normal */
2015-06-01 15:39:56 +02:00
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } , /* 800 Hz sample */
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } , /* 400 Hz sample */
{ { 8 , 0 } , { 4 , 0 } , { 2 , 0 } , { 1 , 0 } } , /* 200 Hz sample */
{ { 4 , 0 } , { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } } , /* 100 Hz sample */
{ { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } } , /* 50 Hz sample */
{ { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } } , /* 12.5 Hz sample */
{ { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } } , /* 6.25 Hz sample */
{ { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } } /* 1.56 Hz sample */
2016-04-25 14:08:25 +02:00
} ,
{ /* low noise low power */
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 8 , 0 } , { 4 , 0 } , { 2 , 0 } , { 1 , 0 } } ,
{ { 4 , 0 } , { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } } ,
{ { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } } ,
{ { 0 , 500000 } , { 0 , 250000 } , { 0 , 125000 } , { 0 , 063000 } } ,
{ { 0 , 500000 } , { 0 , 250000 } , { 0 , 125000 } , { 0 , 063000 } } ,
{ { 0 , 500000 } , { 0 , 250000 } , { 0 , 125000 } , { 0 , 063000 } }
} ,
{ /* high resolution */
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } }
} ,
{ /* low power */
{ { 16 , 0 } , { 8 , 0 } , { 4 , 0 } , { 2 , 0 } } ,
{ { 8 , 0 } , { 4 , 0 } , { 2 , 0 } , { 1 , 0 } } ,
{ { 4 , 0 } , { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } } ,
{ { 2 , 0 } , { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } } ,
{ { 1 , 0 } , { 0 , 500000 } , { 0 , 250000 } , { 0 , 125000 } } ,
{ { 0 , 250000 } , { 0 , 125000 } , { 0 , 063000 } , { 0 , 031000 } } ,
{ { 0 , 250000 } , { 0 , 125000 } , { 0 , 063000 } , { 0 , 031000 } } ,
{ { 0 , 250000 } , { 0 , 125000 } , { 0 , 063000 } , { 0 , 031000 } }
}
2015-06-01 15:39:56 +02:00
} ;
2016-04-25 14:08:25 +02:00
/* Datasheet table "MODS Oversampling modes averaging values at each ODR" */
static const u16 mma8452_os_ratio [ 4 ] [ 8 ] = {
/* 800 Hz, 400 Hz, ... , 1.56 Hz */
{ 2 , 4 , 4 , 4 , 4 , 16 , 32 , 128 } , /* normal */
{ 2 , 4 , 4 , 4 , 4 , 4 , 8 , 32 } , /* low power low noise */
{ 2 , 4 , 8 , 16 , 32 , 128 , 256 , 1024 } , /* high resolution */
{ 2 , 2 , 2 , 2 , 2 , 2 , 4 , 16 } /* low power */
} ;
static int mma8452_get_power_mode ( struct mma8452_data * data )
{
int reg ;
reg = i2c_smbus_read_byte_data ( data - > client ,
MMA8452_CTRL_REG2 ) ;
if ( reg < 0 )
return reg ;
return ( ( reg & MMA8452_CTRL_REG2_MODS_MASK ) > >
MMA8452_CTRL_REG2_MODS_SHIFT ) ;
}
2014-02-05 09:51:00 +00:00
static ssize_t mma8452_show_samp_freq_avail ( struct device * dev ,
2015-08-02 22:43:51 +02:00
struct device_attribute * attr ,
char * buf )
2014-02-05 09:51:00 +00:00
{
return mma8452_show_int_plus_micros ( buf , mma8452_samp_freq ,
2015-08-02 22:43:51 +02:00
ARRAY_SIZE ( mma8452_samp_freq ) ) ;
2014-02-05 09:51:00 +00:00
}
static ssize_t mma8452_show_scale_avail ( struct device * dev ,
2015-08-02 22:43:51 +02:00
struct device_attribute * attr ,
char * buf )
2014-02-05 09:51:00 +00:00
{
2022-02-22 10:42:21 +08:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2015-09-01 13:45:08 +02:00
return mma8452_show_int_plus_micros ( buf , data - > chip_info - > mma_scales ,
ARRAY_SIZE ( data - > chip_info - > mma_scales ) ) ;
2014-02-05 09:51:00 +00:00
}
2015-06-01 15:39:56 +02:00
static ssize_t mma8452_show_hp_cutoff_avail ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2016-04-25 14:08:25 +02:00
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
int i , j ;
i = mma8452_get_odr_index ( data ) ;
j = mma8452_get_power_mode ( data ) ;
if ( j < 0 )
return j ;
return mma8452_show_int_plus_micros ( buf , mma8452_hp_filter_cutoff [ j ] [ i ] ,
ARRAY_SIZE ( mma8452_hp_filter_cutoff [ 0 ] [ 0 ] ) ) ;
}
static ssize_t mma8452_show_os_ratio_avail ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2015-06-01 15:39:56 +02:00
{
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
int i = mma8452_get_odr_index ( data ) ;
2016-04-25 14:08:25 +02:00
int j ;
u16 val = 0 ;
size_t len = 0 ;
for ( j = 0 ; j < ARRAY_SIZE ( mma8452_os_ratio ) ; j + + ) {
if ( val = = mma8452_os_ratio [ j ] [ i ] )
continue ;
val = mma8452_os_ratio [ j ] [ i ] ;
len + = scnprintf ( buf + len , PAGE_SIZE - len , " %d " , val ) ;
}
buf [ len - 1 ] = ' \n ' ;
2015-06-01 15:39:56 +02:00
2016-04-25 14:08:25 +02:00
return len ;
2015-06-01 15:39:56 +02:00
}
2014-02-05 09:51:00 +00:00
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL ( mma8452_show_samp_freq_avail ) ;
2017-09-23 16:56:29 -04:00
static IIO_DEVICE_ATTR ( in_accel_scale_available , 0444 ,
2015-08-02 22:43:51 +02:00
mma8452_show_scale_avail , NULL , 0 ) ;
2015-06-01 15:39:56 +02:00
static IIO_DEVICE_ATTR ( in_accel_filter_high_pass_3db_frequency_available ,
2017-09-23 16:56:29 -04:00
0444 , mma8452_show_hp_cutoff_avail , NULL , 0 ) ;
static IIO_DEVICE_ATTR ( in_accel_oversampling_ratio_available , 0444 ,
2016-04-25 14:08:25 +02:00
mma8452_show_os_ratio_avail , NULL , 0 ) ;
2014-02-05 09:51:00 +00:00
static int mma8452_get_samp_freq_index ( struct mma8452_data * data ,
2015-08-02 22:43:51 +02:00
int val , int val2 )
2014-02-05 09:51:00 +00:00
{
return mma8452_get_int_plus_micros_index ( mma8452_samp_freq ,
2015-08-02 22:43:51 +02:00
ARRAY_SIZE ( mma8452_samp_freq ) ,
val , val2 ) ;
2014-02-05 09:51:00 +00:00
}
2015-08-02 22:43:51 +02:00
static int mma8452_get_scale_index ( struct mma8452_data * data , int val , int val2 )
2014-02-05 09:51:00 +00:00
{
2015-09-01 13:45:08 +02:00
return mma8452_get_int_plus_micros_index ( data - > chip_info - > mma_scales ,
ARRAY_SIZE ( data - > chip_info - > mma_scales ) , val , val2 ) ;
2014-02-05 09:51:00 +00:00
}
2015-06-01 15:39:56 +02:00
static int mma8452_get_hp_filter_index ( struct mma8452_data * data ,
int val , int val2 )
{
2016-04-25 14:08:25 +02:00
int i , j ;
i = mma8452_get_odr_index ( data ) ;
j = mma8452_get_power_mode ( data ) ;
if ( j < 0 )
return j ;
2015-06-01 15:39:56 +02:00
2016-04-25 14:08:25 +02:00
return mma8452_get_int_plus_micros_index ( mma8452_hp_filter_cutoff [ j ] [ i ] ,
ARRAY_SIZE ( mma8452_hp_filter_cutoff [ 0 ] [ 0 ] ) , val , val2 ) ;
2015-06-01 15:39:56 +02:00
}
static int mma8452_read_hp_filter ( struct mma8452_data * data , int * hz , int * uHz )
{
2016-04-25 14:08:25 +02:00
int j , i , ret ;
2015-06-01 15:39:56 +02:00
ret = i2c_smbus_read_byte_data ( data - > client , MMA8452_HP_FILTER_CUTOFF ) ;
if ( ret < 0 )
return ret ;
i = mma8452_get_odr_index ( data ) ;
2016-04-25 14:08:25 +02:00
j = mma8452_get_power_mode ( data ) ;
if ( j < 0 )
return j ;
2015-06-01 15:39:56 +02:00
ret & = MMA8452_HP_FILTER_CUTOFF_SEL_MASK ;
2016-04-25 14:08:25 +02:00
* hz = mma8452_hp_filter_cutoff [ j ] [ i ] [ ret ] [ 0 ] ;
* uHz = mma8452_hp_filter_cutoff [ j ] [ i ] [ ret ] [ 1 ] ;
2015-06-01 15:39:56 +02:00
return 0 ;
}
2014-02-05 09:51:00 +00:00
static int mma8452_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
__be16 buffer [ 3 ] ;
int i , ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2016-10-11 12:31:36 -07:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
return ret ;
2014-02-05 09:51:00 +00:00
mutex_lock ( & data - > lock ) ;
ret = mma8452_read ( data , buffer ) ;
mutex_unlock ( & data - > lock ) ;
2016-10-11 12:31:36 -07:00
iio_device_release_direct_mode ( indio_dev ) ;
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
return ret ;
2015-08-02 22:43:51 +02:00
2015-09-01 13:45:08 +02:00
* val = sign_extend32 ( be16_to_cpu (
buffer [ chan - > scan_index ] ) > > chan - > scan_type . shift ,
chan - > scan_type . realbits - 1 ) ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
i = data - > data_cfg & MMA8452_DATA_CFG_FS_MASK ;
2015-09-01 13:45:08 +02:00
* val = data - > chip_info - > mma_scales [ i ] [ 0 ] ;
* val2 = data - > chip_info - > mma_scales [ i ] [ 1 ] ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_SAMP_FREQ :
2015-06-01 15:39:54 +02:00
i = mma8452_get_odr_index ( data ) ;
2014-02-05 09:51:00 +00:00
* val = mma8452_samp_freq [ i ] [ 0 ] ;
* val2 = mma8452_samp_freq [ i ] [ 1 ] ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_CALIBBIAS :
2015-08-02 22:43:51 +02:00
ret = i2c_smbus_read_byte_data ( data - > client ,
2016-03-03 09:24:01 +01:00
MMA8452_OFF_X +
chan - > scan_index ) ;
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
return ret ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
* val = sign_extend32 ( ret , 7 ) ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return IIO_VAL_INT ;
2015-06-01 15:39:56 +02:00
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY :
if ( data - > data_cfg & MMA8452_DATA_CFG_HPF_MASK ) {
ret = mma8452_read_hp_filter ( data , val , val2 ) ;
if ( ret < 0 )
return ret ;
} else {
* val = 0 ;
* val2 = 0 ;
}
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:56 +02:00
return IIO_VAL_INT_PLUS_MICRO ;
2016-04-25 14:08:25 +02:00
case IIO_CHAN_INFO_OVERSAMPLING_RATIO :
ret = mma8452_get_power_mode ( data ) ;
if ( ret < 0 )
return ret ;
i = mma8452_get_odr_index ( data ) ;
* val = mma8452_os_ratio [ ret ] [ i ] ;
return IIO_VAL_INT ;
2014-02-05 09:51:00 +00:00
}
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return - EINVAL ;
}
2018-05-11 16:54:59 +08:00
static int mma8452_calculate_sleep ( struct mma8452_data * data )
{
int ret , i = mma8452_get_odr_index ( data ) ;
if ( mma8452_samp_freq [ i ] [ 0 ] > 0 )
ret = 1000 / mma8452_samp_freq [ i ] [ 0 ] ;
else
ret = 1000 ;
return ret = = 0 ? 1 : ret ;
}
2014-02-05 09:51:00 +00:00
static int mma8452_standby ( struct mma8452_data * data )
{
return i2c_smbus_write_byte_data ( data - > client , MMA8452_CTRL_REG1 ,
2015-08-02 22:43:51 +02:00
data - > ctrl_reg1 & ~ MMA8452_CTRL_ACTIVE ) ;
2014-02-05 09:51:00 +00:00
}
static int mma8452_active ( struct mma8452_data * data )
{
return i2c_smbus_write_byte_data ( data - > client , MMA8452_CTRL_REG1 ,
2015-08-02 22:43:51 +02:00
data - > ctrl_reg1 ) ;
2014-02-05 09:51:00 +00:00
}
2016-03-03 09:24:02 +01:00
/* returns >0 if active, 0 if in standby and <0 on error */
static int mma8452_is_active ( struct mma8452_data * data )
{
int reg ;
reg = i2c_smbus_read_byte_data ( data - > client , MMA8452_CTRL_REG1 ) ;
if ( reg < 0 )
return reg ;
return reg & MMA8452_CTRL_ACTIVE ;
}
2014-02-05 09:51:00 +00:00
static int mma8452_change_config ( struct mma8452_data * data , u8 reg , u8 val )
{
int ret ;
2016-03-03 09:24:02 +01:00
int is_active ;
2014-02-05 09:51:00 +00:00
mutex_lock ( & data - > lock ) ;
2016-03-03 09:24:02 +01:00
is_active = mma8452_is_active ( data ) ;
if ( is_active < 0 ) {
ret = is_active ;
2014-02-05 09:51:00 +00:00
goto fail ;
2016-03-03 09:24:02 +01:00
}
/* config can only be changed when in standby */
if ( is_active > 0 ) {
ret = mma8452_standby ( data ) ;
if ( ret < 0 )
goto fail ;
}
2014-02-05 09:51:00 +00:00
ret = i2c_smbus_write_byte_data ( data - > client , reg , val ) ;
if ( ret < 0 )
goto fail ;
2016-03-03 09:24:02 +01:00
if ( is_active > 0 ) {
ret = mma8452_active ( data ) ;
if ( ret < 0 )
goto fail ;
}
2014-02-05 09:51:00 +00:00
ret = 0 ;
fail :
mutex_unlock ( & data - > lock ) ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return ret ;
}
2016-04-25 14:08:25 +02:00
static int mma8452_set_power_mode ( struct mma8452_data * data , u8 mode )
{
int reg ;
reg = i2c_smbus_read_byte_data ( data - > client ,
MMA8452_CTRL_REG2 ) ;
if ( reg < 0 )
return reg ;
reg & = ~ MMA8452_CTRL_REG2_MODS_MASK ;
reg | = mode < < MMA8452_CTRL_REG2_MODS_SHIFT ;
return mma8452_change_config ( data , MMA8452_CTRL_REG2 , reg ) ;
}
2016-03-03 09:24:01 +01:00
/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */
2016-01-16 15:35:20 +01:00
static int mma8452_freefall_mode_enabled ( struct mma8452_data * data )
{
int val ;
2017-09-09 15:56:58 -04:00
val = i2c_smbus_read_byte_data ( data - > client , MMA8452_FF_MT_CFG ) ;
2016-01-16 15:35:20 +01:00
if ( val < 0 )
return val ;
return ! ( val & MMA8452_FF_MT_CFG_OAE ) ;
}
static int mma8452_set_freefall_mode ( struct mma8452_data * data , bool state )
{
int val ;
if ( ( state & & mma8452_freefall_mode_enabled ( data ) ) | |
( ! state & & ! ( mma8452_freefall_mode_enabled ( data ) ) ) )
return 0 ;
2017-09-09 15:56:58 -04:00
val = i2c_smbus_read_byte_data ( data - > client , MMA8452_FF_MT_CFG ) ;
2016-01-16 15:35:20 +01:00
if ( val < 0 )
return val ;
if ( state ) {
2017-09-09 15:56:58 -04:00
val | = BIT ( idx_x + MMA8452_FF_MT_CHAN_SHIFT ) ;
val | = BIT ( idx_y + MMA8452_FF_MT_CHAN_SHIFT ) ;
val | = BIT ( idx_z + MMA8452_FF_MT_CHAN_SHIFT ) ;
2016-01-16 15:35:20 +01:00
val & = ~ MMA8452_FF_MT_CFG_OAE ;
} else {
2017-09-09 15:56:58 -04:00
val & = ~ BIT ( idx_x + MMA8452_FF_MT_CHAN_SHIFT ) ;
val & = ~ BIT ( idx_y + MMA8452_FF_MT_CHAN_SHIFT ) ;
val & = ~ BIT ( idx_z + MMA8452_FF_MT_CHAN_SHIFT ) ;
2016-01-16 15:35:20 +01:00
val | = MMA8452_FF_MT_CFG_OAE ;
}
2017-09-09 15:56:58 -04:00
return mma8452_change_config ( data , MMA8452_FF_MT_CFG , val ) ;
2016-01-16 15:35:20 +01:00
}
2015-06-01 15:39:56 +02:00
static int mma8452_set_hp_filter_frequency ( struct mma8452_data * data ,
int val , int val2 )
{
int i , reg ;
i = mma8452_get_hp_filter_index ( data , val , val2 ) ;
if ( i < 0 )
2015-08-02 22:43:48 +02:00
return i ;
2015-06-01 15:39:56 +02:00
reg = i2c_smbus_read_byte_data ( data - > client ,
MMA8452_HP_FILTER_CUTOFF ) ;
if ( reg < 0 )
return reg ;
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:56 +02:00
reg & = ~ MMA8452_HP_FILTER_CUTOFF_SEL_MASK ;
reg | = i ;
return mma8452_change_config ( data , MMA8452_HP_FILTER_CUTOFF , reg ) ;
}
2014-02-05 09:51:00 +00:00
static int mma8452_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2015-06-01 15:39:56 +02:00
int i , ret ;
2014-02-05 09:51:00 +00:00
2016-10-15 15:55:06 +01:00
ret = iio_device_claim_direct_mode ( indio_dev ) ;
if ( ret )
return ret ;
2014-02-05 09:51:00 +00:00
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
i = mma8452_get_samp_freq_index ( data , val , val2 ) ;
2016-10-15 15:55:06 +01:00
if ( i < 0 ) {
ret = i ;
break ;
}
2014-02-05 09:51:00 +00:00
data - > ctrl_reg1 & = ~ MMA8452_CTRL_DR_MASK ;
data - > ctrl_reg1 | = i < < MMA8452_CTRL_DR_SHIFT ;
2015-08-02 22:43:51 +02:00
2018-05-11 16:54:59 +08:00
data - > sleep_val = mma8452_calculate_sleep ( data ) ;
2016-10-15 15:55:06 +01:00
ret = mma8452_change_config ( data , MMA8452_CTRL_REG1 ,
data - > ctrl_reg1 ) ;
break ;
2014-02-05 09:51:00 +00:00
case IIO_CHAN_INFO_SCALE :
i = mma8452_get_scale_index ( data , val , val2 ) ;
2016-10-15 15:55:06 +01:00
if ( i < 0 ) {
ret = i ;
break ;
}
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
data - > data_cfg & = ~ MMA8452_DATA_CFG_FS_MASK ;
data - > data_cfg | = i ;
2015-08-02 22:43:51 +02:00
2016-10-15 15:55:06 +01:00
ret = mma8452_change_config ( data , MMA8452_DATA_CFG ,
data - > data_cfg ) ;
break ;
2014-02-05 09:51:00 +00:00
case IIO_CHAN_INFO_CALIBBIAS :
2016-10-15 15:55:06 +01:00
if ( val < - 128 | | val > 127 ) {
ret = - EINVAL ;
break ;
}
2015-08-02 22:43:51 +02:00
2016-10-15 15:55:06 +01:00
ret = mma8452_change_config ( data ,
MMA8452_OFF_X + chan - > scan_index ,
val ) ;
break ;
2015-06-01 15:39:56 +02:00
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY :
if ( val = = 0 & & val2 = = 0 ) {
data - > data_cfg & = ~ MMA8452_DATA_CFG_HPF_MASK ;
} else {
data - > data_cfg | = MMA8452_DATA_CFG_HPF_MASK ;
ret = mma8452_set_hp_filter_frequency ( data , val , val2 ) ;
if ( ret < 0 )
2016-10-15 15:55:06 +01:00
break ;
2015-06-01 15:39:56 +02:00
}
2015-08-02 22:43:51 +02:00
2016-10-15 15:55:06 +01:00
ret = mma8452_change_config ( data , MMA8452_DATA_CFG ,
2015-08-02 22:43:51 +02:00
data - > data_cfg ) ;
2016-10-15 15:55:06 +01:00
break ;
2015-06-01 15:39:56 +02:00
2016-04-25 14:08:25 +02:00
case IIO_CHAN_INFO_OVERSAMPLING_RATIO :
ret = mma8452_get_odr_index ( data ) ;
for ( i = 0 ; i < ARRAY_SIZE ( mma8452_os_ratio ) ; i + + ) {
2016-10-15 15:55:06 +01:00
if ( mma8452_os_ratio [ i ] [ ret ] = = val ) {
ret = mma8452_set_power_mode ( data , i ) ;
break ;
}
2016-04-25 14:08:25 +02:00
}
2016-10-15 15:55:06 +01:00
break ;
2014-02-05 09:51:00 +00:00
default :
2016-10-15 15:55:06 +01:00
ret = - EINVAL ;
break ;
2014-02-05 09:51:00 +00:00
}
2016-10-15 15:55:06 +01:00
iio_device_release_direct_mode ( indio_dev ) ;
return ret ;
2014-02-05 09:51:00 +00:00
}
2017-09-09 15:56:58 -04:00
static int mma8452_get_event_regs ( struct mma8452_data * data ,
const struct iio_chan_spec * chan , enum iio_event_direction dir ,
const struct mma8452_event_regs * * ev_reg )
{
if ( ! chan )
return - EINVAL ;
switch ( chan - > type ) {
case IIO_ACCEL :
switch ( dir ) {
case IIO_EV_DIR_RISING :
if ( ( data - > chip_info - > all_events
& MMA8452_INT_TRANS ) & &
( data - > chip_info - > enabled_events
& MMA8452_INT_TRANS ) )
2017-11-05 13:00:03 -05:00
* ev_reg = & trans_ev_regs ;
2017-09-09 15:56:58 -04:00
else
2017-11-05 13:00:03 -05:00
* ev_reg = & ff_mt_ev_regs ;
2017-09-09 15:56:58 -04:00
return 0 ;
case IIO_EV_DIR_FALLING :
2017-11-05 13:00:03 -05:00
* ev_reg = & ff_mt_ev_regs ;
2017-09-09 15:56:58 -04:00
return 0 ;
default :
return - EINVAL ;
}
default :
return - EINVAL ;
}
}
2017-09-25 06:40:08 -04:00
static int mma8452_read_event_value ( struct iio_dev * indio_dev ,
2015-06-01 15:39:52 +02:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir ,
enum iio_event_info info ,
int * val , int * val2 )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2016-04-25 14:08:25 +02:00
int ret , us , power_mode ;
2017-09-09 15:56:58 -04:00
const struct mma8452_event_regs * ev_regs ;
ret = mma8452_get_event_regs ( data , chan , dir , & ev_regs ) ;
if ( ret )
return ret ;
2015-06-01 15:39:52 +02:00
2015-06-01 15:39:54 +02:00
switch ( info ) {
case IIO_EV_INFO_VALUE :
2017-09-09 15:56:58 -04:00
ret = i2c_smbus_read_byte_data ( data - > client , ev_regs - > ev_ths ) ;
2015-06-01 15:39:54 +02:00
if ( ret < 0 )
return ret ;
2017-09-09 15:56:58 -04:00
* val = ret & ev_regs - > ev_ths_mask ;
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:54 +02:00
return IIO_VAL_INT ;
2015-06-01 15:39:52 +02:00
2015-06-01 15:39:54 +02:00
case IIO_EV_INFO_PERIOD :
2017-09-09 15:56:58 -04:00
ret = i2c_smbus_read_byte_data ( data - > client , ev_regs - > ev_count ) ;
2015-06-01 15:39:54 +02:00
if ( ret < 0 )
return ret ;
2016-04-25 14:08:25 +02:00
power_mode = mma8452_get_power_mode ( data ) ;
if ( power_mode < 0 )
return power_mode ;
2017-11-05 13:00:02 -05:00
us = ret * mma8452_time_step_us [ power_mode ] [
2015-06-01 15:39:54 +02:00
mma8452_get_odr_index ( data ) ] ;
* val = us / USEC_PER_SEC ;
* val2 = us % USEC_PER_SEC ;
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:54 +02:00
return IIO_VAL_INT_PLUS_MICRO ;
2015-06-01 15:39:52 +02:00
2015-06-01 15:39:56 +02:00
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB :
ret = i2c_smbus_read_byte_data ( data - > client ,
MMA8452_TRANSIENT_CFG ) ;
if ( ret < 0 )
return ret ;
if ( ret & MMA8452_TRANSIENT_CFG_HPF_BYP ) {
* val = 0 ;
* val2 = 0 ;
} else {
ret = mma8452_read_hp_filter ( data , val , val2 ) ;
if ( ret < 0 )
return ret ;
}
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:56 +02:00
return IIO_VAL_INT_PLUS_MICRO ;
2015-06-01 15:39:54 +02:00
default :
return - EINVAL ;
}
2015-06-01 15:39:52 +02:00
}
2017-09-25 06:40:08 -04:00
static int mma8452_write_event_value ( struct iio_dev * indio_dev ,
2015-06-01 15:39:52 +02:00
const struct iio_chan_spec * chan ,
enum iio_event_type type ,
enum iio_event_direction dir ,
enum iio_event_info info ,
int val , int val2 )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2015-06-01 15:39:56 +02:00
int ret , reg , steps ;
2017-09-09 15:56:58 -04:00
const struct mma8452_event_regs * ev_regs ;
ret = mma8452_get_event_regs ( data , chan , dir , & ev_regs ) ;
if ( ret )
return ret ;
2015-06-01 15:39:52 +02:00
2015-06-01 15:39:54 +02:00
switch ( info ) {
case IIO_EV_INFO_VALUE :
2017-09-09 15:56:58 -04:00
if ( val < 0 | | val > ev_regs - > ev_ths_mask )
2015-08-02 22:43:49 +02:00
return - EINVAL ;
2017-09-09 15:56:58 -04:00
return mma8452_change_config ( data , ev_regs - > ev_ths , val ) ;
2015-06-01 15:39:54 +02:00
case IIO_EV_INFO_PERIOD :
2016-04-25 14:08:25 +02:00
ret = mma8452_get_power_mode ( data ) ;
if ( ret < 0 )
return ret ;
2015-06-01 15:39:54 +02:00
steps = ( val * USEC_PER_SEC + val2 ) /
2017-11-05 13:00:02 -05:00
mma8452_time_step_us [ ret ] [
2015-06-01 15:39:54 +02:00
mma8452_get_odr_index ( data ) ] ;
2015-08-02 22:43:49 +02:00
if ( steps < 0 | | steps > 0xff )
2015-06-01 15:39:54 +02:00
return - EINVAL ;
2017-09-09 15:56:58 -04:00
return mma8452_change_config ( data , ev_regs - > ev_count , steps ) ;
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:56 +02:00
case IIO_EV_INFO_HIGH_PASS_FILTER_3DB :
reg = i2c_smbus_read_byte_data ( data - > client ,
MMA8452_TRANSIENT_CFG ) ;
if ( reg < 0 )
return reg ;
if ( val = = 0 & & val2 = = 0 ) {
reg | = MMA8452_TRANSIENT_CFG_HPF_BYP ;
} else {
reg & = ~ MMA8452_TRANSIENT_CFG_HPF_BYP ;
ret = mma8452_set_hp_filter_frequency ( data , val , val2 ) ;
if ( ret < 0 )
return ret ;
}
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:56 +02:00
return mma8452_change_config ( data , MMA8452_TRANSIENT_CFG , reg ) ;
2015-06-01 15:39:54 +02:00
default :
return - EINVAL ;
}
2015-06-01 15:39:52 +02:00
}
static int mma8452_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 mma8452_data * data = iio_priv ( indio_dev ) ;
int ret ;
2017-09-09 15:56:58 -04:00
const struct mma8452_event_regs * ev_regs ;
ret = mma8452_get_event_regs ( data , chan , dir , & ev_regs ) ;
if ( ret )
return ret ;
2015-06-01 15:39:52 +02:00
2016-01-16 15:35:20 +01:00
switch ( dir ) {
case IIO_EV_DIR_FALLING :
return mma8452_freefall_mode_enabled ( data ) ;
case IIO_EV_DIR_RISING :
ret = i2c_smbus_read_byte_data ( data - > client ,
2017-09-09 15:56:58 -04:00
ev_regs - > ev_cfg ) ;
2016-01-16 15:35:20 +01:00
if ( ret < 0 )
return ret ;
2015-06-01 15:39:52 +02:00
2016-03-03 09:24:01 +01:00
return ! ! ( ret & BIT ( chan - > scan_index +
2017-09-09 15:56:58 -04:00
ev_regs - > ev_cfg_chan_shift ) ) ;
2016-01-16 15:35:20 +01:00
default :
return - EINVAL ;
}
2015-06-01 15:39:52 +02:00
}
static int mma8452_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 mma8452_data * data = iio_priv ( indio_dev ) ;
2016-03-03 09:24:03 +01:00
int val , ret ;
2017-09-09 15:56:58 -04:00
const struct mma8452_event_regs * ev_regs ;
ret = mma8452_get_event_regs ( data , chan , dir , & ev_regs ) ;
if ( ret )
return ret ;
2016-03-03 09:24:03 +01:00
ret = mma8452_set_runtime_pm_state ( data - > client , state ) ;
if ( ret )
return ret ;
2015-06-01 15:39:52 +02:00
2016-01-16 15:35:20 +01:00
switch ( dir ) {
case IIO_EV_DIR_FALLING :
return mma8452_set_freefall_mode ( data , state ) ;
case IIO_EV_DIR_RISING :
2017-09-09 15:56:58 -04:00
val = i2c_smbus_read_byte_data ( data - > client , ev_regs - > ev_cfg ) ;
2016-01-16 15:35:20 +01:00
if ( val < 0 )
return val ;
if ( state ) {
if ( mma8452_freefall_mode_enabled ( data ) ) {
2017-09-09 15:56:58 -04:00
val & = ~ BIT ( idx_x + ev_regs - > ev_cfg_chan_shift ) ;
val & = ~ BIT ( idx_y + ev_regs - > ev_cfg_chan_shift ) ;
val & = ~ BIT ( idx_z + ev_regs - > ev_cfg_chan_shift ) ;
2016-01-16 15:35:20 +01:00
val | = MMA8452_FF_MT_CFG_OAE ;
}
2017-09-09 15:56:58 -04:00
val | = BIT ( chan - > scan_index +
ev_regs - > ev_cfg_chan_shift ) ;
2016-01-16 15:35:20 +01:00
} else {
if ( mma8452_freefall_mode_enabled ( data ) )
return 0 ;
2015-06-01 15:39:52 +02:00
2017-09-09 15:56:58 -04:00
val & = ~ BIT ( chan - > scan_index +
ev_regs - > ev_cfg_chan_shift ) ;
2016-01-16 15:35:20 +01:00
}
2015-06-01 15:39:52 +02:00
2017-09-09 15:56:58 -04:00
val | = ev_regs - > ev_cfg_ele ;
2015-06-01 15:39:52 +02:00
2017-09-09 15:56:58 -04:00
return mma8452_change_config ( data , ev_regs - > ev_cfg , val ) ;
2016-01-16 15:35:20 +01:00
default :
return - EINVAL ;
}
2015-06-01 15:39:52 +02:00
}
static void mma8452_transient_interrupt ( struct iio_dev * indio_dev )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2016-03-09 19:05:49 +01:00
s64 ts = iio_get_time_ns ( indio_dev ) ;
2015-06-01 15:39:52 +02:00
int src ;
2017-09-09 15:56:58 -04:00
src = i2c_smbus_read_byte_data ( data - > client , MMA8452_TRANSIENT_SRC ) ;
2015-06-01 15:39:52 +02:00
if ( src < 0 )
return ;
2017-09-09 15:56:58 -04:00
if ( src & MMA8452_TRANSIENT_SRC_XTRANSE )
2015-06-01 15:39:52 +02:00
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 , IIO_MOD_X ,
2015-07-05 19:50:18 +02:00
IIO_EV_TYPE_MAG ,
2015-06-01 15:39:52 +02:00
IIO_EV_DIR_RISING ) ,
ts ) ;
2017-09-09 15:56:58 -04:00
if ( src & MMA8452_TRANSIENT_SRC_YTRANSE )
2015-06-01 15:39:52 +02:00
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 , IIO_MOD_Y ,
2015-07-05 19:50:18 +02:00
IIO_EV_TYPE_MAG ,
2015-06-01 15:39:52 +02:00
IIO_EV_DIR_RISING ) ,
ts ) ;
2017-09-09 15:56:58 -04:00
if ( src & MMA8452_TRANSIENT_SRC_ZTRANSE )
2015-06-01 15:39:52 +02:00
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 , IIO_MOD_Z ,
2015-07-05 19:50:18 +02:00
IIO_EV_TYPE_MAG ,
2015-06-01 15:39:52 +02:00
IIO_EV_DIR_RISING ) ,
ts ) ;
}
static irqreturn_t mma8452_interrupt ( int irq , void * p )
{
struct iio_dev * indio_dev = p ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2021-11-01 11:27:34 +01:00
irqreturn_t ret = IRQ_NONE ;
2015-06-01 15:39:52 +02:00
int src ;
src = i2c_smbus_read_byte_data ( data - > client , MMA8452_INT_SRC ) ;
if ( src < 0 )
return IRQ_NONE ;
2018-06-07 21:52:50 +03:00
if ( ! ( src & ( data - > chip_info - > enabled_events | MMA8452_INT_DRDY ) ) )
2017-09-09 15:56:58 -04:00
return IRQ_NONE ;
2015-06-01 15:39:58 +02:00
if ( src & MMA8452_INT_DRDY ) {
iio_trigger_poll_chained ( indio_dev - > trig ) ;
ret = IRQ_HANDLED ;
}
2017-09-09 15:56:58 -04:00
if ( src & MMA8452_INT_FF_MT ) {
if ( mma8452_freefall_mode_enabled ( data ) ) {
s64 ts = iio_get_time_ns ( indio_dev ) ;
iio_push_event ( indio_dev ,
IIO_MOD_EVENT_CODE ( IIO_ACCEL , 0 ,
IIO_MOD_X_AND_Y_AND_Z ,
IIO_EV_TYPE_MAG ,
IIO_EV_DIR_FALLING ) ,
ts ) ;
}
ret = IRQ_HANDLED ;
}
if ( src & MMA8452_INT_TRANS ) {
2015-06-01 15:39:52 +02:00
mma8452_transient_interrupt ( indio_dev ) ;
2015-06-01 15:39:58 +02:00
ret = IRQ_HANDLED ;
2015-06-01 15:39:52 +02:00
}
2015-06-01 15:39:58 +02:00
return ret ;
2015-06-01 15:39:52 +02:00
}
2014-02-05 09:51:00 +00:00
static irqreturn_t mma8452_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
int ret ;
2020-07-22 16:50:38 +01:00
ret = mma8452_read ( data , data - > buffer . channels ) ;
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
goto done ;
2020-07-22 16:50:38 +01:00
iio_push_to_buffers_with_timestamp ( indio_dev , & data - > buffer ,
2016-03-09 19:05:49 +01:00
iio_get_time_ns ( indio_dev ) ) ;
2014-02-05 09:51:00 +00:00
done :
iio_trigger_notify_done ( indio_dev - > trig ) ;
2015-08-02 22:43:51 +02:00
2014-02-05 09:51:00 +00:00
return IRQ_HANDLED ;
}
2015-05-13 12:26:40 +02:00
static int mma8452_reg_access_dbg ( struct iio_dev * indio_dev ,
2017-09-23 16:56:30 -04:00
unsigned int reg , unsigned int writeval ,
unsigned int * readval )
2015-05-13 12:26:40 +02:00
{
int ret ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
if ( reg > MMA8452_MAX_REG )
return - EINVAL ;
if ( ! readval )
return mma8452_change_config ( data , reg , writeval ) ;
ret = i2c_smbus_read_byte_data ( data - > client , reg ) ;
if ( ret < 0 )
return ret ;
* readval = ret ;
return 0 ;
}
2016-01-16 15:35:20 +01:00
static const struct iio_event_spec mma8452_freefall_event [ ] = {
{
. type = IIO_EV_TYPE_MAG ,
. dir = IIO_EV_DIR_FALLING ,
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_PERIOD ) |
BIT ( IIO_EV_INFO_HIGH_PASS_FILTER_3DB )
} ,
} ;
static const struct iio_event_spec mma8652_freefall_event [ ] = {
{
. type = IIO_EV_TYPE_MAG ,
. dir = IIO_EV_DIR_FALLING ,
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_PERIOD )
} ,
} ;
2015-06-01 15:39:52 +02:00
static const struct iio_event_spec mma8452_transient_event [ ] = {
{
2015-07-05 19:50:18 +02:00
. type = IIO_EV_TYPE_MAG ,
2015-06-01 15:39:52 +02:00
. dir = IIO_EV_DIR_RISING ,
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) ,
2015-06-01 15:39:54 +02:00
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
2015-06-01 15:39:56 +02:00
BIT ( IIO_EV_INFO_PERIOD ) |
BIT ( IIO_EV_INFO_HIGH_PASS_FILTER_3DB )
2015-06-01 15:39:52 +02:00
} ,
} ;
2015-09-01 13:45:10 +02:00
static const struct iio_event_spec mma8452_motion_event [ ] = {
{
. type = IIO_EV_TYPE_MAG ,
. dir = IIO_EV_DIR_RISING ,
. mask_separate = BIT ( IIO_EV_INFO_ENABLE ) ,
. mask_shared_by_type = BIT ( IIO_EV_INFO_VALUE ) |
BIT ( IIO_EV_INFO_PERIOD )
} ,
} ;
2015-06-01 15:39:52 +02:00
/*
* Threshold is configured in fixed 8 G / 127 steps regardless of
* currently selected scale for measurement .
*/
static IIO_CONST_ATTR_NAMED ( accel_transient_scale , in_accel_scale , " 0.617742 " ) ;
static struct attribute * mma8452_event_attributes [ ] = {
& iio_const_attr_accel_transient_scale . dev_attr . attr ,
NULL ,
} ;
2020-10-01 01:29:39 +02:00
static const struct attribute_group mma8452_event_attribute_group = {
2015-06-01 15:39:52 +02:00
. attrs = mma8452_event_attributes ,
} ;
2022-02-08 13:43:36 +01:00
static const struct iio_mount_matrix *
mma8452_get_mount_matrix ( const struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
return & data - > orientation ;
}
static const struct iio_chan_spec_ext_info mma8452_ext_info [ ] = {
IIO_MOUNT_MATRIX ( IIO_SHARED_BY_TYPE , mma8452_get_mount_matrix ) ,
{ }
} ;
2016-01-16 15:35:20 +01:00
# define MMA8452_FREEFALL_CHANNEL(modifier) { \
. type = IIO_ACCEL , \
. modified = 1 , \
. channel2 = modifier , \
. scan_index = - 1 , \
. event_spec = mma8452_freefall_event , \
. num_event_specs = ARRAY_SIZE ( mma8452_freefall_event ) , \
}
# define MMA8652_FREEFALL_CHANNEL(modifier) { \
. type = IIO_ACCEL , \
. modified = 1 , \
. channel2 = modifier , \
. scan_index = - 1 , \
. event_spec = mma8652_freefall_event , \
. num_event_specs = ARRAY_SIZE ( mma8652_freefall_event ) , \
}
2015-09-01 13:45:08 +02:00
# define MMA8452_CHANNEL(axis, idx, bits) { \
2014-02-05 09:51:00 +00:00
. type = IIO_ACCEL , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # axis , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
2015-08-02 22:43:51 +02:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , \
2014-02-05 09:51:00 +00:00
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) | \
2015-08-02 22:43:51 +02:00
BIT ( IIO_CHAN_INFO_SCALE ) | \
2016-04-25 14:08:25 +02:00
BIT ( IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY ) | \
BIT ( IIO_CHAN_INFO_OVERSAMPLING_RATIO ) , \
2014-02-05 09:51:00 +00:00
. scan_index = idx , \
. scan_type = { \
. sign = ' s ' , \
2015-09-01 13:45:08 +02:00
. realbits = ( bits ) , \
2014-02-05 09:51:00 +00:00
. storagebits = 16 , \
2015-09-01 13:45:08 +02:00
. shift = 16 - ( bits ) , \
2014-02-05 09:51:00 +00:00
. endianness = IIO_BE , \
} , \
2015-06-01 15:39:52 +02:00
. event_spec = mma8452_transient_event , \
. num_event_specs = ARRAY_SIZE ( mma8452_transient_event ) , \
2022-02-08 13:43:36 +01:00
. ext_info = mma8452_ext_info , \
2014-02-05 09:51:00 +00:00
}
2015-09-01 13:45:11 +02:00
# define MMA8652_CHANNEL(axis, idx, bits) { \
. type = IIO_ACCEL , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # axis , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_CALIBBIAS ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SAMP_FREQ ) | \
2016-04-25 14:08:25 +02:00
BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_OVERSAMPLING_RATIO ) , \
2015-09-01 13:45:11 +02:00
. scan_index = idx , \
. scan_type = { \
. sign = ' s ' , \
. realbits = ( bits ) , \
. storagebits = 16 , \
. shift = 16 - ( bits ) , \
. endianness = IIO_BE , \
} , \
. event_spec = mma8452_motion_event , \
. num_event_specs = ARRAY_SIZE ( mma8452_motion_event ) , \
2022-02-08 13:43:36 +01:00
. ext_info = mma8452_ext_info , \
2015-09-01 13:45:11 +02:00
}
2016-01-16 15:35:22 +01:00
static const struct iio_chan_spec mma8451_channels [ ] = {
MMA8452_CHANNEL ( X , idx_x , 14 ) ,
MMA8452_CHANNEL ( Y , idx_y , 14 ) ,
MMA8452_CHANNEL ( Z , idx_z , 14 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( idx_ts ) ,
MMA8452_FREEFALL_CHANNEL ( IIO_MOD_X_AND_Y_AND_Z ) ,
} ;
2014-02-05 09:51:00 +00:00
static const struct iio_chan_spec mma8452_channels [ ] = {
2015-12-15 17:45:00 +01:00
MMA8452_CHANNEL ( X , idx_x , 12 ) ,
MMA8452_CHANNEL ( Y , idx_y , 12 ) ,
MMA8452_CHANNEL ( Z , idx_z , 12 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( idx_ts ) ,
2016-01-16 15:35:20 +01:00
MMA8452_FREEFALL_CHANNEL ( IIO_MOD_X_AND_Y_AND_Z ) ,
2014-02-05 09:51:00 +00:00
} ;
2015-09-01 13:45:09 +02:00
static const struct iio_chan_spec mma8453_channels [ ] = {
2015-12-15 17:45:00 +01:00
MMA8452_CHANNEL ( X , idx_x , 10 ) ,
MMA8452_CHANNEL ( Y , idx_y , 10 ) ,
MMA8452_CHANNEL ( Z , idx_z , 10 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( idx_ts ) ,
2016-01-16 15:35:20 +01:00
MMA8452_FREEFALL_CHANNEL ( IIO_MOD_X_AND_Y_AND_Z ) ,
2015-09-01 13:45:09 +02:00
} ;
2015-09-01 13:45:11 +02:00
static const struct iio_chan_spec mma8652_channels [ ] = {
2015-12-15 17:45:00 +01:00
MMA8652_CHANNEL ( X , idx_x , 12 ) ,
MMA8652_CHANNEL ( Y , idx_y , 12 ) ,
MMA8652_CHANNEL ( Z , idx_z , 12 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( idx_ts ) ,
2016-01-16 15:35:20 +01:00
MMA8652_FREEFALL_CHANNEL ( IIO_MOD_X_AND_Y_AND_Z ) ,
2015-09-01 13:45:11 +02:00
} ;
static const struct iio_chan_spec mma8653_channels [ ] = {
2015-12-15 17:45:00 +01:00
MMA8652_CHANNEL ( X , idx_x , 10 ) ,
MMA8652_CHANNEL ( Y , idx_y , 10 ) ,
MMA8652_CHANNEL ( Z , idx_z , 10 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( idx_ts ) ,
2016-01-16 15:35:20 +01:00
MMA8652_FREEFALL_CHANNEL ( IIO_MOD_X_AND_Y_AND_Z ) ,
2015-09-01 13:45:11 +02:00
} ;
2015-09-01 13:45:08 +02:00
enum {
2016-01-16 15:35:22 +01:00
mma8451 ,
2015-09-01 13:45:08 +02:00
mma8452 ,
2015-09-01 13:45:09 +02:00
mma8453 ,
2015-09-01 13:45:11 +02:00
mma8652 ,
mma8653 ,
2016-03-09 12:01:29 +01:00
fxls8471 ,
2015-09-01 13:45:08 +02:00
} ;
static const struct mma_chip_info mma_chip_info_table [ ] = {
2016-01-16 15:35:22 +01:00
[ mma8451 ] = {
2022-02-08 13:43:35 +01:00
. name = " mma8451 " ,
2016-01-16 15:35:22 +01:00
. chip_id = MMA8451_DEVICE_ID ,
. channels = mma8451_channels ,
. num_channels = ARRAY_SIZE ( mma8451_channels ) ,
2015-09-01 13:45:08 +02:00
/*
* Hardware has fullscale of - 2 G , - 4 G , - 8 G corresponding to
2016-01-16 15:35:22 +01:00
* raw value - 8192 for 14 bit , - 2048 for 12 bit or - 512 for 10
* bit .
2015-09-01 13:45:08 +02:00
* The userspace interface uses m / s ^ 2 and we declare micro units
* So scale factor for 12 bit here is given by :
2016-03-03 09:24:01 +01:00
* g * N * 1000000 / 2048 for N = 2 , 4 , 8 and g = 9.80665
2015-09-01 13:45:08 +02:00
*/
2016-01-16 15:35:22 +01:00
. mma_scales = { { 0 , 2394 } , { 0 , 4788 } , { 0 , 9577 } } ,
2017-09-09 15:56:58 -04:00
/*
* Although we enable the interrupt sources once and for
* all here the event detection itself is not enabled until
* userspace asks for it by mma8452_write_event_config ( )
*/
. all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
. enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
2016-01-16 15:35:22 +01:00
} ,
[ mma8452 ] = {
2022-02-08 13:43:35 +01:00
. name = " mma8452 " ,
2016-01-16 15:35:22 +01:00
. chip_id = MMA8452_DEVICE_ID ,
. channels = mma8452_channels ,
. num_channels = ARRAY_SIZE ( mma8452_channels ) ,
2015-09-01 13:45:08 +02:00
. mma_scales = { { 0 , 9577 } , { 0 , 19154 } , { 0 , 38307 } } ,
2017-09-09 15:56:58 -04:00
/*
* Although we enable the interrupt sources once and for
* all here the event detection itself is not enabled until
* userspace asks for it by mma8452_write_event_config ( )
*/
. all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
. enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
2015-09-01 13:45:08 +02:00
} ,
2015-09-01 13:45:09 +02:00
[ mma8453 ] = {
2022-02-08 13:43:35 +01:00
. name = " mma8453 " ,
2015-09-01 13:45:09 +02:00
. chip_id = MMA8453_DEVICE_ID ,
. channels = mma8453_channels ,
. num_channels = ARRAY_SIZE ( mma8453_channels ) ,
. mma_scales = { { 0 , 38307 } , { 0 , 76614 } , { 0 , 153228 } } ,
2017-09-09 15:56:58 -04:00
/*
* Although we enable the interrupt sources once and for
* all here the event detection itself is not enabled until
* userspace asks for it by mma8452_write_event_config ( )
*/
. all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
. enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
2015-09-01 13:45:09 +02:00
} ,
2015-09-01 13:45:11 +02:00
[ mma8652 ] = {
2022-02-08 13:43:35 +01:00
. name = " mma8652 " ,
2015-09-01 13:45:11 +02:00
. chip_id = MMA8652_DEVICE_ID ,
. channels = mma8652_channels ,
. num_channels = ARRAY_SIZE ( mma8652_channels ) ,
. mma_scales = { { 0 , 9577 } , { 0 , 19154 } , { 0 , 38307 } } ,
2017-09-09 15:56:58 -04:00
. all_events = MMA8452_INT_DRDY |
MMA8452_INT_FF_MT ,
. enabled_events = MMA8452_INT_FF_MT ,
2015-09-01 13:45:11 +02:00
} ,
[ mma8653 ] = {
2022-02-08 13:43:35 +01:00
. name = " mma8653 " ,
2015-09-01 13:45:11 +02:00
. chip_id = MMA8653_DEVICE_ID ,
. channels = mma8653_channels ,
. num_channels = ARRAY_SIZE ( mma8653_channels ) ,
. mma_scales = { { 0 , 38307 } , { 0 , 76614 } , { 0 , 153228 } } ,
2017-09-09 15:56:58 -04:00
/*
* Although we enable the interrupt sources once and for
* all here the event detection itself is not enabled until
* userspace asks for it by mma8452_write_event_config ( )
*/
. all_events = MMA8452_INT_DRDY |
MMA8452_INT_FF_MT ,
. enabled_events = MMA8452_INT_FF_MT ,
2015-09-01 13:45:11 +02:00
} ,
2016-03-09 12:01:29 +01:00
[ fxls8471 ] = {
2022-02-08 13:43:35 +01:00
. name = " fxls8471 " ,
2016-03-09 12:01:29 +01:00
. chip_id = FXLS8471_DEVICE_ID ,
. channels = mma8451_channels ,
. num_channels = ARRAY_SIZE ( mma8451_channels ) ,
. mma_scales = { { 0 , 2394 } , { 0 , 4788 } , { 0 , 9577 } } ,
2017-09-09 15:56:58 -04:00
/*
* Although we enable the interrupt sources once and for
* all here the event detection itself is not enabled until
* userspace asks for it by mma8452_write_event_config ( )
*/
. all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
. enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT ,
2016-03-09 12:01:29 +01:00
} ,
2015-09-01 13:45:08 +02:00
} ;
2014-02-05 09:51:00 +00:00
static struct attribute * mma8452_attributes [ ] = {
& iio_dev_attr_sampling_frequency_available . dev_attr . attr ,
& iio_dev_attr_in_accel_scale_available . dev_attr . attr ,
2015-06-01 15:39:56 +02:00
& iio_dev_attr_in_accel_filter_high_pass_3db_frequency_available . dev_attr . attr ,
2016-04-25 14:08:25 +02:00
& iio_dev_attr_in_accel_oversampling_ratio_available . dev_attr . attr ,
2014-02-05 09:51:00 +00:00
NULL
} ;
static const struct attribute_group mma8452_group = {
. attrs = mma8452_attributes ,
} ;
static const struct iio_info mma8452_info = {
. attrs = & mma8452_group ,
. read_raw = & mma8452_read_raw ,
. write_raw = & mma8452_write_raw ,
2015-06-01 15:39:52 +02:00
. event_attrs = & mma8452_event_attribute_group ,
2017-09-25 06:40:08 -04:00
. read_event_value = & mma8452_read_event_value ,
. write_event_value = & mma8452_write_event_value ,
2015-06-01 15:39:52 +02:00
. read_event_config = & mma8452_read_event_config ,
. write_event_config = & mma8452_write_event_config ,
2015-05-13 12:26:40 +02:00
. debugfs_reg_access = & mma8452_reg_access_dbg ,
2014-02-05 09:51:00 +00:00
} ;
static const unsigned long mma8452_scan_masks [ ] = { 0x7 , 0 } ;
2015-06-01 15:39:58 +02:00
static int mma8452_data_rdy_trigger_set_state ( struct iio_trigger * trig ,
bool state )
{
struct iio_dev * indio_dev = iio_trigger_get_drvdata ( trig ) ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2016-03-03 09:24:03 +01:00
int reg , ret ;
ret = mma8452_set_runtime_pm_state ( data - > client , state ) ;
if ( ret )
return ret ;
2015-06-01 15:39:58 +02:00
reg = i2c_smbus_read_byte_data ( data - > client , MMA8452_CTRL_REG4 ) ;
if ( reg < 0 )
return reg ;
if ( state )
reg | = MMA8452_INT_DRDY ;
else
reg & = ~ MMA8452_INT_DRDY ;
return mma8452_change_config ( data , MMA8452_CTRL_REG4 , reg ) ;
}
static const struct iio_trigger_ops mma8452_trigger_ops = {
. set_trigger_state = mma8452_data_rdy_trigger_set_state ,
2016-09-23 17:19:42 +02:00
. validate_device = iio_trigger_validate_own_device ,
2015-06-01 15:39:58 +02:00
} ;
static int mma8452_trigger_setup ( struct iio_dev * indio_dev )
{
struct mma8452_data * data = iio_priv ( indio_dev ) ;
struct iio_trigger * trig ;
int ret ;
trig = devm_iio_trigger_alloc ( & data - > client - > dev , " %s-dev%d " ,
indio_dev - > name ,
2021-04-26 18:49:03 +01:00
iio_device_id ( indio_dev ) ) ;
2015-06-01 15:39:58 +02:00
if ( ! trig )
return - ENOMEM ;
trig - > ops = & mma8452_trigger_ops ;
iio_trigger_set_drvdata ( trig , indio_dev ) ;
ret = iio_trigger_register ( trig ) ;
if ( ret )
return ret ;
2021-10-24 11:26:59 +02:00
indio_dev - > trig = iio_trigger_get ( trig ) ;
2015-08-02 22:43:51 +02:00
2015-06-01 15:39:58 +02:00
return 0 ;
}
static void mma8452_trigger_cleanup ( struct iio_dev * indio_dev )
{
if ( indio_dev - > trig )
iio_trigger_unregister ( indio_dev - > trig ) ;
}
2015-05-13 12:26:38 +02:00
static int mma8452_reset ( struct i2c_client * client )
{
int i ;
int ret ;
2022-06-15 19:31:58 +08:00
/*
* Find on fxls8471 , after config reset bit , it reset immediately ,
* and will not give ACK , so here do not check the return value .
* The following code will read the reset register , and check whether
* this reset works .
*/
i2c_smbus_write_byte_data ( client , MMA8452_CTRL_REG2 ,
2015-05-13 12:26:38 +02:00
MMA8452_CTRL_REG2_RST ) ;
for ( i = 0 ; i < 10 ; i + + ) {
usleep_range ( 100 , 200 ) ;
ret = i2c_smbus_read_byte_data ( client , MMA8452_CTRL_REG2 ) ;
if ( ret = = - EIO )
continue ; /* I2C comm reset */
if ( ret < 0 )
return ret ;
if ( ! ( ret & MMA8452_CTRL_REG2_RST ) )
return 0 ;
}
return - ETIMEDOUT ;
}
2015-09-01 13:45:08 +02:00
static const struct of_device_id mma8452_dt_ids [ ] = {
2016-01-16 15:35:22 +01:00
{ . compatible = " fsl,mma8451 " , . data = & mma_chip_info_table [ mma8451 ] } ,
2015-09-01 13:45:08 +02:00
{ . compatible = " fsl,mma8452 " , . data = & mma_chip_info_table [ mma8452 ] } ,
2015-09-01 13:45:09 +02:00
{ . compatible = " fsl,mma8453 " , . data = & mma_chip_info_table [ mma8453 ] } ,
2015-09-01 13:45:11 +02:00
{ . compatible = " fsl,mma8652 " , . data = & mma_chip_info_table [ mma8652 ] } ,
{ . compatible = " fsl,mma8653 " , . data = & mma_chip_info_table [ mma8653 ] } ,
2016-03-09 12:01:29 +01:00
{ . compatible = " fsl,fxls8471 " , . data = & mma_chip_info_table [ fxls8471 ] } ,
2015-09-01 13:45:08 +02:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , mma8452_dt_ids ) ;
2014-02-05 09:51:00 +00:00
static int mma8452_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct mma8452_data * data ;
struct iio_dev * indio_dev ;
int ret ;
2015-09-01 13:45:08 +02:00
2014-02-05 09:51:00 +00:00
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
data - > client = client ;
mutex_init ( & data - > lock ) ;
2022-02-08 13:43:35 +01:00
data - > chip_info = device_get_match_data ( & client - > dev ) ;
2022-04-25 16:41:00 +08:00
if ( ! data - > chip_info ) {
if ( id ) {
data - > chip_info = & mma_chip_info_table [ id - > driver_data ] ;
} else {
dev_err ( & client - > dev , " unknown device model \n " ) ;
return - ENODEV ;
}
2022-02-08 13:43:35 +01:00
}
2015-09-01 13:45:08 +02:00
2022-02-08 13:43:36 +01:00
ret = iio_read_mount_matrix ( & client - > dev , & data - > orientation ) ;
if ( ret )
return ret ;
2019-01-08 09:14:06 +00:00
data - > vdd_reg = devm_regulator_get ( & client - > dev , " vdd " ) ;
2020-08-29 08:47:10 +02:00
if ( IS_ERR ( data - > vdd_reg ) )
return dev_err_probe ( & client - > dev , PTR_ERR ( data - > vdd_reg ) ,
" failed to get VDD regulator! \n " ) ;
2019-01-08 09:14:06 +00:00
data - > vddio_reg = devm_regulator_get ( & client - > dev , " vddio " ) ;
2020-08-29 08:47:10 +02:00
if ( IS_ERR ( data - > vddio_reg ) )
return dev_err_probe ( & client - > dev , PTR_ERR ( data - > vddio_reg ) ,
" failed to get VDDIO regulator! \n " ) ;
2019-01-08 09:14:06 +00:00
ret = regulator_enable ( data - > vdd_reg ) ;
if ( ret ) {
dev_err ( & client - > dev , " failed to enable VDD regulator! \n " ) ;
return ret ;
}
ret = regulator_enable ( data - > vddio_reg ) ;
if ( ret ) {
dev_err ( & client - > dev , " failed to enable VDDIO regulator! \n " ) ;
goto disable_regulator_vdd ;
}
2015-09-01 13:45:11 +02:00
ret = i2c_smbus_read_byte_data ( client , MMA8452_WHO_AM_I ) ;
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2015-09-01 13:45:11 +02:00
switch ( ret ) {
2016-01-16 15:35:22 +01:00
case MMA8451_DEVICE_ID :
2015-09-01 13:45:11 +02:00
case MMA8452_DEVICE_ID :
case MMA8453_DEVICE_ID :
case MMA8652_DEVICE_ID :
case MMA8653_DEVICE_ID :
2016-03-09 12:01:29 +01:00
case FXLS8471_DEVICE_ID :
2015-09-01 13:45:11 +02:00
if ( ret = = data - > chip_info - > chip_id )
break ;
2020-08-23 17:36:59 -05:00
fallthrough ;
2015-09-01 13:45:11 +02:00
default :
2019-01-08 09:14:06 +00:00
ret = - ENODEV ;
goto disable_regulators ;
2015-09-01 13:45:11 +02:00
}
2015-09-01 13:45:08 +02:00
dev_info ( & client - > dev , " registering %s accelerometer; ID 0x%x \n " ,
2022-02-08 13:43:35 +01:00
data - > chip_info - > name , data - > chip_info - > chip_id ) ;
2014-02-05 09:51:00 +00:00
i2c_set_clientdata ( client , indio_dev ) ;
indio_dev - > info = & mma8452_info ;
2022-02-08 13:43:35 +01:00
indio_dev - > name = data - > chip_info - > name ;
2014-02-05 09:51:00 +00:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
2015-09-01 13:45:08 +02:00
indio_dev - > channels = data - > chip_info - > channels ;
indio_dev - > num_channels = data - > chip_info - > num_channels ;
2014-02-05 09:51:00 +00:00
indio_dev - > available_scan_masks = mma8452_scan_masks ;
2015-05-13 12:26:38 +02:00
ret = mma8452_reset ( client ) ;
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2014-02-05 09:51:00 +00:00
data - > data_cfg = MMA8452_DATA_CFG_FS_2G ;
ret = i2c_smbus_write_byte_data ( client , MMA8452_DATA_CFG ,
2015-08-02 22:43:51 +02:00
data - > data_cfg ) ;
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2014-02-05 09:51:00 +00:00
2015-06-01 15:39:52 +02:00
/*
* By default set transient threshold to max to avoid events if
* enabling without configuring threshold .
*/
ret = i2c_smbus_write_byte_data ( client , MMA8452_TRANSIENT_THS ,
MMA8452_TRANSIENT_THS_MASK ) ;
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2015-06-01 15:39:52 +02:00
if ( client - > irq ) {
2015-10-15 15:10:32 +02:00
int irq2 ;
2015-06-01 15:39:52 +02:00
2015-10-15 15:10:32 +02:00
irq2 = of_irq_get_byname ( client - > dev . of_node , " INT2 " ) ;
if ( irq2 = = client - > irq ) {
dev_dbg ( & client - > dev , " using interrupt line INT2 \n " ) ;
} else {
ret = i2c_smbus_write_byte_data ( client ,
2017-09-09 15:56:58 -04:00
MMA8452_CTRL_REG5 ,
data - > chip_info - > all_events ) ;
2015-10-15 15:10:32 +02:00
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2015-10-15 15:10:32 +02:00
dev_dbg ( & client - > dev , " using interrupt line INT1 \n " ) ;
}
2015-06-01 15:39:52 +02:00
ret = i2c_smbus_write_byte_data ( client ,
2017-09-09 15:56:58 -04:00
MMA8452_CTRL_REG4 ,
data - > chip_info - > enabled_events ) ;
2015-06-01 15:39:58 +02:00
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2015-06-01 15:39:58 +02:00
ret = mma8452_trigger_setup ( indio_dev ) ;
2015-06-01 15:39:52 +02:00
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto disable_regulators ;
2015-06-01 15:39:52 +02:00
}
2015-05-13 12:26:38 +02:00
data - > ctrl_reg1 = MMA8452_CTRL_ACTIVE |
2015-08-02 22:43:51 +02:00
( MMA8452_CTRL_DR_DEFAULT < < MMA8452_CTRL_DR_SHIFT ) ;
2018-05-11 16:54:59 +08:00
data - > sleep_val = mma8452_calculate_sleep ( data ) ;
2015-05-13 12:26:38 +02:00
ret = i2c_smbus_write_byte_data ( client , MMA8452_CTRL_REG1 ,
data - > ctrl_reg1 ) ;
if ( ret < 0 )
2015-06-01 15:39:58 +02:00
goto trigger_cleanup ;
2015-05-13 12:26:38 +02:00
2014-02-05 09:51:00 +00:00
ret = iio_triggered_buffer_setup ( indio_dev , NULL ,
2015-08-02 22:43:51 +02:00
mma8452_trigger_handler , NULL ) ;
2014-02-05 09:51:00 +00:00
if ( ret < 0 )
2015-06-01 15:39:58 +02:00
goto trigger_cleanup ;
2014-02-05 09:51:00 +00:00
2015-06-01 15:39:52 +02:00
if ( client - > irq ) {
ret = devm_request_threaded_irq ( & client - > dev ,
client - > irq ,
NULL , mma8452_interrupt ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
client - > name , indio_dev ) ;
if ( ret )
goto buffer_cleanup ;
}
2016-03-03 09:24:03 +01:00
ret = pm_runtime_set_active ( & client - > dev ) ;
if ( ret < 0 )
goto buffer_cleanup ;
pm_runtime_enable ( & client - > dev ) ;
pm_runtime_set_autosuspend_delay ( & client - > dev ,
MMA8452_AUTO_SUSPEND_DELAY_MS ) ;
pm_runtime_use_autosuspend ( & client - > dev ) ;
2014-02-05 09:51:00 +00:00
ret = iio_device_register ( indio_dev ) ;
if ( ret < 0 )
goto buffer_cleanup ;
2015-06-01 15:39:52 +02:00
2016-01-16 15:35:20 +01:00
ret = mma8452_set_freefall_mode ( data , false ) ;
2016-07-04 10:08:53 +00:00
if ( ret < 0 )
2020-05-28 14:41:21 +08:00
goto unregister_device ;
2016-01-16 15:35:20 +01:00
2014-02-05 09:51:00 +00:00
return 0 ;
2020-05-28 14:41:21 +08:00
unregister_device :
iio_device_unregister ( indio_dev ) ;
2014-02-05 09:51:00 +00:00
buffer_cleanup :
iio_triggered_buffer_cleanup ( indio_dev ) ;
2015-06-01 15:39:58 +02:00
trigger_cleanup :
mma8452_trigger_cleanup ( indio_dev ) ;
2019-01-08 09:14:06 +00:00
disable_regulators :
regulator_disable ( data - > vddio_reg ) ;
disable_regulator_vdd :
regulator_disable ( data - > vdd_reg ) ;
2014-02-05 09:51:00 +00:00
return ret ;
}
2022-08-15 10:02:30 +02:00
static void mma8452_remove ( struct i2c_client * client )
2014-02-05 09:51:00 +00:00
{
struct iio_dev * indio_dev = i2c_get_clientdata ( client ) ;
2019-01-08 09:14:06 +00:00
struct mma8452_data * data = iio_priv ( indio_dev ) ;
2014-02-05 09:51:00 +00:00
iio_device_unregister ( indio_dev ) ;
2016-03-03 09:24:03 +01:00
pm_runtime_disable ( & client - > dev ) ;
pm_runtime_set_suspended ( & client - > dev ) ;
2014-02-05 09:51:00 +00:00
iio_triggered_buffer_cleanup ( indio_dev ) ;
2015-06-01 15:39:58 +02:00
mma8452_trigger_cleanup ( indio_dev ) ;
2014-02-05 09:51:00 +00:00
mma8452_standby ( iio_priv ( indio_dev ) ) ;
2019-01-08 09:14:06 +00:00
regulator_disable ( data - > vddio_reg ) ;
regulator_disable ( data - > vdd_reg ) ;
2014-02-05 09:51:00 +00:00
}
2016-03-03 09:24:03 +01:00
# ifdef CONFIG_PM
static int mma8452_runtime_suspend ( struct device * dev )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
int ret ;
mutex_lock ( & data - > lock ) ;
ret = mma8452_standby ( data ) ;
mutex_unlock ( & data - > lock ) ;
if ( ret < 0 ) {
dev_err ( & data - > client - > dev , " powering off device failed \n " ) ;
return - EAGAIN ;
}
2019-01-08 09:14:06 +00:00
ret = regulator_disable ( data - > vddio_reg ) ;
if ( ret ) {
dev_err ( dev , " failed to disable VDDIO regulator \n " ) ;
return ret ;
}
ret = regulator_disable ( data - > vdd_reg ) ;
if ( ret ) {
dev_err ( dev , " failed to disable VDD regulator \n " ) ;
return ret ;
}
2016-03-03 09:24:03 +01:00
return 0 ;
}
static int mma8452_runtime_resume ( struct device * dev )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
struct mma8452_data * data = iio_priv ( indio_dev ) ;
int ret , sleep_val ;
2019-01-08 09:14:06 +00:00
ret = regulator_enable ( data - > vdd_reg ) ;
if ( ret ) {
dev_err ( dev , " failed to enable VDD regulator \n " ) ;
return ret ;
}
ret = regulator_enable ( data - > vddio_reg ) ;
if ( ret ) {
dev_err ( dev , " failed to enable VDDIO regulator \n " ) ;
regulator_disable ( data - > vdd_reg ) ;
return ret ;
}
2016-03-03 09:24:03 +01:00
ret = mma8452_active ( data ) ;
if ( ret < 0 )
2019-01-08 09:14:06 +00:00
goto runtime_resume_failed ;
2016-03-03 09:24:03 +01:00
ret = mma8452_get_odr_index ( data ) ;
sleep_val = 1000 / mma8452_samp_freq [ ret ] [ 0 ] ;
if ( sleep_val < 20 )
usleep_range ( sleep_val * 1000 , 20000 ) ;
else
msleep_interruptible ( sleep_val ) ;
return 0 ;
2019-01-08 09:14:06 +00:00
runtime_resume_failed :
regulator_disable ( data - > vddio_reg ) ;
regulator_disable ( data - > vdd_reg ) ;
2014-02-05 09:51:00 +00:00
2019-01-08 09:14:06 +00:00
return ret ;
2014-02-05 09:51:00 +00:00
}
# endif
2016-03-03 09:24:03 +01:00
static const struct dev_pm_ops mma8452_pm_ops = {
2019-01-08 09:14:06 +00:00
SET_SYSTEM_SLEEP_PM_OPS ( pm_runtime_force_suspend , pm_runtime_force_resume )
2016-03-03 09:24:03 +01:00
SET_RUNTIME_PM_OPS ( mma8452_runtime_suspend ,
mma8452_runtime_resume , NULL )
} ;
2014-02-05 09:51:00 +00:00
static const struct i2c_device_id mma8452_id [ ] = {
2016-03-14 12:33:14 +01:00
{ " mma8451 " , mma8451 } ,
2015-09-01 13:45:08 +02:00
{ " mma8452 " , mma8452 } ,
2015-09-01 13:45:09 +02:00
{ " mma8453 " , mma8453 } ,
2015-09-01 13:45:11 +02:00
{ " mma8652 " , mma8652 } ,
{ " mma8653 " , mma8653 } ,
2016-03-09 12:01:29 +01:00
{ " fxls8471 " , fxls8471 } ,
2014-02-05 09:51:00 +00:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , mma8452_id ) ;
static struct i2c_driver mma8452_driver = {
. driver = {
. name = " mma8452 " ,
2022-02-08 13:43:35 +01:00
. of_match_table = mma8452_dt_ids ,
2016-03-03 09:24:03 +01:00
. pm = & mma8452_pm_ops ,
2014-02-05 09:51:00 +00:00
} ,
. probe = mma8452_probe ,
. remove = mma8452_remove ,
. id_table = mma8452_id ,
} ;
module_i2c_driver ( mma8452_driver ) ;
MODULE_AUTHOR ( " Peter Meerwald <pmeerw@pmeerw.net> " ) ;
2016-06-03 14:51:52 +02:00
MODULE_DESCRIPTION ( " Freescale / NXP MMA8452 accelerometer driver " ) ;
2014-02-05 09:51:00 +00:00
MODULE_LICENSE ( " GPL " ) ;