From b4b7ff4b08e691656c9d77c758fc355833128ac0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 20 Jan 2016 14:01:31 -0300 Subject: Linux-libre 4.4-gnu --- drivers/iio/accel/Kconfig | 33 +- drivers/iio/accel/Makefile | 6 +- drivers/iio/accel/bmc150-accel-core.c | 1754 +++++++++++++++++++++++++++++++ drivers/iio/accel/bmc150-accel-i2c.c | 102 ++ drivers/iio/accel/bmc150-accel-spi.c | 91 ++ drivers/iio/accel/bmc150-accel.c | 1867 --------------------------------- drivers/iio/accel/bmc150-accel.h | 20 + drivers/iio/accel/kxcjk-1013.c | 34 +- drivers/iio/accel/kxsd9.c | 1 - drivers/iio/accel/mma8452.c | 356 +++++-- drivers/iio/accel/mma9553.c | 29 - drivers/iio/accel/mxc4005.c | 567 ++++++++++ drivers/iio/accel/st_accel_core.c | 1 + drivers/iio/accel/st_accel_spi.c | 1 - drivers/iio/accel/stk8312.c | 30 +- drivers/iio/accel/stk8ba50.c | 30 +- 16 files changed, 2862 insertions(+), 2060 deletions(-) create mode 100644 drivers/iio/accel/bmc150-accel-core.c create mode 100644 drivers/iio/accel/bmc150-accel-i2c.c create mode 100644 drivers/iio/accel/bmc150-accel-spi.c delete mode 100644 drivers/iio/accel/bmc150-accel.c create mode 100644 drivers/iio/accel/bmc150-accel.h create mode 100644 drivers/iio/accel/mxc4005.c (limited to 'drivers/iio/accel') diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index a59047d76..969428dd6 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -19,19 +19,27 @@ config BMA180 config BMC150_ACCEL tristate "Bosch BMC150 Accelerometer Driver" - depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER + select REGMAP + select BMC150_ACCEL_I2C if I2C + select BMC150_ACCEL_SPI if SPI help Say yes here to build support for the following Bosch accelerometers: BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280. - Currently this only supports the device via an i2c interface. - This is a combo module with both accelerometer and magnetometer. This driver is only implementing accelerometer part, which has its own address and register map. +config BMC150_ACCEL_I2C + tristate + select REGMAP_I2C + +config BMC150_ACCEL_SPI + tristate + select REGMAP_SPI + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER @@ -100,13 +108,13 @@ config KXCJK1013 be called kxcjk-1013. config MMA8452 - tristate "Freescale MMA8452Q Accelerometer Driver" + tristate "Freescale MMA8452Q and similar Accelerometers Driver" depends on I2C select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for the Freescale MMA8452Q 3-axis - accelerometer. + Say yes here to build support for the following Freescale 3-axis + accelerometers: MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC. To compile this driver as a module, choose M here: the module will be called mma8452. @@ -137,6 +145,19 @@ config MMA9553 To compile this driver as a module, choose M here: the module will be called mma9553. +config MXC4005 + tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + help + Say yes here to build support for the Memsic MXC4005XC 3-axis + accelerometer. + + To compile this driver as a module, choose M. The module will be + called mxc4005. + config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index ebd2675b2..7925f166e 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -4,7 +4,9 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o -obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o +obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o +obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o +obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o @@ -14,6 +16,8 @@ obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o obj-$(CONFIG_MMA9551) += mma9551.o obj-$(CONFIG_MMA9553) += mma9553.o +obj-$(CONFIG_MXC4005) += mxc4005.o + obj-$(CONFIG_STK8312) += stk8312.o obj-$(CONFIG_STK8BA50) += stk8ba50.o diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c new file mode 100644 index 000000000..2d33f1e82 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -0,0 +1,1754 @@ +/* + * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: + * - BMC150 + * - BMI055 + * - BMA255 + * - BMA250E + * - BMA222E + * - BMA280 + * + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bmc150-accel.h" + +#define BMC150_ACCEL_DRV_NAME "bmc150_accel" +#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" + +#define BMC150_ACCEL_REG_CHIP_ID 0x00 + +#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B +#define BMC150_ACCEL_ANY_MOTION_MASK 0x07 +#define BMC150_ACCEL_ANY_MOTION_BIT_X BIT(0) +#define BMC150_ACCEL_ANY_MOTION_BIT_Y BIT(1) +#define BMC150_ACCEL_ANY_MOTION_BIT_Z BIT(2) +#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) + +#define BMC150_ACCEL_REG_PMU_LPW 0x11 +#define BMC150_ACCEL_PMU_MODE_MASK 0xE0 +#define BMC150_ACCEL_PMU_MODE_SHIFT 5 +#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_MASK 0x17 +#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT 1 + +#define BMC150_ACCEL_REG_PMU_RANGE 0x0F + +#define BMC150_ACCEL_DEF_RANGE_2G 0x03 +#define BMC150_ACCEL_DEF_RANGE_4G 0x05 +#define BMC150_ACCEL_DEF_RANGE_8G 0x08 +#define BMC150_ACCEL_DEF_RANGE_16G 0x0C + +/* Default BW: 125Hz */ +#define BMC150_ACCEL_REG_PMU_BW 0x10 +#define BMC150_ACCEL_DEF_BW 125 + +#define BMC150_ACCEL_REG_INT_MAP_0 0x19 +#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2) + +#define BMC150_ACCEL_REG_INT_MAP_1 0x1A +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0) +#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1) +#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2) + +#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21 +#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 +#define BMC150_ACCEL_INT_MODE_LATCH_INT 0x0F +#define BMC150_ACCEL_INT_MODE_NON_LATCH_INT 0x00 + +#define BMC150_ACCEL_REG_INT_EN_0 0x16 +#define BMC150_ACCEL_INT_EN_BIT_SLP_X BIT(0) +#define BMC150_ACCEL_INT_EN_BIT_SLP_Y BIT(1) +#define BMC150_ACCEL_INT_EN_BIT_SLP_Z BIT(2) + +#define BMC150_ACCEL_REG_INT_EN_1 0x17 +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4) +#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN BIT(5) +#define BMC150_ACCEL_INT_EN_BIT_FWM_EN BIT(6) + +#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20 +#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) + +#define BMC150_ACCEL_REG_INT_5 0x27 +#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03 + +#define BMC150_ACCEL_REG_INT_6 0x28 +#define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF + +/* Slope duration in terms of number of samples */ +#define BMC150_ACCEL_DEF_SLOPE_DURATION 1 +/* in terms of multiples of g's/LSB, based on range */ +#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 1 + +#define BMC150_ACCEL_REG_XOUT_L 0x02 + +#define BMC150_ACCEL_MAX_STARTUP_TIME_MS 100 + +/* Sleep Duration values */ +#define BMC150_ACCEL_SLEEP_500_MICRO 0x05 +#define BMC150_ACCEL_SLEEP_1_MS 0x06 +#define BMC150_ACCEL_SLEEP_2_MS 0x07 +#define BMC150_ACCEL_SLEEP_4_MS 0x08 +#define BMC150_ACCEL_SLEEP_6_MS 0x09 +#define BMC150_ACCEL_SLEEP_10_MS 0x0A +#define BMC150_ACCEL_SLEEP_25_MS 0x0B +#define BMC150_ACCEL_SLEEP_50_MS 0x0C +#define BMC150_ACCEL_SLEEP_100_MS 0x0D +#define BMC150_ACCEL_SLEEP_500_MS 0x0E +#define BMC150_ACCEL_SLEEP_1_SEC 0x0F + +#define BMC150_ACCEL_REG_TEMP 0x08 +#define BMC150_ACCEL_TEMP_CENTER_VAL 24 + +#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) +#define BMC150_AUTO_SUSPEND_DELAY_MS 2000 + +#define BMC150_ACCEL_REG_FIFO_STATUS 0x0E +#define BMC150_ACCEL_REG_FIFO_CONFIG0 0x30 +#define BMC150_ACCEL_REG_FIFO_CONFIG1 0x3E +#define BMC150_ACCEL_REG_FIFO_DATA 0x3F +#define BMC150_ACCEL_FIFO_LENGTH 32 + +enum bmc150_accel_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum bmc150_power_modes { + BMC150_ACCEL_SLEEP_MODE_NORMAL, + BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, + BMC150_ACCEL_SLEEP_MODE_LPM, + BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04, +}; + +struct bmc150_scale_info { + int scale; + u8 reg_range; +}; + +struct bmc150_accel_chip_info { + const char *name; + u8 chip_id; + const struct iio_chan_spec *channels; + int num_channels; + const struct bmc150_scale_info scale_table[4]; +}; + +struct bmc150_accel_interrupt { + const struct bmc150_accel_interrupt_info *info; + atomic_t users; +}; + +struct bmc150_accel_trigger { + struct bmc150_accel_data *data; + struct iio_trigger *indio_trig; + int (*setup)(struct bmc150_accel_trigger *t, bool state); + int intr; + bool enabled; +}; + +enum bmc150_accel_interrupt_id { + BMC150_ACCEL_INT_DATA_READY, + BMC150_ACCEL_INT_ANY_MOTION, + BMC150_ACCEL_INT_WATERMARK, + BMC150_ACCEL_INTERRUPTS, +}; + +enum bmc150_accel_trigger_id { + BMC150_ACCEL_TRIGGER_DATA_READY, + BMC150_ACCEL_TRIGGER_ANY_MOTION, + BMC150_ACCEL_TRIGGERS, +}; + +struct bmc150_accel_data { + struct regmap *regmap; + struct device *dev; + int irq; + struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; + atomic_t active_intr; + struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; + struct mutex mutex; + u8 fifo_mode, watermark; + s16 buffer[8]; + u8 bw_bits; + u32 slope_dur; + u32 slope_thres; + u32 range; + int ev_enable_state; + int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ + const struct bmc150_accel_chip_info *chip_info; +}; + +static const struct { + int val; + int val2; + u8 bw_bits; +} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08}, + {31, 260000, 0x09}, + {62, 500000, 0x0A}, + {125, 0, 0x0B}, + {250, 0, 0x0C}, + {500, 0, 0x0D}, + {1000, 0, 0x0E}, + {2000, 0, 0x0F} }; + +static const struct { + int bw_bits; + int msec; +} bmc150_accel_sample_upd_time[] = { {0x08, 64}, + {0x09, 32}, + {0x0A, 16}, + {0x0B, 8}, + {0x0C, 4}, + {0x0D, 2}, + {0x0E, 1}, + {0x0F, 1} }; + +static const struct { + int sleep_dur; + u8 reg_value; +} bmc150_accel_sleep_value_table[] = { {0, 0}, + {500, BMC150_ACCEL_SLEEP_500_MICRO}, + {1000, BMC150_ACCEL_SLEEP_1_MS}, + {2000, BMC150_ACCEL_SLEEP_2_MS}, + {4000, BMC150_ACCEL_SLEEP_4_MS}, + {6000, BMC150_ACCEL_SLEEP_6_MS}, + {10000, BMC150_ACCEL_SLEEP_10_MS}, + {25000, BMC150_ACCEL_SLEEP_25_MS}, + {50000, BMC150_ACCEL_SLEEP_50_MS}, + {100000, BMC150_ACCEL_SLEEP_100_MS}, + {500000, BMC150_ACCEL_SLEEP_500_MS}, + {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; + +static const struct regmap_config bmc150_i2c_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x3f, +}; + +static int bmc150_accel_set_mode(struct bmc150_accel_data *data, + enum bmc150_power_modes mode, + int dur_us) +{ + int i; + int ret; + u8 lpw_bits; + int dur_val = -1; + + if (dur_us > 0) { + for (i = 0; i < ARRAY_SIZE(bmc150_accel_sleep_value_table); + ++i) { + if (bmc150_accel_sleep_value_table[i].sleep_dur == + dur_us) + dur_val = + bmc150_accel_sleep_value_table[i].reg_value; + } + } else { + dur_val = 0; + } + + if (dur_val < 0) + return -EINVAL; + + lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; + lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); + + dev_dbg(data->dev, "Set Mode bits %x\n", lpw_bits); + + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_LPW, lpw_bits); + if (ret < 0) { + dev_err(data->dev, "Error writing reg_pmu_lpw\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, + int val2) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { + if (bmc150_accel_samp_freq_table[i].val == val && + bmc150_accel_samp_freq_table[i].val2 == val2) { + ret = regmap_write(data->regmap, + BMC150_ACCEL_REG_PMU_BW, + bmc150_accel_samp_freq_table[i].bw_bits); + if (ret < 0) + return ret; + + data->bw_bits = + bmc150_accel_samp_freq_table[i].bw_bits; + return 0; + } + } + + return -EINVAL; +} + +static int bmc150_accel_update_slope(struct bmc150_accel_data *data) +{ + int ret; + + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_6, + data->slope_thres); + if (ret < 0) { + dev_err(data->dev, "Error writing reg_int_6\n"); + return ret; + } + + ret = regmap_update_bits(data->regmap, BMC150_ACCEL_REG_INT_5, + BMC150_ACCEL_SLOPE_DUR_MASK, data->slope_dur); + if (ret < 0) { + dev_err(data->dev, "Error updating reg_int_5\n"); + return ret; + } + + dev_dbg(data->dev, "%s: %x %x\n", __func__, data->slope_thres, + data->slope_dur); + + return ret; +} + +static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, + bool state) +{ + if (state) + return bmc150_accel_update_slope(t->data); + + return 0; +} + +static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, + int *val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { + if (bmc150_accel_samp_freq_table[i].bw_bits == data->bw_bits) { + *val = bmc150_accel_samp_freq_table[i].val; + *val2 = bmc150_accel_samp_freq_table[i].val2; + return IIO_VAL_INT_PLUS_MICRO; + } + } + + return -EINVAL; +} + +#ifdef CONFIG_PM +static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_sample_upd_time); ++i) { + if (bmc150_accel_sample_upd_time[i].bw_bits == data->bw_bits) + return bmc150_accel_sample_upd_time[i].msec; + } + + return BMC150_ACCEL_MAX_STARTUP_TIME_MS; +} + +static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) +{ + int ret; + + if (on) { + ret = pm_runtime_get_sync(data->dev); + } else { + pm_runtime_mark_last_busy(data->dev); + ret = pm_runtime_put_autosuspend(data->dev); + } + + if (ret < 0) { + dev_err(data->dev, + "Failed: bmc150_accel_set_power_state for %d\n", on); + if (on) + pm_runtime_put_noidle(data->dev); + + return ret; + } + + return 0; +} +#else +static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) +{ + return 0; +} +#endif + +static const struct bmc150_accel_interrupt_info { + u8 map_reg; + u8 map_bitmask; + u8 en_reg; + u8 en_bitmask; +} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = { + { /* data ready interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_1, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA, + .en_reg = BMC150_ACCEL_REG_INT_EN_1, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN, + }, + { /* motion interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_0, + .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE, + .en_reg = BMC150_ACCEL_REG_INT_EN_0, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X | + BMC150_ACCEL_INT_EN_BIT_SLP_Y | + BMC150_ACCEL_INT_EN_BIT_SLP_Z + }, + { /* fifo watermark interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_1, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM, + .en_reg = BMC150_ACCEL_REG_INT_EN_1, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN, + }, +}; + +static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev, + struct bmc150_accel_data *data) +{ + int i; + + for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++) + data->interrupts[i].info = &bmc150_accel_interrupts[i]; +} + +static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, + bool state) +{ + struct bmc150_accel_interrupt *intr = &data->interrupts[i]; + const struct bmc150_accel_interrupt_info *info = intr->info; + int ret; + + if (state) { + if (atomic_inc_return(&intr->users) > 1) + return 0; + } else { + if (atomic_dec_return(&intr->users) > 0) + return 0; + } + + /* + * We will expect the enable and disable to do operation in reverse + * order. This will happen here anyway, as our resume operation uses + * sync mode runtime pm calls. The suspend operation will be delayed + * by autosuspend delay. + * So the disable operation will still happen in reverse order of + * enable operation. When runtime pm is disabled the mode is always on, + * so sequence doesn't matter. + */ + ret = bmc150_accel_set_power_state(data, state); + if (ret < 0) + return ret; + + /* map the interrupt to the appropriate pins */ + ret = regmap_update_bits(data->regmap, info->map_reg, info->map_bitmask, + (state ? info->map_bitmask : 0)); + if (ret < 0) { + dev_err(data->dev, "Error updating reg_int_map\n"); + goto out_fix_power_state; + } + + /* enable/disable the interrupt */ + ret = regmap_update_bits(data->regmap, info->en_reg, info->en_bitmask, + (state ? info->en_bitmask : 0)); + if (ret < 0) { + dev_err(data->dev, "Error updating reg_int_en\n"); + goto out_fix_power_state; + } + + if (state) + atomic_inc(&data->active_intr); + else + atomic_dec(&data->active_intr); + + return 0; + +out_fix_power_state: + bmc150_accel_set_power_state(data, false); + return ret; +} + +static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) { + if (data->chip_info->scale_table[i].scale == val) { + ret = regmap_write(data->regmap, + BMC150_ACCEL_REG_PMU_RANGE, + data->chip_info->scale_table[i].reg_range); + if (ret < 0) { + dev_err(data->dev, + "Error writing pmu_range\n"); + return ret; + } + + data->range = data->chip_info->scale_table[i].reg_range; + return 0; + } + } + + return -EINVAL; +} + +static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) +{ + int ret; + unsigned int value; + + mutex_lock(&data->mutex); + + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_TEMP, &value); + if (ret < 0) { + dev_err(data->dev, "Error reading reg_temp\n"); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(value, 7); + + mutex_unlock(&data->mutex); + + return IIO_VAL_INT; +} + +static int bmc150_accel_get_axis(struct bmc150_accel_data *data, + struct iio_chan_spec const *chan, + int *val) +{ + int ret; + int axis = chan->scan_index; + unsigned int raw_val; + + mutex_lock(&data->mutex); + ret = bmc150_accel_set_power_state(data, true); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = regmap_bulk_read(data->regmap, BMC150_ACCEL_AXIS_TO_REG(axis), + &raw_val, 2); + if (ret < 0) { + dev_err(data->dev, "Error reading axis %d\n", axis); + bmc150_accel_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(raw_val >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + ret = bmc150_accel_set_power_state(data, false); + mutex_unlock(&data->mutex); + if (ret < 0) + return ret; + + return IIO_VAL_INT; +} + +static int bmc150_accel_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + return bmc150_accel_get_temp(data, val); + case IIO_ACCEL: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + else + return bmc150_accel_get_axis(data, chan, val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + *val = BMC150_ACCEL_TEMP_CENTER_VAL; + return IIO_VAL_INT; + } else { + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + *val = 0; + switch (chan->type) { + case IIO_TEMP: + *val2 = 500000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ACCEL: + { + int i; + const struct bmc150_scale_info *si; + int st_size = ARRAY_SIZE(data->chip_info->scale_table); + + for (i = 0; i < st_size; ++i) { + si = &data->chip_info->scale_table[i]; + if (si->reg_range == data->range) { + *val2 = si->scale; + return IIO_VAL_INT_PLUS_MICRO; + } + } + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = bmc150_accel_get_bw(data, val, val2); + mutex_unlock(&data->mutex); + return ret; + default: + return -EINVAL; + } +} + +static int bmc150_accel_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = bmc150_accel_set_bw(data, val, val2); + mutex_unlock(&data->mutex); + break; + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = bmc150_accel_set_scale(data, val2); + mutex_unlock(&data->mutex); + return ret; + default: + ret = -EINVAL; + } + + return ret; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + *val2 = 0; + switch (info) { + case IIO_EV_INFO_VALUE: + *val = data->slope_thres; + break; + case IIO_EV_INFO_PERIOD: + *val = data->slope_dur; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + if (data->ev_enable_state) + return -EBUSY; + + switch (info) { + case IIO_EV_INFO_VALUE: + data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK; + break; + case IIO_EV_INFO_PERIOD: + data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + return data->ev_enable_state; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + if (state == data->ev_enable_state) + return 0; + + mutex_lock(&data->mutex); + + ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION, + state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + data->ev_enable_state = state; + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int i; + + for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { + if (data->triggers[i].indio_trig == trig) + return 0; + } + + return -EINVAL; +} + +static ssize_t bmc150_accel_get_fifo_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int wm; + + mutex_lock(&data->mutex); + wm = data->watermark; + mutex_unlock(&data->mutex); + + return sprintf(buf, "%d\n", wm); +} + +static ssize_t bmc150_accel_get_fifo_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + bool state; + + mutex_lock(&data->mutex); + state = data->fifo_mode; + mutex_unlock(&data->mutex); + + return sprintf(buf, "%d\n", state); +} + +static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); +static IIO_CONST_ATTR(hwfifo_watermark_max, + __stringify(BMC150_ACCEL_FIFO_LENGTH)); +static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO, + bmc150_accel_get_fifo_state, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, + bmc150_accel_get_fifo_watermark, NULL, 0); + +static const struct attribute *bmc150_accel_fifo_attributes[] = { + &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, + &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + +static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + if (val > BMC150_ACCEL_FIFO_LENGTH) + val = BMC150_ACCEL_FIFO_LENGTH; + + mutex_lock(&data->mutex); + data->watermark = val; + mutex_unlock(&data->mutex); + + return 0; +} + +/* + * We must read at least one full frame in one burst, otherwise the rest of the + * frame data is discarded. + */ +static int bmc150_accel_fifo_transfer(struct bmc150_accel_data *data, + char *buffer, int samples) +{ + int sample_length = 3 * 2; + int ret; + int total_length = samples * sample_length; + int i; + size_t step = regmap_get_raw_read_max(data->regmap); + + if (!step || step > total_length) + step = total_length; + else if (step < total_length) + step = sample_length; + + /* + * Seems we have a bus with size limitation so we have to execute + * multiple reads + */ + for (i = 0; i < total_length; i += step) { + ret = regmap_raw_read(data->regmap, BMC150_ACCEL_REG_FIFO_DATA, + &buffer[i], step); + if (ret) + break; + } + + if (ret) + dev_err(data->dev, "Error transferring data from fifo in single steps of %zu\n", + step); + + return ret; +} + +static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, + unsigned samples, bool irq) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret, i; + u8 count; + u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; + int64_t tstamp; + uint64_t sample_period; + unsigned int val; + + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_FIFO_STATUS, &val); + if (ret < 0) { + dev_err(data->dev, "Error reading reg_fifo_status\n"); + return ret; + } + + count = val & 0x7F; + + if (!count) + return 0; + + /* + * If we getting called from IRQ handler we know the stored timestamp is + * fairly accurate for the last stored sample. Otherwise, if we are + * called as a result of a read operation from userspace and hence + * before the watermark interrupt was triggered, take a timestamp + * now. We can fall anywhere in between two samples so the error in this + * case is at most one sample period. + */ + if (!irq) { + data->old_timestamp = data->timestamp; + data->timestamp = iio_get_time_ns(); + } + + /* + * Approximate timestamps for each of the sample based on the sampling + * frequency, timestamp for last sample and number of samples. + * + * Note that we can't use the current bandwidth settings to compute the + * sample period because the sample rate varies with the device + * (e.g. between 31.70ms to 32.20ms for a bandwidth of 15.63HZ). That + * small variation adds when we store a large number of samples and + * creates significant jitter between the last and first samples in + * different batches (e.g. 32ms vs 21ms). + * + * To avoid this issue we compute the actual sample period ourselves + * based on the timestamp delta between the last two flush operations. + */ + sample_period = (data->timestamp - data->old_timestamp); + do_div(sample_period, count); + tstamp = data->timestamp - (count - 1) * sample_period; + + if (samples && count > samples) + count = samples; + + ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count); + if (ret) + return ret; + + /* + * Ideally we want the IIO core to handle the demux when running in fifo + * mode but not when running in triggered buffer mode. Unfortunately + * this does not seem to be possible, so stick with driver demux for + * now. + */ + for (i = 0; i < count; i++) { + u16 sample[8]; + int j, bit; + + j = 0; + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) + memcpy(&sample[j++], &buffer[i * 3 + bit], 2); + + iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp); + + tstamp += sample_period; + } + + return count; +} + +static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev, unsigned samples) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + ret = __bmc150_accel_fifo_flush(indio_dev, samples, false); + mutex_unlock(&data->mutex); + + return ret; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( + "15.620000 31.260000 62.50000 125 250 500 1000 2000"); + +static struct attribute *bmc150_accel_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bmc150_accel_attrs_group = { + .attrs = bmc150_accel_attributes, +}; + +static const struct iio_event_spec bmc150_accel_event = { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) +}; + +#define BMC150_ACCEL_CHANNEL(_axis, bits) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 16 - (bits), \ + }, \ + .event_spec = &bmc150_accel_event, \ + .num_event_specs = 1 \ +} + +#define BMC150_ACCEL_CHANNELS(bits) { \ + { \ + .type = IIO_TEMP, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = -1, \ + }, \ + BMC150_ACCEL_CHANNEL(X, bits), \ + BMC150_ACCEL_CHANNEL(Y, bits), \ + BMC150_ACCEL_CHANNEL(Z, bits), \ + IIO_CHAN_SOFT_TIMESTAMP(3), \ +} + +static const struct iio_chan_spec bma222e_accel_channels[] = + BMC150_ACCEL_CHANNELS(8); +static const struct iio_chan_spec bma250e_accel_channels[] = + BMC150_ACCEL_CHANNELS(10); +static const struct iio_chan_spec bmc150_accel_channels[] = + BMC150_ACCEL_CHANNELS(12); +static const struct iio_chan_spec bma280_accel_channels[] = + BMC150_ACCEL_CHANNELS(14); + +static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { + [bmc150] = { + .name = "BMC150A", + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bmi055] = { + .name = "BMI055A", + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma255] = { + .name = "BMA0255", + .chip_id = 0xFA, + .channels = bmc150_accel_channels, + .num_channels = ARRAY_SIZE(bmc150_accel_channels), + .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {76590, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma250e] = { + .name = "BMA250E", + .chip_id = 0xF9, + .channels = bma250e_accel_channels, + .num_channels = ARRAY_SIZE(bma250e_accel_channels), + .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G}, + {76590, BMC150_ACCEL_DEF_RANGE_4G}, + {153277, BMC150_ACCEL_DEF_RANGE_8G}, + {306457, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma222e] = { + .name = "BMA222E", + .chip_id = 0xF8, + .channels = bma222e_accel_channels, + .num_channels = ARRAY_SIZE(bma222e_accel_channels), + .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G}, + {306457, BMC150_ACCEL_DEF_RANGE_4G}, + {612915, BMC150_ACCEL_DEF_RANGE_8G}, + {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, + }, + [bma280] = { + .name = "BMA0280", + .chip_id = 0xFB, + .channels = bma280_accel_channels, + .num_channels = ARRAY_SIZE(bma280_accel_channels), + .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G}, + {4785, BMC150_ACCEL_DEF_RANGE_4G}, + {9581, BMC150_ACCEL_DEF_RANGE_8G}, + {19152, BMC150_ACCEL_DEF_RANGE_16G} }, + }, +}; + +static const struct iio_info bmc150_accel_info = { + .attrs = &bmc150_accel_attrs_group, + .read_raw = bmc150_accel_read_raw, + .write_raw = bmc150_accel_write_raw, + .read_event_value = bmc150_accel_read_event, + .write_event_value = bmc150_accel_write_event, + .write_event_config = bmc150_accel_write_event_config, + .read_event_config = bmc150_accel_read_event_config, + .driver_module = THIS_MODULE, +}; + +static const struct iio_info bmc150_accel_info_fifo = { + .attrs = &bmc150_accel_attrs_group, + .read_raw = bmc150_accel_read_raw, + .write_raw = bmc150_accel_write_raw, + .read_event_value = bmc150_accel_read_event, + .write_event_value = bmc150_accel_write_event, + .write_event_config = bmc150_accel_write_event_config, + .read_event_config = bmc150_accel_read_event_config, + .validate_trigger = bmc150_accel_validate_trigger, + .hwfifo_set_watermark = bmc150_accel_set_watermark, + .hwfifo_flush_to_buffer = bmc150_accel_fifo_flush, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bmc150_accel_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + unsigned int raw_val; + + mutex_lock(&data->mutex); + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = regmap_bulk_read(data->regmap, + BMC150_ACCEL_AXIS_TO_REG(bit), &raw_val, + 2); + if (ret < 0) { + mutex_unlock(&data->mutex); + goto err_read; + } + data->buffer[i++] = raw_val; + } + mutex_unlock(&data->mutex); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); +err_read: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) +{ + struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = t->data; + int ret; + + /* new data interrupts don't need ack */ + if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY]) + return 0; + + mutex_lock(&data->mutex); + /* clear any latched interrupt */ + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + mutex_unlock(&data->mutex); + if (ret < 0) { + dev_err(data->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = t->data; + int ret; + + mutex_lock(&data->mutex); + + if (t->enabled == state) { + mutex_unlock(&data->mutex); + return 0; + } + + if (t->setup) { + ret = t->setup(t, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + } + + ret = bmc150_accel_set_interrupt(data, t->intr, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + t->enabled = state; + + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_trigger_ops bmc150_accel_trigger_ops = { + .set_trigger_state = bmc150_accel_trigger_set_state, + .try_reenable = bmc150_accel_trig_try_reen, + .owner = THIS_MODULE, +}; + +static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int dir; + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_INT_STATUS_2, &val); + if (ret < 0) { + dev_err(data->dev, "Error reading reg_int_status_2\n"); + return ret; + } + + if (val & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) + dir = IIO_EV_DIR_FALLING; + else + dir = IIO_EV_DIR_RISING; + + if (val & BMC150_ACCEL_ANY_MOTION_BIT_X) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + + if (val & BMC150_ACCEL_ANY_MOTION_BIT_Y) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + + if (val & BMC150_ACCEL_ANY_MOTION_BIT_Z) + iio_push_event(indio_dev, + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_ROC, + dir), + data->timestamp); + + return ret; +} + +static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmc150_accel_data *data = iio_priv(indio_dev); + bool ack = false; + int ret; + + mutex_lock(&data->mutex); + + if (data->fifo_mode) { + ret = __bmc150_accel_fifo_flush(indio_dev, + BMC150_ACCEL_FIFO_LENGTH, true); + if (ret > 0) + ack = true; + } + + if (data->ev_enable_state) { + ret = bmc150_accel_handle_roc_event(indio_dev); + if (ret > 0) + ack = true; + } + + if (ack) { + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret) + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); + + ret = IRQ_HANDLED; + } else { + ret = IRQ_NONE; + } + + mutex_unlock(&data->mutex); + + return ret; +} + +static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmc150_accel_data *data = iio_priv(indio_dev); + bool ack = false; + int i; + + data->old_timestamp = data->timestamp; + data->timestamp = iio_get_time_ns(); + + for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { + if (data->triggers[i].enabled) { + iio_trigger_poll(data->triggers[i].indio_trig); + ack = true; + break; + } + } + + if (data->ev_enable_state || data->fifo_mode) + return IRQ_WAKE_THREAD; + + if (ack) + return IRQ_HANDLED; + + return IRQ_NONE; +} + +static const struct { + int intr; + const char *name; + int (*setup)(struct bmc150_accel_trigger *t, bool state); +} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = { + { + .intr = 0, + .name = "%s-dev%d", + }, + { + .intr = 1, + .name = "%s-any-motion-dev%d", + .setup = bmc150_accel_any_motion_setup, + }, +}; + +static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data, + int from) +{ + int i; + + for (i = from; i >= 0; i--) { + if (data->triggers[i].indio_trig) { + iio_trigger_unregister(data->triggers[i].indio_trig); + data->triggers[i].indio_trig = NULL; + } + } +} + +static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, + struct bmc150_accel_data *data) +{ + int i, ret; + + for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { + struct bmc150_accel_trigger *t = &data->triggers[i]; + + t->indio_trig = devm_iio_trigger_alloc(data->dev, + bmc150_accel_triggers[i].name, + indio_dev->name, + indio_dev->id); + if (!t->indio_trig) { + ret = -ENOMEM; + break; + } + + t->indio_trig->dev.parent = data->dev; + t->indio_trig->ops = &bmc150_accel_trigger_ops; + t->intr = bmc150_accel_triggers[i].intr; + t->data = data; + t->setup = bmc150_accel_triggers[i].setup; + iio_trigger_set_drvdata(t->indio_trig, t); + + ret = iio_trigger_register(t->indio_trig); + if (ret) + break; + } + + if (ret) + bmc150_accel_unregister_triggers(data, i - 1); + + return ret; +} + +#define BMC150_ACCEL_FIFO_MODE_STREAM 0x80 +#define BMC150_ACCEL_FIFO_MODE_FIFO 0x40 +#define BMC150_ACCEL_FIFO_MODE_BYPASS 0x00 + +static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data) +{ + u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1; + int ret; + + ret = regmap_write(data->regmap, reg, data->fifo_mode); + if (ret < 0) { + dev_err(data->dev, "Error writing reg_fifo_config1\n"); + return ret; + } + + if (!data->fifo_mode) + return 0; + + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_FIFO_CONFIG0, + data->watermark); + if (ret < 0) + dev_err(data->dev, "Error writing reg_fifo_config0\n"); + + return ret; +} + +static int bmc150_accel_buffer_preenable(struct iio_dev *indio_dev) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + return bmc150_accel_set_power_state(data, true); +} + +static int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret = 0; + + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) + return iio_triggered_buffer_postenable(indio_dev); + + mutex_lock(&data->mutex); + + if (!data->watermark) + goto out; + + ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, + true); + if (ret) + goto out; + + data->fifo_mode = BMC150_ACCEL_FIFO_MODE_FIFO; + + ret = bmc150_accel_fifo_set_mode(data); + if (ret) { + data->fifo_mode = 0; + bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, + false); + } + +out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bmc150_accel_buffer_predisable(struct iio_dev *indio_dev) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) + return iio_triggered_buffer_predisable(indio_dev); + + mutex_lock(&data->mutex); + + if (!data->fifo_mode) + goto out; + + bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, false); + __bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false); + data->fifo_mode = 0; + bmc150_accel_fifo_set_mode(data); + +out: + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmc150_accel_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + return bmc150_accel_set_power_state(data, false); +} + +static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { + .preenable = bmc150_accel_buffer_preenable, + .postenable = bmc150_accel_buffer_postenable, + .predisable = bmc150_accel_buffer_predisable, + .postdisable = bmc150_accel_buffer_postdisable, +}; + +static int bmc150_accel_chip_init(struct bmc150_accel_data *data) +{ + int ret, i; + unsigned int val; + + ret = regmap_read(data->regmap, BMC150_ACCEL_REG_CHIP_ID, &val); + if (ret < 0) { + dev_err(data->dev, + "Error: Reading chip id\n"); + return ret; + } + + dev_dbg(data->dev, "Chip Id %x\n", val); + for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { + if (bmc150_accel_chip_info_tbl[i].chip_id == val) { + data->chip_info = &bmc150_accel_chip_info_tbl[i]; + break; + } + } + + if (!data->chip_info) { + dev_err(data->dev, "Invalid chip %x\n", val); + return -ENODEV; + } + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + /* Set Bandwidth */ + ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); + if (ret < 0) { + dev_err(data->dev, + "Error writing reg_pmu_range\n"); + return ret; + } + + data->range = BMC150_ACCEL_DEF_RANGE_4G; + + /* Set default slope duration and thresholds */ + data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; + data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = bmc150_accel_update_slope(data); + if (ret < 0) + return ret; + + /* Set default as latched interrupts */ + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(data->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + +int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name, bool block_supported) +{ + struct bmc150_accel_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->dev = dev; + data->irq = irq; + + data->regmap = regmap; + + ret = bmc150_accel_chip_init(data); + if (ret < 0) + return ret; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = dev; + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; + indio_dev->name = name ? name : data->chip_info->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmc150_accel_info; + + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, + bmc150_accel_trigger_handler, + &bmc150_accel_buffer_ops); + if (ret < 0) { + dev_err(data->dev, "Failed: iio triggered buffer setup\n"); + return ret; + } + + if (data->irq > 0) { + ret = devm_request_threaded_irq( + data->dev, data->irq, + bmc150_accel_irq_handler, + bmc150_accel_irq_thread_handler, + IRQF_TRIGGER_RISING, + BMC150_ACCEL_IRQ_NAME, + indio_dev); + if (ret) + goto err_buffer_cleanup; + + /* + * Set latched mode interrupt. While certain interrupts are + * non-latched regardless of this settings (e.g. new data) we + * want to use latch mode when we can to prevent interrupt + * flooding. + */ + ret = regmap_write(data->regmap, BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(data->dev, "Error writing reg_int_rst_latch\n"); + goto err_buffer_cleanup; + } + + bmc150_accel_interrupts_setup(indio_dev, data); + + ret = bmc150_accel_triggers_setup(indio_dev, data); + if (ret) + goto err_buffer_cleanup; + + if (block_supported) { + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + indio_dev->info = &bmc150_accel_info_fifo; + indio_dev->buffer->attrs = bmc150_accel_fifo_attributes; + } + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(dev, "Unable to register iio device\n"); + goto err_trigger_unregister; + } + + ret = pm_runtime_set_active(dev); + if (ret) + goto err_iio_unregister; + + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + + return 0; + +err_iio_unregister: + iio_device_unregister(indio_dev); +err_trigger_unregister: + bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + + return ret; +} +EXPORT_SYMBOL_GPL(bmc150_accel_core_probe); + +int bmc150_accel_core_remove(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + pm_runtime_disable(data->dev); + pm_runtime_set_suspended(data->dev); + pm_runtime_put_noidle(data->dev); + + iio_device_unregister(indio_dev); + + bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); + + iio_triggered_buffer_cleanup(indio_dev); + + mutex_lock(&data->mutex); + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0); + mutex_unlock(&data->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(bmc150_accel_core_remove); + +#ifdef CONFIG_PM_SLEEP +static int bmc150_accel_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmc150_accel_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + if (atomic_read(&data->active_intr)) + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + bmc150_accel_fifo_set_mode(data); + mutex_unlock(&data->mutex); + + return 0; +} +#endif + +#ifdef CONFIG_PM +static int bmc150_accel_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + dev_dbg(data->dev, __func__); + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); + if (ret < 0) + return -EAGAIN; + + return 0; +} + +static int bmc150_accel_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + int sleep_val; + + dev_dbg(data->dev, __func__); + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + ret = bmc150_accel_fifo_set_mode(data); + if (ret < 0) + return ret; + + sleep_val = bmc150_accel_get_startup_times(data); + if (sleep_val < 20) + usleep_range(sleep_val * 1000, 20000); + else + msleep_interruptible(sleep_val); + + return 0; +} +#endif + +const struct dev_pm_ops bmc150_accel_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) + SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, + bmc150_accel_runtime_resume, NULL) +}; +EXPORT_SYMBOL_GPL(bmc150_accel_pm_ops); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 accelerometer driver"); diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c new file mode 100644 index 000000000..b41404ba3 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -0,0 +1,102 @@ +/* + * 3-axis accelerometer driver supporting following I2C Bosch-Sensortec chips: + * - BMC150 + * - BMI055 + * - BMA255 + * - BMA250E + * - BMA222E + * - BMA280 + * + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "bmc150-accel.h" + +static const struct regmap_config bmc150_i2c_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int bmc150_accel_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + const char *name = NULL; + bool block_supported = + i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK); + + regmap = devm_regmap_init_i2c(client, &bmc150_i2c_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to initialize i2c regmap\n"); + return PTR_ERR(regmap); + } + + if (id) + name = id->name; + + return bmc150_accel_core_probe(&client->dev, regmap, client->irq, name, + block_supported); +} + +static int bmc150_accel_remove(struct i2c_client *client) +{ + return bmc150_accel_core_remove(&client->dev); +} + +static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BSBA0150", bmc150}, + {"BMC150A", bmc150}, + {"BMI055A", bmi055}, + {"BMA0255", bma255}, + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); + +static const struct i2c_device_id bmc150_accel_id[] = { + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); + +static struct i2c_driver bmc150_accel_driver = { + .driver = { + .name = "bmc150_accel_i2c", + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .pm = &bmc150_accel_pm_ops, + }, + .probe = bmc150_accel_probe, + .remove = bmc150_accel_remove, + .id_table = bmc150_accel_id, +}; +module_i2c_driver(bmc150_accel_driver); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 I2C accelerometer driver"); diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c new file mode 100644 index 000000000..16b66f2a7 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -0,0 +1,91 @@ +/* + * 3-axis accelerometer driver supporting SPI Bosch-Sensortec accelerometer chip + * Copyright © 2015 Pengutronix, Markus Pargmann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "bmc150-accel.h" + +static const struct regmap_config bmc150_spi_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x3f, +}; + +static int bmc150_accel_probe(struct spi_device *spi) +{ + struct regmap *regmap; + const struct spi_device_id *id = spi_get_device_id(spi); + + regmap = devm_regmap_init_spi(spi, &bmc150_spi_regmap_conf); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to initialize spi regmap\n"); + return PTR_ERR(regmap); + } + + return bmc150_accel_core_probe(&spi->dev, regmap, spi->irq, id->name, + true); +} + +static int bmc150_accel_remove(struct spi_device *spi) +{ + return bmc150_accel_core_remove(&spi->dev); +} + +static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BSBA0150", bmc150}, + {"BMC150A", bmc150}, + {"BMI055A", bmi055}, + {"BMA0255", bma255}, + {"BMA250E", bma250e}, + {"BMA222E", bma222e}, + {"BMA0280", bma280}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); + +static const struct spi_device_id bmc150_accel_id[] = { + {"bmc150_accel", bmc150}, + {"bmi055_accel", bmi055}, + {"bma255", bma255}, + {"bma250e", bma250e}, + {"bma222e", bma222e}, + {"bma280", bma280}, + {} +}; +MODULE_DEVICE_TABLE(spi, bmc150_accel_id); + +static struct spi_driver bmc150_accel_driver = { + .driver = { + .name = "bmc150_accel_spi", + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .pm = &bmc150_accel_pm_ops, + }, + .probe = bmc150_accel_probe, + .remove = bmc150_accel_remove, + .id_table = bmc150_accel_id, +}; +module_spi_driver(bmc150_accel_driver); + +MODULE_AUTHOR("Markus Pargmann "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 SPI accelerometer driver"); diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c deleted file mode 100644 index 0104cdef8..000000000 --- a/drivers/iio/accel/bmc150-accel.c +++ /dev/null @@ -1,1867 +0,0 @@ -/* - * 3-axis accelerometer driver supporting following Bosch-Sensortec chips: - * - BMC150 - * - BMI055 - * - BMA255 - * - BMA250E - * - BMA222E - * - BMA280 - * - * Copyright (c) 2014, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BMC150_ACCEL_DRV_NAME "bmc150_accel" -#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" -#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" - -#define BMC150_ACCEL_REG_CHIP_ID 0x00 - -#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B -#define BMC150_ACCEL_ANY_MOTION_MASK 0x07 -#define BMC150_ACCEL_ANY_MOTION_BIT_X BIT(0) -#define BMC150_ACCEL_ANY_MOTION_BIT_Y BIT(1) -#define BMC150_ACCEL_ANY_MOTION_BIT_Z BIT(2) -#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) - -#define BMC150_ACCEL_REG_PMU_LPW 0x11 -#define BMC150_ACCEL_PMU_MODE_MASK 0xE0 -#define BMC150_ACCEL_PMU_MODE_SHIFT 5 -#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_MASK 0x17 -#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT 1 - -#define BMC150_ACCEL_REG_PMU_RANGE 0x0F - -#define BMC150_ACCEL_DEF_RANGE_2G 0x03 -#define BMC150_ACCEL_DEF_RANGE_4G 0x05 -#define BMC150_ACCEL_DEF_RANGE_8G 0x08 -#define BMC150_ACCEL_DEF_RANGE_16G 0x0C - -/* Default BW: 125Hz */ -#define BMC150_ACCEL_REG_PMU_BW 0x10 -#define BMC150_ACCEL_DEF_BW 125 - -#define BMC150_ACCEL_REG_INT_MAP_0 0x19 -#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2) - -#define BMC150_ACCEL_REG_INT_MAP_1 0x1A -#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0) -#define BMC150_ACCEL_INT_MAP_1_BIT_FWM BIT(1) -#define BMC150_ACCEL_INT_MAP_1_BIT_FFULL BIT(2) - -#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21 -#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 -#define BMC150_ACCEL_INT_MODE_LATCH_INT 0x0F -#define BMC150_ACCEL_INT_MODE_NON_LATCH_INT 0x00 - -#define BMC150_ACCEL_REG_INT_EN_0 0x16 -#define BMC150_ACCEL_INT_EN_BIT_SLP_X BIT(0) -#define BMC150_ACCEL_INT_EN_BIT_SLP_Y BIT(1) -#define BMC150_ACCEL_INT_EN_BIT_SLP_Z BIT(2) - -#define BMC150_ACCEL_REG_INT_EN_1 0x17 -#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4) -#define BMC150_ACCEL_INT_EN_BIT_FFULL_EN BIT(5) -#define BMC150_ACCEL_INT_EN_BIT_FWM_EN BIT(6) - -#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20 -#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) - -#define BMC150_ACCEL_REG_INT_5 0x27 -#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03 - -#define BMC150_ACCEL_REG_INT_6 0x28 -#define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF - -/* Slope duration in terms of number of samples */ -#define BMC150_ACCEL_DEF_SLOPE_DURATION 1 -/* in terms of multiples of g's/LSB, based on range */ -#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 1 - -#define BMC150_ACCEL_REG_XOUT_L 0x02 - -#define BMC150_ACCEL_MAX_STARTUP_TIME_MS 100 - -/* Sleep Duration values */ -#define BMC150_ACCEL_SLEEP_500_MICRO 0x05 -#define BMC150_ACCEL_SLEEP_1_MS 0x06 -#define BMC150_ACCEL_SLEEP_2_MS 0x07 -#define BMC150_ACCEL_SLEEP_4_MS 0x08 -#define BMC150_ACCEL_SLEEP_6_MS 0x09 -#define BMC150_ACCEL_SLEEP_10_MS 0x0A -#define BMC150_ACCEL_SLEEP_25_MS 0x0B -#define BMC150_ACCEL_SLEEP_50_MS 0x0C -#define BMC150_ACCEL_SLEEP_100_MS 0x0D -#define BMC150_ACCEL_SLEEP_500_MS 0x0E -#define BMC150_ACCEL_SLEEP_1_SEC 0x0F - -#define BMC150_ACCEL_REG_TEMP 0x08 -#define BMC150_ACCEL_TEMP_CENTER_VAL 24 - -#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) -#define BMC150_AUTO_SUSPEND_DELAY_MS 2000 - -#define BMC150_ACCEL_REG_FIFO_STATUS 0x0E -#define BMC150_ACCEL_REG_FIFO_CONFIG0 0x30 -#define BMC150_ACCEL_REG_FIFO_CONFIG1 0x3E -#define BMC150_ACCEL_REG_FIFO_DATA 0x3F -#define BMC150_ACCEL_FIFO_LENGTH 32 - -enum bmc150_accel_axis { - AXIS_X, - AXIS_Y, - AXIS_Z, -}; - -enum bmc150_power_modes { - BMC150_ACCEL_SLEEP_MODE_NORMAL, - BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, - BMC150_ACCEL_SLEEP_MODE_LPM, - BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04, -}; - -struct bmc150_scale_info { - int scale; - u8 reg_range; -}; - -struct bmc150_accel_chip_info { - const char *name; - u8 chip_id; - const struct iio_chan_spec *channels; - int num_channels; - const struct bmc150_scale_info scale_table[4]; -}; - -struct bmc150_accel_interrupt { - const struct bmc150_accel_interrupt_info *info; - atomic_t users; -}; - -struct bmc150_accel_trigger { - struct bmc150_accel_data *data; - struct iio_trigger *indio_trig; - int (*setup)(struct bmc150_accel_trigger *t, bool state); - int intr; - bool enabled; -}; - -enum bmc150_accel_interrupt_id { - BMC150_ACCEL_INT_DATA_READY, - BMC150_ACCEL_INT_ANY_MOTION, - BMC150_ACCEL_INT_WATERMARK, - BMC150_ACCEL_INTERRUPTS, -}; - -enum bmc150_accel_trigger_id { - BMC150_ACCEL_TRIGGER_DATA_READY, - BMC150_ACCEL_TRIGGER_ANY_MOTION, - BMC150_ACCEL_TRIGGERS, -}; - -struct bmc150_accel_data { - struct i2c_client *client; - struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; - atomic_t active_intr; - struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; - struct mutex mutex; - u8 fifo_mode, watermark; - s16 buffer[8]; - u8 bw_bits; - u32 slope_dur; - u32 slope_thres; - u32 range; - int ev_enable_state; - int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */ - const struct bmc150_accel_chip_info *chip_info; -}; - -static const struct { - int val; - int val2; - u8 bw_bits; -} bmc150_accel_samp_freq_table[] = { {15, 620000, 0x08}, - {31, 260000, 0x09}, - {62, 500000, 0x0A}, - {125, 0, 0x0B}, - {250, 0, 0x0C}, - {500, 0, 0x0D}, - {1000, 0, 0x0E}, - {2000, 0, 0x0F} }; - -static const struct { - int bw_bits; - int msec; -} bmc150_accel_sample_upd_time[] = { {0x08, 64}, - {0x09, 32}, - {0x0A, 16}, - {0x0B, 8}, - {0x0C, 4}, - {0x0D, 2}, - {0x0E, 1}, - {0x0F, 1} }; - -static const struct { - int sleep_dur; - u8 reg_value; -} bmc150_accel_sleep_value_table[] = { {0, 0}, - {500, BMC150_ACCEL_SLEEP_500_MICRO}, - {1000, BMC150_ACCEL_SLEEP_1_MS}, - {2000, BMC150_ACCEL_SLEEP_2_MS}, - {4000, BMC150_ACCEL_SLEEP_4_MS}, - {6000, BMC150_ACCEL_SLEEP_6_MS}, - {10000, BMC150_ACCEL_SLEEP_10_MS}, - {25000, BMC150_ACCEL_SLEEP_25_MS}, - {50000, BMC150_ACCEL_SLEEP_50_MS}, - {100000, BMC150_ACCEL_SLEEP_100_MS}, - {500000, BMC150_ACCEL_SLEEP_500_MS}, - {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; - -static int bmc150_accel_set_mode(struct bmc150_accel_data *data, - enum bmc150_power_modes mode, - int dur_us) -{ - int i; - int ret; - u8 lpw_bits; - int dur_val = -1; - - if (dur_us > 0) { - for (i = 0; i < ARRAY_SIZE(bmc150_accel_sleep_value_table); - ++i) { - if (bmc150_accel_sleep_value_table[i].sleep_dur == - dur_us) - dur_val = - bmc150_accel_sleep_value_table[i].reg_value; - } - } else { - dur_val = 0; - } - - if (dur_val < 0) - return -EINVAL; - - lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; - lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); - - dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits); - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_LPW, lpw_bits); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); - return ret; - } - - return 0; -} - -static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, - int val2) -{ - int i; - int ret; - - for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { - if (bmc150_accel_samp_freq_table[i].val == val && - bmc150_accel_samp_freq_table[i].val2 == val2) { - ret = i2c_smbus_write_byte_data( - data->client, - BMC150_ACCEL_REG_PMU_BW, - bmc150_accel_samp_freq_table[i].bw_bits); - if (ret < 0) - return ret; - - data->bw_bits = - bmc150_accel_samp_freq_table[i].bw_bits; - return 0; - } - } - - return -EINVAL; -} - -static int bmc150_accel_update_slope(struct bmc150_accel_data *data) -{ - int ret, val; - - ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6, - data->slope_thres); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_6\n"); - return ret; - } - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_5\n"); - return ret; - } - - val = (ret & ~BMC150_ACCEL_SLOPE_DUR_MASK) | data->slope_dur; - ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5, - val); - if (ret < 0) { - dev_err(&data->client->dev, "Error write reg_int_5\n"); - return ret; - } - - dev_dbg(&data->client->dev, "%s: %x %x\n", __func__, data->slope_thres, - data->slope_dur); - - return ret; -} - -static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, - bool state) -{ - if (state) - return bmc150_accel_update_slope(t->data); - - return 0; -} - -static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, - int *val2) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { - if (bmc150_accel_samp_freq_table[i].bw_bits == data->bw_bits) { - *val = bmc150_accel_samp_freq_table[i].val; - *val2 = bmc150_accel_samp_freq_table[i].val2; - return IIO_VAL_INT_PLUS_MICRO; - } - } - - return -EINVAL; -} - -#ifdef CONFIG_PM -static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bmc150_accel_sample_upd_time); ++i) { - if (bmc150_accel_sample_upd_time[i].bw_bits == data->bw_bits) - return bmc150_accel_sample_upd_time[i].msec; - } - - return BMC150_ACCEL_MAX_STARTUP_TIME_MS; -} - -static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) -{ - int ret; - - if (on) { - ret = pm_runtime_get_sync(&data->client->dev); - } else { - pm_runtime_mark_last_busy(&data->client->dev); - ret = pm_runtime_put_autosuspend(&data->client->dev); - } - - if (ret < 0) { - dev_err(&data->client->dev, - "Failed: bmc150_accel_set_power_state for %d\n", on); - if (on) - pm_runtime_put_noidle(&data->client->dev); - - return ret; - } - - return 0; -} -#else -static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) -{ - return 0; -} -#endif - -static const struct bmc150_accel_interrupt_info { - u8 map_reg; - u8 map_bitmask; - u8 en_reg; - u8 en_bitmask; -} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = { - { /* data ready interrupt */ - .map_reg = BMC150_ACCEL_REG_INT_MAP_1, - .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA, - .en_reg = BMC150_ACCEL_REG_INT_EN_1, - .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN, - }, - { /* motion interrupt */ - .map_reg = BMC150_ACCEL_REG_INT_MAP_0, - .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE, - .en_reg = BMC150_ACCEL_REG_INT_EN_0, - .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X | - BMC150_ACCEL_INT_EN_BIT_SLP_Y | - BMC150_ACCEL_INT_EN_BIT_SLP_Z - }, - { /* fifo watermark interrupt */ - .map_reg = BMC150_ACCEL_REG_INT_MAP_1, - .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_FWM, - .en_reg = BMC150_ACCEL_REG_INT_EN_1, - .en_bitmask = BMC150_ACCEL_INT_EN_BIT_FWM_EN, - }, -}; - -static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev, - struct bmc150_accel_data *data) -{ - int i; - - for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++) - data->interrupts[i].info = &bmc150_accel_interrupts[i]; -} - -static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, - bool state) -{ - struct bmc150_accel_interrupt *intr = &data->interrupts[i]; - const struct bmc150_accel_interrupt_info *info = intr->info; - int ret; - - if (state) { - if (atomic_inc_return(&intr->users) > 1) - return 0; - } else { - if (atomic_dec_return(&intr->users) > 0) - return 0; - } - - /* - * We will expect the enable and disable to do operation in reverse - * order. This will happen here anyway, as our resume operation uses - * sync mode runtime pm calls. The suspend operation will be delayed - * by autosuspend delay. - * So the disable operation will still happen in reverse order of - * enable operation. When runtime pm is disabled the mode is always on, - * so sequence doesn't matter. - */ - ret = bmc150_accel_set_power_state(data, state); - if (ret < 0) - return ret; - - /* map the interrupt to the appropriate pins */ - ret = i2c_smbus_read_byte_data(data->client, info->map_reg); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_map\n"); - goto out_fix_power_state; - } - if (state) - ret |= info->map_bitmask; - else - ret &= ~info->map_bitmask; - - ret = i2c_smbus_write_byte_data(data->client, info->map_reg, - ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_map\n"); - goto out_fix_power_state; - } - - /* enable/disable the interrupt */ - ret = i2c_smbus_read_byte_data(data->client, info->en_reg); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_en\n"); - goto out_fix_power_state; - } - - if (state) - ret |= info->en_bitmask; - else - ret &= ~info->en_bitmask; - - ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_en\n"); - goto out_fix_power_state; - } - - if (state) - atomic_inc(&data->active_intr); - else - atomic_dec(&data->active_intr); - - return 0; - -out_fix_power_state: - bmc150_accel_set_power_state(data, false); - return ret; -} - -static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) -{ - int ret, i; - - for (i = 0; i < ARRAY_SIZE(data->chip_info->scale_table); ++i) { - if (data->chip_info->scale_table[i].scale == val) { - ret = i2c_smbus_write_byte_data( - data->client, - BMC150_ACCEL_REG_PMU_RANGE, - data->chip_info->scale_table[i].reg_range); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing pmu_range\n"); - return ret; - } - - data->range = data->chip_info->scale_table[i].reg_range; - return 0; - } - } - - return -EINVAL; -} - -static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) -{ - int ret; - - mutex_lock(&data->mutex); - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_temp\n"); - mutex_unlock(&data->mutex); - return ret; - } - *val = sign_extend32(ret, 7); - - mutex_unlock(&data->mutex); - - return IIO_VAL_INT; -} - -static int bmc150_accel_get_axis(struct bmc150_accel_data *data, - struct iio_chan_spec const *chan, - int *val) -{ - int ret; - int axis = chan->scan_index; - - mutex_lock(&data->mutex); - ret = bmc150_accel_set_power_state(data, true); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } - - ret = i2c_smbus_read_word_data(data->client, - BMC150_ACCEL_AXIS_TO_REG(axis)); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading axis %d\n", axis); - bmc150_accel_set_power_state(data, false); - mutex_unlock(&data->mutex); - return ret; - } - *val = sign_extend32(ret >> chan->scan_type.shift, - chan->scan_type.realbits - 1); - ret = bmc150_accel_set_power_state(data, false); - mutex_unlock(&data->mutex); - if (ret < 0) - return ret; - - return IIO_VAL_INT; -} - -static int bmc150_accel_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_RAW: - switch (chan->type) { - case IIO_TEMP: - return bmc150_accel_get_temp(data, val); - case IIO_ACCEL: - if (iio_buffer_enabled(indio_dev)) - return -EBUSY; - else - return bmc150_accel_get_axis(data, chan, val); - default: - return -EINVAL; - } - case IIO_CHAN_INFO_OFFSET: - if (chan->type == IIO_TEMP) { - *val = BMC150_ACCEL_TEMP_CENTER_VAL; - return IIO_VAL_INT; - } else { - return -EINVAL; - } - case IIO_CHAN_INFO_SCALE: - *val = 0; - switch (chan->type) { - case IIO_TEMP: - *val2 = 500000; - return IIO_VAL_INT_PLUS_MICRO; - case IIO_ACCEL: - { - int i; - const struct bmc150_scale_info *si; - int st_size = ARRAY_SIZE(data->chip_info->scale_table); - - for (i = 0; i < st_size; ++i) { - si = &data->chip_info->scale_table[i]; - if (si->reg_range == data->range) { - *val2 = si->scale; - return IIO_VAL_INT_PLUS_MICRO; - } - } - return -EINVAL; - } - default: - return -EINVAL; - } - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&data->mutex); - ret = bmc150_accel_get_bw(data, val, val2); - mutex_unlock(&data->mutex); - return ret; - default: - return -EINVAL; - } -} - -static int bmc150_accel_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - - switch (mask) { - case IIO_CHAN_INFO_SAMP_FREQ: - mutex_lock(&data->mutex); - ret = bmc150_accel_set_bw(data, val, val2); - mutex_unlock(&data->mutex); - break; - case IIO_CHAN_INFO_SCALE: - if (val) - return -EINVAL; - - mutex_lock(&data->mutex); - ret = bmc150_accel_set_scale(data, val2); - mutex_unlock(&data->mutex); - return ret; - default: - ret = -EINVAL; - } - - return ret; -} - -static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); - - *val2 = 0; - switch (info) { - case IIO_EV_INFO_VALUE: - *val = data->slope_thres; - break; - case IIO_EV_INFO_PERIOD: - *val = data->slope_dur; - break; - default: - return -EINVAL; - } - - return IIO_VAL_INT; -} - -static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); - - if (data->ev_enable_state) - return -EBUSY; - - switch (info) { - case IIO_EV_INFO_VALUE: - data->slope_thres = val & BMC150_ACCEL_SLOPE_THRES_MASK; - break; - case IIO_EV_INFO_PERIOD: - data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); - - return data->ev_enable_state; -} - -static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - - if (state == data->ev_enable_state) - return 0; - - mutex_lock(&data->mutex); - - ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION, - state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } - - data->ev_enable_state = state; - mutex_unlock(&data->mutex); - - return 0; -} - -static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int i; - - for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { - if (data->triggers[i].indio_trig == trig) - return 0; - } - - return -EINVAL; -} - -static ssize_t bmc150_accel_get_fifo_watermark(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct bmc150_accel_data *data = iio_priv(indio_dev); - int wm; - - mutex_lock(&data->mutex); - wm = data->watermark; - mutex_unlock(&data->mutex); - - return sprintf(buf, "%d\n", wm); -} - -static ssize_t bmc150_accel_get_fifo_state(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct bmc150_accel_data *data = iio_priv(indio_dev); - bool state; - - mutex_lock(&data->mutex); - state = data->fifo_mode; - mutex_unlock(&data->mutex); - - return sprintf(buf, "%d\n", state); -} - -static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); -static IIO_CONST_ATTR(hwfifo_watermark_max, - __stringify(BMC150_ACCEL_FIFO_LENGTH)); -static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO, - bmc150_accel_get_fifo_state, NULL, 0); -static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, - bmc150_accel_get_fifo_watermark, NULL, 0); - -static const struct attribute *bmc150_accel_fifo_attributes[] = { - &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, - &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, - &iio_dev_attr_hwfifo_watermark.dev_attr.attr, - &iio_dev_attr_hwfifo_enabled.dev_attr.attr, - NULL, -}; - -static int bmc150_accel_set_watermark(struct iio_dev *indio_dev, unsigned val) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - - if (val > BMC150_ACCEL_FIFO_LENGTH) - val = BMC150_ACCEL_FIFO_LENGTH; - - mutex_lock(&data->mutex); - data->watermark = val; - mutex_unlock(&data->mutex); - - return 0; -} - -/* - * We must read at least one full frame in one burst, otherwise the rest of the - * frame data is discarded. - */ -static int bmc150_accel_fifo_transfer(const struct i2c_client *client, - char *buffer, int samples) -{ - int sample_length = 3 * 2; - u8 reg_fifo_data = BMC150_ACCEL_REG_FIFO_DATA; - int ret = -EIO; - - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - struct i2c_msg msg[2] = { - { - .addr = client->addr, - .flags = 0, - .buf = ®_fifo_data, - .len = sizeof(reg_fifo_data), - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .buf = (u8 *)buffer, - .len = samples * sample_length, - } - }; - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret != 2) - ret = -EIO; - else - ret = 0; - } else { - int i, step = I2C_SMBUS_BLOCK_MAX / sample_length; - - for (i = 0; i < samples * sample_length; i += step) { - ret = i2c_smbus_read_i2c_block_data(client, - reg_fifo_data, step, - &buffer[i]); - if (ret != step) { - ret = -EIO; - break; - } - - ret = 0; - } - } - - if (ret) - dev_err(&client->dev, "Error transferring data from fifo\n"); - - return ret; -} - -static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev, - unsigned samples, bool irq) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret, i; - u8 count; - u16 buffer[BMC150_ACCEL_FIFO_LENGTH * 3]; - int64_t tstamp; - uint64_t sample_period; - - ret = i2c_smbus_read_byte_data(data->client, - BMC150_ACCEL_REG_FIFO_STATUS); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_fifo_status\n"); - return ret; - } - - count = ret & 0x7F; - - if (!count) - return 0; - - /* - * If we getting called from IRQ handler we know the stored timestamp is - * fairly accurate for the last stored sample. Otherwise, if we are - * called as a result of a read operation from userspace and hence - * before the watermark interrupt was triggered, take a timestamp - * now. We can fall anywhere in between two samples so the error in this - * case is at most one sample period. - */ - if (!irq) { - data->old_timestamp = data->timestamp; - data->timestamp = iio_get_time_ns(); - } - - /* - * Approximate timestamps for each of the sample based on the sampling - * frequency, timestamp for last sample and number of samples. - * - * Note that we can't use the current bandwidth settings to compute the - * sample period because the sample rate varies with the device - * (e.g. between 31.70ms to 32.20ms for a bandwidth of 15.63HZ). That - * small variation adds when we store a large number of samples and - * creates significant jitter between the last and first samples in - * different batches (e.g. 32ms vs 21ms). - * - * To avoid this issue we compute the actual sample period ourselves - * based on the timestamp delta between the last two flush operations. - */ - sample_period = (data->timestamp - data->old_timestamp); - do_div(sample_period, count); - tstamp = data->timestamp - (count - 1) * sample_period; - - if (samples && count > samples) - count = samples; - - ret = bmc150_accel_fifo_transfer(data->client, (u8 *)buffer, count); - if (ret) - return ret; - - /* - * Ideally we want the IIO core to handle the demux when running in fifo - * mode but not when running in triggered buffer mode. Unfortunately - * this does not seem to be possible, so stick with driver demux for - * now. - */ - for (i = 0; i < count; i++) { - u16 sample[8]; - int j, bit; - - j = 0; - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) - memcpy(&sample[j++], &buffer[i * 3 + bit], 2); - - iio_push_to_buffers_with_timestamp(indio_dev, sample, tstamp); - - tstamp += sample_period; - } - - return count; -} - -static int bmc150_accel_fifo_flush(struct iio_dev *indio_dev, unsigned samples) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - - mutex_lock(&data->mutex); - ret = __bmc150_accel_fifo_flush(indio_dev, samples, false); - mutex_unlock(&data->mutex); - - return ret; -} - -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( - "15.620000 31.260000 62.50000 125 250 500 1000 2000"); - -static struct attribute *bmc150_accel_attributes[] = { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group bmc150_accel_attrs_group = { - .attrs = bmc150_accel_attributes, -}; - -static const struct iio_event_spec bmc150_accel_event = { - .type = IIO_EV_TYPE_ROC, - .dir = IIO_EV_DIR_EITHER, - .mask_separate = BIT(IIO_EV_INFO_VALUE) | - BIT(IIO_EV_INFO_ENABLE) | - BIT(IIO_EV_INFO_PERIOD) -}; - -#define BMC150_ACCEL_CHANNEL(_axis, bits) { \ - .type = IIO_ACCEL, \ - .modified = 1, \ - .channel2 = IIO_MOD_##_axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_SAMP_FREQ), \ - .scan_index = AXIS_##_axis, \ - .scan_type = { \ - .sign = 's', \ - .realbits = (bits), \ - .storagebits = 16, \ - .shift = 16 - (bits), \ - }, \ - .event_spec = &bmc150_accel_event, \ - .num_event_specs = 1 \ -} - -#define BMC150_ACCEL_CHANNELS(bits) { \ - { \ - .type = IIO_TEMP, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_OFFSET), \ - .scan_index = -1, \ - }, \ - BMC150_ACCEL_CHANNEL(X, bits), \ - BMC150_ACCEL_CHANNEL(Y, bits), \ - BMC150_ACCEL_CHANNEL(Z, bits), \ - IIO_CHAN_SOFT_TIMESTAMP(3), \ -} - -static const struct iio_chan_spec bma222e_accel_channels[] = - BMC150_ACCEL_CHANNELS(8); -static const struct iio_chan_spec bma250e_accel_channels[] = - BMC150_ACCEL_CHANNELS(10); -static const struct iio_chan_spec bmc150_accel_channels[] = - BMC150_ACCEL_CHANNELS(12); -static const struct iio_chan_spec bma280_accel_channels[] = - BMC150_ACCEL_CHANNELS(14); - -enum { - bmc150, - bmi055, - bma255, - bma250e, - bma222e, - bma280, -}; - -static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { - [bmc150] = { - .name = "BMC150A", - .chip_id = 0xFA, - .channels = bmc150_accel_channels, - .num_channels = ARRAY_SIZE(bmc150_accel_channels), - .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, - {19122, BMC150_ACCEL_DEF_RANGE_4G}, - {38344, BMC150_ACCEL_DEF_RANGE_8G}, - {76590, BMC150_ACCEL_DEF_RANGE_16G} }, - }, - [bmi055] = { - .name = "BMI055A", - .chip_id = 0xFA, - .channels = bmc150_accel_channels, - .num_channels = ARRAY_SIZE(bmc150_accel_channels), - .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, - {19122, BMC150_ACCEL_DEF_RANGE_4G}, - {38344, BMC150_ACCEL_DEF_RANGE_8G}, - {76590, BMC150_ACCEL_DEF_RANGE_16G} }, - }, - [bma255] = { - .name = "BMA0255", - .chip_id = 0xFA, - .channels = bmc150_accel_channels, - .num_channels = ARRAY_SIZE(bmc150_accel_channels), - .scale_table = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, - {19122, BMC150_ACCEL_DEF_RANGE_4G}, - {38344, BMC150_ACCEL_DEF_RANGE_8G}, - {76590, BMC150_ACCEL_DEF_RANGE_16G} }, - }, - [bma250e] = { - .name = "BMA250E", - .chip_id = 0xF9, - .channels = bma250e_accel_channels, - .num_channels = ARRAY_SIZE(bma250e_accel_channels), - .scale_table = { {38344, BMC150_ACCEL_DEF_RANGE_2G}, - {76590, BMC150_ACCEL_DEF_RANGE_4G}, - {153277, BMC150_ACCEL_DEF_RANGE_8G}, - {306457, BMC150_ACCEL_DEF_RANGE_16G} }, - }, - [bma222e] = { - .name = "BMA222E", - .chip_id = 0xF8, - .channels = bma222e_accel_channels, - .num_channels = ARRAY_SIZE(bma222e_accel_channels), - .scale_table = { {153277, BMC150_ACCEL_DEF_RANGE_2G}, - {306457, BMC150_ACCEL_DEF_RANGE_4G}, - {612915, BMC150_ACCEL_DEF_RANGE_8G}, - {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, - }, - [bma280] = { - .name = "BMA0280", - .chip_id = 0xFB, - .channels = bma280_accel_channels, - .num_channels = ARRAY_SIZE(bma280_accel_channels), - .scale_table = { {2392, BMC150_ACCEL_DEF_RANGE_2G}, - {4785, BMC150_ACCEL_DEF_RANGE_4G}, - {9581, BMC150_ACCEL_DEF_RANGE_8G}, - {19152, BMC150_ACCEL_DEF_RANGE_16G} }, - }, -}; - -static const struct iio_info bmc150_accel_info = { - .attrs = &bmc150_accel_attrs_group, - .read_raw = bmc150_accel_read_raw, - .write_raw = bmc150_accel_write_raw, - .read_event_value = bmc150_accel_read_event, - .write_event_value = bmc150_accel_write_event, - .write_event_config = bmc150_accel_write_event_config, - .read_event_config = bmc150_accel_read_event_config, - .driver_module = THIS_MODULE, -}; - -static const struct iio_info bmc150_accel_info_fifo = { - .attrs = &bmc150_accel_attrs_group, - .read_raw = bmc150_accel_read_raw, - .write_raw = bmc150_accel_write_raw, - .read_event_value = bmc150_accel_read_event, - .write_event_value = bmc150_accel_write_event, - .write_event_config = bmc150_accel_write_event_config, - .read_event_config = bmc150_accel_read_event_config, - .validate_trigger = bmc150_accel_validate_trigger, - .hwfifo_set_watermark = bmc150_accel_set_watermark, - .hwfifo_flush_to_buffer = bmc150_accel_fifo_flush, - .driver_module = THIS_MODULE, -}; - -static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct bmc150_accel_data *data = iio_priv(indio_dev); - int bit, ret, i = 0; - - mutex_lock(&data->mutex); - for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { - ret = i2c_smbus_read_word_data(data->client, - BMC150_ACCEL_AXIS_TO_REG(bit)); - if (ret < 0) { - mutex_unlock(&data->mutex); - goto err_read; - } - data->buffer[i++] = ret; - } - mutex_unlock(&data->mutex); - - iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, - pf->timestamp); -err_read: - iio_trigger_notify_done(indio_dev->trig); - - return IRQ_HANDLED; -} - -static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) -{ - struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); - struct bmc150_accel_data *data = t->data; - int ret; - - /* new data interrupts don't need ack */ - if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY]) - return 0; - - mutex_lock(&data->mutex); - /* clear any latched interrupt */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - mutex_unlock(&data->mutex); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - return 0; -} - -static int bmc150_accel_trigger_set_state(struct iio_trigger *trig, - bool state) -{ - struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); - struct bmc150_accel_data *data = t->data; - int ret; - - mutex_lock(&data->mutex); - - if (t->enabled == state) { - mutex_unlock(&data->mutex); - return 0; - } - - if (t->setup) { - ret = t->setup(t, state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } - } - - ret = bmc150_accel_set_interrupt(data, t->intr, state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } - - t->enabled = state; - - mutex_unlock(&data->mutex); - - return ret; -} - -static const struct iio_trigger_ops bmc150_accel_trigger_ops = { - .set_trigger_state = bmc150_accel_trigger_set_state, - .try_reenable = bmc150_accel_trig_try_reen, - .owner = THIS_MODULE, -}; - -static int bmc150_accel_handle_roc_event(struct iio_dev *indio_dev) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int dir; - int ret; - - ret = i2c_smbus_read_byte_data(data->client, - BMC150_ACCEL_REG_INT_STATUS_2); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_status_2\n"); - return ret; - } - - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) - dir = IIO_EV_DIR_FALLING; - else - dir = IIO_EV_DIR_RISING; - - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_X, - IIO_EV_TYPE_ROC, - dir), - data->timestamp); - - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Y, - IIO_EV_TYPE_ROC, - dir), - data->timestamp); - - if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z) - iio_push_event(indio_dev, - IIO_MOD_EVENT_CODE(IIO_ACCEL, - 0, - IIO_MOD_Z, - IIO_EV_TYPE_ROC, - dir), - data->timestamp); - - return ret; -} - -static irqreturn_t bmc150_accel_irq_thread_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct bmc150_accel_data *data = iio_priv(indio_dev); - bool ack = false; - int ret; - - mutex_lock(&data->mutex); - - if (data->fifo_mode) { - ret = __bmc150_accel_fifo_flush(indio_dev, - BMC150_ACCEL_FIFO_LENGTH, true); - if (ret > 0) - ack = true; - } - - if (data->ev_enable_state) { - ret = bmc150_accel_handle_roc_event(indio_dev); - if (ret > 0) - ack = true; - } - - if (ack) { - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret) - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - - ret = IRQ_HANDLED; - } else { - ret = IRQ_NONE; - } - - mutex_unlock(&data->mutex); - - return ret; -} - -static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) -{ - struct iio_dev *indio_dev = private; - struct bmc150_accel_data *data = iio_priv(indio_dev); - bool ack = false; - int i; - - data->old_timestamp = data->timestamp; - data->timestamp = iio_get_time_ns(); - - for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { - if (data->triggers[i].enabled) { - iio_trigger_poll(data->triggers[i].indio_trig); - ack = true; - break; - } - } - - if (data->ev_enable_state || data->fifo_mode) - return IRQ_WAKE_THREAD; - - if (ack) - return IRQ_HANDLED; - - return IRQ_NONE; -} - -static int bmc150_accel_gpio_probe(struct i2c_client *client, - struct bmc150_accel_data *data) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "Failed: gpio get index\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - -static const struct { - int intr; - const char *name; - int (*setup)(struct bmc150_accel_trigger *t, bool state); -} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = { - { - .intr = 0, - .name = "%s-dev%d", - }, - { - .intr = 1, - .name = "%s-any-motion-dev%d", - .setup = bmc150_accel_any_motion_setup, - }, -}; - -static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data, - int from) -{ - int i; - - for (i = from; i >= 0; i--) { - if (data->triggers[i].indio_trig) { - iio_trigger_unregister(data->triggers[i].indio_trig); - data->triggers[i].indio_trig = NULL; - } - } -} - -static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, - struct bmc150_accel_data *data) -{ - int i, ret; - - for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { - struct bmc150_accel_trigger *t = &data->triggers[i]; - - t->indio_trig = devm_iio_trigger_alloc(&data->client->dev, - bmc150_accel_triggers[i].name, - indio_dev->name, - indio_dev->id); - if (!t->indio_trig) { - ret = -ENOMEM; - break; - } - - t->indio_trig->dev.parent = &data->client->dev; - t->indio_trig->ops = &bmc150_accel_trigger_ops; - t->intr = bmc150_accel_triggers[i].intr; - t->data = data; - t->setup = bmc150_accel_triggers[i].setup; - iio_trigger_set_drvdata(t->indio_trig, t); - - ret = iio_trigger_register(t->indio_trig); - if (ret) - break; - } - - if (ret) - bmc150_accel_unregister_triggers(data, i - 1); - - return ret; -} - -#define BMC150_ACCEL_FIFO_MODE_STREAM 0x80 -#define BMC150_ACCEL_FIFO_MODE_FIFO 0x40 -#define BMC150_ACCEL_FIFO_MODE_BYPASS 0x00 - -static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data) -{ - u8 reg = BMC150_ACCEL_REG_FIFO_CONFIG1; - int ret; - - ret = i2c_smbus_write_byte_data(data->client, reg, data->fifo_mode); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_fifo_config1\n"); - return ret; - } - - if (!data->fifo_mode) - return 0; - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_FIFO_CONFIG0, - data->watermark); - if (ret < 0) - dev_err(&data->client->dev, "Error writing reg_fifo_config0\n"); - - return ret; -} - -static int bmc150_accel_buffer_preenable(struct iio_dev *indio_dev) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - - return bmc150_accel_set_power_state(data, true); -} - -static int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret = 0; - - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) - return iio_triggered_buffer_postenable(indio_dev); - - mutex_lock(&data->mutex); - - if (!data->watermark) - goto out; - - ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, - true); - if (ret) - goto out; - - data->fifo_mode = BMC150_ACCEL_FIFO_MODE_FIFO; - - ret = bmc150_accel_fifo_set_mode(data); - if (ret) { - data->fifo_mode = 0; - bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, - false); - } - -out: - mutex_unlock(&data->mutex); - - return ret; -} - -static int bmc150_accel_buffer_predisable(struct iio_dev *indio_dev) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - - if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) - return iio_triggered_buffer_predisable(indio_dev); - - mutex_lock(&data->mutex); - - if (!data->fifo_mode) - goto out; - - bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_WATERMARK, false); - __bmc150_accel_fifo_flush(indio_dev, BMC150_ACCEL_FIFO_LENGTH, false); - data->fifo_mode = 0; - bmc150_accel_fifo_set_mode(data); - -out: - mutex_unlock(&data->mutex); - - return 0; -} - -static int bmc150_accel_buffer_postdisable(struct iio_dev *indio_dev) -{ - struct bmc150_accel_data *data = iio_priv(indio_dev); - - return bmc150_accel_set_power_state(data, false); -} - -static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { - .preenable = bmc150_accel_buffer_preenable, - .postenable = bmc150_accel_buffer_postenable, - .predisable = bmc150_accel_buffer_predisable, - .postdisable = bmc150_accel_buffer_postdisable, -}; - -static int bmc150_accel_chip_init(struct bmc150_accel_data *data) -{ - int ret, i; - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); - if (ret < 0) { - dev_err(&data->client->dev, "Error: Reading chip id\n"); - return ret; - } - - dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { - if (bmc150_accel_chip_info_tbl[i].chip_id == ret) { - data->chip_info = &bmc150_accel_chip_info_tbl[i]; - break; - } - } - - if (!data->chip_info) { - dev_err(&data->client->dev, "Unsupported chip %x\n", ret); - return -ENODEV; - } - - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - if (ret < 0) - return ret; - - /* Set Bandwidth */ - ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); - if (ret < 0) - return ret; - - /* Set Default Range */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_RANGE, - BMC150_ACCEL_DEF_RANGE_4G); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); - return ret; - } - - data->range = BMC150_ACCEL_DEF_RANGE_4G; - - /* Set default slope duration and thresholds */ - data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; - data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; - ret = bmc150_accel_update_slope(data); - if (ret < 0) - return ret; - - /* Set default as latched interrupts */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - return 0; -} - -static int bmc150_accel_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct bmc150_accel_data *data; - struct iio_dev *indio_dev; - int ret; - const char *name = NULL; - - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - data = iio_priv(indio_dev); - i2c_set_clientdata(client, indio_dev); - data->client = client; - - if (id) - name = id->name; - - ret = bmc150_accel_chip_init(data); - if (ret < 0) - return ret; - - mutex_init(&data->mutex); - - indio_dev->dev.parent = &client->dev; - indio_dev->channels = data->chip_info->channels; - indio_dev->num_channels = data->chip_info->num_channels; - indio_dev->name = name ? name : data->chip_info->name; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->info = &bmc150_accel_info; - - ret = iio_triggered_buffer_setup(indio_dev, - &iio_pollfunc_store_time, - bmc150_accel_trigger_handler, - &bmc150_accel_buffer_ops); - if (ret < 0) { - dev_err(&client->dev, "Failed: iio triggered buffer setup\n"); - return ret; - } - - if (client->irq < 0) - client->irq = bmc150_accel_gpio_probe(client, data); - - if (client->irq > 0) { - ret = devm_request_threaded_irq( - &client->dev, client->irq, - bmc150_accel_irq_handler, - bmc150_accel_irq_thread_handler, - IRQF_TRIGGER_RISING, - BMC150_ACCEL_IRQ_NAME, - indio_dev); - if (ret) - goto err_buffer_cleanup; - - /* - * Set latched mode interrupt. While certain interrupts are - * non-latched regardless of this settings (e.g. new data) we - * want to use latch mode when we can to prevent interrupt - * flooding. - */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n"); - goto err_buffer_cleanup; - } - - bmc150_accel_interrupts_setup(indio_dev, data); - - ret = bmc150_accel_triggers_setup(indio_dev, data); - if (ret) - goto err_buffer_cleanup; - - if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - indio_dev->modes |= INDIO_BUFFER_SOFTWARE; - indio_dev->info = &bmc150_accel_info_fifo; - indio_dev->buffer->attrs = bmc150_accel_fifo_attributes; - } - } - - ret = iio_device_register(indio_dev); - if (ret < 0) { - dev_err(&client->dev, "Unable to register iio device\n"); - goto err_trigger_unregister; - } - - ret = pm_runtime_set_active(&client->dev); - if (ret) - goto err_iio_unregister; - - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, - BMC150_AUTO_SUSPEND_DELAY_MS); - pm_runtime_use_autosuspend(&client->dev); - - return 0; - -err_iio_unregister: - iio_device_unregister(indio_dev); -err_trigger_unregister: - bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); -err_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - - return ret; -} - -static int bmc150_accel_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct bmc150_accel_data *data = iio_priv(indio_dev); - - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); - - iio_device_unregister(indio_dev); - - bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); - - iio_triggered_buffer_cleanup(indio_dev); - - mutex_lock(&data->mutex); - bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0); - mutex_unlock(&data->mutex); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int bmc150_accel_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct bmc150_accel_data *data = iio_priv(indio_dev); - - mutex_lock(&data->mutex); - bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); - mutex_unlock(&data->mutex); - - return 0; -} - -static int bmc150_accel_resume(struct device *dev) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct bmc150_accel_data *data = iio_priv(indio_dev); - - mutex_lock(&data->mutex); - if (atomic_read(&data->active_intr)) - bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - bmc150_accel_fifo_set_mode(data); - mutex_unlock(&data->mutex); - - return 0; -} -#endif - -#ifdef CONFIG_PM -static int bmc150_accel_runtime_suspend(struct device *dev) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - - dev_dbg(&data->client->dev, __func__); - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); - if (ret < 0) - return -EAGAIN; - - return 0; -} - -static int bmc150_accel_runtime_resume(struct device *dev) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); - struct bmc150_accel_data *data = iio_priv(indio_dev); - int ret; - int sleep_val; - - dev_dbg(&data->client->dev, __func__); - - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - if (ret < 0) - return ret; - ret = bmc150_accel_fifo_set_mode(data); - if (ret < 0) - return ret; - - sleep_val = bmc150_accel_get_startup_times(data); - if (sleep_val < 20) - usleep_range(sleep_val * 1000, 20000); - else - msleep_interruptible(sleep_val); - - return 0; -} -#endif - -static const struct dev_pm_ops bmc150_accel_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) - SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, - bmc150_accel_runtime_resume, NULL) -}; - -static const struct acpi_device_id bmc150_accel_acpi_match[] = { - {"BSBA0150", bmc150}, - {"BMC150A", bmc150}, - {"BMI055A", bmi055}, - {"BMA0255", bma255}, - {"BMA250E", bma250e}, - {"BMA222E", bma222e}, - {"BMA0280", bma280}, - { }, -}; -MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); - -static const struct i2c_device_id bmc150_accel_id[] = { - {"bmc150_accel", bmc150}, - {"bmi055_accel", bmi055}, - {"bma255", bma255}, - {"bma250e", bma250e}, - {"bma222e", bma222e}, - {"bma280", bma280}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); - -static struct i2c_driver bmc150_accel_driver = { - .driver = { - .name = BMC150_ACCEL_DRV_NAME, - .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), - .pm = &bmc150_accel_pm_ops, - }, - .probe = bmc150_accel_probe, - .remove = bmc150_accel_remove, - .id_table = bmc150_accel_id, -}; -module_i2c_driver(bmc150_accel_driver); - -MODULE_AUTHOR("Srinivas Pandruvada "); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("BMC150 accelerometer driver"); diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h new file mode 100644 index 000000000..ba0335987 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel.h @@ -0,0 +1,20 @@ +#ifndef _BMC150_ACCEL_H_ +#define _BMC150_ACCEL_H_ + +struct regmap; + +enum { + bmc150, + bmi055, + bma255, + bma250e, + bma222e, + bma280, +}; + +int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, + const char *name, bool block_supported); +int bmc150_accel_core_remove(struct device *dev); +extern const struct dev_pm_ops bmc150_accel_pm_ops; + +#endif /* _BMC150_ACCEL_H_ */ diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 3292bc0c1..18c1b0668 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1162,35 +1162,6 @@ static const char *kxcjk1013_match_acpi_device(struct device *dev, return dev_name(dev); } -static int kxcjk1013_gpio_probe(struct i2c_client *client, - struct kxcjk1013_data *data) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - if (data->is_smo8500_device) - return -ENOTSUPP; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "acpi gpio get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static int kxcjk1013_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1237,10 +1208,7 @@ static int kxcjk1013_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &kxcjk1013_info; - if (client->irq < 0) - client->irq = kxcjk1013_gpio_probe(client, data); - - if (client->irq > 0) { + if (client->irq > 0 && !data->is_smo8500_device) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c index 98ba761cb..923f56598 100644 --- a/drivers/iio/accel/kxsd9.c +++ b/drivers/iio/accel/kxsd9.c @@ -263,7 +263,6 @@ MODULE_DEVICE_TABLE(spi, kxsd9_id); static struct spi_driver kxsd9_driver = { .driver = { .name = "kxsd9", - .owner = THIS_MODULE, }, .probe = kxsd9_probe, .remove = kxsd9_remove, diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index b921d84c1..1eccc2dcf 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1,6 +1,12 @@ /* - * mma8452.c - Support for Freescale MMA8452Q 3-axis 12-bit accelerometer + * 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 * Copyright 2014 Peter Meerwald * * This file is subject to the terms and conditions of version 2 of @@ -22,10 +28,11 @@ #include #include #include +#include #define MMA8452_STATUS 0x00 #define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) -#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ +#define MMA8452_OUT_X 0x01 /* MSB first */ #define MMA8452_OUT_Y 0x03 #define MMA8452_OUT_Z 0x05 #define MMA8452_INT_SRC 0x0c @@ -38,6 +45,16 @@ #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_CHAN(chan) BIT(chan + 1) @@ -65,15 +82,65 @@ #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; }; static int mma8452_drdy(struct mma8452_data *data) @@ -143,16 +210,6 @@ static const int mma8452_samp_freq[8][2] = { {6, 250000}, {1, 560000} }; -/* - * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 - * The userspace interface uses m/s^2 and we declare micro units - * So scale factor is given by: - * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665 - */ -static const int mma8452_scales[3][2] = { - {0, 9577}, {0, 19154}, {0, 38307} -}; - /* Datasheet table 35 (step time vs sample frequency) */ static const int mma8452_transient_time_step_us[8] = { 1250, @@ -189,8 +246,11 @@ static ssize_t mma8452_show_scale_avail(struct device *dev, struct device_attribute *attr, char *buf) { - return mma8452_show_int_plus_micros(buf, mma8452_scales, - ARRAY_SIZE(mma8452_scales)); + struct mma8452_data *data = iio_priv(i2c_get_clientdata( + to_i2c_client(dev))); + + return mma8452_show_int_plus_micros(buf, data->chip_info->mma_scales, + ARRAY_SIZE(data->chip_info->mma_scales)); } static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, @@ -221,9 +281,8 @@ static int mma8452_get_samp_freq_index(struct mma8452_data *data, static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) { - return mma8452_get_int_plus_micros_index(mma8452_scales, - ARRAY_SIZE(mma8452_scales), - val, val2); + return mma8452_get_int_plus_micros_index(data->chip_info->mma_scales, + ARRAY_SIZE(data->chip_info->mma_scales), val, val2); } static int mma8452_get_hp_filter_index(struct mma8452_data *data, @@ -270,14 +329,15 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4, - 11); + *val = sign_extend32(be16_to_cpu( + buffer[chan->scan_index]) >> chan->scan_type.shift, + chan->scan_type.realbits - 1); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; - *val = mma8452_scales[i][0]; - *val2 = mma8452_scales[i][1]; + *val = data->chip_info->mma_scales[i][0]; + *val2 = data->chip_info->mma_scales[i][1]; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: @@ -439,17 +499,17 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: ret = i2c_smbus_read_byte_data(data->client, - MMA8452_TRANSIENT_THS); + data->chip_info->ev_ths); if (ret < 0) return ret; - *val = ret & MMA8452_TRANSIENT_THS_MASK; + *val = ret & data->chip_info->ev_ths_mask; return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: ret = i2c_smbus_read_byte_data(data->client, - MMA8452_TRANSIENT_COUNT); + data->chip_info->ev_count); if (ret < 0) return ret; @@ -497,7 +557,8 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) return -EINVAL; - return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); + return mma8452_change_config(data, data->chip_info->ev_ths, + val); case IIO_EV_INFO_PERIOD: steps = (val * USEC_PER_SEC + val2) / @@ -507,7 +568,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (steps < 0 || steps > 0xff) return -EINVAL; - return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, + return mma8452_change_config(data, data->chip_info->ev_count, steps); case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: @@ -538,13 +599,15 @@ static int mma8452_read_event_config(struct iio_dev *indio_dev, enum iio_event_direction dir) { struct mma8452_data *data = iio_priv(indio_dev); + const struct mma_chip_info *chip = data->chip_info; int ret; - ret = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); + ret = i2c_smbus_read_byte_data(data->client, + data->chip_info->ev_cfg); if (ret < 0) return ret; - return ret & MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index) ? 1 : 0; + return !!(ret & BIT(chan->scan_index + chip->ev_cfg_chan_shift)); } static int mma8452_write_event_config(struct iio_dev *indio_dev, @@ -554,20 +617,22 @@ static int mma8452_write_event_config(struct iio_dev *indio_dev, int state) { struct mma8452_data *data = iio_priv(indio_dev); + const struct mma_chip_info *chip = data->chip_info; int val; - val = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); + val = i2c_smbus_read_byte_data(data->client, chip->ev_cfg); if (val < 0) return val; if (state) - val |= MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); + val |= BIT(chan->scan_index + chip->ev_cfg_chan_shift); else - val &= ~MMA8452_TRANSIENT_CFG_CHAN(chan->scan_index); + val &= ~BIT(chan->scan_index + chip->ev_cfg_chan_shift); - val |= MMA8452_TRANSIENT_CFG_ELE; + val |= chip->ev_cfg_ele; + val |= MMA8452_FF_MT_CFG_OAE; - return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, val); + return mma8452_change_config(data, chip->ev_cfg, val); } static void mma8452_transient_interrupt(struct iio_dev *indio_dev) @@ -576,25 +641,25 @@ static void mma8452_transient_interrupt(struct iio_dev *indio_dev) s64 ts = iio_get_time_ns(); int src; - src = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_SRC); + src = i2c_smbus_read_byte_data(data->client, data->chip_info->ev_src); if (src < 0) return; - if (src & MMA8452_TRANSIENT_SRC_XTRANSE) + if (src & data->chip_info->ev_src_xe) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), ts); - if (src & MMA8452_TRANSIENT_SRC_YTRANSE) + if (src & data->chip_info->ev_src_ye) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Y, IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING), ts); - if (src & MMA8452_TRANSIENT_SRC_ZTRANSE) + if (src & data->chip_info->ev_src_ze) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_Z, IIO_EV_TYPE_MAG, @@ -606,6 +671,7 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) { struct iio_dev *indio_dev = p; struct mma8452_data *data = iio_priv(indio_dev); + const struct mma_chip_info *chip = data->chip_info; int ret = IRQ_NONE; int src; @@ -618,7 +684,10 @@ static irqreturn_t mma8452_interrupt(int irq, void *p) ret = IRQ_HANDLED; } - if (src & MMA8452_INT_TRANS) { + if ((src & MMA8452_INT_TRANS && + chip->ev_src == MMA8452_TRANSIENT_SRC) || + (src & MMA8452_INT_FF_MT && + chip->ev_src == MMA8452_FF_MT_SRC)) { mma8452_transient_interrupt(indio_dev); ret = IRQ_HANDLED; } @@ -680,6 +749,16 @@ static const struct iio_event_spec mma8452_transient_event[] = { }, }; +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) + }, +}; + /* * Threshold is configured in fixed 8G/127 steps regardless of * currently selected scale for measurement. @@ -693,10 +772,9 @@ static struct attribute *mma8452_event_attributes[] = { static struct attribute_group mma8452_event_attribute_group = { .attrs = mma8452_event_attributes, - .name = "events", }; -#define MMA8452_CHANNEL(axis, idx) { \ +#define MMA8452_CHANNEL(axis, idx, bits) { \ .type = IIO_ACCEL, \ .modified = 1, \ .channel2 = IIO_MOD_##axis, \ @@ -708,22 +786,144 @@ static struct attribute_group mma8452_event_attribute_group = { .scan_index = idx, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = (bits), \ .storagebits = 16, \ - .shift = 4, \ + .shift = 16 - (bits), \ .endianness = IIO_BE, \ }, \ .event_spec = mma8452_transient_event, \ .num_event_specs = ARRAY_SIZE(mma8452_transient_event), \ } +#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) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .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), \ +} + static const struct iio_chan_spec mma8452_channels[] = { - MMA8452_CHANNEL(X, 0), - MMA8452_CHANNEL(Y, 1), - MMA8452_CHANNEL(Z, 2), + MMA8452_CHANNEL(X, 0, 12), + MMA8452_CHANNEL(Y, 1, 12), + MMA8452_CHANNEL(Z, 2, 12), IIO_CHAN_SOFT_TIMESTAMP(3), }; +static const struct iio_chan_spec mma8453_channels[] = { + MMA8452_CHANNEL(X, 0, 10), + MMA8452_CHANNEL(Y, 1, 10), + MMA8452_CHANNEL(Z, 2, 10), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec mma8652_channels[] = { + MMA8652_CHANNEL(X, 0, 12), + MMA8652_CHANNEL(Y, 1, 12), + MMA8652_CHANNEL(Z, 2, 12), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_chan_spec mma8653_channels[] = { + MMA8652_CHANNEL(X, 0, 10), + MMA8652_CHANNEL(Y, 1, 10), + MMA8652_CHANNEL(Z, 2, 10), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +enum { + mma8452, + mma8453, + mma8652, + mma8653, +}; + +static const struct mma_chip_info mma_chip_info_table[] = { + [mma8452] = { + .chip_id = MMA8452_DEVICE_ID, + .channels = mma8452_channels, + .num_channels = ARRAY_SIZE(mma8452_channels), + /* + * Hardware has fullscale of -2G, -4G, -8G corresponding to + * raw value -2048 for 12 bit or -512 for 10 bit. + * The userspace interface uses m/s^2 and we declare micro units + * So scale factor for 12 bit here is given by: + * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 + */ + .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, + .ev_cfg = MMA8452_TRANSIENT_CFG, + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, + .ev_cfg_chan_shift = 1, + .ev_src = MMA8452_TRANSIENT_SRC, + .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, + .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, + .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, + .ev_ths = MMA8452_TRANSIENT_THS, + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, + .ev_count = MMA8452_TRANSIENT_COUNT, + }, + [mma8453] = { + .chip_id = MMA8453_DEVICE_ID, + .channels = mma8453_channels, + .num_channels = ARRAY_SIZE(mma8453_channels), + .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, + .ev_cfg = MMA8452_TRANSIENT_CFG, + .ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE, + .ev_cfg_chan_shift = 1, + .ev_src = MMA8452_TRANSIENT_SRC, + .ev_src_xe = MMA8452_TRANSIENT_SRC_XTRANSE, + .ev_src_ye = MMA8452_TRANSIENT_SRC_YTRANSE, + .ev_src_ze = MMA8452_TRANSIENT_SRC_ZTRANSE, + .ev_ths = MMA8452_TRANSIENT_THS, + .ev_ths_mask = MMA8452_TRANSIENT_THS_MASK, + .ev_count = MMA8452_TRANSIENT_COUNT, + }, + [mma8652] = { + .chip_id = MMA8652_DEVICE_ID, + .channels = mma8652_channels, + .num_channels = ARRAY_SIZE(mma8652_channels), + .mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, + .ev_cfg = MMA8452_FF_MT_CFG, + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, + .ev_cfg_chan_shift = 3, + .ev_src = MMA8452_FF_MT_SRC, + .ev_src_xe = MMA8452_FF_MT_SRC_XHE, + .ev_src_ye = MMA8452_FF_MT_SRC_YHE, + .ev_src_ze = MMA8452_FF_MT_SRC_ZHE, + .ev_ths = MMA8452_FF_MT_THS, + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, + .ev_count = MMA8452_FF_MT_COUNT, + }, + [mma8653] = { + .chip_id = MMA8653_DEVICE_ID, + .channels = mma8653_channels, + .num_channels = ARRAY_SIZE(mma8653_channels), + .mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, + .ev_cfg = MMA8452_FF_MT_CFG, + .ev_cfg_ele = MMA8452_FF_MT_CFG_ELE, + .ev_cfg_chan_shift = 3, + .ev_src = MMA8452_FF_MT_SRC, + .ev_src_xe = MMA8452_FF_MT_SRC_XHE, + .ev_src_ye = MMA8452_FF_MT_SRC_YHE, + .ev_src_ze = MMA8452_FF_MT_SRC_ZHE, + .ev_ths = MMA8452_FF_MT_THS, + .ev_ths_mask = MMA8452_FF_MT_THS_MASK, + .ev_count = MMA8452_FF_MT_COUNT, + }, +}; + static struct attribute *mma8452_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, &iio_dev_attr_in_accel_scale_available.dev_attr.attr, @@ -841,18 +1041,28 @@ static int mma8452_reset(struct i2c_client *client) return -ETIMEDOUT; } +static const struct of_device_id mma8452_dt_ids[] = { + { .compatible = "fsl,mma8452", .data = &mma_chip_info_table[mma8452] }, + { .compatible = "fsl,mma8453", .data = &mma_chip_info_table[mma8453] }, + { .compatible = "fsl,mma8652", .data = &mma_chip_info_table[mma8652] }, + { .compatible = "fsl,mma8653", .data = &mma_chip_info_table[mma8653] }, + { } +}; +MODULE_DEVICE_TABLE(of, mma8452_dt_ids); + 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; + const struct of_device_id *match; - ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); - if (ret < 0) - return ret; - if (ret != MMA8452_DEVICE_ID) + match = of_match_device(mma8452_dt_ids, &client->dev); + if (!match) { + dev_err(&client->dev, "unknown device model\n"); return -ENODEV; + } indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -861,14 +1071,33 @@ static int mma8452_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->lock); + data->chip_info = match->data; + + ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); + if (ret < 0) + return ret; + + switch (ret) { + case MMA8452_DEVICE_ID: + case MMA8453_DEVICE_ID: + case MMA8652_DEVICE_ID: + case MMA8653_DEVICE_ID: + if (ret == data->chip_info->chip_id) + break; + default: + return -ENODEV; + } + + dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n", + match->compatible, data->chip_info->chip_id); i2c_set_clientdata(client, indio_dev); indio_dev->info = &mma8452_info; indio_dev->name = id->name; indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = mma8452_channels; - indio_dev->num_channels = ARRAY_SIZE(mma8452_channels); + indio_dev->channels = data->chip_info->channels; + indio_dev->num_channels = data->chip_info->num_channels; indio_dev->available_scan_masks = mma8452_scan_masks; ret = mma8452_reset(client); @@ -892,13 +1121,15 @@ static int mma8452_probe(struct i2c_client *client, if (client->irq) { /* - * Although we enable the transient interrupt source once and - * for all here the transient event detection itself is not - * enabled until userspace asks for it by - * mma8452_write_event_config() + * 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() */ - int supported_interrupts = MMA8452_INT_DRDY | MMA8452_INT_TRANS; - int enabled_interrupts = MMA8452_INT_TRANS; + int supported_interrupts = MMA8452_INT_DRDY | + MMA8452_INT_TRANS | + MMA8452_INT_FF_MT; + int enabled_interrupts = MMA8452_INT_TRANS | + MMA8452_INT_FF_MT; /* Assume wired to INT1 pin */ ret = i2c_smbus_write_byte_data(client, @@ -987,17 +1218,14 @@ static SIMPLE_DEV_PM_OPS(mma8452_pm_ops, mma8452_suspend, mma8452_resume); #endif static const struct i2c_device_id mma8452_id[] = { - { "mma8452", 0 }, + { "mma8452", mma8452 }, + { "mma8453", mma8453 }, + { "mma8652", mma8652 }, + { "mma8653", mma8653 }, { } }; MODULE_DEVICE_TABLE(i2c, mma8452_id); -static const struct of_device_id mma8452_dt_ids[] = { - { .compatible = "fsl,mma8452" }, - { } -}; -MODULE_DEVICE_TABLE(of, mma8452_dt_ids); - static struct i2c_driver mma8452_driver = { .driver = { .name = "mma8452", diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 771858cb6..9408ef3ad 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -26,7 +26,6 @@ #define MMA9553_DRV_NAME "mma9553" #define MMA9553_IRQ_NAME "mma9553_event" -#define MMA9553_GPIO_NAME "mma9553_int" /* Pedometer configuration registers (R/W) */ #define MMA9553_REG_CONF_SLEEPMIN 0x00 @@ -1073,31 +1072,6 @@ static irqreturn_t mma9553_event_handler(int irq, void *private) return IRQ_HANDLED; } -static int mma9553_gpio_probe(struct i2c_client *client) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready GPIO interrupt pin */ - gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "ACPI GPIO get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static const char *mma9553_match_acpi_device(struct device *dev) { const struct acpi_device_id *id; @@ -1146,9 +1120,6 @@ static int mma9553_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &mma9553_info; - if (client->irq < 0) - client->irq = mma9553_gpio_probe(client); - if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, mma9553_irq_handler, diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c new file mode 100644 index 000000000..e72e218c2 --- /dev/null +++ b/drivers/iio/accel/mxc4005.c @@ -0,0 +1,567 @@ +/* + * 3-axis accelerometer driver for MXC4005XC Memsic sensor + * + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MXC4005_DRV_NAME "mxc4005" +#define MXC4005_IRQ_NAME "mxc4005_event" +#define MXC4005_REGMAP_NAME "mxc4005_regmap" + +#define MXC4005_REG_XOUT_UPPER 0x03 +#define MXC4005_REG_XOUT_LOWER 0x04 +#define MXC4005_REG_YOUT_UPPER 0x05 +#define MXC4005_REG_YOUT_LOWER 0x06 +#define MXC4005_REG_ZOUT_UPPER 0x07 +#define MXC4005_REG_ZOUT_LOWER 0x08 + +#define MXC4005_REG_INT_MASK1 0x0B +#define MXC4005_REG_INT_MASK1_BIT_DRDYE 0x01 + +#define MXC4005_REG_INT_CLR1 0x01 +#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01 + +#define MXC4005_REG_CONTROL 0x0D +#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5) +#define MXC4005_CONTROL_FSR_SHIFT 5 + +#define MXC4005_REG_DEVICE_ID 0x0E + +enum mxc4005_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum mxc4005_range { + MXC4005_RANGE_2G, + MXC4005_RANGE_4G, + MXC4005_RANGE_8G, +}; + +struct mxc4005_data { + struct device *dev; + struct mutex mutex; + struct regmap *regmap; + struct iio_trigger *dready_trig; + __be16 buffer[8]; + bool trigger_enabled; +}; + +/* + * MXC4005 can operate in the following ranges: + * +/- 2G, 4G, 8G (the default +/-2G) + * + * (2 + 2) * 9.81 / (2^12 - 1) = 0.009582 + * (4 + 4) * 9.81 / (2^12 - 1) = 0.019164 + * (8 + 8) * 9.81 / (2^12 - 1) = 0.038329 + */ +static const struct { + u8 range; + int scale; +} mxc4005_scale_table[] = { + {MXC4005_RANGE_2G, 9582}, + {MXC4005_RANGE_4G, 19164}, + {MXC4005_RANGE_8G, 38329}, +}; + + +static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019164 0.038329"); + +static struct attribute *mxc4005_attributes[] = { + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group mxc4005_attrs_group = { + .attrs = mxc4005_attributes, +}; + +static bool mxc4005_is_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MXC4005_REG_XOUT_UPPER: + case MXC4005_REG_XOUT_LOWER: + case MXC4005_REG_YOUT_UPPER: + case MXC4005_REG_YOUT_LOWER: + case MXC4005_REG_ZOUT_UPPER: + case MXC4005_REG_ZOUT_LOWER: + case MXC4005_REG_DEVICE_ID: + case MXC4005_REG_CONTROL: + return true; + default: + return false; + } +} + +static bool mxc4005_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MXC4005_REG_INT_CLR1: + case MXC4005_REG_INT_MASK1: + case MXC4005_REG_CONTROL: + return true; + default: + return false; + } +} + +static const struct regmap_config mxc4005_regmap_config = { + .name = MXC4005_REGMAP_NAME, + + .reg_bits = 8, + .val_bits = 8, + + .max_register = MXC4005_REG_DEVICE_ID, + + .readable_reg = mxc4005_is_readable_reg, + .writeable_reg = mxc4005_is_writeable_reg, +}; + +static int mxc4005_read_xyz(struct mxc4005_data *data) +{ + int ret; + + ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, + (u8 *) data->buffer, sizeof(data->buffer)); + if (ret < 0) { + dev_err(data->dev, "failed to read axes\n"); + return ret; + } + + return 0; +} + +static int mxc4005_read_axis(struct mxc4005_data *data, + unsigned int addr) +{ + __be16 reg; + int ret; + + ret = regmap_bulk_read(data->regmap, addr, (u8 *) ®, sizeof(reg)); + if (ret < 0) { + dev_err(data->dev, "failed to read reg %02x\n", addr); + return ret; + } + + return be16_to_cpu(reg); +} + +static int mxc4005_read_scale(struct mxc4005_data *data) +{ + unsigned int reg; + int ret; + int i; + + ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, ®); + if (ret < 0) { + dev_err(data->dev, "failed to read reg_control\n"); + return ret; + } + + i = reg >> MXC4005_CONTROL_FSR_SHIFT; + + if (i < 0 || i >= ARRAY_SIZE(mxc4005_scale_table)) + return -EINVAL; + + return mxc4005_scale_table[i].scale; +} + +static int mxc4005_set_scale(struct mxc4005_data *data, int val) +{ + unsigned int reg; + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(mxc4005_scale_table); i++) { + if (mxc4005_scale_table[i].scale == val) { + reg = i << MXC4005_CONTROL_FSR_SHIFT; + ret = regmap_update_bits(data->regmap, + MXC4005_REG_CONTROL, + MXC4005_REG_CONTROL_MASK_FSR, + reg); + if (ret < 0) + dev_err(data->dev, + "failed to write reg_control\n"); + return ret; + } + } + + return -EINVAL; +} + +static int mxc4005_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_ACCEL: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + ret = mxc4005_read_axis(data, chan->address); + if (ret < 0) + return ret; + *val = sign_extend32(ret >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SCALE: + ret = mxc4005_read_scale(data); + if (ret < 0) + return ret; + + *val = 0; + *val2 = ret; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int mxc4005_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct mxc4005_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + if (val != 0) + return -EINVAL; + + return mxc4005_set_scale(data, val2); + default: + return -EINVAL; + } +} + +static const struct iio_info mxc4005_info = { + .driver_module = THIS_MODULE, + .read_raw = mxc4005_read_raw, + .write_raw = mxc4005_write_raw, + .attrs = &mxc4005_attrs_group, +}; + +static const unsigned long mxc4005_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0 +}; + +#define MXC4005_CHANNEL(_axis, _addr) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = _addr, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec mxc4005_channels[] = { + MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER), + MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER), + MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static irqreturn_t mxc4005_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + ret = mxc4005_read_xyz(data); + if (ret < 0) + goto err; + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); + +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int mxc4005_clr_intr(struct mxc4005_data *data) +{ + int ret; + + /* clear interrupt */ + ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1, + MXC4005_REG_INT_CLR1_BIT_DRDYC); + if (ret < 0) { + dev_err(data->dev, "failed to write to reg_int_clr1\n"); + return ret; + } + + return 0; +} + +static int mxc4005_set_trigger_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct mxc4005_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + if (state) { + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, + MXC4005_REG_INT_MASK1_BIT_DRDYE); + } else { + ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, + ~MXC4005_REG_INT_MASK1_BIT_DRDYE); + } + + if (ret < 0) { + mutex_unlock(&data->mutex); + dev_err(data->dev, "failed to update reg_int_mask1"); + return ret; + } + + data->trigger_enabled = state; + mutex_unlock(&data->mutex); + + return 0; +} + +static int mxc4005_trigger_try_reen(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct mxc4005_data *data = iio_priv(indio_dev); + + if (!data->dready_trig) + return 0; + + return mxc4005_clr_intr(data); +} + +static const struct iio_trigger_ops mxc4005_trigger_ops = { + .set_trigger_state = mxc4005_set_trigger_state, + .try_reenable = mxc4005_trigger_try_reen, + .owner = THIS_MODULE, +}; + +static int mxc4005_gpio_probe(struct i2c_client *client, + struct mxc4005_data *data) +{ + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + + gpio = devm_gpiod_get_index(dev, "mxc4005_int", 0, GPIOD_IN); + if (IS_ERR(gpio)) { + dev_err(dev, "failed to get acpi gpio index\n"); + return PTR_ERR(gpio); + } + + ret = gpiod_to_irq(gpio); + + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); + + return ret; +} + +static int mxc4005_chip_init(struct mxc4005_data *data) +{ + int ret; + unsigned int reg; + + ret = regmap_read(data->regmap, MXC4005_REG_DEVICE_ID, ®); + if (ret < 0) { + dev_err(data->dev, "failed to read chip id\n"); + return ret; + } + + dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg); + + return 0; +} + +static int mxc4005_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mxc4005_data *data; + struct iio_dev *indio_dev; + struct regmap *regmap; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(client, &mxc4005_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "failed to initialize regmap\n"); + return PTR_ERR(regmap); + } + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->dev = &client->dev; + data->regmap = regmap; + + ret = mxc4005_chip_init(data); + if (ret < 0) { + dev_err(&client->dev, "failed to initialize chip\n"); + return ret; + } + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = mxc4005_channels; + indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels); + indio_dev->available_scan_masks = mxc4005_scan_masks; + indio_dev->name = MXC4005_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &mxc4005_info; + + ret = iio_triggered_buffer_setup(indio_dev, + iio_pollfunc_store_time, + mxc4005_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "failed to setup iio triggered buffer\n"); + return ret; + } + + if (client->irq < 0) + client->irq = mxc4005_gpio_probe(client, data); + + if (client->irq > 0) { + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) + return -ENOMEM; + + ret = devm_request_threaded_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, + NULL, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + MXC4005_IRQ_NAME, + data->dready_trig); + if (ret) { + dev_err(&client->dev, + "failed to init threaded irq\n"); + goto err_buffer_cleanup; + } + + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &mxc4005_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + indio_dev->trig = data->dready_trig; + iio_trigger_get(indio_dev->trig); + ret = iio_trigger_register(data->dready_trig); + if (ret) { + dev_err(&client->dev, + "failed to register trigger\n"); + goto err_trigger_unregister; + } + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, + "unable to register iio device %d\n", ret); + goto err_buffer_cleanup; + } + + return 0; + +err_trigger_unregister: + iio_trigger_unregister(data->dready_trig); +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); + + return ret; +} + +static int mxc4005_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mxc4005_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + iio_triggered_buffer_cleanup(indio_dev); + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + + return 0; +} + +static const struct acpi_device_id mxc4005_acpi_match[] = { + {"MXC4005", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, mxc4005_acpi_match); + +static const struct i2c_device_id mxc4005_id[] = { + {"mxc4005", 0}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, mxc4005_id); + +static struct i2c_driver mxc4005_driver = { + .driver = { + .name = MXC4005_DRV_NAME, + .acpi_match_table = ACPI_PTR(mxc4005_acpi_match), + }, + .probe = mxc4005_probe, + .remove = mxc4005_remove, + .id_table = mxc4005_id, +}; + +module_i2c_driver(mxc4005_driver); + +MODULE_AUTHOR("Teodora Baluta "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MXC4005 3-axis accelerometer driver"); diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index fb9311110..197a08b4e 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -612,6 +612,7 @@ static const struct iio_info accel_info = { .attrs = &st_accel_attribute_group, .read_raw = &st_accel_read_raw, .write_raw = &st_accel_write_raw, + .debugfs_reg_access = &st_sensors_debugfs_reg_access, }; #ifdef CONFIG_IIO_TRIGGER diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 54b61a396..f71b0d391 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -64,7 +64,6 @@ MODULE_DEVICE_TABLE(spi, st_accel_id_table); static struct spi_driver st_accel_driver = { .driver = { - .owner = THIS_MODULE, .name = "st-accel-spi", }, .probe = st_accel_spi_probe, diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c764af284..85fe7f724 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -50,7 +50,6 @@ #define STK8312_ALL_CHANNEL_SIZE 3 #define STK8312_DRIVER_NAME "stk8312" -#define STK8312_GPIO "stk8312_gpio" #define STK8312_IRQ_NAME "stk8312_event" /* @@ -504,30 +503,6 @@ static const struct iio_buffer_setup_ops stk8312_buffer_setup_ops = { .postdisable = stk8312_buffer_postdisable, }; -static int stk8312_gpio_probe(struct i2c_client *client) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, STK8312_GPIO, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "acpi gpio get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static int stk8312_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -569,10 +544,7 @@ static int stk8312_probe(struct i2c_client *client, if (ret < 0) return ret; - if (client->irq < 0) - client->irq = stk8312_gpio_probe(client); - - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, stk8312_data_rdy_trig_poll, NULL, diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 80f77d870..5709d9eb8 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -45,7 +45,6 @@ #define STK8BA50_ALL_CHANNEL_SIZE 6 #define STK8BA50_DRIVER_NAME "stk8ba50" -#define STK8BA50_GPIO "stk8ba50_gpio" #define STK8BA50_IRQ_NAME "stk8ba50_event" #define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069" @@ -388,30 +387,6 @@ static const struct iio_buffer_setup_ops stk8ba50_buffer_setup_ops = { .postdisable = stk8ba50_buffer_postdisable, }; -static int stk8ba50_gpio_probe(struct i2c_client *client) -{ - struct device *dev; - struct gpio_desc *gpio; - int ret; - - if (!client) - return -EINVAL; - - dev = &client->dev; - - /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, STK8BA50_GPIO, 0, GPIOD_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "acpi gpio get index failed\n"); - return PTR_ERR(gpio); - } - - ret = gpiod_to_irq(gpio); - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; -} - static int stk8ba50_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -465,10 +440,7 @@ static int stk8ba50_probe(struct i2c_client *client, goto err_power_off; } - if (client->irq < 0) - client->irq = stk8ba50_gpio_probe(client); - - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, stk8ba50_data_rdy_trig_poll, NULL, -- cgit v1.2.3-54-g00ecf