#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>

#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>

#include "fxls8962af.h"

#define FXLS8962AF_INT_STATUS			0x00
#define FXLS8962AF_INT_STATUS_SRC_BOOT		BIT(0)
#define FXLS8962AF_INT_STATUS_SRC_SDCD_OT	BIT(4)
#define FXLS8962AF_INT_STATUS_SRC_BUF		BIT(5)
#define FXLS8962AF_INT_STATUS_SRC_DRDY		BIT(7)
#define FXLS8962AF_TEMP_OUT			0x01
#define FXLS8962AF_VECM_LSB			0x02
#define FXLS8962AF_OUT_X_LSB			0x04
#define FXLS8962AF_OUT_Y_LSB			0x06
#define FXLS8962AF_OUT_Z_LSB			0x08
#define FXLS8962AF_BUF_STATUS			0x0b
#define FXLS8962AF_BUF_STATUS_BUF_CNT		GENMASK(5, 0)
#define FXLS8962AF_BUF_STATUS_BUF_OVF		BIT(6)
#define FXLS8962AF_BUF_STATUS_BUF_WMRK		BIT(7)
#define FXLS8962AF_BUF_X_LSB			0x0c
#define FXLS8962AF_BUF_Y_LSB			0x0e
#define FXLS8962AF_BUF_Z_LSB			0x10

#define FXLS8962AF_PROD_REV			0x12
#define FXLS8962AF_WHO_AM_I			0x13

#define FXLS8962AF_SYS_MODE			0x14
#define FXLS8962AF_SENS_CONFIG1			0x15
#define FXLS8962AF_SENS_CONFIG1_ACTIVE		BIT(0)
#define FXLS8962AF_SENS_CONFIG1_RST		BIT(7)
#define FXLS8962AF_SC1_FSR_MASK			GENMASK(2, 1)
#define FXLS8962AF_SC1_FSR_PREP(x)		FIELD_PREP(FXLS8962AF_SC1_FSR_MASK, (x))
#define FXLS8962AF_SC1_FSR_GET(x)		FIELD_GET(FXLS8962AF_SC1_FSR_MASK, (x))

#define FXLS8962AF_SENS_CONFIG2			0x16
#define FXLS8962AF_SENS_CONFIG3			0x17
#define FXLS8962AF_SC3_WAKE_ODR_MASK		GENMASK(7, 4)
#define FXLS8962AF_SC3_WAKE_ODR_PREP(x)		FIELD_PREP(FXLS8962AF_SC3_WAKE_ODR_MASK, (x))
#define FXLS8962AF_SC3_WAKE_ODR_GET(x)		FIELD_GET(FXLS8962AF_SC3_WAKE_ODR_MASK, (x))
#define FXLS8962AF_SENS_CONFIG4			0x18
#define FXLS8962AF_SC4_INT_PP_OD_MASK		BIT(1)
#define FXLS8962AF_SC4_INT_PP_OD_PREP(x)	FIELD_PREP(FXLS8962AF_SC4_INT_PP_OD_MASK, (x))
#define FXLS8962AF_SC4_INT_POL_MASK		BIT(0)
#define FXLS8962AF_SC4_INT_POL_PREP(x)		FIELD_PREP(FXLS8962AF_SC4_INT_POL_MASK, (x))
#define FXLS8962AF_SENS_CONFIG5			0x19

#define FXLS8962AF_WAKE_IDLE_LSB		0x1b
#define FXLS8962AF_SLEEP_IDLE_LSB		0x1c
#define FXLS8962AF_ASLP_COUNT_LSB		0x1e

#define FXLS8962AF_INT_EN			0x20
#define FXLS8962AF_INT_EN_SDCD_OT_EN		BIT(5)
#define FXLS8962AF_INT_EN_BUF_EN		BIT(6)
#define FXLS8962AF_INT_PIN_SEL			0x21
#define FXLS8962AF_INT_PIN_SEL_MASK		GENMASK(7, 0)
#define FXLS8962AF_INT_PIN_SEL_INT1		0x00
#define FXLS8962AF_INT_PIN_SEL_INT2		GENMASK(7, 0)

#define FXLS8962AF_OFF_X			0x22
#define FXLS8962AF_OFF_Y			0x23
#define FXLS8962AF_OFF_Z			0x24

#define FXLS8962AF_BUF_CONFIG1			0x26
#define FXLS8962AF_BC1_BUF_MODE_MASK		GENMASK(6, 5)
#define FXLS8962AF_BC1_BUF_MODE_PREP(x)		FIELD_PREP(FXLS8962AF_BC1_BUF_MODE_MASK, (x))
#define FXLS8962AF_BUF_CONFIG2			0x27
#define FXLS8962AF_BUF_CONFIG2_BUF_WMRK		GENMASK(5, 0)

#define FXLS8962AF_ORIENT_STATUS		0x28
#define FXLS8962AF_ORIENT_CONFIG		0x29
#define FXLS8962AF_ORIENT_DBCOUNT		0x2a
#define FXLS8962AF_ORIENT_BF_ZCOMP		0x2b
#define FXLS8962AF_ORIENT_THS_REG		0x2c

#define FXLS8962AF_SDCD_INT_SRC1		0x2d
#define FXLS8962AF_SDCD_INT_SRC1_X_OT		BIT(5)
#define FXLS8962AF_SDCD_INT_SRC1_X_POL		BIT(4)
#define FXLS8962AF_SDCD_INT_SRC1_Y_OT		BIT(3)
#define FXLS8962AF_SDCD_INT_SRC1_Y_POL		BIT(2)
#define FXLS8962AF_SDCD_INT_SRC1_Z_OT		BIT(1)
#define FXLS8962AF_SDCD_INT_SRC1_Z_POL		BIT(0)
#define FXLS8962AF_SDCD_INT_SRC2		0x2e
#define FXLS8962AF_SDCD_CONFIG1			0x2f
#define FXLS8962AF_SDCD_CONFIG1_Z_OT_EN		BIT(3)
#define FXLS8962AF_SDCD_CONFIG1_Y_OT_EN		BIT(4)
#define FXLS8962AF_SDCD_CONFIG1_X_OT_EN		BIT(5)
#define FXLS8962AF_SDCD_CONFIG1_OT_ELE		BIT(7)
#define FXLS8962AF_SDCD_CONFIG2			0x30
#define FXLS8962AF_SDCD_CONFIG2_SDCD_EN		BIT(7)
#define FXLS8962AF_SC2_REF_UPDM_AC		GENMASK(6, 5)
#define FXLS8962AF_SDCD_OT_DBCNT		0x31
#define FXLS8962AF_SDCD_WT_DBCNT		0x32
#define FXLS8962AF_SDCD_LTHS_LSB		0x33
#define FXLS8962AF_SDCD_UTHS_LSB		0x35

#define FXLS8962AF_SELF_TEST_CONFIG1		0x37
#define FXLS8962AF_SELF_TEST_CONFIG2		0x38

#define FXLS8962AF_MAX_REG			0x38

#define FXLS8962AF_DEVICE_ID			0x62
#define FXLS8964AF_DEVICE_ID			0x84

/* Raw temp channel offset */
#define FXLS8962AF_TEMP_CENTER_VAL		25

#define FXLS8962AF_AUTO_SUSPEND_DELAY_MS	2000

#define FXLS8962AF_FIFO_LENGTH			32
#define FXLS8962AF_SCALE_TABLE_LEN		4
#define FXLS8962AF_SAMP_FREQ_TABLE_LEN		13

static const int fxls8962af_scale_table[FXLS8962AF_SCALE_TABLE_LEN][2] = {
{0, IIO_G_TO_M_S_2(980000)},
{0, IIO_G_TO_M_S_2(1950000)},
{0, IIO_G_TO_M_S_2(3910000)},
{0, IIO_G_TO_M_S_2(7810000)},
};

static const int fxls8962af_samp_freq_table[FXLS8962AF_SAMP_FREQ_TABLE_LEN][2] = {
{3200, 0}, {1600, 0}, {800, 0}, {400, 0}, {200, 0}, {100, 0},
{50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000},
{1, 563000}, {0, 781000},
};

struct fxls8962af_chip_info {
const char *name;
const struct iio_chan_spec *channels;
int num_channels;
u8 chip_id;
};

struct fxls8962af_data {
struct regmap *regmap;
const struct fxls8962af_chip_info *chip_info;
struct {
__le16 channels[3];
s64 ts __aligned(8);
} scan;
int64_t timestamp, old_timestamp;	/* Only used in hw fifo mode. */
struct iio_mount_matrix orientation;
int irq;
u8 watermark;
u8 enable_event;
u16 lower_thres;
u16 upper_thres;
};

const struct regmap_config fxls8962af_i2c_regmap_conf = {
.reg_bits = 8,
.val_bits = 8,
.max_register = FXLS8962AF_MAX_REG,
};
EXPORT_SYMBOL_NS_GPL(fxls8962af_i2c_regmap_conf, IIO_FXLS8962AF);

const struct regmap_config fxls8962af_spi_regmap_conf = {
.reg_bits = 8,
.pad_bits = 8,
.val_bits = 8,
.max_register = FXLS8962AF_MAX_REG,
};
EXPORT_SYMBOL_NS_GPL(fxls8962af_spi_regmap_conf, IIO_FXLS8962AF);

enum {
fxls8962af_idx_x,
fxls8962af_idx_y,
fxls8962af_idx_z,
fxls8962af_idx_ts,
};

enum fxls8962af_int_pin {
FXLS8962AF_PIN_INT1,
FXLS8962AF_PIN_INT2,
};

static int fxls8962af_power_on(struct fxls8962af_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;

ret = pm_runtime_resume_and_get(dev);
if (ret)
dev_err(dev, "failed to power on
");

return ret;
}

static int fxls8962af_power_off(struct fxls8962af_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;

pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
if (ret)
dev_err(dev, "failed to power off
");

return ret;
}

static int fxls8962af_standby(struct fxls8962af_data *data)
{
return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_ACTIVE, 0);
}

static int fxls8962af_active(struct fxls8962af_data *data)
{
return regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_ACTIVE, 1);
}

static int fxls8962af_is_active(struct fxls8962af_data *data)
{
unsigned int reg;
int ret;

ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, &reg);
if (ret)
return ret;

return reg & FXLS8962AF_SENS_CONFIG1_ACTIVE;
}

static int fxls8962af_get_out(struct fxls8962af_data *data,
struct iio_chan_spec const *chan, int *val)
{
struct device *dev = regmap_get_device(data->regmap);
__le16 raw_val;
int is_active;
int ret;

is_active = fxls8962af_is_active(data);
if (!is_active) {
ret = fxls8962af_power_on(data);
if (ret)
return ret;
}

ret = regmap_bulk_read(data->regmap, chan->address,
&raw_val, sizeof(data->lower_thres));

if (!is_active)
fxls8962af_power_off(data);

if (ret) {
dev_err(dev, "failed to get out reg 0x%lx
", chan->address);
return ret;
}

*val = sign_extend32(le16_to_cpu(raw_val),
chan->scan_type.realbits - 1);

return IIO_VAL_INT;
}

static int fxls8962af_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_INT_PLUS_NANO;
*vals = (int *)fxls8962af_scale_table;
*length = ARRAY_SIZE(fxls8962af_scale_table) * 2;
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = (int *)fxls8962af_samp_freq_table;
*length = ARRAY_SIZE(fxls8962af_samp_freq_table) * 2;
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}

static int fxls8962af_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
default:
return IIO_VAL_INT_PLUS_NANO;
}
}

static int fxls8962af_update_config(struct fxls8962af_data *data, u8 reg,
u8 mask, u8 val)
{
int ret;
int is_active;

is_active = fxls8962af_is_active(data);
if (is_active) {
ret = fxls8962af_standby(data);
if (ret)
return ret;
}

ret = regmap_update_bits(data->regmap, reg, mask, val);
if (ret)
return ret;

if (is_active) {
ret = fxls8962af_active(data);
if (ret)
return ret;
}

return 0;
}

static int fxls8962af_set_full_scale(struct fxls8962af_data *data, u32 scale)
{
int i;

for (i = 0; i < ARRAY_SIZE(fxls8962af_scale_table); i++)
if (scale == fxls8962af_scale_table[i][1])
break;

if (i == ARRAY_SIZE(fxls8962af_scale_table))
return -EINVAL;

return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SC1_FSR_MASK,
FXLS8962AF_SC1_FSR_PREP(i));
}

static unsigned int fxls8962af_read_full_scale(struct fxls8962af_data *data,
int *val)
{
int ret;
unsigned int reg;
u8 range_idx;

ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG1, &reg);
if (ret)
return ret;

range_idx = FXLS8962AF_SC1_FSR_GET(reg);

*val = fxls8962af_scale_table[range_idx][1];

return IIO_VAL_INT_PLUS_NANO;
}

static int fxls8962af_set_samp_freq(struct fxls8962af_data *data, u32 val,
u32 val2)
{
int i;

for (i = 0; i < ARRAY_SIZE(fxls8962af_samp_freq_table); i++)
if (val == fxls8962af_samp_freq_table[i][0] &&
val2 == fxls8962af_samp_freq_table[i][1])
break;

if (i == ARRAY_SIZE(fxls8962af_samp_freq_table))
return -EINVAL;

return fxls8962af_update_config(data, FXLS8962AF_SENS_CONFIG3,
FXLS8962AF_SC3_WAKE_ODR_MASK,
FXLS8962AF_SC3_WAKE_ODR_PREP(i));
}

static unsigned int fxls8962af_read_samp_freq(struct fxls8962af_data *data,
int *val, int *val2)
{
int ret;
unsigned int reg;
u8 range_idx;

ret = regmap_read(data->regmap, FXLS8962AF_SENS_CONFIG3, &reg);
if (ret)
return ret;

range_idx = FXLS8962AF_SC3_WAKE_ODR_GET(reg);

*val = fxls8962af_samp_freq_table[range_idx][0];
*val2 = fxls8962af_samp_freq_table[range_idx][1];

return IIO_VAL_INT_PLUS_MICRO;
}

static int fxls8962af_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct fxls8962af_data *data = iio_priv(indio_dev);

switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_TEMP:
case IIO_ACCEL:
return fxls8962af_get_out(data, chan, val);
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
if (chan->type != IIO_TEMP)
return -EINVAL;

*val = FXLS8962AF_TEMP_CENTER_VAL;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
return fxls8962af_read_full_scale(data, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
return fxls8962af_read_samp_freq(data, val, val2);
default:
return -EINVAL;
}
}

static int fxls8962af_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
int ret;

switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (val != 0)
return -EINVAL;

ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;

ret = fxls8962af_set_full_scale(data, val2);

iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;

ret = fxls8962af_set_samp_freq(data, val, val2);

iio_device_release_direct_mode(indio_dev);
return ret;
default:
return -EINVAL;
}
}

static int fxls8962af_event_setup(struct fxls8962af_data *data, int state)
{
/* Enable wakeup interrupt */
int mask = FXLS8962AF_INT_EN_SDCD_OT_EN;
int value = state ? mask : 0;

return regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, mask, value);
}

static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
{
struct fxls8962af_data *data = iio_priv(indio_dev);

if (val > FXLS8962AF_FIFO_LENGTH)
val = FXLS8962AF_FIFO_LENGTH;

data->watermark = val;

return 0;
}

static int __fxls8962af_set_thresholds(struct fxls8962af_data *data,
const struct iio_chan_spec *chan,
enum iio_event_direction dir,
int val)
{
switch (dir) {
case IIO_EV_DIR_FALLING:
data->lower_thres = val;
return regmap_bulk_write(data->regmap, FXLS8962AF_SDCD_LTHS_LSB,
&data->lower_thres, sizeof(data->lower_thres));
case IIO_EV_DIR_RISING:
data->upper_thres = val;
return regmap_bulk_write(data->regmap, FXLS8962AF_SDCD_UTHS_LSB,
&data->upper_thres, sizeof(data->upper_thres));
default:
return -EINVAL;
}
}

static int fxls8962af_read_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
int ret;

if (type != IIO_EV_TYPE_THRESH)
return -EINVAL;

switch (dir) {
case IIO_EV_DIR_FALLING:
ret = regmap_bulk_read(data->regmap, FXLS8962AF_SDCD_LTHS_LSB,
&data->lower_thres, sizeof(data->lower_thres));
if (ret)
return ret;

*val = sign_extend32(data->lower_thres, chan->scan_type.realbits - 1);
return IIO_VAL_INT;
case IIO_EV_DIR_RISING:
ret = regmap_bulk_read(data->regmap, FXLS8962AF_SDCD_UTHS_LSB,
&data->upper_thres, sizeof(data->upper_thres));
if (ret)
return ret;

*val = sign_extend32(data->upper_thres, chan->scan_type.realbits - 1);
return IIO_VAL_INT;
default:
return -EINVAL;
}
}

static int fxls8962af_write_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
int ret, val_masked;

if (type != IIO_EV_TYPE_THRESH)
return -EINVAL;

if (val < -2048 || val > 2047)
return -EINVAL;

if (data->enable_event)
return -EBUSY;

val_masked = val & GENMASK(11, 0);
if (fxls8962af_is_active(data)) {
ret = fxls8962af_standby(data);
if (ret)
return ret;

ret = __fxls8962af_set_thresholds(data, chan, dir, val_masked);
if (ret)
return ret;

return fxls8962af_active(data);
} else {
return __fxls8962af_set_thresholds(data, chan, dir, val_masked);
}
}

static int
fxls8962af_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 fxls8962af_data *data = iio_priv(indio_dev);

if (type != IIO_EV_TYPE_THRESH)
return -EINVAL;

switch (chan->channel2) {
case IIO_MOD_X:
return !!(FXLS8962AF_SDCD_CONFIG1_X_OT_EN & data->enable_event);
case IIO_MOD_Y:
return !!(FXLS8962AF_SDCD_CONFIG1_Y_OT_EN & data->enable_event);
case IIO_MOD_Z:
return !!(FXLS8962AF_SDCD_CONFIG1_Z_OT_EN & data->enable_event);
default:
return -EINVAL;
}
}

static int
fxls8962af_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 fxls8962af_data *data = iio_priv(indio_dev);
u8 enable_event, enable_bits;
int ret, value;

if (type != IIO_EV_TYPE_THRESH)
return -EINVAL;

switch (chan->channel2) {
case IIO_MOD_X:
enable_bits = FXLS8962AF_SDCD_CONFIG1_X_OT_EN;
break;
case IIO_MOD_Y:
enable_bits = FXLS8962AF_SDCD_CONFIG1_Y_OT_EN;
break;
case IIO_MOD_Z:
enable_bits = FXLS8962AF_SDCD_CONFIG1_Z_OT_EN;
break;
default:
return -EINVAL;
}

if (state)
enable_event = data->enable_event | enable_bits;
else
enable_event = data->enable_event & ~enable_bits;

if (data->enable_event == enable_event)
return 0;

ret = fxls8962af_standby(data);
if (ret)
return ret;

/* Enable events */
value = enable_event | FXLS8962AF_SDCD_CONFIG1_OT_ELE;
ret = regmap_write(data->regmap, FXLS8962AF_SDCD_CONFIG1, value);
if (ret)
return ret;

/*
* Enable update of SDCD_REF_X/Y/Z values with the current decimated and
* trimmed X/Y/Z acceleration input data. This allows for acceleration
* slope detection with Data(n) to Data(n–1) always used as the input
* to the window comparator.
*/
value = enable_event ?
FXLS8962AF_SDCD_CONFIG2_SDCD_EN | FXLS8962AF_SC2_REF_UPDM_AC :
0x00;
ret = regmap_write(data->regmap, FXLS8962AF_SDCD_CONFIG2, value);
if (ret)
return ret;

ret = fxls8962af_event_setup(data, state);
if (ret)
return ret;

data->enable_event = enable_event;

if (data->enable_event) {
fxls8962af_active(data);
ret = fxls8962af_power_on(data);
} else {
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;

/* Not in buffered mode so disable power */
ret = fxls8962af_power_off(data);

iio_device_release_direct_mode(indio_dev);
}

return ret;
}

static const struct iio_event_spec fxls8962af_event[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
},
};

#define FXLS8962AF_CHANNEL(axis, reg, idx) { \n.type = IIO_ACCEL, \n.address = reg, \n.modified = 1, \n.channel2 = IIO_MOD_##axis, \n.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \n.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \nBIT(IIO_CHAN_INFO_SAMP_FREQ), \n.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) | \nBIT(IIO_CHAN_INFO_SAMP_FREQ), \n.scan_index = idx, \n.scan_type = { \n.sign = 's', \n.realbits = 12, \n.storagebits = 16, \n.endianness = IIO_LE, \n}, \n.event_spec = fxls8962af_event, \n.num_event_specs = ARRAY_SIZE(fxls8962af_event), \n}

#define FXLS8962AF_TEMP_CHANNEL { \n.type = IIO_TEMP, \n.address = FXLS8962AF_TEMP_OUT, \n.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \nBIT(IIO_CHAN_INFO_OFFSET),\n.scan_index = -1, \n.scan_type = { \n.realbits = 8, \n.storagebits = 8, \n}, \n}

static const struct iio_chan_spec fxls8962af_channels[] = {
FXLS8962AF_CHANNEL(X, FXLS8962AF_OUT_X_LSB, fxls8962af_idx_x),
FXLS8962AF_CHANNEL(Y, FXLS8962AF_OUT_Y_LSB, fxls8962af_idx_y),
FXLS8962AF_CHANNEL(Z, FXLS8962AF_OUT_Z_LSB, fxls8962af_idx_z),
IIO_CHAN_SOFT_TIMESTAMP(fxls8962af_idx_ts),
FXLS8962AF_TEMP_CHANNEL,
};

static const struct fxls8962af_chip_info fxls_chip_info_table[] = {
[fxls8962af] = {
.chip_id = FXLS8962AF_DEVICE_ID,
.name = "fxls8962af",
.channels = fxls8962af_channels,
.num_channels = ARRAY_SIZE(fxls8962af_channels),
},
[fxls8964af] = {
.chip_id = FXLS8964AF_DEVICE_ID,
.name = "fxls8964af",
.channels = fxls8962af_channels,
.num_channels = ARRAY_SIZE(fxls8962af_channels),
},
};

static const struct iio_info fxls8962af_info = {
.read_raw = &fxls8962af_read_raw,
.write_raw = &fxls8962af_write_raw,
.write_raw_get_fmt = fxls8962af_write_raw_get_fmt,
.read_event_value = fxls8962af_read_event,
.write_event_value = fxls8962af_write_event,
.read_event_config = fxls8962af_read_event_config,
.write_event_config = fxls8962af_write_event_config,
.read_avail = fxls8962af_read_avail,
.hwfifo_set_watermark = fxls8962af_set_watermark,
};

static int fxls8962af_reset(struct fxls8962af_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
unsigned int reg;
int ret;

ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG1,
FXLS8962AF_SENS_CONFIG1_RST,
FXLS8962AF_SENS_CONFIG1_RST);
if (ret)
return ret;

/* TBOOT1, TBOOT2, specifies we have to wait between 1 - 17.7ms */
ret = regmap_read_poll_timeout(data->regmap, FXLS8962AF_INT_STATUS, reg,
(reg & FXLS8962AF_INT_STATUS_SRC_BOOT),
1000, 18000);
if (ret == -ETIMEDOUT)
dev_err(dev, "reset timeout, int_status = 0x%x
", reg);

return ret;
}

static int __fxls8962af_fifo_set_mode(struct fxls8962af_data *data, bool onoff)
{
int ret;

/* Enable watermark at max fifo size */
ret = regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG2,
FXLS8962AF_BUF_CONFIG2_BUF_WMRK,
data->watermark);
if (ret)
return ret;

return regmap_update_bits(data->regmap, FXLS8962AF_BUF_CONFIG1,
FXLS8962AF_BC1_BUF_MODE_MASK,
FXLS8962AF_BC1_BUF_MODE_PREP(onoff));
}

static int fxls8962af_buffer_preenable(struct iio_dev *indio_dev)
{
return fxls8962af_power_on(iio_priv(indio_dev));
}

static int fxls8962af_buffer_postenable(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
int ret;

fxls8962af_standby(data);

/* Enable buffer interrupt */
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
FXLS8962AF_INT_EN_BUF_EN,
FXLS8962AF_INT_EN_BUF_EN);
if (ret)
return ret;

ret = __fxls8962af_fifo_set_mode(data, true);

fxls8962af_active(data);

return ret;
}

static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
int ret;

fxls8962af_standby(data);

/* Disable buffer interrupt */
ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_EN,
FXLS8962AF_INT_EN_BUF_EN, 0);
if (ret)
return ret;

ret = __fxls8962af_fifo_set_mode(data, false);

if (data->enable_event)
fxls8962af_active(data);

return ret;
}

static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);

if (!data->enable_event)
fxls8962af_power_off(data);

return 0;
}

static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = {
.preenable = fxls8962af_buffer_preenable,
.postenable = fxls8962af_buffer_postenable,
.predisable = fxls8962af_buffer_predisable,
.postdisable = fxls8962af_buffer_postdisable,
};

static int fxls8962af_i2c_raw_read_errata3(struct fxls8962af_data *data,
u16 *buffer, int samples,
int sample_length)
{
int i, ret;

for (i = 0; i < samples; i++) {
ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB,
&buffer[i * 3], sample_length);
if (ret)
return ret;
}

return 0;
}

static int fxls8962af_fifo_transfer(struct fxls8962af_data *data,
u16 *buffer, int samples)
{
struct device *dev = regmap_get_device(data->regmap);
int sample_length = 3 * sizeof(*buffer);
int total_length = samples * sample_length;
int ret;

if (i2c_verify_client(dev) &&
data->chip_info->chip_id == FXLS8962AF_DEVICE_ID)
/*
* Due to errata bug (only applicable on fxls8962af):
* E3: FIFO burst read operation error using I2C interface
* We have to avoid burst reads on I2C..
*/
ret = fxls8962af_i2c_raw_read_errata3(data, buffer, samples,
sample_length);
else
ret = regmap_raw_read(data->regmap, FXLS8962AF_BUF_X_LSB, buffer,
total_length);

if (ret)
dev_err(dev, "Error transferring data from fifo: %d
", ret);

return ret;
}

static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
u16 buffer[FXLS8962AF_FIFO_LENGTH * 3];
uint64_t sample_period;
unsigned int reg;
int64_t tstamp;
int ret, i;
u8 count;

ret = regmap_read(data->regmap, FXLS8962AF_BUF_STATUS, &reg);
if (ret)
return ret;

if (reg & FXLS8962AF_BUF_STATUS_BUF_OVF) {
dev_err(dev, "Buffer overflow");
return -EOVERFLOW;
}

count = reg & FXLS8962AF_BUF_STATUS_BUF_CNT;
if (!count)
return 0;

data->old_timestamp = data->timestamp;
data->timestamp = iio_get_time_ns(indio_dev);

/*
* Approximate timestamps for each of the sample based on the sampling,
* frequency, timestamp for last sample and number of samples.
*/
sample_period = (data->timestamp - data->old_timestamp);
do_div(sample_period, count);
tstamp = data->timestamp - (count - 1) * sample_period;

ret = fxls8962af_fifo_transfer(data, buffer, count);
if (ret)
return ret;

/* Demux hw FIFO into kfifo. */
for (i = 0; i < count; i++) {
int j, bit;

j = 0;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->masklength) {
memcpy(&data->scan.channels[j++], &buffer[i * 3 + bit],
sizeof(data->scan.channels[0]));
}

iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
tstamp);

tstamp += sample_period;
}

return count;
}

static int fxls8962af_event_interrupt(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
s64 ts = iio_get_time_ns(indio_dev);
unsigned int reg;
u64 ev_code;
int ret;

ret = regmap_read(data->regmap, FXLS8962AF_SDCD_INT_SRC1, &reg);
if (ret)
return ret;

if (reg & FXLS8962AF_SDCD_INT_SRC1_X_OT) {
ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_X_POL ?
IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
IIO_EV_TYPE_THRESH, ev_code), ts);
}

if (reg & FXLS8962AF_SDCD_INT_SRC1_Y_OT) {
ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Y_POL ?
IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
IIO_EV_TYPE_THRESH, ev_code), ts);
}

if (reg & FXLS8962AF_SDCD_INT_SRC1_Z_OT) {
ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Z_POL ?
IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
IIO_EV_TYPE_THRESH, ev_code), ts);
}

return 0;
}

static irqreturn_t fxls8962af_interrupt(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct fxls8962af_data *data = iio_priv(indio_dev);
unsigned int reg;
int ret;

ret = regmap_read(data->regmap, FXLS8962AF_INT_STATUS, &reg);
if (ret)
return IRQ_NONE;

if (reg & FXLS8962AF_INT_STATUS_SRC_BUF) {
ret = fxls8962af_fifo_flush(indio_dev);
if (ret < 0)
return IRQ_NONE;

return IRQ_HANDLED;
}

if (reg & FXLS8962AF_INT_STATUS_SRC_SDCD_OT) {
ret = fxls8962af_event_interrupt(indio_dev);
if (ret < 0)
return IRQ_NONE;

return IRQ_HANDLED;
}

return IRQ_NONE;
}

static void fxls8962af_pm_disable(void *dev_ptr)
{
struct device *dev = dev_ptr;
struct iio_dev *indio_dev = dev_get_drvdata(dev);

pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
pm_runtime_put_noidle(dev);

fxls8962af_standby(iio_priv(indio_dev));
}

static void fxls8962af_get_irq(struct device_node *of_node,
enum fxls8962af_int_pin *pin)
{
int irq;

irq = of_irq_get_byname(of_node, "INT2");
if (irq > 0) {
*pin = FXLS8962AF_PIN_INT2;
return;
}

*pin = FXLS8962AF_PIN_INT1;
}

static int fxls8962af_irq_setup(struct iio_dev *indio_dev, int irq)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
struct device *dev = regmap_get_device(data->regmap);
unsigned long irq_type;
bool irq_active_high;
enum fxls8962af_int_pin int_pin;
u8 int_pin_sel;
int ret;

fxls8962af_get_irq(dev->of_node, &int_pin);
switch (int_pin) {
case FXLS8962AF_PIN_INT1:
int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT1;
break;
case FXLS8962AF_PIN_INT2:
int_pin_sel = FXLS8962AF_INT_PIN_SEL_INT2;
break;
default:
dev_err(dev, "unsupported int pin selected
");
return -EINVAL;
}

ret = regmap_update_bits(data->regmap, FXLS8962AF_INT_PIN_SEL,
FXLS8962AF_INT_PIN_SEL_MASK, int_pin_sel);
if (ret)
return ret;

irq_type = irqd_get_trigger_type(irq_get_irq_data(irq));

switch (irq_type) {
case IRQF_TRIGGER_HIGH:
case IRQF_TRIGGER_RISING:
irq_active_high = true;
break;
case IRQF_TRIGGER_LOW:
case IRQF_TRIGGER_FALLING:
irq_active_high = false;
break;
default:
dev_info(dev, "mode %lx unsupported
", irq_type);
return -EINVAL;
}

ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4,
FXLS8962AF_SC4_INT_POL_MASK,
FXLS8962AF_SC4_INT_POL_PREP(irq_active_high));
if (ret)
return ret;

if (device_property_read_bool(dev, "drive-open-drain")) {
ret = regmap_update_bits(data->regmap, FXLS8962AF_SENS_CONFIG4,
FXLS8962AF_SC4_INT_PP_OD_MASK,
FXLS8962AF_SC4_INT_PP_OD_PREP(1));
if (ret)
return ret;

irq_type |= IRQF_SHARED;
}

return devm_request_threaded_irq(dev,
irq,
NULL, fxls8962af_interrupt,
irq_type | IRQF_ONESHOT,
indio_dev->name, indio_dev);
}

int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
{
struct fxls8962af_data *data;
struct iio_dev *indio_dev;
unsigned int reg;
int ret, i;

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;
data->irq = irq;

ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;

ret = devm_regulator_get_enable(dev, "vdd");
if (ret)
return dev_err_probe(dev, ret,
"Failed to get vdd regulator
");

ret = regmap_read(data->regmap, FXLS8962AF_WHO_AM_I, &reg);
if (ret)
return ret;

for (i = 0; i < ARRAY_SIZE(fxls_chip_info_table); i++) {
if (fxls_chip_info_table[i].chip_id == reg) {
data->chip_info = &fxls_chip_info_table[i];
break;
}
}
if (i == ARRAY_SIZE(fxls_chip_info_table)) {
dev_err(dev, "failed to match device in table
");
return -ENXIO;
}

indio_dev->channels = data->chip_info->channels;
indio_dev->num_channels = data->chip_info->num_channels;
indio_dev->name = data->chip_info->name;
indio_dev->info = &fxls8962af_info;
indio_dev->modes = INDIO_DIRECT_MODE;

ret = fxls8962af_reset(data);
if (ret)
return ret;

if (irq) {
ret = fxls8962af_irq_setup(indio_dev, irq);
if (ret)
return ret;

ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
&fxls8962af_buffer_ops);
if (ret)
return ret;
}

ret = pm_runtime_set_active(dev);
if (ret)
return ret;

pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, FXLS8962AF_AUTO_SUSPEND_DELAY_MS);
pm_runtime_use_autosuspend(dev);

ret = devm_add_action_or_reset(dev, fxls8962af_pm_disable, dev);
if (ret)
return ret;

if (device_property_read_bool(dev, "wakeup-source"))
device_init_wakeup(dev, true);

return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(fxls8962af_core_probe, IIO_FXLS8962AF);

static int fxls8962af_runtime_suspend(struct device *dev)
{
struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));
int ret;

ret = fxls8962af_standby(data);
if (ret) {
dev_err(dev, "powering off device failed
");
return ret;
}

return 0;
}

static int fxls8962af_runtime_resume(struct device *dev)
{
struct fxls8962af_data *data = iio_priv(dev_get_drvdata(dev));

return fxls8962af_active(data);
}

static int fxls8962af_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct fxls8962af_data *data = iio_priv(indio_dev);

if (device_may_wakeup(dev) && data->enable_event) {
enable_irq_wake(data->irq);

/*
* Disable buffer, as the buffer is so small the device will wake
* almost immediately.
*/
if (iio_buffer_enabled(indio_dev))
fxls8962af_buffer_predisable(indio_dev);
} else {
fxls8962af_runtime_suspend(dev);
}

return 0;
}

static int fxls8962af_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct fxls8962af_data *data = iio_priv(indio_dev);

if (device_may_wakeup(dev) && data->enable_event) {
disable_irq_wake(data->irq);

if (iio_buffer_enabled(indio_dev))
fxls8962af_buffer_postenable(indio_dev);
} else {
fxls8962af_runtime_resume(dev);
}

return 0;
}

EXPORT_NS_GPL_DEV_PM_OPS(fxls8962af_pm_ops, IIO_FXLS8962AF) = {
SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
RUNTIME_PM_OPS(fxls8962af_runtime_suspend, fxls8962af_runtime_resume, NULL)
};

MODULE_AUTHOR("Sean Nyekjaer <sean@geanix.com>");
MODULE_DESCRIPTION("NXP FXLS8962AF/FXLS8964AF accelerometer driver");
MODULE_LICENSE("GPL v2");


#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>

#include <asm/unaligned.h>

#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>

#include "bma400.h"

/*
* The G-range selection may be one of 2g, 4g, 8, or 16g. The scale may
* be selected with the acc_range bits of the ACC_CONFIG1 register.
* NB: This buffer is populated in the device init.
*/
static int bma400_scales[8];

/*
* See the ACC_CONFIG1 section of the datasheet.
* NB: This buffer is populated in the device init.
*/
static int bma400_sample_freqs[14];

static const int bma400_osr_range[] = { 0, 1, 3 };

static int tap_reset_timeout[BMA400_TAP_TIM_LIST_LEN] = {
300000,
400000,
500000,
600000
};

static int tap_max2min_time[BMA400_TAP_TIM_LIST_LEN] = {
30000,
45000,
60000,
90000
};

static int double_tap2_min_delay[BMA400_TAP_TIM_LIST_LEN] = {
20000,
40000,
60000,
80000
};

/* See the ACC_CONFIG0 section of the datasheet */
enum bma400_power_mode {
POWER_MODE_SLEEP   = 0x00,
POWER_MODE_LOW     = 0x01,
POWER_MODE_NORMAL  = 0x02,
POWER_MODE_INVALID = 0x03,
};

enum bma400_scan {
BMA400_ACCL_X,
BMA400_ACCL_Y,
BMA400_ACCL_Z,
BMA400_TEMP,
};

struct bma400_sample_freq {
int hz;
int uhz;
};

enum bma400_activity {
BMA400_STILL,
BMA400_WALKING,
BMA400_RUNNING,
};

struct bma400_data {
struct device *dev;
struct regmap *regmap;
struct mutex mutex; /* data register lock */
struct iio_mount_matrix orientation;
enum bma400_power_mode power_mode;
struct bma400_sample_freq sample_freq;
int oversampling_ratio;
int scale;
struct iio_trigger *trig;
int steps_enabled;
bool step_event_en;
bool activity_event_en;
unsigned int generic_event_en;
unsigned int tap_event_en_bitmask;
/* Correct time stamp alignment */
struct {
__le16 buff[3];
u8 temperature;
s64 ts __aligned(8);
} buffer __aligned(IIO_DMA_MINALIGN);
__le16 status;
__be16 duration;
};

static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_CHIP_ID_REG:
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return false;
default:
return true;
}
}

static bool bma400_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return true;
default:
return false;
}
}

const struct regmap_config bma400_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BMA400_CMD_REG,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bma400_is_writable_reg,
.volatile_reg = bma400_is_volatile_reg,
};
EXPORT_SYMBOL_NS(bma400_regmap_config, IIO_BMA400);

static const struct iio_mount_matrix *
bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bma400_data *data = iio_priv(indio_dev);

return &data->orientation;
}

static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma400_accel_get_mount_matrix),
{ }
};

static const struct iio_event_spec bma400_step_detect_event = {
.type = IIO_EV_TYPE_CHANGE,
.dir = IIO_EV_DIR_NONE,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
};

static const struct iio_event_spec bma400_activity_event = {
.type = IIO_EV_TYPE_CHANGE,
.dir = IIO_EV_DIR_NONE,
.mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE),
};

static const struct iio_event_spec bma400_accel_event[] = {
{
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_FALLING,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD) |
BIT(IIO_EV_INFO_HYSTERESIS) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_RISING,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD) |
BIT(IIO_EV_INFO_HYSTERESIS) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_GESTURE,
.dir = IIO_EV_DIR_SINGLETAP,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE) |
BIT(IIO_EV_INFO_RESET_TIMEOUT),
},
{
.type = IIO_EV_TYPE_GESTURE,
.dir = IIO_EV_DIR_DOUBLETAP,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE) |
BIT(IIO_EV_INFO_RESET_TIMEOUT) |
BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
},
};

static int usec_to_tapreg_raw(int usec, const int *time_list)
{
int index;

for (index = 0; index < BMA400_TAP_TIM_LIST_LEN; index++) {
if (usec == time_list[index])
return index;
}
return -EINVAL;
}

static ssize_t in_accel_gesture_tap_maxtomin_time_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct bma400_data *data = iio_priv(indio_dev);
int ret, reg_val, raw, vals[2];

ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1, &reg_val);
if (ret)
return ret;

raw = FIELD_GET(BMA400_TAP_TICSTH_MSK, reg_val);
vals[0] = 0;
vals[1] = tap_max2min_time[raw];

return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals);
}

static ssize_t in_accel_gesture_tap_maxtomin_time_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct bma400_data *data = iio_priv(indio_dev);
int ret, val_int, val_fract, raw;

ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract);
if (ret)
return ret;

raw = usec_to_tapreg_raw(val_fract, tap_max2min_time);
if (raw < 0)
return -EINVAL;

ret = regmap_update_bits(data->regmap, BMA400_TAP_CONFIG1,
BMA400_TAP_TICSTH_MSK,
FIELD_PREP(BMA400_TAP_TICSTH_MSK, raw));
if (ret)
return ret;

return len;
}

static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_maxtomin_time, 0);

/*
* Tap interrupts works with 200 Hz input data rate and the time based tap
* controls are in the terms of data samples so the below calculation is
* used to convert the configuration values into seconds.
* e.g.:
* 60 data samples * 0.005 ms = 0.3 seconds.
* 80 data samples * 0.005 ms = 0.4 seconds.
*/

/* quiet configuration values in seconds */
static IIO_CONST_ATTR(in_accel_gesture_tap_reset_timeout_available,
"0.3 0.4 0.5 0.6");

/* tics_th configuration values in seconds */
static IIO_CONST_ATTR(in_accel_gesture_tap_maxtomin_time_available,
"0.03 0.045 0.06 0.09");

/* quiet_dt configuration values in seconds */
static IIO_CONST_ATTR(in_accel_gesture_doubletap_tap2_min_delay_available,
"0.02 0.04 0.06 0.08");

/* List of sensitivity values available to configure tap interrupts */
static IIO_CONST_ATTR(in_accel_gesture_tap_value_available, "0 1 2 3 4 5 6 7");

static struct attribute *bma400_event_attributes[] = {
&iio_const_attr_in_accel_gesture_tap_value_available.dev_attr.attr,
&iio_const_attr_in_accel_gesture_tap_reset_timeout_available.dev_attr.attr,
&iio_const_attr_in_accel_gesture_tap_maxtomin_time_available.dev_attr.attr,
&iio_const_attr_in_accel_gesture_doubletap_tap2_min_delay_available.dev_attr.attr,
&iio_dev_attr_in_accel_gesture_tap_maxtomin_time.dev_attr.attr,
NULL
};

static const struct attribute_group bma400_event_attribute_group = {
.attrs = bma400_event_attributes,
};

#define BMA400_ACC_CHANNEL(_index, _axis) { \n.type = IIO_ACCEL, \n.modified = 1, \n.channel2 = IIO_MOD_##_axis, \n.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \n.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \nBIT(IIO_CHAN_INFO_SCALE) | \nBIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \n.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \nBIT(IIO_CHAN_INFO_SCALE) | \nBIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \n.ext_info = bma400_ext_info, \n.scan_index = _index,	\n.scan_type = {		\n.sign = 's',	\n.realbits = 12,		\n.storagebits = 16,	\n.endianness = IIO_LE,	\n},				\n.event_spec = bma400_accel_event,			\n.num_event_specs = ARRAY_SIZE(bma400_accel_event)	\n}

#define BMA400_ACTIVITY_CHANNEL(_chan2) {	\n.type = IIO_ACTIVITY,			\n.modified = 1,				\n.channel2 = _chan2,			\n.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),	\n.scan_index = -1, /* No buffer support */		\n.event_spec = &bma400_activity_event,			\n.num_event_specs = 1,					\n}

static const struct iio_chan_spec bma400_channels[] = {
BMA400_ACC_CHANNEL(0, X),
BMA400_ACC_CHANNEL(1, Y),
BMA400_ACC_CHANNEL(2, Z),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 3,
.scan_type = {
.sign = 's',
.realbits = 8,
.storagebits = 8,
.endianness = IIO_LE,
},
},
{
.type = IIO_STEPS,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_ENABLE),
.scan_index = -1, /* No buffer support */
.event_spec = &bma400_step_detect_event,
.num_event_specs = 1,
},
BMA400_ACTIVITY_CHANNEL(IIO_MOD_STILL),
BMA400_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
BMA400_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
IIO_CHAN_SOFT_TIMESTAMP(4),
};

static int bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
{
unsigned int raw_temp;
int host_temp;
int ret;

if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;

ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &raw_temp);
if (ret)
return ret;

host_temp = sign_extend32(raw_temp, 7);
/*
* The formula for the TEMP_DATA register in the datasheet
* is: x * 0.5 + 23
*/
*val = (host_temp >> 1) + 23;
*val2 = (host_temp & 0x1) * 500000;
return IIO_VAL_INT_PLUS_MICRO;
}

static int bma400_get_accel_reg(struct bma400_data *data,
const struct iio_chan_spec *chan,
int *val)
{
__le16 raw_accel;
int lsb_reg;
int ret;

if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;

switch (chan->channel2) {
case IIO_MOD_X:
lsb_reg = BMA400_X_AXIS_LSB_REG;
break;
case IIO_MOD_Y:
lsb_reg = BMA400_Y_AXIS_LSB_REG;
break;
case IIO_MOD_Z:
lsb_reg = BMA400_Z_AXIS_LSB_REG;
break;
default:
dev_err(data->dev, "invalid axis channel modifier
");
return -EINVAL;
}

/* bulk read two registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, lsb_reg, &raw_accel,
sizeof(raw_accel));
if (ret)
return ret;

*val = sign_extend32(le16_to_cpu(raw_accel), 11);
return IIO_VAL_INT;
}

static void bma400_output_data_rate_from_raw(int raw, unsigned int *val,
unsigned int *val2)
{
*val = BMA400_ACC_ODR_MAX_HZ >> (BMA400_ACC_ODR_MAX_RAW - raw);
if (raw > BMA400_ACC_ODR_MIN_RAW)
*val2 = 0;
else
*val2 = 500000;
}

static int bma400_get_accel_output_data_rate(struct bma400_data *data)
{
unsigned int val;
unsigned int odr;
int ret;

switch (data->power_mode) {
case POWER_MODE_LOW:
/*
* Runs at a fixed rate in low-power mode. See section 4.3
* in the datasheet.
*/
bma400_output_data_rate_from_raw(BMA400_ACC_ODR_LP_RAW,
&data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_NORMAL:
/*
* In normal mode the ODR can be found in the ACC_CONFIG1
* register.
*/
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
goto error;

odr = val & BMA400_ACC_ODR_MASK;
if (odr < BMA400_ACC_ODR_MIN_RAW ||
odr > BMA400_ACC_ODR_MAX_RAW) {
ret = -EINVAL;
goto error;
}

bma400_output_data_rate_from_raw(odr, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_SLEEP:
data->sample_freq.hz = 0;
data->sample_freq.uhz = 0;
return 0;
default:
ret = 0;
goto error;
}
error:
data->sample_freq.hz = -1;
data->sample_freq.uhz = -1;
return ret;
}

static int bma400_set_accel_output_data_rate(struct bma400_data *data,
int hz, int uhz)
{
unsigned int idx;
unsigned int odr;
unsigned int val;
int ret;

if (hz >= BMA400_ACC_ODR_MIN_WHOLE_HZ) {
if (uhz || hz > BMA400_ACC_ODR_MAX_HZ)
return -EINVAL;

/* Note this works because MIN_WHOLE_HZ is odd */
idx = __ffs(hz);

if (hz >> idx != BMA400_ACC_ODR_MIN_WHOLE_HZ)
return -EINVAL;

idx += BMA400_ACC_ODR_MIN_RAW + 1;
} else if (hz == BMA400_ACC_ODR_MIN_HZ && uhz == 500000) {
idx = BMA400_ACC_ODR_MIN_RAW;
} else {
return -EINVAL;
}

ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;

/* preserve the range and normal mode osr */
odr = (~BMA400_ACC_ODR_MASK & val) | idx;

ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, odr);
if (ret)
return ret;

bma400_output_data_rate_from_raw(idx, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
}

static int bma400_get_accel_oversampling_ratio(struct bma400_data *data)
{
unsigned int val;
unsigned int osr;
int ret;

/*
* The oversampling ratio is stored in a different register
* based on the power-mode. In normal mode the OSR is stored
* in ACC_CONFIG1. In low-power mode it is stored in
* ACC_CONFIG0.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}

osr = (val & BMA400_LP_OSR_MASK) >> BMA400_LP_OSR_SHIFT;

data->oversampling_ratio = osr;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}

osr = (val & BMA400_NP_OSR_MASK) >> BMA400_NP_OSR_SHIFT;

data->oversampling_ratio = osr;
return 0;
case POWER_MODE_SLEEP:
data->oversampling_ratio = 0;
return 0;
default:
data->oversampling_ratio = -1;
return -EINVAL;
}
}

static int bma400_set_accel_oversampling_ratio(struct bma400_data *data,
int val)
{
unsigned int acc_config;
int ret;

if (val & ~BMA400_TWO_BITS_MASK)
return -EINVAL;

/*
* The oversampling ratio is stored in a different register
* based on the power-mode.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG,
&acc_config);
if (ret)
return ret;

ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
(acc_config & ~BMA400_LP_OSR_MASK) |
(val << BMA400_LP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR
");
return ret;
}

data->oversampling_ratio = val;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG,
&acc_config);
if (ret)
return ret;

ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_NP_OSR_MASK) |
(val << BMA400_NP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR
");
return ret;
}

data->oversampling_ratio = val;
return 0;
default:
return -EINVAL;
}
return ret;
}

static int bma400_accel_scale_to_raw(struct bma400_data *data,
unsigned int val)
{
int raw;

if (val == 0)
return -EINVAL;

/* Note this works because BMA400_SCALE_MIN is odd */
raw = __ffs(val);

if (val >> raw != BMA400_SCALE_MIN)
return -EINVAL;

return raw;
}

static int bma400_get_accel_scale(struct bma400_data *data)
{
unsigned int raw_scale;
unsigned int val;
int ret;

ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;

raw_scale = (val & BMA400_ACC_SCALE_MASK) >> BMA400_SCALE_SHIFT;
if (raw_scale > BMA400_TWO_BITS_MASK)
return -EINVAL;

data->scale = BMA400_SCALE_MIN << raw_scale;

return 0;
}

static int bma400_set_accel_scale(struct bma400_data *data, unsigned int val)
{
unsigned int acc_config;
int raw;
int ret;

ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &acc_config);
if (ret)
return ret;

raw = bma400_accel_scale_to_raw(data, val);
if (raw < 0)
return raw;

ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_ACC_SCALE_MASK) |
(raw << BMA400_SCALE_SHIFT));
if (ret)
return ret;

data->scale = val;
return 0;
}

static int bma400_get_power_mode(struct bma400_data *data)
{
unsigned int val;
int ret;

ret = regmap_read(data->regmap, BMA400_STATUS_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read status register
");
return ret;
}

data->power_mode = (val >> 1) & BMA400_TWO_BITS_MASK;
return 0;
}

static int bma400_set_power_mode(struct bma400_data *data,
enum bma400_power_mode mode)
{
unsigned int val;
int ret;

ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret)
return ret;

if (data->power_mode == mode)
return 0;

if (mode == POWER_MODE_INVALID)
return -EINVAL;

/* Preserve the low-power oversample ratio etc */
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
mode | (val & ~BMA400_TWO_BITS_MASK));
if (ret) {
dev_err(data->dev, "Failed to write to power-mode
");
return ret;
}

data->power_mode = mode;

/*
* Update our cached osr and odr based on the new
* power-mode.
*/
bma400_get_accel_output_data_rate(data);
bma400_get_accel_oversampling_ratio(data);
return 0;
}

static int bma400_enable_steps(struct bma400_data *data, int val)
{
int ret;

if (data->steps_enabled == val)
return 0;

ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG1_REG,
BMA400_STEP_INT_MSK,
FIELD_PREP(BMA400_STEP_INT_MSK, val ? 1 : 0));
if (ret)
return ret;
data->steps_enabled = val;
return ret;
}

static int bma400_get_steps_reg(struct bma400_data *data, int *val)
{
u8 *steps_raw;
int ret;

steps_raw = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL);
if (!steps_raw)
return -ENOMEM;

ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG,
steps_raw, BMA400_STEP_RAW_LEN);
if (ret) {
kfree(steps_raw);
return ret;
}
*val = get_unaligned_le24(steps_raw);
kfree(steps_raw);
return IIO_VAL_INT;
}

static void bma400_init_tables(void)
{
int raw;
int i;

for (i = 0; i + 1 < ARRAY_SIZE(bma400_sample_freqs); i += 2) {
raw = (i / 2) + 5;
bma400_output_data_rate_from_raw(raw, &bma400_sample_freqs[i],
&bma400_sample_freqs[i + 1]);
}

for (i = 0; i + 1 < ARRAY_SIZE(bma400_scales); i += 2) {
raw = i / 2;
bma400_scales[i] = 0;
bma400_scales[i + 1] = BMA400_SCALE_MIN << raw;
}
}

static void bma400_power_disable(void *data_ptr)
{
struct bma400_data *data = data_ptr;
int ret;

mutex_lock(&data->mutex);
ret = bma400_set_power_mode(data, POWER_MODE_SLEEP);
mutex_unlock(&data->mutex);
if (ret)
dev_warn(data->dev, "Failed to put device into sleep mode (%pe)
",
ERR_PTR(ret));
}

static enum iio_modifier bma400_act_to_mod(enum bma400_activity activity)
{
switch (activity) {
case BMA400_STILL:
return IIO_MOD_STILL;
case BMA400_WALKING:
return IIO_MOD_WALKING;
case BMA400_RUNNING:
return IIO_MOD_RUNNING;
default:
return IIO_NO_MOD;
}
}

static int bma400_init(struct bma400_data *data)
{
static const char * const regulator_names[] = { "vdd", "vddio" };
unsigned int val;
int ret;

ret = devm_regulator_bulk_get_enable(data->dev,
ARRAY_SIZE(regulator_names),
regulator_names);
if (ret)
return dev_err_probe(data->dev, ret, "Failed to get regulators
");

/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read chip id register
");
return ret;
}

if (val != BMA400_ID_REG_VAL) {
dev_err(data->dev, "Chip ID mismatch
");
return -ENODEV;
}

ret = bma400_get_power_mode(data);
if (ret) {
dev_err(data->dev, "Failed to get the initial power-mode
");
return ret;
}

if (data->power_mode != POWER_MODE_NORMAL) {
ret = bma400_set_power_mode(data, POWER_MODE_NORMAL);
if (ret) {
dev_err(data->dev, "Failed to wake up the device
");
return ret;
}
/*
* TODO: The datasheet waits 1500us here in the example, but
* lists 2/ODR as the wakeup time.
*/
usleep_range(1500, 2000);
}

ret = devm_add_action_or_reset(data->dev, bma400_power_disable, data);
if (ret)
return ret;

bma400_init_tables();

ret = bma400_get_accel_output_data_rate(data);
if (ret)
return ret;

ret = bma400_get_accel_oversampling_ratio(data);
if (ret)
return ret;

ret = bma400_get_accel_scale(data);
if (ret)
return ret;

/* Configure INT1 pin to open drain */
ret = regmap_write(data->regmap, BMA400_INT_IO_CTRL_REG, 0x06);
if (ret)
return ret;
/*
* Once the interrupt engine is supported we might use the
* data_src_reg, but for now ensure this is set to the
* variable ODR filter selectable by the sample frequency
* channel.
*/
return regmap_write(data->regmap, BMA400_ACC_CONFIG2_REG, 0x00);
}

static int bma400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
unsigned int activity;
int ret;

switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_TEMP:
mutex_lock(&data->mutex);
ret = bma400_get_temp_reg(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_STEPS:
return bma400_get_steps_reg(data, val);
case IIO_ACTIVITY:
ret = regmap_read(data->regmap, BMA400_STEP_STAT_REG,
&activity);
if (ret)
return ret;
/*
* The device does not support confidence value levels,
* so we will always have 100% for current activity and
* 0% for the others.
*/
if (chan->channel2 == bma400_act_to_mod(activity))
*val = 100;
else
*val = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
ret = bma400_get_accel_reg(data, chan, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
case IIO_ACCEL:
if (data->sample_freq.hz < 0)
return -EINVAL;

*val = data->sample_freq.hz;
*val2 = data->sample_freq.uhz;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
/*
* Runs at a fixed sampling frequency. See Section 4.4
* of the datasheet.
*/
*val = 6;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->scale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
/*
* TODO: We could avoid this logic and returning -EINVAL here if
* we set both the low-power and normal mode OSR registers when
* we configure the device.
*/
if (data->oversampling_ratio < 0)
return -EINVAL;

*val = data->oversampling_ratio;
return IIO_VAL_INT;
case IIO_CHAN_INFO_ENABLE:
*val = data->steps_enabled;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}

static int bma400_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_scales;
*length = ARRAY_SIZE(bma400_scales);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*type = IIO_VAL_INT;
*vals = bma400_osr_range;
*length = ARRAY_SIZE(bma400_osr_range);
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_sample_freqs;
*length = ARRAY_SIZE(bma400_sample_freqs);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}

static int bma400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;

switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
/*
* The sample frequency is readonly for the temperature
* register and a fixed value in low-power mode.
*/
if (chan->type != IIO_ACCEL)
return -EINVAL;

mutex_lock(&data->mutex);
ret = bma400_set_accel_output_data_rate(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SCALE:
if (val != 0 ||
val2 < BMA400_SCALE_MIN || val2 > BMA400_SCALE_MAX)
return -EINVAL;

mutex_lock(&data->mutex);
ret = bma400_set_accel_scale(data, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
mutex_lock(&data->mutex);
ret = bma400_set_accel_oversampling_ratio(data, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_ENABLE:
mutex_lock(&data->mutex);
ret = bma400_enable_steps(data, val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}

static int bma400_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return IIO_VAL_INT;
case IIO_CHAN_INFO_ENABLE:
return IIO_VAL_INT;
default:
return -EINVAL;
}
}

static int bma400_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct bma400_data *data = iio_priv(indio_dev);

switch (chan->type) {
case IIO_ACCEL:
switch (dir) {
case IIO_EV_DIR_RISING:
return FIELD_GET(BMA400_INT_GEN1_MSK,
data->generic_event_en);
case IIO_EV_DIR_FALLING:
return FIELD_GET(BMA400_INT_GEN2_MSK,
data->generic_event_en);
case IIO_EV_DIR_SINGLETAP:
return FIELD_GET(BMA400_S_TAP_MSK,
data->tap_event_en_bitmask);
case IIO_EV_DIR_DOUBLETAP:
return FIELD_GET(BMA400_D_TAP_MSK,
data->tap_event_en_bitmask);
default:
return -EINVAL;
}
case IIO_STEPS:
return data->step_event_en;
case IIO_ACTIVITY:
return data->activity_event_en;
default:
return -EINVAL;
}
}

static int bma400_steps_event_enable(struct bma400_data *data, int state)
{
int ret;

ret = bma400_enable_steps(data, 1);
if (ret)
return ret;

ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG,
BMA400_STEP_INT_MSK,
FIELD_PREP(BMA400_STEP_INT_MSK,
state));
if (ret)
return ret;
data->step_event_en = state;
return 0;
}

static int bma400_activity_event_en(struct bma400_data *data,
enum iio_event_direction dir,
int state)
{
int ret, reg, msk, value;
int field_value = 0;

switch (dir) {
case IIO_EV_DIR_RISING:
reg = BMA400_GEN1INT_CONFIG0;
msk = BMA400_INT_GEN1_MSK;
value = 2;
set_mask_bits(&field_value, BMA400_INT_GEN1_MSK,
FIELD_PREP(BMA400_INT_GEN1_MSK, state));
break;
case IIO_EV_DIR_FALLING:
reg = BMA400_GEN2INT_CONFIG0;
msk = BMA400_INT_GEN2_MSK;
value = 0;
set_mask_bits(&field_value, BMA400_INT_GEN2_MSK,
FIELD_PREP(BMA400_INT_GEN2_MSK, state));
break;
default:
return -EINVAL;
}

/* Enabling all axis for interrupt evaluation */
ret = regmap_write(data->regmap, reg, 0xF8);
if (ret)
return ret;

/* OR combination of all axis for interrupt evaluation */
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG1_OFF, value);
if (ret)
return ret;

/* Initial value to avoid interrupts while enabling*/
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG2_OFF, 0x0A);
if (ret)
return ret;

/* Initial duration value to avoid interrupts while enabling*/
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG31_OFF, 0x0F);
if (ret)
return ret;

ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, msk,
field_value);
if (ret)
return ret;

ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, msk,
field_value);
if (ret)
return ret;

set_mask_bits(&data->generic_event_en, msk, field_value);
return 0;
}

static int bma400_tap_event_en(struct bma400_data *data,
enum iio_event_direction dir, int state)
{
unsigned int mask, field_value;
int ret;

/*
* Tap interrupts can be configured only in normal mode.
* See table in section 4.3 "Power modes - performance modes" of
* datasheet v1.2.
*/
if (data->power_mode != POWER_MODE_NORMAL)
return -EINVAL;

/*
* Tap interrupts are operating with a data rate of 200Hz.
* See section 4.7 "Tap sensing interrupt" in datasheet v1.2.
*/
if (data->sample_freq.hz != 200 && state) {
dev_err(data->dev, "Invalid data rate for tap interrupts.
");
return -EINVAL;
}

ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG,
BMA400_S_TAP_MSK,
FIELD_PREP(BMA400_S_TAP_MSK, state));
if (ret)
return ret;

switch (dir) {
case IIO_EV_DIR_SINGLETAP:
mask = BMA400_S_TAP_MSK;
set_mask_bits(&field_value, BMA400_S_TAP_MSK,
FIELD_PREP(BMA400_S_TAP_MSK, state));
break;
case IIO_EV_DIR_DOUBLETAP:
mask = BMA400_D_TAP_MSK;
set_mask_bits(&field_value, BMA400_D_TAP_MSK,
FIELD_PREP(BMA400_D_TAP_MSK, state));
break;
default:
return -EINVAL;
}

ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG1_REG, mask,
field_value);
if (ret)
return ret;

set_mask_bits(&data->tap_event_en_bitmask, mask, field_value);

return 0;
}

static int bma400_disable_adv_interrupt(struct bma400_data *data)
{
int ret;

ret = regmap_write(data->regmap, BMA400_INT_CONFIG0_REG, 0);
if (ret)
return ret;

ret = regmap_write(data->regmap, BMA400_INT_CONFIG1_REG, 0);
if (ret)
return ret;

data->tap_event_en_bitmask = 0;
data->generic_event_en = 0;
data->step_event_en = false;
data->activity_event_en = false;

return 0;
}

static int bma400_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;

switch (chan->type) {
case IIO_ACCEL:
switch (type) {
case IIO_EV_TYPE_MAG:
mutex_lock(&data->mutex);
ret = bma400_activity_event_en(data, dir, state);
mutex_unlock(&data->mutex);
return ret;
case IIO_EV_TYPE_GESTURE:
mutex_lock(&data->mutex);
ret = bma400_tap_event_en(data, dir, state);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
case IIO_STEPS:
mutex_lock(&data->mutex);
ret = bma400_steps_event_enable(data, state);
mutex_unlock(&data->mutex);
return ret;
case IIO_ACTIVITY:
mutex_lock(&data->mutex);
if (!data->step_event_en) {
ret = bma400_steps_event_enable(data, true);
if (ret) {
mutex_unlock(&data->mutex);
return ret;
}
}
data->activity_event_en = state;
mutex_unlock(&data->mutex);
return 0;
default:
return -EINVAL;
}
}

static int get_gen_config_reg(enum iio_event_direction dir)
{
switch (dir) {
case IIO_EV_DIR_FALLING:
return BMA400_GEN2INT_CONFIG0;
case IIO_EV_DIR_RISING:
return BMA400_GEN1INT_CONFIG0;
default:
return -EINVAL;
}
}

static int bma400_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret, reg, reg_val, raw;

if (chan->type != IIO_ACCEL)
return -EINVAL;

switch (type) {
case IIO_EV_TYPE_MAG:
reg = get_gen_config_reg(dir);
if (reg < 0)
return -EINVAL;

*val2 = 0;
switch (info) {
case IIO_EV_INFO_VALUE:
ret = regmap_read(data->regmap,
reg + BMA400_GEN_CONFIG2_OFF,
val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
mutex_lock(&data->mutex);
ret = regmap_bulk_read(data->regmap,
reg + BMA400_GEN_CONFIG3_OFF,
&data->duration,
sizeof(data->duration));
if (ret) {
mutex_unlock(&data->mutex);
return ret;
}
*val = be16_to_cpu(data->duration);
mutex_unlock(&data->mutex);
return IIO_VAL_INT;
case IIO_EV_INFO_HYSTERESIS:
ret = regmap_read(data->regmap, reg, val);
if (ret)
return ret;
*val = FIELD_GET(BMA400_GEN_HYST_MSK, *val);
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_EV_TYPE_GESTURE:
switch (info) {
case IIO_EV_INFO_VALUE:
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG,
&reg_val);
if (ret)
return ret;

*val = FIELD_GET(BMA400_TAP_SEN_MSK, reg_val);
return IIO_VAL_INT;
case IIO_EV_INFO_RESET_TIMEOUT:
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1,
&reg_val);
if (ret)
return ret;

raw = FIELD_GET(BMA400_TAP_QUIET_MSK, reg_val);
*val = 0;
*val2 = tap_reset_timeout[raw];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_EV_INFO_TAP2_MIN_DELAY:
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1,
&reg_val);
if (ret)
return ret;

raw = FIELD_GET(BMA400_TAP_QUIETDT_MSK, reg_val);
*val = 0;
*val2 = double_tap2_min_delay[raw];
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}

static int bma400_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
struct bma400_data *data = iio_priv(indio_dev);
int reg, ret, raw;

if (chan->type != IIO_ACCEL)
return -EINVAL;

switch (type) {
case IIO_EV_TYPE_MAG:
reg = get_gen_config_reg(dir);
if (reg < 0)
return -EINVAL;

switch (info) {
case IIO_EV_INFO_VALUE:
if (val < 1 || val > 255)
return -EINVAL;

return regmap_write(data->regmap,
reg + BMA400_GEN_CONFIG2_OFF,
val);
case IIO_EV_INFO_PERIOD:
if (val < 1 || val > 65535)
return -EINVAL;

mutex_lock(&data->mutex);
put_unaligned_be16(val, &data->duration);
ret = regmap_bulk_write(data->regmap,
reg + BMA400_GEN_CONFIG3_OFF,
&data->duration,
sizeof(data->duration));
mutex_unlock(&data->mutex);
return ret;
case IIO_EV_INFO_HYSTERESIS:
if (val < 0 || val > 3)
return -EINVAL;

return regmap_update_bits(data->regmap, reg,
BMA400_GEN_HYST_MSK,
FIELD_PREP(BMA400_GEN_HYST_MSK,
val));
default:
return -EINVAL;
}
case IIO_EV_TYPE_GESTURE:
switch (info) {
case IIO_EV_INFO_VALUE:
if (val < 0 || val > 7)
return -EINVAL;

return regmap_update_bits(data->regmap,
BMA400_TAP_CONFIG,
BMA400_TAP_SEN_MSK,
FIELD_PREP(BMA400_TAP_SEN_MSK,
val));
case IIO_EV_INFO_RESET_TIMEOUT:
raw = usec_to_tapreg_raw(val2, tap_reset_timeout);
if (raw < 0)
return -EINVAL;

return regmap_update_bits(data->regmap,
BMA400_TAP_CONFIG1,
BMA400_TAP_QUIET_MSK,
FIELD_PREP(BMA400_TAP_QUIET_MSK,
raw));
case IIO_EV_INFO_TAP2_MIN_DELAY:
raw = usec_to_tapreg_raw(val2, double_tap2_min_delay);
if (raw < 0)
return -EINVAL;

return regmap_update_bits(data->regmap,
BMA400_TAP_CONFIG1,
BMA400_TAP_QUIETDT_MSK,
FIELD_PREP(BMA400_TAP_QUIETDT_MSK,
raw));
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}

static int bma400_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bma400_data *data = iio_priv(indio_dev);
int ret;

ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG,
BMA400_INT_DRDY_MSK,
FIELD_PREP(BMA400_INT_DRDY_MSK, state));
if (ret)
return ret;

return regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG,
BMA400_INT_DRDY_MSK,
FIELD_PREP(BMA400_INT_DRDY_MSK, state));
}

static const unsigned long bma400_avail_scan_masks[] = {
BIT(BMA400_ACCL_X) | BIT(BMA400_ACCL_Y) | BIT(BMA400_ACCL_Z),
BIT(BMA400_ACCL_X) | BIT(BMA400_ACCL_Y) | BIT(BMA400_ACCL_Z)
| BIT(BMA400_TEMP),
0
};

static const struct iio_info bma400_info = {
.read_raw          = bma400_read_raw,
.read_avail        = bma400_read_avail,
.write_raw         = bma400_write_raw,
.write_raw_get_fmt = bma400_write_raw_get_fmt,
.read_event_config = bma400_read_event_config,
.write_event_config = bma400_write_event_config,
.write_event_value = bma400_write_event_value,
.read_event_value = bma400_read_event_value,
.event_attrs = &bma400_event_attribute_group,
};

static const struct iio_trigger_ops bma400_trigger_ops = {
.set_trigger_state = &bma400_data_rdy_trigger_set_state,
.validate_device = &iio_trigger_validate_own_device,
};

static irqreturn_t bma400_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bma400_data *data = iio_priv(indio_dev);
int ret, temp;

/* Lock to protect the data->buffer */
mutex_lock(&data->mutex);

/* bulk read six registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
&data->buffer.buff, sizeof(data->buffer.buff));
if (ret)
goto unlock_err;

if (test_bit(BMA400_TEMP, indio_dev->active_scan_mask)) {
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &temp);
if (ret)
goto unlock_err;

data->buffer.temperature = temp;
}

iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
iio_get_time_ns(indio_dev));

mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;

unlock_err:
mutex_unlock(&data->mutex);
return IRQ_NONE;
}

static irqreturn_t bma400_interrupt(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct bma400_data *data = iio_priv(indio_dev);
s64 timestamp = iio_get_time_ns(indio_dev);
unsigned int act, ev_dir = IIO_EV_DIR_NONE;
int ret;

/* Lock to protect the data->status */
mutex_lock(&data->mutex);
ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG,
&data->status,
sizeof(data->status));
/*
* if none of the bit is set in the status register then it is
* spurious interrupt.
*/
if (ret || !data->status)
goto unlock_err;

/*
* Disable all advance interrupts if interrupt engine overrun occurs.
* See section 4.7 "Interrupt engine overrun" in datasheet v1.2.
*/
if (FIELD_GET(BMA400_INT_ENG_OVRUN_MSK, le16_to_cpu(data->status))) {
bma400_disable_adv_interrupt(data);
dev_err(data->dev, "Interrupt engine overrun
");
goto unlock_err;
}

if (FIELD_GET(BMA400_INT_S_TAP_MSK, le16_to_cpu(data->status)))
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_GESTURE,
IIO_EV_DIR_SINGLETAP),
timestamp);

if (FIELD_GET(BMA400_INT_D_TAP_MSK, le16_to_cpu(data->status)))
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_GESTURE,
IIO_EV_DIR_DOUBLETAP),
timestamp);

if (FIELD_GET(BMA400_INT_GEN1_MSK, le16_to_cpu(data->status)))
ev_dir = IIO_EV_DIR_RISING;

if (FIELD_GET(BMA400_INT_GEN2_MSK, le16_to_cpu(data->status)))
ev_dir = IIO_EV_DIR_FALLING;

if (ev_dir != IIO_EV_DIR_NONE) {
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_MAG, ev_dir),
timestamp);
}

if (FIELD_GET(BMA400_STEP_STAT_MASK, le16_to_cpu(data->status))) {
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
IIO_EV_TYPE_CHANGE,
IIO_EV_DIR_NONE),
timestamp);

if (data->activity_event_en) {
ret = regmap_read(data->regmap, BMA400_STEP_STAT_REG,
&act);
if (ret)
goto unlock_err;

iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0,
bma400_act_to_mod(act),
IIO_EV_TYPE_CHANGE,
IIO_EV_DIR_NONE),
timestamp);
}
}

if (FIELD_GET(BMA400_INT_DRDY_MSK, le16_to_cpu(data->status))) {
mutex_unlock(&data->mutex);
iio_trigger_poll_nested(data->trig);
return IRQ_HANDLED;
}

mutex_unlock(&data->mutex);
return IRQ_HANDLED;

unlock_err:
mutex_unlock(&data->mutex);
return IRQ_NONE;
}

int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name)
{
struct iio_dev *indio_dev;
struct bma400_data *data;
int ret;

indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;

data = iio_priv(indio_dev);
data->regmap = regmap;
data->dev = dev;

ret = bma400_init(data);
if (ret)
return ret;

ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;

mutex_init(&data->mutex);
indio_dev->name = name;
indio_dev->info = &bma400_info;
indio_dev->channels = bma400_channels;
indio_dev->num_channels = ARRAY_SIZE(bma400_channels);
indio_dev->available_scan_masks = bma400_avail_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;

if (irq > 0) {
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
if (!data->trig)
return -ENOMEM;

data->trig->ops = &bma400_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);

ret = devm_iio_trigger_register(data->dev, data->trig);
if (ret)
return dev_err_probe(data->dev, ret,
"iio trigger register fail
");

indio_dev->trig = iio_trigger_get(data->trig);
ret = devm_request_threaded_irq(dev, irq, NULL,
&bma400_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
return dev_err_probe(data->dev, ret,
"request irq %d failed
", irq);
}

ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
&bma400_trigger_handler, NULL);
if (ret)
return dev_err_probe(data->dev, ret,
"iio triggered buffer setup failed
");

return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS(bma400_probe, IIO_BMA400);

MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>");
MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>");
MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor core");
MODULE_LICENSE("GPL");