/*
* mma8452.c - Support for following Freescale 3-axis accelerometers:
*
* MMA8452Q (12 bit)
* MMA8453Q (10 bit)
* MMA8652FC (12 bit)
* MMA8653FC (10 bit)
*
* Copyright 2015 Martin Kepplinger <martin.kepplinger@theobroma-systems.com>
* Copyright 2014 Peter Meerwald <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address 0x1c/0x1d (pin selectable)
*
* TODO: orientation / freefall events, autosleep
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/events.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#define MMA8452_STATUS 0x00
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
#define MMA8452_OUT_X 0x01 /* MSB first */
#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)
#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
#define MMA8452_TRANSIENT_CFG 0x1d
#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
#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)
#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
#define MMA8452_MAX_REG 0x31
#define MMA8452_INT_DRDY BIT(0)
#define MMA8452_INT_FF_MT BIT(2)
#define MMA8452_INT_TRANS BIT(5)
#define MMA8452_DEVICE_ID 0x2a
#define MMA8453_DEVICE_ID 0x3a
#define MMA8652_DEVICE_ID 0x4a
#define MMA8653_DEVICE_ID 0x5a
struct mma8452_data {
struct i2c_client *client;
struct mutex lock;
u8 ctrl_reg1;
u8 data_cfg;
const struct mma_chip_info *chip_info;
};
/**
* struct mma_chip_info - chip specific data for Freescale's accelerometers
* @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: 2g, 4g, 8g; 2 integers
* per mode: m/s^2 and micro m/s^2
* @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_src_xe: bit in event source register that indicates
* an event in X direction
* @ev_src_ye: bit in event source register that indicates
* an event in Y direction
* @ev_src_ze: bit in event source register that indicates
* an event in Z direction
* @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 mma_chip_info {
u8 chip_id;
const struct iio_chan_spec *channels;
int num_channels;
const int mma_scales[3][2];
u8 ev_cfg;
u8 ev_cfg_ele;
u8 ev_cfg_chan_shift;
u8 ev_src;
u8 ev_src_xe;
u8 ev_src_ye;
u8 ev_src_ze;
u8 ev_ths;
u8 ev_ths_mask;
u8 ev_count;
};
enum {
idx_x,
idx_y,
idx_z,
idx_ts,
};
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;