linux-stable/drivers/iio/accel/bma400_core.c
Greg Kroah-Hartman 56d784d177 1st set of IIO new device support, feature and cleanup for 6.2 (take2)
We have finally managed to take the mlock mutex entirely private so as
 to avoid it being used for multiple purposes.  Now it is just used to
 protect device mode transitions (typically to and from buffered capture).
 
 Includes merge of an immutable i2c branch to get the new
 i2c_client_get_device_id() (thanks to Wolfram for providing the branch).
 
 Based on rc3 to pick up some precursor fixes from early in the cycle and
 avoid an unnecessarily messy history.
 
 New device support
 * adi,ad4310
   - New driver to support this very flexible measurement device including
     a 24 bit ADC. Later fix for documentation build issue.
 * adi,adxl355
   - Add support of the ADXL359 accelerometer.
 * adi,ltc2983
   - Support additional variants of the temperatures sensor:
     LTC2984 with an EEPROM
     LTC2985, LTC2986 with only 10 channels.
 * invensense,icm42600
   - Add support for icm42631 (needed only ID and WHOAMI)
 * kionix,kx022a
   - New driver for this 3 axis accelerometer.
 * maxim,max11401
   - New driver to support this 24-bit 10 channel ADC.
     Includes some new ABI to support configuration of notch filters.
 * mediatek,mt6370
   - Add new driver to support the ADC part of the mt6370.
 * st,lsm6dsx
   - Add support for LSM6DSV accelerometer and gyroscope. Simple additional
     of chip specific data and IDs.
   - Add support for LSM6DSV16X accelerometer and gyroscope.  Compatible with
     features currently implemented for the LSM6DSV.
 * st,stm32-adc
   - Add support for stm32pm13x SoCs.
 
 core / subsystem wide:
  - Add new IIO_STATIC_CONST_DEVICE_ATTR() which is a dance necessary to
    allow for the wrapping of attributes in the code that duplicates them
    for multiple buffers.
  - Harden against future issues with expectation that all buffer attributes
    are iio_dev_attrs by changing the code to take an array of pointers
    of the correct type.
  - Last transitions of drivers to local locks rather than missuses of mlock.
  - Add an iio_device_claim_buffer_mode() callback to avoid a race in the
    max30100 driver without directly using mlock.
  - Move mlock to the opaque IIO device structure to prevent misuse.
  - Add missing spi_device_id tables to support auto loading of modules.
  - Update some ADI maintainers in DT bindings.
  - A few more moves of bus drivers and core module sets to export
    name spaces.
  - Extensive use of new devm_regulator_get_enable() and friends.
  - Switch a bunch of i2c drivers to probe_new() including the bmp280
    which makes use of the new i2c_client_get_device_id() helper to
    simplify this change.
 
 dt-bindings:
  - More use of spi-peripheral-props.yaml.
 
 Features
 * freescale,mpl115
   - Use runtime PM to implement shutdown GPIO support.
 * melexis,mlx90632
   - More sophisticated runtime power management
   - Provide access to sampling frequency.
   - Trivial follow up fixes.
 * microchip,mcp3911
   - Support control of PGA.
 * st,lsm6dsx
   - Add support for software triggers for cases where the IRQ lines
     are not wired up.
 * vishay,vcnl4000
   - Add control of integration time.
 
 Minor cleanups and fixes
 * adi,ad4130
   - Improve ABI documentation formatting.
   - Kconfig dependency fixup.
 * adi,ad5758
   - Minor dt binding fix.
 * adi,ad9834
   - Tidy up line breaks.
 * adi,ade7854
   - Minor improvement in code clarity by replacing a ternary.
 * adi,admv8818
   - Harden code against hardware returning wrong values.
 * adi,adxl355
   - Warn only if unknown device ID detected to allow for fall back
     device tree compatibles on future devices.
 * adi,ltc2983
   - dt-bindings clarifications and general improvements.
   - Ensure DMA safe buffer for bulk writes without relying on current
     regmap implementation choices.
 * avago,adps9960
   - Fix up a disconnect between event enable attributes and what was
     enabled.
 * bosch,bma400
   - Switch to dev_err_probe() from open coded EPROBE_DEFER handling.
 * cosmic,cc10001
   - Fully devm managed probe() and related tidying up.
 * meas,ms5611
   - Add an example of spi-max-frequency.
 * meleixs,mlx90632
   - Tidy up confusing error return value.
   - Style improvements.
 * multiplexer
   - Switch to dev_err_probe() from open coded EPROBE_DEFER handling.
 * qcom,spmi-vadc
   - Minor dt binding improvements.
 * rockchip,saradc
   - Add ID for rv1126.
 * semtech,sx9360
   - Add SAMM0208 ACPI ID. Doesn't appear to be a valid vendor prefix
     but is in the wild.
 * st,lsm6dsx
   - Factor out common code as _device_set_enable().
   - Fix up wrong docs after LSM6DSV addition.
 * st,stm32-adc
   - Manage the min sampling time on all internal channels.
 * trig,sysfs
   - Improve error labels.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmN+fI4RHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FogY1Q/7BTdKLbRuFoE4aK9AABv+m4w91s+RlBg6
 eXRw3Gt4IHHht7gIUVZByYztyoKkmW3RzsPafIlfJJkWAsiBpv6gXTW2h6UvjHg8
 SW3k91oVk5iLEeTaUSfJqxHCXX+VRYanyeti53MkpUvR2QUgAengP11N6bWmNXav
 D6OFGSTn9QpJ0XRmEmfxXt3pt/Miuz7GT2sN5ut1ZvTgN0wZ2aMMdEa8w3UQvxoN
 +Iu0Z3kRtltbw5zqTTdJfXPHS3K1I+361zTT6E4KDVun2939C3Tzw6ziy6MIsng+
 nysaMbZTc5MmdIDPYtSlIV+i4S4DyqvAKsv5PBqqbD3oQfo8AkmnyY6Hdygbv23O
 vK23x19GYcpgLQ42C0g+LFUYxJOJMnMiOocISq8V7Df9+CQRNnk4e7s8MvmhAXmu
 VrOT1VDEL8bJFeukiMRtVTsDo/KRHOWUjEi+1dxJ7aOqry8FGrlR4L+ZtjbMTnmw
 V+7CN0euOdpiDV6jJwmXHQvLWlG3wgq7ZHHj6toaFtq8FI4OaQiA7Ko5WuBLTBxw
 V0jtK/Fru77P0aR7dAd5ck6Rwek8N2rSuOvpucLmImt9asZP3uzoM/LRmtv4Gzjq
 Dp8koqSwx6YMtMAHmXgB/2GkSoOV7eByvIkYCoFCxEp2tst+mIOKSQPDKP8PKuRd
 VBSmvuEilis=
 =Fo38
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-6.2a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next

Jonathan writes:

1st set of IIO new device support, feature and cleanup for 6.2 (take2)

We have finally managed to take the mlock mutex entirely private so as
to avoid it being used for multiple purposes.  Now it is just used to
protect device mode transitions (typically to and from buffered capture).

Includes merge of an immutable i2c branch to get the new
i2c_client_get_device_id() (thanks to Wolfram for providing the branch).

Based on rc3 to pick up some precursor fixes from early in the cycle and
avoid an unnecessarily messy history.

New device support
* adi,ad4310
  - New driver to support this very flexible measurement device including
    a 24 bit ADC. Later fix for documentation build issue.
* adi,adxl355
  - Add support of the ADXL359 accelerometer.
* adi,ltc2983
  - Support additional variants of the temperatures sensor:
    LTC2984 with an EEPROM
    LTC2985, LTC2986 with only 10 channels.
* invensense,icm42600
  - Add support for icm42631 (needed only ID and WHOAMI)
* kionix,kx022a
  - New driver for this 3 axis accelerometer.
* maxim,max11401
  - New driver to support this 24-bit 10 channel ADC.
    Includes some new ABI to support configuration of notch filters.
* mediatek,mt6370
  - Add new driver to support the ADC part of the mt6370.
* st,lsm6dsx
  - Add support for LSM6DSV accelerometer and gyroscope. Simple additional
    of chip specific data and IDs.
  - Add support for LSM6DSV16X accelerometer and gyroscope.  Compatible with
    features currently implemented for the LSM6DSV.
* st,stm32-adc
  - Add support for stm32pm13x SoCs.

core / subsystem wide:
 - Add new IIO_STATIC_CONST_DEVICE_ATTR() which is a dance necessary to
   allow for the wrapping of attributes in the code that duplicates them
   for multiple buffers.
 - Harden against future issues with expectation that all buffer attributes
   are iio_dev_attrs by changing the code to take an array of pointers
   of the correct type.
 - Last transitions of drivers to local locks rather than missuses of mlock.
 - Add an iio_device_claim_buffer_mode() callback to avoid a race in the
   max30100 driver without directly using mlock.
 - Move mlock to the opaque IIO device structure to prevent misuse.
 - Add missing spi_device_id tables to support auto loading of modules.
 - Update some ADI maintainers in DT bindings.
 - A few more moves of bus drivers and core module sets to export
   name spaces.
 - Extensive use of new devm_regulator_get_enable() and friends.
 - Switch a bunch of i2c drivers to probe_new() including the bmp280
   which makes use of the new i2c_client_get_device_id() helper to
   simplify this change.

dt-bindings:
 - More use of spi-peripheral-props.yaml.

Features
* freescale,mpl115
  - Use runtime PM to implement shutdown GPIO support.
* melexis,mlx90632
  - More sophisticated runtime power management
  - Provide access to sampling frequency.
  - Trivial follow up fixes.
* microchip,mcp3911
  - Support control of PGA.
* st,lsm6dsx
  - Add support for software triggers for cases where the IRQ lines
    are not wired up.
* vishay,vcnl4000
  - Add control of integration time.

Minor cleanups and fixes
* adi,ad4130
  - Improve ABI documentation formatting.
  - Kconfig dependency fixup.
* adi,ad5758
  - Minor dt binding fix.
* adi,ad9834
  - Tidy up line breaks.
* adi,ade7854
  - Minor improvement in code clarity by replacing a ternary.
* adi,admv8818
  - Harden code against hardware returning wrong values.
* adi,adxl355
  - Warn only if unknown device ID detected to allow for fall back
    device tree compatibles on future devices.
* adi,ltc2983
  - dt-bindings clarifications and general improvements.
  - Ensure DMA safe buffer for bulk writes without relying on current
    regmap implementation choices.
* avago,adps9960
  - Fix up a disconnect between event enable attributes and what was
    enabled.
* bosch,bma400
  - Switch to dev_err_probe() from open coded EPROBE_DEFER handling.
* cosmic,cc10001
  - Fully devm managed probe() and related tidying up.
* meas,ms5611
  - Add an example of spi-max-frequency.
* meleixs,mlx90632
  - Tidy up confusing error return value.
  - Style improvements.
* multiplexer
  - Switch to dev_err_probe() from open coded EPROBE_DEFER handling.
* qcom,spmi-vadc
  - Minor dt binding improvements.
* rockchip,saradc
  - Add ID for rv1126.
* semtech,sx9360
  - Add SAMM0208 ACPI ID. Doesn't appear to be a valid vendor prefix
    but is in the wild.
* st,lsm6dsx
  - Factor out common code as _device_set_enable().
  - Fix up wrong docs after LSM6DSV addition.
* st,stm32-adc
  - Manage the min sampling time on all internal channels.
* trig,sysfs
  - Improve error labels.

* tag 'iio-for-6.2a-take2' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (146 commits)
  iio: pressure: bmp280: convert to i2c's .probe_new()
  iio: imu: st_lsm6dsx: fix LSM6DSV sensor description
  iio: adc: ad4130: depend on GPIOLIB
  staging: iio: meter: replace ternary operator by if condition
  iio: light: apds9960: Fix iio_event_spec structures
  dt-bindings: iio: imu: Add inv_icm42600 documentation
  iio: imu: inv_icm42600: Add support for icm42631
  dt-bindings: iio: adc: rockchip-saradc: Add saradc for rv1126
  dt-bindings: iio: dac: adi,ad5758: Drop 'contains' from 'adi,dc-dc-mode'
  dt-bindings: iio: imu: st_lsm6dsx: add lsm6dsv16x
  iio: imu: st_lsm6dsx: add support to LSM6DSV16X
  iio: proximity: sx9360: Add a new ACPI hardware ID
  iio: temperature: mlx90632: Add missing static marking on devm_pm_ops
  iio: temperature: mlx90632: Add error handling for devm_pm_runtime_enable()
  iio: temperature: ltc2983: support more parts
  dt-bindings: iio: temperature: ltc2983: support more parts
  dt-bindings: iio: temperature: ltc2983: use generic node name in example
  dt-bindings: iio: temperature: ltc2983: describe broken mux delay property
  dt-bindings: iio: temperature: ltc2983: refine descriptions
  dt-bindings: iio: temperature: ltc2983: change default excitation for custom thermistors
  ...
2022-11-25 18:35:16 +01:00

1791 lines
43 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Core IIO driver for Bosch BMA400 triaxial acceleration sensor.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*
* TODO:
* - Support for power management
* - Support events and interrupts
* - Create channel for step count
* - Create channel for sensor time
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/events.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include "bma400.h"
/*
* The G-range selection may be one of 2g, 4g, 8, or 16g. The scale may
* be selected with the acc_range bits of the ACC_CONFIG1 register.
* NB: This buffer is populated in the device init.
*/
static int bma400_scales[8];
/*
* See the ACC_CONFIG1 section of the datasheet.
* NB: This buffer is populated in the device init.
*/
static int bma400_sample_freqs[14];
static const int bma400_osr_range[] = { 0, 1, 3 };
static int tap_reset_timeout[BMA400_TAP_TIM_LIST_LEN] = {
300000,
400000,
500000,
600000
};
static int tap_max2min_time[BMA400_TAP_TIM_LIST_LEN] = {
30000,
45000,
60000,
90000
};
static int double_tap2_min_delay[BMA400_TAP_TIM_LIST_LEN] = {
20000,
40000,
60000,
80000
};
/* See the ACC_CONFIG0 section of the datasheet */
enum bma400_power_mode {
POWER_MODE_SLEEP = 0x00,
POWER_MODE_LOW = 0x01,
POWER_MODE_NORMAL = 0x02,
POWER_MODE_INVALID = 0x03,
};
enum bma400_scan {
BMA400_ACCL_X,
BMA400_ACCL_Y,
BMA400_ACCL_Z,
BMA400_TEMP,
};
struct bma400_sample_freq {
int hz;
int uhz;
};
enum bma400_activity {
BMA400_STILL,
BMA400_WALKING,
BMA400_RUNNING,
};
struct bma400_data {
struct device *dev;
struct regmap *regmap;
struct regulator_bulk_data regulators[BMA400_NUM_REGULATORS];
struct mutex mutex; /* data register lock */
struct iio_mount_matrix orientation;
enum bma400_power_mode power_mode;
struct bma400_sample_freq sample_freq;
int oversampling_ratio;
int scale;
struct iio_trigger *trig;
int steps_enabled;
bool step_event_en;
bool activity_event_en;
unsigned int generic_event_en;
unsigned int tap_event_en_bitmask;
/* Correct time stamp alignment */
struct {
__le16 buff[3];
u8 temperature;
s64 ts __aligned(8);
} buffer __aligned(IIO_DMA_MINALIGN);
__le16 status;
__be16 duration;
};
static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_CHIP_ID_REG:
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return false;
default:
return true;
}
}
static bool bma400_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return true;
default:
return false;
}
}
const struct regmap_config bma400_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BMA400_CMD_REG,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bma400_is_writable_reg,
.volatile_reg = bma400_is_volatile_reg,
};
EXPORT_SYMBOL_NS(bma400_regmap_config, IIO_BMA400);
static const struct iio_mount_matrix *
bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bma400_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma400_accel_get_mount_matrix),
{ }
};
static const struct iio_event_spec bma400_step_detect_event = {
.type = IIO_EV_TYPE_CHANGE,
.dir = IIO_EV_DIR_NONE,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
};
static const struct iio_event_spec bma400_activity_event = {
.type = IIO_EV_TYPE_CHANGE,
.dir = IIO_EV_DIR_NONE,
.mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE),
};
static const struct iio_event_spec bma400_accel_event[] = {
{
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_FALLING,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD) |
BIT(IIO_EV_INFO_HYSTERESIS) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_MAG,
.dir = IIO_EV_DIR_RISING,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_PERIOD) |
BIT(IIO_EV_INFO_HYSTERESIS) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_GESTURE,
.dir = IIO_EV_DIR_SINGLETAP,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE) |
BIT(IIO_EV_INFO_RESET_TIMEOUT),
},
{
.type = IIO_EV_TYPE_GESTURE,
.dir = IIO_EV_DIR_DOUBLETAP,
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE) |
BIT(IIO_EV_INFO_RESET_TIMEOUT) |
BIT(IIO_EV_INFO_TAP2_MIN_DELAY),
},
};
static int usec_to_tapreg_raw(int usec, const int *time_list)
{
int index;
for (index = 0; index < BMA400_TAP_TIM_LIST_LEN; index++) {
if (usec == time_list[index])
return index;
}
return -EINVAL;
}
static ssize_t in_accel_gesture_tap_maxtomin_time_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct bma400_data *data = iio_priv(indio_dev);
int ret, reg_val, raw, vals[2];
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1, &reg_val);
if (ret)
return ret;
raw = FIELD_GET(BMA400_TAP_TICSTH_MSK, reg_val);
vals[0] = 0;
vals[1] = tap_max2min_time[raw];
return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals);
}
static ssize_t in_accel_gesture_tap_maxtomin_time_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct bma400_data *data = iio_priv(indio_dev);
int ret, val_int, val_fract, raw;
ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract);
if (ret)
return ret;
raw = usec_to_tapreg_raw(val_fract, tap_max2min_time);
if (raw < 0)
return -EINVAL;
ret = regmap_update_bits(data->regmap, BMA400_TAP_CONFIG1,
BMA400_TAP_TICSTH_MSK,
FIELD_PREP(BMA400_TAP_TICSTH_MSK, raw));
if (ret)
return ret;
return len;
}
static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_maxtomin_time, 0);
/*
* Tap interrupts works with 200 Hz input data rate and the time based tap
* controls are in the terms of data samples so the below calculation is
* used to convert the configuration values into seconds.
* e.g.:
* 60 data samples * 0.005 ms = 0.3 seconds.
* 80 data samples * 0.005 ms = 0.4 seconds.
*/
/* quiet configuration values in seconds */
static IIO_CONST_ATTR(in_accel_gesture_tap_reset_timeout_available,
"0.3 0.4 0.5 0.6");
/* tics_th configuration values in seconds */
static IIO_CONST_ATTR(in_accel_gesture_tap_maxtomin_time_available,
"0.03 0.045 0.06 0.09");
/* quiet_dt configuration values in seconds */
static IIO_CONST_ATTR(in_accel_gesture_doubletap_tap2_min_delay_available,
"0.02 0.04 0.06 0.08");
/* List of sensitivity values available to configure tap interrupts */
static IIO_CONST_ATTR(in_accel_gesture_tap_value_available, "0 1 2 3 4 5 6 7");
static struct attribute *bma400_event_attributes[] = {
&iio_const_attr_in_accel_gesture_tap_value_available.dev_attr.attr,
&iio_const_attr_in_accel_gesture_tap_reset_timeout_available.dev_attr.attr,
&iio_const_attr_in_accel_gesture_tap_maxtomin_time_available.dev_attr.attr,
&iio_const_attr_in_accel_gesture_doubletap_tap2_min_delay_available.dev_attr.attr,
&iio_dev_attr_in_accel_gesture_tap_maxtomin_time.dev_attr.attr,
NULL
};
static const struct attribute_group bma400_event_attribute_group = {
.attrs = bma400_event_attributes,
};
#define BMA400_ACC_CHANNEL(_index, _axis) { \
.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_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.ext_info = bma400_ext_info, \
.scan_index = _index, \
.scan_type = { \
.sign = 's', \
.realbits = 12, \
.storagebits = 16, \
.endianness = IIO_LE, \
}, \
.event_spec = bma400_accel_event, \
.num_event_specs = ARRAY_SIZE(bma400_accel_event) \
}
#define BMA400_ACTIVITY_CHANNEL(_chan2) { \
.type = IIO_ACTIVITY, \
.modified = 1, \
.channel2 = _chan2, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.scan_index = -1, /* No buffer support */ \
.event_spec = &bma400_activity_event, \
.num_event_specs = 1, \
}
static const struct iio_chan_spec bma400_channels[] = {
BMA400_ACC_CHANNEL(0, X),
BMA400_ACC_CHANNEL(1, Y),
BMA400_ACC_CHANNEL(2, Z),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 3,
.scan_type = {
.sign = 's',
.realbits = 8,
.storagebits = 8,
.endianness = IIO_LE,
},
},
{
.type = IIO_STEPS,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_ENABLE),
.scan_index = -1, /* No buffer support */
.event_spec = &bma400_step_detect_event,
.num_event_specs = 1,
},
BMA400_ACTIVITY_CHANNEL(IIO_MOD_STILL),
BMA400_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
BMA400_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static int bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
{
unsigned int raw_temp;
int host_temp;
int ret;
if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &raw_temp);
if (ret)
return ret;
host_temp = sign_extend32(raw_temp, 7);
/*
* The formula for the TEMP_DATA register in the datasheet
* is: x * 0.5 + 23
*/
*val = (host_temp >> 1) + 23;
*val2 = (host_temp & 0x1) * 500000;
return IIO_VAL_INT_PLUS_MICRO;
}
static int bma400_get_accel_reg(struct bma400_data *data,
const struct iio_chan_spec *chan,
int *val)
{
__le16 raw_accel;
int lsb_reg;
int ret;
if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;
switch (chan->channel2) {
case IIO_MOD_X:
lsb_reg = BMA400_X_AXIS_LSB_REG;
break;
case IIO_MOD_Y:
lsb_reg = BMA400_Y_AXIS_LSB_REG;
break;
case IIO_MOD_Z:
lsb_reg = BMA400_Z_AXIS_LSB_REG;
break;
default:
dev_err(data->dev, "invalid axis channel modifier\n");
return -EINVAL;
}
/* bulk read two registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, lsb_reg, &raw_accel,
sizeof(raw_accel));
if (ret)
return ret;
*val = sign_extend32(le16_to_cpu(raw_accel), 11);
return IIO_VAL_INT;
}
static void bma400_output_data_rate_from_raw(int raw, unsigned int *val,
unsigned int *val2)
{
*val = BMA400_ACC_ODR_MAX_HZ >> (BMA400_ACC_ODR_MAX_RAW - raw);
if (raw > BMA400_ACC_ODR_MIN_RAW)
*val2 = 0;
else
*val2 = 500000;
}
static int bma400_get_accel_output_data_rate(struct bma400_data *data)
{
unsigned int val;
unsigned int odr;
int ret;
switch (data->power_mode) {
case POWER_MODE_LOW:
/*
* Runs at a fixed rate in low-power mode. See section 4.3
* in the datasheet.
*/
bma400_output_data_rate_from_raw(BMA400_ACC_ODR_LP_RAW,
&data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_NORMAL:
/*
* In normal mode the ODR can be found in the ACC_CONFIG1
* register.
*/
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
goto error;
odr = val & BMA400_ACC_ODR_MASK;
if (odr < BMA400_ACC_ODR_MIN_RAW ||
odr > BMA400_ACC_ODR_MAX_RAW) {
ret = -EINVAL;
goto error;
}
bma400_output_data_rate_from_raw(odr, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_SLEEP:
data->sample_freq.hz = 0;
data->sample_freq.uhz = 0;
return 0;
default:
ret = 0;
goto error;
}
error:
data->sample_freq.hz = -1;
data->sample_freq.uhz = -1;
return ret;
}
static int bma400_set_accel_output_data_rate(struct bma400_data *data,
int hz, int uhz)
{
unsigned int idx;
unsigned int odr;
unsigned int val;
int ret;
if (hz >= BMA400_ACC_ODR_MIN_WHOLE_HZ) {
if (uhz || hz > BMA400_ACC_ODR_MAX_HZ)
return -EINVAL;
/* Note this works because MIN_WHOLE_HZ is odd */
idx = __ffs(hz);
if (hz >> idx != BMA400_ACC_ODR_MIN_WHOLE_HZ)
return -EINVAL;
idx += BMA400_ACC_ODR_MIN_RAW + 1;
} else if (hz == BMA400_ACC_ODR_MIN_HZ && uhz == 500000) {
idx = BMA400_ACC_ODR_MIN_RAW;
} else {
return -EINVAL;
}
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;
/* preserve the range and normal mode osr */
odr = (~BMA400_ACC_ODR_MASK & val) | idx;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, odr);
if (ret)
return ret;
bma400_output_data_rate_from_raw(idx, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
}
static int bma400_get_accel_oversampling_ratio(struct bma400_data *data)
{
unsigned int val;
unsigned int osr;
int ret;
/*
* The oversampling ratio is stored in a different register
* based on the power-mode. In normal mode the OSR is stored
* in ACC_CONFIG1. In low-power mode it is stored in
* ACC_CONFIG0.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}
osr = (val & BMA400_LP_OSR_MASK) >> BMA400_LP_OSR_SHIFT;
data->oversampling_ratio = osr;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}
osr = (val & BMA400_NP_OSR_MASK) >> BMA400_NP_OSR_SHIFT;
data->oversampling_ratio = osr;
return 0;
case POWER_MODE_SLEEP:
data->oversampling_ratio = 0;
return 0;
default:
data->oversampling_ratio = -1;
return -EINVAL;
}
}
static int bma400_set_accel_oversampling_ratio(struct bma400_data *data,
int val)
{
unsigned int acc_config;
int ret;
if (val & ~BMA400_TWO_BITS_MASK)
return -EINVAL;
/*
* The oversampling ratio is stored in a different register
* based on the power-mode.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG,
&acc_config);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
(acc_config & ~BMA400_LP_OSR_MASK) |
(val << BMA400_LP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR\n");
return ret;
}
data->oversampling_ratio = val;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG,
&acc_config);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_NP_OSR_MASK) |
(val << BMA400_NP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR\n");
return ret;
}
data->oversampling_ratio = val;
return 0;
default:
return -EINVAL;
}
return ret;
}
static int bma400_accel_scale_to_raw(struct bma400_data *data,
unsigned int val)
{
int raw;
if (val == 0)
return -EINVAL;
/* Note this works because BMA400_SCALE_MIN is odd */
raw = __ffs(val);
if (val >> raw != BMA400_SCALE_MIN)
return -EINVAL;
return raw;
}
static int bma400_get_accel_scale(struct bma400_data *data)
{
unsigned int raw_scale;
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;
raw_scale = (val & BMA400_ACC_SCALE_MASK) >> BMA400_SCALE_SHIFT;
if (raw_scale > BMA400_TWO_BITS_MASK)
return -EINVAL;
data->scale = BMA400_SCALE_MIN << raw_scale;
return 0;
}
static int bma400_set_accel_scale(struct bma400_data *data, unsigned int val)
{
unsigned int acc_config;
int raw;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &acc_config);
if (ret)
return ret;
raw = bma400_accel_scale_to_raw(data, val);
if (raw < 0)
return raw;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_ACC_SCALE_MASK) |
(raw << BMA400_SCALE_SHIFT));
if (ret)
return ret;
data->scale = val;
return 0;
}
static int bma400_get_power_mode(struct bma400_data *data)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_STATUS_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read status register\n");
return ret;
}
data->power_mode = (val >> 1) & BMA400_TWO_BITS_MASK;
return 0;
}
static int bma400_set_power_mode(struct bma400_data *data,
enum bma400_power_mode mode)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret)
return ret;
if (data->power_mode == mode)
return 0;
if (mode == POWER_MODE_INVALID)
return -EINVAL;
/* Preserve the low-power oversample ratio etc */
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
mode | (val & ~BMA400_TWO_BITS_MASK));
if (ret) {
dev_err(data->dev, "Failed to write to power-mode\n");
return ret;
}
data->power_mode = mode;
/*
* Update our cached osr and odr based on the new
* power-mode.
*/
bma400_get_accel_output_data_rate(data);
bma400_get_accel_oversampling_ratio(data);
return 0;
}
static int bma400_enable_steps(struct bma400_data *data, int val)
{
int ret;
if (data->steps_enabled == val)
return 0;
ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG1_REG,
BMA400_STEP_INT_MSK,
FIELD_PREP(BMA400_STEP_INT_MSK, val ? 1 : 0));
if (ret)
return ret;
data->steps_enabled = val;
return ret;
}
static int bma400_get_steps_reg(struct bma400_data *data, int *val)
{
u8 *steps_raw;
int ret;
steps_raw = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL);
if (!steps_raw)
return -ENOMEM;
ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG,
steps_raw, BMA400_STEP_RAW_LEN);
if (ret)
return ret;
*val = get_unaligned_le24(steps_raw);
kfree(steps_raw);
return IIO_VAL_INT;
}
static void bma400_init_tables(void)
{
int raw;
int i;
for (i = 0; i + 1 < ARRAY_SIZE(bma400_sample_freqs); i += 2) {
raw = (i / 2) + 5;
bma400_output_data_rate_from_raw(raw, &bma400_sample_freqs[i],
&bma400_sample_freqs[i + 1]);
}
for (i = 0; i + 1 < ARRAY_SIZE(bma400_scales); i += 2) {
raw = i / 2;
bma400_scales[i] = 0;
bma400_scales[i + 1] = BMA400_SCALE_MIN << raw;
}
}
static void bma400_regulators_disable(void *data_ptr)
{
struct bma400_data *data = data_ptr;
regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
}
static void bma400_power_disable(void *data_ptr)
{
struct bma400_data *data = data_ptr;
int ret;
mutex_lock(&data->mutex);
ret = bma400_set_power_mode(data, POWER_MODE_SLEEP);
mutex_unlock(&data->mutex);
if (ret)
dev_warn(data->dev, "Failed to put device into sleep mode (%pe)\n",
ERR_PTR(ret));
}
static enum iio_modifier bma400_act_to_mod(enum bma400_activity activity)
{
switch (activity) {
case BMA400_STILL:
return IIO_MOD_STILL;
case BMA400_WALKING:
return IIO_MOD_WALKING;
case BMA400_RUNNING:
return IIO_MOD_RUNNING;
default:
return IIO_NO_MOD;
}
}
static int bma400_init(struct bma400_data *data)
{
unsigned int val;
int ret;
data->regulators[BMA400_VDD_REGULATOR].supply = "vdd";
data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio";
ret = devm_regulator_bulk_get(data->dev,
ARRAY_SIZE(data->regulators),
data->regulators);
if (ret)
return dev_err_probe(data->dev, ret, "Failed to get regulators: %d\n",
ret);
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
dev_err(data->dev, "Failed to enable regulators: %d\n",
ret);
return ret;
}
ret = devm_add_action_or_reset(data->dev, bma400_regulators_disable, data);
if (ret)
return ret;
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read chip id register\n");
return ret;
}
if (val != BMA400_ID_REG_VAL) {
dev_err(data->dev, "Chip ID mismatch\n");
return -ENODEV;
}
ret = bma400_get_power_mode(data);
if (ret) {
dev_err(data->dev, "Failed to get the initial power-mode\n");
return ret;
}
if (data->power_mode != POWER_MODE_NORMAL) {
ret = bma400_set_power_mode(data, POWER_MODE_NORMAL);
if (ret) {
dev_err(data->dev, "Failed to wake up the device\n");
return ret;
}
/*
* TODO: The datasheet waits 1500us here in the example, but
* lists 2/ODR as the wakeup time.
*/
usleep_range(1500, 2000);
}
ret = devm_add_action_or_reset(data->dev, bma400_power_disable, data);
if (ret)
return ret;
bma400_init_tables();
ret = bma400_get_accel_output_data_rate(data);
if (ret)
return ret;
ret = bma400_get_accel_oversampling_ratio(data);
if (ret)
return ret;
ret = bma400_get_accel_scale(data);
if (ret)
return ret;
/* Configure INT1 pin to open drain */
ret = regmap_write(data->regmap, BMA400_INT_IO_CTRL_REG, 0x06);
if (ret)
return ret;
/*
* Once the interrupt engine is supported we might use the
* data_src_reg, but for now ensure this is set to the
* variable ODR filter selectable by the sample frequency
* channel.
*/
return regmap_write(data->regmap, BMA400_ACC_CONFIG2_REG, 0x00);
}
static int bma400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
unsigned int activity;
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_TEMP:
mutex_lock(&data->mutex);
ret = bma400_get_temp_reg(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_STEPS:
return bma400_get_steps_reg(data, val);
case IIO_ACTIVITY:
ret = regmap_read(data->regmap, BMA400_STEP_STAT_REG,
&activity);
if (ret)
return ret;
/*
* The device does not support confidence value levels,
* so we will always have 100% for current activity and
* 0% for the others.
*/
if (chan->channel2 == bma400_act_to_mod(activity))
*val = 100;
else
*val = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
ret = bma400_get_accel_reg(data, chan, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
case IIO_ACCEL:
if (data->sample_freq.hz < 0)
return -EINVAL;
*val = data->sample_freq.hz;
*val2 = data->sample_freq.uhz;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
/*
* Runs at a fixed sampling frequency. See Section 4.4
* of the datasheet.
*/
*val = 6;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->scale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
/*
* TODO: We could avoid this logic and returning -EINVAL here if
* we set both the low-power and normal mode OSR registers when
* we configure the device.
*/
if (data->oversampling_ratio < 0)
return -EINVAL;
*val = data->oversampling_ratio;
return IIO_VAL_INT;
case IIO_CHAN_INFO_ENABLE:
*val = data->steps_enabled;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int bma400_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_scales;
*length = ARRAY_SIZE(bma400_scales);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*type = IIO_VAL_INT;
*vals = bma400_osr_range;
*length = ARRAY_SIZE(bma400_osr_range);
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_sample_freqs;
*length = ARRAY_SIZE(bma400_sample_freqs);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int bma400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
/*
* The sample frequency is readonly for the temperature
* register and a fixed value in low-power mode.
*/
if (chan->type != IIO_ACCEL)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_output_data_rate(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SCALE:
if (val != 0 ||
val2 < BMA400_SCALE_MIN || val2 > BMA400_SCALE_MAX)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_scale(data, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
mutex_lock(&data->mutex);
ret = bma400_set_accel_oversampling_ratio(data, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_ENABLE:
mutex_lock(&data->mutex);
ret = bma400_enable_steps(data, val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static int bma400_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return IIO_VAL_INT;
case IIO_CHAN_INFO_ENABLE:
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int bma400_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct bma400_data *data = iio_priv(indio_dev);
switch (chan->type) {
case IIO_ACCEL:
switch (dir) {
case IIO_EV_DIR_RISING:
return FIELD_GET(BMA400_INT_GEN1_MSK,
data->generic_event_en);
case IIO_EV_DIR_FALLING:
return FIELD_GET(BMA400_INT_GEN2_MSK,
data->generic_event_en);
case IIO_EV_DIR_SINGLETAP:
return FIELD_GET(BMA400_S_TAP_MSK,
data->tap_event_en_bitmask);
case IIO_EV_DIR_DOUBLETAP:
return FIELD_GET(BMA400_D_TAP_MSK,
data->tap_event_en_bitmask);
default:
return -EINVAL;
}
case IIO_STEPS:
return data->step_event_en;
case IIO_ACTIVITY:
return data->activity_event_en;
default:
return -EINVAL;
}
}
static int bma400_steps_event_enable(struct bma400_data *data, int state)
{
int ret;
ret = bma400_enable_steps(data, 1);
if (ret)
return ret;
ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG,
BMA400_STEP_INT_MSK,
FIELD_PREP(BMA400_STEP_INT_MSK,
state));
if (ret)
return ret;
data->step_event_en = state;
return 0;
}
static int bma400_activity_event_en(struct bma400_data *data,
enum iio_event_direction dir,
int state)
{
int ret, reg, msk, value;
int field_value = 0;
switch (dir) {
case IIO_EV_DIR_RISING:
reg = BMA400_GEN1INT_CONFIG0;
msk = BMA400_INT_GEN1_MSK;
value = 2;
set_mask_bits(&field_value, BMA400_INT_GEN1_MSK,
FIELD_PREP(BMA400_INT_GEN1_MSK, state));
break;
case IIO_EV_DIR_FALLING:
reg = BMA400_GEN2INT_CONFIG0;
msk = BMA400_INT_GEN2_MSK;
value = 0;
set_mask_bits(&field_value, BMA400_INT_GEN2_MSK,
FIELD_PREP(BMA400_INT_GEN2_MSK, state));
break;
default:
return -EINVAL;
}
/* Enabling all axis for interrupt evaluation */
ret = regmap_write(data->regmap, reg, 0xF8);
if (ret)
return ret;
/* OR combination of all axis for interrupt evaluation */
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG1_OFF, value);
if (ret)
return ret;
/* Initial value to avoid interrupts while enabling*/
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG2_OFF, 0x0A);
if (ret)
return ret;
/* Initial duration value to avoid interrupts while enabling*/
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG31_OFF, 0x0F);
if (ret)
return ret;
ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, msk,
field_value);
if (ret)
return ret;
ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, msk,
field_value);
if (ret)
return ret;
set_mask_bits(&data->generic_event_en, msk, field_value);
return 0;
}
static int bma400_tap_event_en(struct bma400_data *data,
enum iio_event_direction dir, int state)
{
unsigned int mask, field_value;
int ret;
/*
* Tap interrupts can be configured only in normal mode.
* See table in section 4.3 "Power modes - performance modes" of
* datasheet v1.2.
*/
if (data->power_mode != POWER_MODE_NORMAL)
return -EINVAL;
/*
* Tap interrupts are operating with a data rate of 200Hz.
* See section 4.7 "Tap sensing interrupt" in datasheet v1.2.
*/
if (data->sample_freq.hz != 200 && state) {
dev_err(data->dev, "Invalid data rate for tap interrupts.\n");
return -EINVAL;
}
ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG,
BMA400_S_TAP_MSK,
FIELD_PREP(BMA400_S_TAP_MSK, state));
if (ret)
return ret;
switch (dir) {
case IIO_EV_DIR_SINGLETAP:
mask = BMA400_S_TAP_MSK;
set_mask_bits(&field_value, BMA400_S_TAP_MSK,
FIELD_PREP(BMA400_S_TAP_MSK, state));
break;
case IIO_EV_DIR_DOUBLETAP:
mask = BMA400_D_TAP_MSK;
set_mask_bits(&field_value, BMA400_D_TAP_MSK,
FIELD_PREP(BMA400_D_TAP_MSK, state));
break;
default:
return -EINVAL;
}
ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG1_REG, mask,
field_value);
if (ret)
return ret;
set_mask_bits(&data->tap_event_en_bitmask, mask, field_value);
return 0;
}
static int bma400_disable_adv_interrupt(struct bma400_data *data)
{
int ret;
ret = regmap_write(data->regmap, BMA400_INT_CONFIG0_REG, 0);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_INT_CONFIG1_REG, 0);
if (ret)
return ret;
data->tap_event_en_bitmask = 0;
data->generic_event_en = 0;
data->step_event_en = false;
data->activity_event_en = false;
return 0;
}
static int bma400_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir, int state)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;
switch (chan->type) {
case IIO_ACCEL:
switch (type) {
case IIO_EV_TYPE_MAG:
mutex_lock(&data->mutex);
ret = bma400_activity_event_en(data, dir, state);
mutex_unlock(&data->mutex);
return ret;
case IIO_EV_TYPE_GESTURE:
mutex_lock(&data->mutex);
ret = bma400_tap_event_en(data, dir, state);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
case IIO_STEPS:
mutex_lock(&data->mutex);
ret = bma400_steps_event_enable(data, state);
mutex_unlock(&data->mutex);
return ret;
case IIO_ACTIVITY:
mutex_lock(&data->mutex);
if (!data->step_event_en) {
ret = bma400_steps_event_enable(data, true);
if (ret) {
mutex_unlock(&data->mutex);
return ret;
}
}
data->activity_event_en = state;
mutex_unlock(&data->mutex);
return 0;
default:
return -EINVAL;
}
}
static int get_gen_config_reg(enum iio_event_direction dir)
{
switch (dir) {
case IIO_EV_DIR_FALLING:
return BMA400_GEN2INT_CONFIG0;
case IIO_EV_DIR_RISING:
return BMA400_GEN1INT_CONFIG0;
default:
return -EINVAL;
}
}
static int bma400_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret, reg, reg_val, raw;
if (chan->type != IIO_ACCEL)
return -EINVAL;
switch (type) {
case IIO_EV_TYPE_MAG:
reg = get_gen_config_reg(dir);
if (reg < 0)
return -EINVAL;
*val2 = 0;
switch (info) {
case IIO_EV_INFO_VALUE:
ret = regmap_read(data->regmap,
reg + BMA400_GEN_CONFIG2_OFF,
val);
if (ret)
return ret;
return IIO_VAL_INT;
case IIO_EV_INFO_PERIOD:
mutex_lock(&data->mutex);
ret = regmap_bulk_read(data->regmap,
reg + BMA400_GEN_CONFIG3_OFF,
&data->duration,
sizeof(data->duration));
if (ret) {
mutex_unlock(&data->mutex);
return ret;
}
*val = be16_to_cpu(data->duration);
mutex_unlock(&data->mutex);
return IIO_VAL_INT;
case IIO_EV_INFO_HYSTERESIS:
ret = regmap_read(data->regmap, reg, val);
if (ret)
return ret;
*val = FIELD_GET(BMA400_GEN_HYST_MSK, *val);
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_EV_TYPE_GESTURE:
switch (info) {
case IIO_EV_INFO_VALUE:
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG,
&reg_val);
if (ret)
return ret;
*val = FIELD_GET(BMA400_TAP_SEN_MSK, reg_val);
return IIO_VAL_INT;
case IIO_EV_INFO_RESET_TIMEOUT:
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1,
&reg_val);
if (ret)
return ret;
raw = FIELD_GET(BMA400_TAP_QUIET_MSK, reg_val);
*val = 0;
*val2 = tap_reset_timeout[raw];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_EV_INFO_TAP2_MIN_DELAY:
ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1,
&reg_val);
if (ret)
return ret;
raw = FIELD_GET(BMA400_TAP_QUIETDT_MSK, reg_val);
*val = 0;
*val2 = double_tap2_min_delay[raw];
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int bma400_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
struct bma400_data *data = iio_priv(indio_dev);
int reg, ret, raw;
if (chan->type != IIO_ACCEL)
return -EINVAL;
switch (type) {
case IIO_EV_TYPE_MAG:
reg = get_gen_config_reg(dir);
if (reg < 0)
return -EINVAL;
switch (info) {
case IIO_EV_INFO_VALUE:
if (val < 1 || val > 255)
return -EINVAL;
return regmap_write(data->regmap,
reg + BMA400_GEN_CONFIG2_OFF,
val);
case IIO_EV_INFO_PERIOD:
if (val < 1 || val > 65535)
return -EINVAL;
mutex_lock(&data->mutex);
put_unaligned_be16(val, &data->duration);
ret = regmap_bulk_write(data->regmap,
reg + BMA400_GEN_CONFIG3_OFF,
&data->duration,
sizeof(data->duration));
mutex_unlock(&data->mutex);
return ret;
case IIO_EV_INFO_HYSTERESIS:
if (val < 0 || val > 3)
return -EINVAL;
return regmap_update_bits(data->regmap, reg,
BMA400_GEN_HYST_MSK,
FIELD_PREP(BMA400_GEN_HYST_MSK,
val));
default:
return -EINVAL;
}
case IIO_EV_TYPE_GESTURE:
switch (info) {
case IIO_EV_INFO_VALUE:
if (val < 0 || val > 7)
return -EINVAL;
return regmap_update_bits(data->regmap,
BMA400_TAP_CONFIG,
BMA400_TAP_SEN_MSK,
FIELD_PREP(BMA400_TAP_SEN_MSK,
val));
case IIO_EV_INFO_RESET_TIMEOUT:
raw = usec_to_tapreg_raw(val2, tap_reset_timeout);
if (raw < 0)
return -EINVAL;
return regmap_update_bits(data->regmap,
BMA400_TAP_CONFIG1,
BMA400_TAP_QUIET_MSK,
FIELD_PREP(BMA400_TAP_QUIET_MSK,
raw));
case IIO_EV_INFO_TAP2_MIN_DELAY:
raw = usec_to_tapreg_raw(val2, double_tap2_min_delay);
if (raw < 0)
return -EINVAL;
return regmap_update_bits(data->regmap,
BMA400_TAP_CONFIG1,
BMA400_TAP_QUIETDT_MSK,
FIELD_PREP(BMA400_TAP_QUIETDT_MSK,
raw));
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int bma400_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct bma400_data *data = iio_priv(indio_dev);
int ret;
ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG,
BMA400_INT_DRDY_MSK,
FIELD_PREP(BMA400_INT_DRDY_MSK, state));
if (ret)
return ret;
return regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG,
BMA400_INT_DRDY_MSK,
FIELD_PREP(BMA400_INT_DRDY_MSK, state));
}
static const unsigned long bma400_avail_scan_masks[] = {
BIT(BMA400_ACCL_X) | BIT(BMA400_ACCL_Y) | BIT(BMA400_ACCL_Z),
BIT(BMA400_ACCL_X) | BIT(BMA400_ACCL_Y) | BIT(BMA400_ACCL_Z)
| BIT(BMA400_TEMP),
0
};
static const struct iio_info bma400_info = {
.read_raw = bma400_read_raw,
.read_avail = bma400_read_avail,
.write_raw = bma400_write_raw,
.write_raw_get_fmt = bma400_write_raw_get_fmt,
.read_event_config = bma400_read_event_config,
.write_event_config = bma400_write_event_config,
.write_event_value = bma400_write_event_value,
.read_event_value = bma400_read_event_value,
.event_attrs = &bma400_event_attribute_group,
};
static const struct iio_trigger_ops bma400_trigger_ops = {
.set_trigger_state = &bma400_data_rdy_trigger_set_state,
.validate_device = &iio_trigger_validate_own_device,
};
static irqreturn_t bma400_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct bma400_data *data = iio_priv(indio_dev);
int ret, temp;
/* Lock to protect the data->buffer */
mutex_lock(&data->mutex);
/* bulk read six registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
&data->buffer.buff, sizeof(data->buffer.buff));
if (ret)
goto unlock_err;
if (test_bit(BMA400_TEMP, indio_dev->active_scan_mask)) {
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &temp);
if (ret)
goto unlock_err;
data->buffer.temperature = temp;
}
iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
iio_get_time_ns(indio_dev));
mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
unlock_err:
mutex_unlock(&data->mutex);
return IRQ_NONE;
}
static irqreturn_t bma400_interrupt(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct bma400_data *data = iio_priv(indio_dev);
s64 timestamp = iio_get_time_ns(indio_dev);
unsigned int act, ev_dir = IIO_EV_DIR_NONE;
int ret;
/* Lock to protect the data->status */
mutex_lock(&data->mutex);
ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG,
&data->status,
sizeof(data->status));
/*
* if none of the bit is set in the status register then it is
* spurious interrupt.
*/
if (ret || !data->status)
goto unlock_err;
/*
* Disable all advance interrupts if interrupt engine overrun occurs.
* See section 4.7 "Interrupt engine overrun" in datasheet v1.2.
*/
if (FIELD_GET(BMA400_INT_ENG_OVRUN_MSK, le16_to_cpu(data->status))) {
bma400_disable_adv_interrupt(data);
dev_err(data->dev, "Interrupt engine overrun\n");
goto unlock_err;
}
if (FIELD_GET(BMA400_INT_S_TAP_MSK, le16_to_cpu(data->status)))
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_GESTURE,
IIO_EV_DIR_SINGLETAP),
timestamp);
if (FIELD_GET(BMA400_INT_D_TAP_MSK, le16_to_cpu(data->status)))
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_GESTURE,
IIO_EV_DIR_DOUBLETAP),
timestamp);
if (FIELD_GET(BMA400_INT_GEN1_MSK, le16_to_cpu(data->status)))
ev_dir = IIO_EV_DIR_RISING;
if (FIELD_GET(BMA400_INT_GEN2_MSK, le16_to_cpu(data->status)))
ev_dir = IIO_EV_DIR_FALLING;
if (ev_dir != IIO_EV_DIR_NONE) {
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_MAG, ev_dir),
timestamp);
}
if (FIELD_GET(BMA400_STEP_STAT_MASK, le16_to_cpu(data->status))) {
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
IIO_EV_TYPE_CHANGE,
IIO_EV_DIR_NONE),
timestamp);
if (data->activity_event_en) {
ret = regmap_read(data->regmap, BMA400_STEP_STAT_REG,
&act);
if (ret)
goto unlock_err;
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACTIVITY, 0,
bma400_act_to_mod(act),
IIO_EV_TYPE_CHANGE,
IIO_EV_DIR_NONE),
timestamp);
}
}
if (FIELD_GET(BMA400_INT_DRDY_MSK, le16_to_cpu(data->status))) {
mutex_unlock(&data->mutex);
iio_trigger_poll_chained(data->trig);
return IRQ_HANDLED;
}
mutex_unlock(&data->mutex);
return IRQ_HANDLED;
unlock_err:
mutex_unlock(&data->mutex);
return IRQ_NONE;
}
int bma400_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name)
{
struct iio_dev *indio_dev;
struct bma400_data *data;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->regmap = regmap;
data->dev = dev;
ret = bma400_init(data);
if (ret)
return ret;
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
return ret;
mutex_init(&data->mutex);
indio_dev->name = name;
indio_dev->info = &bma400_info;
indio_dev->channels = bma400_channels;
indio_dev->num_channels = ARRAY_SIZE(bma400_channels);
indio_dev->available_scan_masks = bma400_avail_scan_masks;
indio_dev->modes = INDIO_DIRECT_MODE;
if (irq > 0) {
data->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
indio_dev->name,
iio_device_id(indio_dev));
if (!data->trig)
return -ENOMEM;
data->trig->ops = &bma400_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
ret = devm_iio_trigger_register(data->dev, data->trig);
if (ret)
return dev_err_probe(data->dev, ret,
"iio trigger register fail\n");
indio_dev->trig = iio_trigger_get(data->trig);
ret = devm_request_threaded_irq(dev, irq, NULL,
&bma400_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
indio_dev->name, indio_dev);
if (ret)
return dev_err_probe(data->dev, ret,
"request irq %d failed\n", irq);
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
&bma400_trigger_handler, NULL);
if (ret)
return dev_err_probe(data->dev, ret,
"iio triggered buffer setup failed\n");
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS(bma400_probe, IIO_BMA400);
MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>");
MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>");
MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor core");
MODULE_LICENSE("GPL");