diff options
Diffstat (limited to 'drivers/iio/accel')
| -rw-r--r-- | drivers/iio/accel/Kconfig | 19 | ||||
| -rw-r--r-- | drivers/iio/accel/Makefile | 4 | ||||
| -rw-r--r-- | drivers/iio/accel/adxl380.c | 134 | ||||
| -rw-r--r-- | drivers/iio/accel/adxl380.h | 4 | ||||
| -rw-r--r-- | drivers/iio/accel/adxl380_i2c.c | 4 | ||||
| -rw-r--r-- | drivers/iio/accel/adxl380_spi.c | 4 | ||||
| -rw-r--r-- | drivers/iio/accel/bma220.h | 28 | ||||
| -rw-r--r-- | drivers/iio/accel/bma220_core.c | 585 | ||||
| -rw-r--r-- | drivers/iio/accel/bma220_i2c.c | 69 | ||||
| -rw-r--r-- | drivers/iio/accel/bma220_spi.c | 318 | ||||
| -rw-r--r-- | drivers/iio/accel/bma400.h | 155 | ||||
| -rw-r--r-- | drivers/iio/accel/bma400_core.c | 349 |
12 files changed, 1125 insertions, 548 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 8c3f7cf55d5f..76911278fb21 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -218,15 +218,30 @@ config BMA180 config BMA220 tristate "Bosch BMA220 3-Axis Accelerometer Driver" - depends on SPI + depends on I2C || SPI + select REGMAP select IIO_BUFFER select IIO_TRIGGERED_BUFFER + select BMA220_I2C if I2C + select BMA220_SPI if SPI help Say yes here to add support for the Bosch BMA220 triaxial acceleration sensor. To compile this driver as a module, choose M here: the - module will be called bma220_spi. + module will be called bma220_core and you will also get + bma220_i2c if I2C is enabled and bma220_spi if SPI is + enabled. + +config BMA220_I2C + tristate + select REGMAP_I2C + depends on BMA220 + +config BMA220_SPI + tristate + select REGMAP_SPI + depends on BMA220 config BMA400 tristate "Bosch BMA400 3-Axis Accelerometer Driver" diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index ca8569e25aba..fa440a859283 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -25,7 +25,9 @@ obj-$(CONFIG_ADXL380) += adxl380.o obj-$(CONFIG_ADXL380_I2C) += adxl380_i2c.o obj-$(CONFIG_ADXL380_SPI) += adxl380_spi.o obj-$(CONFIG_BMA180) += bma180.o -obj-$(CONFIG_BMA220) += bma220_spi.o +obj-$(CONFIG_BMA220) += bma220_core.o +obj-$(CONFIG_BMA220_I2C) += bma220_i2c.o +obj-$(CONFIG_BMA220_SPI) += bma220_spi.o obj-$(CONFIG_BMA400) += bma400_core.o obj-$(CONFIG_BMA400_I2C) += bma400_i2c.o obj-$(CONFIG_BMA400_SPI) += bma400_spi.o diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c index 0cf3c6815829..6d5f1a0d51e9 100644 --- a/drivers/iio/accel/adxl380.c +++ b/drivers/iio/accel/adxl380.c @@ -26,7 +26,9 @@ #include "adxl380.h" #define ADXL380_ID_VAL 380 +#define ADXL318_ID_VAL 380 #define ADXL382_ID_VAL 382 +#define ADXL319_ID_VAL 382 #define ADXL380_DEVID_AD_REG 0x00 #define ADLX380_PART_ID_REG 0x02 @@ -178,41 +180,6 @@ enum adxl380_tap_time_type { static const int adxl380_range_scale_factor_tbl[] = { 1, 2, 4 }; -const struct adxl380_chip_info adxl380_chip_info = { - .name = "adxl380", - .chip_id = ADXL380_ID_VAL, - .scale_tbl = { - [ADXL380_OP_MODE_4G_RANGE] = { 0, 1307226 }, - [ADXL380_OP_MODE_8G_RANGE] = { 0, 2615434 }, - [ADXL380_OP_MODE_16G_RANGE] = { 0, 5229886 }, - }, - .samp_freq_tbl = { 8000, 16000, 32000 }, - /* - * The datasheet defines an intercept of 470 LSB at 25 degC - * and a sensitivity of 10.2 LSB/C. - */ - .temp_offset = 25 * 102 / 10 - 470, - -}; -EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, "IIO_ADXL380"); - -const struct adxl380_chip_info adxl382_chip_info = { - .name = "adxl382", - .chip_id = ADXL382_ID_VAL, - .scale_tbl = { - [ADXL382_OP_MODE_15G_RANGE] = { 0, 4903325 }, - [ADXL382_OP_MODE_30G_RANGE] = { 0, 9806650 }, - [ADXL382_OP_MODE_60G_RANGE] = { 0, 19613300 }, - }, - .samp_freq_tbl = { 16000, 32000, 64000 }, - /* - * The datasheet defines an intercept of 570 LSB at 25 degC - * and a sensitivity of 10.2 LSB/C. - */ - .temp_offset = 25 * 102 / 10 - 570, -}; -EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, "IIO_ADXL380"); - static const unsigned int adxl380_th_reg_high_addr[2] = { [ADXL380_ACTIVITY] = ADXL380_THRESH_ACT_H_REG, [ADXL380_INACTIVITY] = ADXL380_THRESH_INACT_H_REG, @@ -276,9 +243,14 @@ static int adxl380_set_measure_en(struct adxl380_state *st, bool en) if (ret) return ret; - /* Activity/ Inactivity detection available only in VLP/ULP mode */ - if (FIELD_GET(ADXL380_ACT_EN_MSK, act_inact_ctl) || - FIELD_GET(ADXL380_INACT_EN_MSK, act_inact_ctl)) + /* + * Activity/Inactivity detection available only in VLP/ULP + * mode and for devices that support low power modes. Otherwise + * go straight to measure mode (same bits as ADXL380_OP_MODE_HP). + */ + if (st->chip_info->has_low_power && + (FIELD_GET(ADXL380_ACT_EN_MSK, act_inact_ctl) || + FIELD_GET(ADXL380_INACT_EN_MSK, act_inact_ctl))) op_mode = ADXL380_OP_MODE_VLP; else op_mode = ADXL380_OP_MODE_HP; @@ -1618,6 +1590,15 @@ static int adxl380_set_watermark(struct iio_dev *indio_dev, unsigned int val) return 0; } +static const struct iio_info adxl318_info = { + .read_raw = adxl380_read_raw, + .read_avail = &adxl380_read_avail, + .write_raw = adxl380_write_raw, + .write_raw_get_fmt = adxl380_write_raw_get_fmt, + .debugfs_reg_access = &adxl380_reg_access, + .hwfifo_set_watermark = adxl380_set_watermark, +}; + static const struct iio_info adxl380_info = { .read_raw = adxl380_read_raw, .read_avail = &adxl380_read_avail, @@ -1632,6 +1613,81 @@ static const struct iio_info adxl380_info = { .hwfifo_set_watermark = adxl380_set_watermark, }; +const struct adxl380_chip_info adxl318_chip_info = { + .name = "adxl318", + .chip_id = ADXL318_ID_VAL, + .scale_tbl = { + [ADXL380_OP_MODE_4G_RANGE] = { 0, 1307226 }, + [ADXL380_OP_MODE_8G_RANGE] = { 0, 2615434 }, + [ADXL380_OP_MODE_16G_RANGE] = { 0, 5229886 }, + }, + .samp_freq_tbl = { 8000, 16000, 32000 }, + /* + * The datasheet defines an intercept of 550 LSB at 25 degC + * and a sensitivity of 10.2 LSB/C. + */ + .temp_offset = 25 * 102 / 10 - 550, + .info = &adxl318_info, +}; +EXPORT_SYMBOL_NS_GPL(adxl318_chip_info, "IIO_ADXL380"); + +const struct adxl380_chip_info adxl319_chip_info = { + .name = "adxl319", + .chip_id = ADXL319_ID_VAL, + .scale_tbl = { + [ADXL382_OP_MODE_15G_RANGE] = { 0, 4903325 }, + [ADXL382_OP_MODE_30G_RANGE] = { 0, 9806650 }, + [ADXL382_OP_MODE_60G_RANGE] = { 0, 19613300 }, + }, + .samp_freq_tbl = { 16000, 32000, 64000 }, + /* + * The datasheet defines an intercept of 550 LSB at 25 degC + * and a sensitivity of 10.2 LSB/C. + */ + .temp_offset = 25 * 102 / 10 - 550, + .info = &adxl318_info, +}; +EXPORT_SYMBOL_NS_GPL(adxl319_chip_info, "IIO_ADXL380"); + +const struct adxl380_chip_info adxl380_chip_info = { + .name = "adxl380", + .chip_id = ADXL380_ID_VAL, + .scale_tbl = { + [ADXL380_OP_MODE_4G_RANGE] = { 0, 1307226 }, + [ADXL380_OP_MODE_8G_RANGE] = { 0, 2615434 }, + [ADXL380_OP_MODE_16G_RANGE] = { 0, 5229886 }, + }, + .samp_freq_tbl = { 8000, 16000, 32000 }, + /* + * The datasheet defines an intercept of 470 LSB at 25 degC + * and a sensitivity of 10.2 LSB/C. + */ + .temp_offset = 25 * 102 / 10 - 470, + .has_low_power = true, + .info = &adxl380_info, + +}; +EXPORT_SYMBOL_NS_GPL(adxl380_chip_info, "IIO_ADXL380"); + +const struct adxl380_chip_info adxl382_chip_info = { + .name = "adxl382", + .chip_id = ADXL382_ID_VAL, + .scale_tbl = { + [ADXL382_OP_MODE_15G_RANGE] = { 0, 4903325 }, + [ADXL382_OP_MODE_30G_RANGE] = { 0, 9806650 }, + [ADXL382_OP_MODE_60G_RANGE] = { 0, 19613300 }, + }, + .samp_freq_tbl = { 16000, 32000, 64000 }, + /* + * The datasheet defines an intercept of 570 LSB at 25 degC + * and a sensitivity of 10.2 LSB/C. + */ + .temp_offset = 25 * 102 / 10 - 570, + .has_low_power = true, + .info = &adxl380_info, +}; +EXPORT_SYMBOL_NS_GPL(adxl382_chip_info, "IIO_ADXL380"); + static const struct iio_event_spec adxl380_events[] = { { .type = IIO_EV_TYPE_THRESH, @@ -1866,7 +1922,7 @@ int adxl380_probe(struct device *dev, struct regmap *regmap, indio_dev->channels = adxl380_channels; indio_dev->num_channels = ARRAY_SIZE(adxl380_channels); indio_dev->name = chip_info->name; - indio_dev->info = &adxl380_info; + indio_dev->info = chip_info->info; indio_dev->modes = INDIO_DIRECT_MODE; ret = devm_regulator_get_enable(dev, "vddio"); diff --git a/drivers/iio/accel/adxl380.h b/drivers/iio/accel/adxl380.h index a683625d897a..e67c5aab8efc 100644 --- a/drivers/iio/accel/adxl380.h +++ b/drivers/iio/accel/adxl380.h @@ -12,10 +12,14 @@ struct adxl380_chip_info { const char *name; const int scale_tbl[3][2]; const int samp_freq_tbl[3]; + const struct iio_info *info; const int temp_offset; const u16 chip_id; + const bool has_low_power; }; +extern const struct adxl380_chip_info adxl318_chip_info; +extern const struct adxl380_chip_info adxl319_chip_info; extern const struct adxl380_chip_info adxl380_chip_info; extern const struct adxl380_chip_info adxl382_chip_info; diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c index b4f86f972361..bd8782d08c7d 100644 --- a/drivers/iio/accel/adxl380_i2c.c +++ b/drivers/iio/accel/adxl380_i2c.c @@ -33,6 +33,8 @@ static int adxl380_i2c_probe(struct i2c_client *client) } static const struct i2c_device_id adxl380_i2c_id[] = { + { "adxl318", (kernel_ulong_t)&adxl318_chip_info }, + { "adxl319", (kernel_ulong_t)&adxl319_chip_info }, { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, { } @@ -40,6 +42,8 @@ static const struct i2c_device_id adxl380_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, adxl380_i2c_id); static const struct of_device_id adxl380_of_match[] = { + { .compatible = "adi,adxl318", .data = &adxl318_chip_info }, + { .compatible = "adi,adxl319", .data = &adxl319_chip_info }, { .compatible = "adi,adxl380", .data = &adxl380_chip_info }, { .compatible = "adi,adxl382", .data = &adxl382_chip_info }, { } diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c index 6edd0d211ffa..4ead949b24f1 100644 --- a/drivers/iio/accel/adxl380_spi.c +++ b/drivers/iio/accel/adxl380_spi.c @@ -35,6 +35,8 @@ static int adxl380_spi_probe(struct spi_device *spi) } static const struct spi_device_id adxl380_spi_id[] = { + { "adxl318", (kernel_ulong_t)&adxl318_chip_info }, + { "adxl319", (kernel_ulong_t)&adxl319_chip_info }, { "adxl380", (kernel_ulong_t)&adxl380_chip_info }, { "adxl382", (kernel_ulong_t)&adxl382_chip_info }, { } @@ -42,6 +44,8 @@ static const struct spi_device_id adxl380_spi_id[] = { MODULE_DEVICE_TABLE(spi, adxl380_spi_id); static const struct of_device_id adxl380_of_match[] = { + { .compatible = "adi,adxl318", .data = &adxl318_chip_info }, + { .compatible = "adi,adxl319", .data = &adxl319_chip_info }, { .compatible = "adi,adxl380", .data = &adxl380_chip_info }, { .compatible = "adi,adxl382", .data = &adxl382_chip_info }, { } diff --git a/drivers/iio/accel/bma220.h b/drivers/iio/accel/bma220.h new file mode 100644 index 000000000000..00dfe275256b --- /dev/null +++ b/drivers/iio/accel/bma220.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Forward declarations needed by the bma220 sources. + * + * Copyright 2025 Petre Rodan <petre.rodan@subdimension.ro> + */ + +#ifndef _BMA220_H +#define _BMA220_H + +#include <linux/pm.h> +#include <linux/regmap.h> + +#define BMA220_REG_WDT 0x17 +#define BMA220_WDT_MASK GENMASK(2, 1) +#define BMA220_WDT_OFF 0x0 +#define BMA220_WDT_1MS 0x2 +#define BMA220_WDT_10MS 0x3 + +struct device; + +extern const struct regmap_config bma220_i2c_regmap_config; +extern const struct regmap_config bma220_spi_regmap_config; +extern const struct dev_pm_ops bma220_pm_ops; + +int bma220_common_probe(struct device *dev, struct regmap *regmap, int irq); + +#endif diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c new file mode 100644 index 000000000000..f32d875b994e --- /dev/null +++ b/drivers/iio/accel/bma220_core.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * BMA220 Digital triaxial acceleration sensor driver + * + * Copyright (c) 2016,2020 Intel Corporation. + * Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro> + */ + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/cleanup.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#include "bma220.h" + +#define BMA220_REG_ID 0x00 +#define BMA220_REG_REVISION_ID 0x01 +#define BMA220_REG_ACCEL_X 0x02 +#define BMA220_REG_ACCEL_Y 0x03 +#define BMA220_REG_ACCEL_Z 0x04 +#define BMA220_REG_CONF0 0x05 +#define BMA220_HIGH_DUR_MSK GENMASK(5, 0) +#define BMA220_HIGH_HY_MSK GENMASK(7, 6) +#define BMA220_REG_CONF1 0x06 +#define BMA220_HIGH_TH_MSK GENMASK(3, 0) +#define BMA220_LOW_TH_MSK GENMASK(7, 4) +#define BMA220_REG_CONF2 0x07 +#define BMA220_LOW_DUR_MSK GENMASK(5, 0) +#define BMA220_LOW_HY_MSK GENMASK(7, 6) +#define BMA220_REG_CONF3 0x08 +#define BMA220_TT_DUR_MSK GENMASK(2, 0) +#define BMA220_TT_TH_MSK GENMASK(6, 3) +#define BMA220_REG_CONF4 0x09 +#define BMA220_SLOPE_DUR_MSK GENMASK(1, 0) +#define BMA220_SLOPE_TH_MSK GENMASK(5, 2) +#define BMA220_REG_CONF5 0x0a +#define BMA220_TIP_EN_MSK BIT(4) +#define BMA220_REG_IF0 0x0b +#define BMA220_REG_IF1 0x0c +#define BMA220_IF_SLOPE BIT(0) +#define BMA220_IF_DRDY BIT(1) +#define BMA220_IF_HIGH BIT(2) +#define BMA220_IF_LOW BIT(3) +#define BMA220_IF_TT BIT(4) +#define BMA220_REG_IE0 0x0d +#define BMA220_INT_EN_TAP_Z_MSK BIT(0) +#define BMA220_INT_EN_TAP_Y_MSK BIT(1) +#define BMA220_INT_EN_TAP_X_MSK BIT(2) +#define BMA220_INT_EN_SLOPE_Z_MSK BIT(3) +#define BMA220_INT_EN_SLOPE_Y_MSK BIT(4) +#define BMA220_INT_EN_SLOPE_X_MSK BIT(5) +#define BMA220_INT_EN_DRDY_MSK BIT(7) +#define BMA220_REG_IE1 0x0e +#define BMA220_INT_EN_HIGH_Z_MSK BIT(0) +#define BMA220_INT_EN_HIGH_Y_MSK BIT(1) +#define BMA220_INT_EN_HIGH_X_MSK BIT(2) +#define BMA220_INT_EN_LOW_MSK BIT(3) +#define BMA220_INT_LATCH_MSK GENMASK(6, 4) +#define BMA220_INT_RST_MSK BIT(7) +#define BMA220_REG_IE2 0x0f +#define BMA220_REG_FILTER 0x10 +#define BMA220_FILTER_MASK GENMASK(3, 0) +#define BMA220_REG_RANGE 0x11 +#define BMA220_RANGE_MASK GENMASK(1, 0) +#define BMA220_REG_SUSPEND 0x18 +#define BMA220_REG_SOFTRESET 0x19 + +#define BMA220_CHIP_ID 0xDD +#define BMA220_SUSPEND_SLEEP 0xFF +#define BMA220_SUSPEND_WAKE 0x00 +#define BMA220_RESET_MODE 0xFF +#define BMA220_NONRESET_MODE 0x00 + +#define BMA220_DEVICE_NAME "bma220" + +#define BMA220_COF_1000Hz 0x0 +#define BMA220_COF_500Hz 0x1 +#define BMA220_COF_250Hz 0x2 +#define BMA220_COF_125Hz 0x3 +#define BMA220_COF_64Hz 0x4 +#define BMA220_COF_32Hz 0x5 + +#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ + .type = IIO_ACCEL, \ + .address = reg, \ + .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_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) |\ + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ + .scan_index = index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 6, \ + .storagebits = 8, \ + .shift = 2, \ + .endianness = IIO_CPU, \ + }, \ +} + +enum bma220_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +static const int bma220_scale_table[][2] = { + { 0, 623000 }, { 1, 248000 }, { 2, 491000 }, { 4, 983000 }, +}; + +struct bma220_data { + struct regmap *regmap; + struct mutex lock; + u8 lpf_3dB_freq_idx; + u8 range_idx; + struct iio_trigger *trig; + struct { + s8 chans[3]; + /* Ensure timestamp is naturally aligned. */ + aligned_s64 timestamp; + } scan __aligned(IIO_DMA_MINALIGN); +}; + +static const struct iio_chan_spec bma220_channels[] = { + BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), + BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), + BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +/* Available cut-off frequencies of the low pass filter in Hz. */ +static const int bma220_lpf_3dB_freq_Hz_table[] = { + [BMA220_COF_1000Hz] = 1000, + [BMA220_COF_500Hz] = 500, + [BMA220_COF_250Hz] = 250, + [BMA220_COF_125Hz] = 125, + [BMA220_COF_64Hz] = 64, + [BMA220_COF_32Hz] = 32, +}; + +static const unsigned long bma220_accel_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0 +}; + +static bool bma220_is_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMA220_REG_CONF0: + case BMA220_REG_CONF1: + case BMA220_REG_CONF2: + case BMA220_REG_CONF3: + case BMA220_REG_CONF4: + case BMA220_REG_CONF5: + case BMA220_REG_IE0: + case BMA220_REG_IE1: + case BMA220_REG_IE2: + case BMA220_REG_FILTER: + case BMA220_REG_RANGE: + case BMA220_REG_WDT: + return true; + default: + return false; + } +} + +const struct regmap_config bma220_spi_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read_flag_mask = BIT(7), + .max_register = BMA220_REG_SOFTRESET, + .cache_type = REGCACHE_NONE, + .writeable_reg = bma220_is_writable_reg, +}; +EXPORT_SYMBOL_NS_GPL(bma220_spi_regmap_config, "IIO_BOSCH_BMA220"); + +/* + * Based on the datasheet the memory map differs between the SPI and the I2C + * implementations. I2C register addresses are simply shifted to the left + * by 1 bit yet the register size remains unchanged. + * This driver employs the SPI memory map to correlate register names to + * addresses regardless of the bus type. + */ + +const struct regmap_config bma220_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .reg_shift = -1, + .max_register = BMA220_REG_SOFTRESET, + .cache_type = REGCACHE_NONE, + .writeable_reg = bma220_is_writable_reg, +}; +EXPORT_SYMBOL_NS_GPL(bma220_i2c_regmap_config, "IIO_BOSCH_BMA220"); + +static int bma220_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bma220_data *data = iio_priv(indio_dev); + + return regmap_update_bits(data->regmap, BMA220_REG_IE0, + BMA220_INT_EN_DRDY_MSK, + FIELD_PREP(BMA220_INT_EN_DRDY_MSK, state)); +} + +static const struct iio_trigger_ops bma220_trigger_ops = { + .set_trigger_state = &bma220_data_rdy_trigger_set_state, + .validate_device = &iio_trigger_validate_own_device, +}; + +static irqreturn_t bma220_trigger_handler(int irq, void *p) +{ + int ret; + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bma220_data *data = iio_priv(indio_dev); + + ret = regmap_bulk_read(data->regmap, BMA220_REG_ACCEL_X, + &data->scan.chans, + sizeof(data->scan.chans)); + if (ret < 0) + return IRQ_NONE; + + iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), + iio_get_time_ns(indio_dev)); + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int bma220_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + u8 index; + unsigned int reg; + struct bma220_data *data = iio_priv(indio_dev); + + guard(mutex)(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_read(data->regmap, chan->address, ®); + if (ret < 0) + return -EINVAL; + *val = sign_extend32(reg >> chan->scan_type.shift, + chan->scan_type.realbits - 1); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + index = data->range_idx; + *val = bma220_scale_table[index][0]; + *val2 = bma220_scale_table[index][1]; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + index = data->lpf_3dB_freq_idx; + *val = bma220_lpf_3dB_freq_Hz_table[index]; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int bma220_find_match_2dt(const int (*tbl)[2], const int n, + const int val, const int val2) +{ + int i; + + for (i = 0; i < n; i++) { + if (tbl[i][0] == val && tbl[i][1] == val2) + return i; + } + + return -EINVAL; +} + +static int bma220_find_match(const int *arr, const int n, const int val) +{ + int i; + + for (i = 0; i < n; i++) { + if (arr[i] == val) + return i; + } + + return -EINVAL; +} + +static int bma220_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int ret; + int index = -1; + struct bma220_data *data = iio_priv(indio_dev); + + guard(mutex)(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + index = bma220_find_match_2dt(bma220_scale_table, + ARRAY_SIZE(bma220_scale_table), + val, val2); + if (index < 0) + return -EINVAL; + + ret = regmap_update_bits(data->regmap, BMA220_REG_RANGE, + BMA220_RANGE_MASK, + FIELD_PREP(BMA220_RANGE_MASK, index)); + if (ret < 0) + return ret; + data->range_idx = index; + + return 0; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + index = bma220_find_match(bma220_lpf_3dB_freq_Hz_table, + ARRAY_SIZE(bma220_lpf_3dB_freq_Hz_table), + val); + if (index < 0) + return -EINVAL; + + ret = regmap_update_bits(data->regmap, BMA220_REG_FILTER, + BMA220_FILTER_MASK, + FIELD_PREP(BMA220_FILTER_MASK, index)); + if (ret < 0) + return ret; + data->lpf_3dB_freq_idx = index; + + return 0; + } + + return -EINVAL; +} + +static int bma220_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: + *vals = (int *)bma220_scale_table; + *type = IIO_VAL_INT_PLUS_MICRO; + *length = ARRAY_SIZE(bma220_scale_table) * 2; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = (const int *)bma220_lpf_3dB_freq_Hz_table; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(bma220_lpf_3dB_freq_Hz_table); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int bma220_reg_access(struct iio_dev *indio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct bma220_data *data = iio_priv(indio_dev); + + if (readval) + return regmap_read(data->regmap, reg, readval); + return regmap_write(data->regmap, reg, writeval); +} + +static const struct iio_info bma220_info = { + .read_raw = bma220_read_raw, + .write_raw = bma220_write_raw, + .read_avail = bma220_read_avail, + .debugfs_reg_access = &bma220_reg_access, +}; + +static int bma220_reset(struct bma220_data *data, bool up) +{ + int ret; + unsigned int i, val; + + /* + * The chip can be reset by a simple register read. + * We need up to 2 register reads of the softreset register + * to make sure that the device is in the desired state. + */ + for (i = 0; i < 2; i++) { + ret = regmap_read(data->regmap, BMA220_REG_SOFTRESET, &val); + if (ret < 0) + return ret; + + if (up && val == BMA220_RESET_MODE) + return 0; + + if (!up && val == BMA220_NONRESET_MODE) + return 0; + } + + return -EBUSY; +} + +static int bma220_power(struct bma220_data *data, bool up) +{ + int ret; + unsigned int i, val; + + /* + * The chip can be suspended/woken up by a simple register read. + * So, we need up to 2 register reads of the suspend register + * to make sure that the device is in the desired state. + */ + for (i = 0; i < 2; i++) { + ret = regmap_read(data->regmap, BMA220_REG_SUSPEND, &val); + if (ret < 0) + return ret; + + if (up && val == BMA220_SUSPEND_SLEEP) + return 0; + + if (!up && val == BMA220_SUSPEND_WAKE) + return 0; + } + + return -EBUSY; +} + +static int bma220_init(struct device *dev, struct bma220_data *data) +{ + int ret; + unsigned int val; + static const char * const regulator_names[] = { "vddd", "vddio", "vdda" }; + + ret = devm_regulator_bulk_get_enable(dev, + ARRAY_SIZE(regulator_names), + regulator_names); + if (ret) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = regmap_read(data->regmap, BMA220_REG_ID, &val); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read chip id register\n"); + + if (val != BMA220_CHIP_ID) + dev_info(dev, "Unknown chip found: 0x%02x\n", val); + + ret = bma220_power(data, true); + if (ret) + return dev_err_probe(dev, ret, "Failed to power-on chip\n"); + + ret = bma220_reset(data, true); + if (ret) + return dev_err_probe(dev, ret, "Failed to soft reset chip\n"); + + return 0; +} + +static void bma220_deinit(void *data_ptr) +{ + struct bma220_data *data = data_ptr; + int ret; + struct device *dev = regmap_get_device(data->regmap); + + ret = bma220_power(data, false); + if (ret) + dev_warn(dev, + "Failed to put device into suspend mode (%pe)\n", + ERR_PTR(ret)); +} + +static irqreturn_t bma220_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bma220_data *data = iio_priv(indio_dev); + int ret; + unsigned int bma220_reg_if1; + + ret = regmap_read(data->regmap, BMA220_REG_IF1, &bma220_reg_if1); + if (ret) + return IRQ_NONE; + + if (FIELD_GET(BMA220_IF_DRDY, bma220_reg_if1)) + iio_trigger_poll_nested(data->trig); + + return IRQ_HANDLED; +} + +int bma220_common_probe(struct device *dev, struct regmap *regmap, int irq) +{ + int ret; + struct iio_dev *indio_dev; + struct bma220_data *data; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->regmap = regmap; + + ret = bma220_init(dev, data); + if (ret) + return ret; + + ret = devm_mutex_init(dev, &data->lock); + if (ret) + return ret; + + indio_dev->info = &bma220_info; + indio_dev->name = BMA220_DEVICE_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = bma220_channels; + indio_dev->num_channels = ARRAY_SIZE(bma220_channels); + indio_dev->available_scan_masks = bma220_accel_scan_masks; + + 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 = &bma220_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + + ret = devm_iio_trigger_register(dev, data->trig); + if (ret) + return dev_err_probe(dev, ret, + "iio trigger register fail\n"); + indio_dev->trig = iio_trigger_get(data->trig); + ret = devm_request_threaded_irq(dev, irq, NULL, + &bma220_irq_handler, IRQF_ONESHOT, + indio_dev->name, indio_dev); + if (ret) + return dev_err_probe(dev, ret, + "request irq %d failed\n", irq); + } + + ret = devm_add_action_or_reset(dev, bma220_deinit, data); + if (ret) + return ret; + + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + bma220_trigger_handler, NULL); + if (ret < 0) + dev_err_probe(dev, ret, "iio triggered buffer setup failed\n"); + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(bma220_common_probe, "IIO_BOSCH_BMA220"); + +static int bma220_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bma220_data *data = iio_priv(indio_dev); + + return bma220_power(data, false); +} + +static int bma220_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct bma220_data *data = iio_priv(indio_dev); + + return bma220_power(data, true); +} +EXPORT_NS_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume, + IIO_BOSCH_BMA220); + +MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); +MODULE_DESCRIPTION("BMA220 acceleration sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/accel/bma220_i2c.c b/drivers/iio/accel/bma220_i2c.c new file mode 100644 index 000000000000..8b6f8e305c8c --- /dev/null +++ b/drivers/iio/accel/bma220_i2c.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Bosch triaxial acceleration sensor + * + * Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro> + * + * Datasheet: https://media.digikey.com/pdf/Data%20Sheets/Bosch/BMA220.pdf + * I2C address is either 0x0b or 0x0a depending on CSB (pin 10) + */ + +#include <linux/bitfield.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include "bma220.h" + +static int bma220_set_wdt(struct regmap *regmap, const u8 val) +{ + return regmap_update_bits(regmap, BMA220_REG_WDT, BMA220_WDT_MASK, + FIELD_PREP(BMA220_WDT_MASK, val)); +} + +static int bma220_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + int ret; + + regmap = devm_regmap_init_i2c(client, &bma220_i2c_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(&client->dev, PTR_ERR(regmap), + "failed to create regmap\n"); + + ret = bma220_common_probe(&client->dev, regmap, client->irq); + if (ret) + return ret; + + return bma220_set_wdt(regmap, BMA220_WDT_1MS); +} + +static const struct of_device_id bma220_i2c_match[] = { + { .compatible = "bosch,bma220" }, + { } +}; +MODULE_DEVICE_TABLE(of, bma220_i2c_match); + +static const struct i2c_device_id bma220_i2c_id[] = { + { "bma220" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bma220_i2c_id); + +static struct i2c_driver bma220_i2c_driver = { + .driver = { + .name = "bma220_i2c", + .pm = pm_sleep_ptr(&bma220_pm_ops), + .of_match_table = bma220_i2c_match, + }, + .probe = bma220_i2c_probe, + .id_table = bma220_i2c_id, +}; +module_i2c_driver(bma220_i2c_driver); + +MODULE_AUTHOR("Petre Rodan <petre.rodan@subdimension.ro>"); +MODULE_DESCRIPTION("Bosch triaxial acceleration sensor i2c driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BOSCH_BMA220"); diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 01592eebf05b..383ee8a135ee 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -5,326 +5,56 @@ * Copyright (c) 2016,2020 Intel Corporation. */ -#include <linux/bits.h> -#include <linux/kernel.h> #include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/regmap.h> #include <linux/types.h> #include <linux/spi/spi.h> -#include <linux/iio/buffer.h> -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> +#include "bma220.h" -#define BMA220_REG_ID 0x00 -#define BMA220_REG_ACCEL_X 0x02 -#define BMA220_REG_ACCEL_Y 0x03 -#define BMA220_REG_ACCEL_Z 0x04 -#define BMA220_REG_RANGE 0x11 -#define BMA220_REG_SUSPEND 0x18 - -#define BMA220_CHIP_ID 0xDD -#define BMA220_READ_MASK BIT(7) -#define BMA220_RANGE_MASK GENMASK(1, 0) -#define BMA220_SUSPEND_SLEEP 0xFF -#define BMA220_SUSPEND_WAKE 0x00 - -#define BMA220_DEVICE_NAME "bma220" - -#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ - .type = IIO_ACCEL, \ - .address = reg, \ - .modified = 1, \ - .channel2 = IIO_MOD_##axis, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .scan_index = index, \ - .scan_type = { \ - .sign = 's', \ - .realbits = 6, \ - .storagebits = 8, \ - .shift = 2, \ - .endianness = IIO_CPU, \ - }, \ -} - -enum bma220_axis { - AXIS_X, - AXIS_Y, - AXIS_Z, -}; - -static const int bma220_scale_table[][2] = { - {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}, -}; - -struct bma220_data { - struct spi_device *spi_device; - struct mutex lock; - struct { - s8 chans[3]; - /* Ensure timestamp is naturally aligned. */ - aligned_s64 timestamp; - } scan; - u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN); -}; - -static const struct iio_chan_spec bma220_channels[] = { - BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), - BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), - BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), - IIO_CHAN_SOFT_TIMESTAMP(3), -}; - -static inline int bma220_read_reg(struct spi_device *spi, u8 reg) +static int bma220_spi_probe(struct spi_device *spi) { - return spi_w8r8(spi, reg | BMA220_READ_MASK); -} - -static const unsigned long bma220_accel_scan_masks[] = { - BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), - 0 -}; - -static irqreturn_t bma220_trigger_handler(int irq, void *p) -{ - int ret; - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct bma220_data *data = iio_priv(indio_dev); - struct spi_device *spi = data->spi_device; - - mutex_lock(&data->lock); - data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; - ret = spi_write_then_read(spi, data->tx_buf, 1, &data->scan.chans, - ARRAY_SIZE(bma220_channels) - 1); - if (ret < 0) - goto err; + struct regmap *regmap; - iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan), - pf->timestamp); -err: - mutex_unlock(&data->lock); - iio_trigger_notify_done(indio_dev->trig); + regmap = devm_regmap_init_spi(spi, &bma220_spi_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(&spi->dev, PTR_ERR(regmap), + "failed to create regmap\n"); - return IRQ_HANDLED; + return bma220_common_probe(&spi->dev, regmap, spi->irq); } -static int bma220_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) -{ - int ret; - u8 range_idx; - struct bma220_data *data = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_RAW: - ret = bma220_read_reg(data->spi_device, chan->address); - if (ret < 0) - return -EINVAL; - *val = sign_extend32(ret >> chan->scan_type.shift, - chan->scan_type.realbits - 1); - return IIO_VAL_INT; - case IIO_CHAN_INFO_SCALE: - ret = bma220_read_reg(data->spi_device, BMA220_REG_RANGE); - if (ret < 0) - return ret; - range_idx = ret & BMA220_RANGE_MASK; - *val = bma220_scale_table[range_idx][0]; - *val2 = bma220_scale_table[range_idx][1]; - return IIO_VAL_INT_PLUS_MICRO; - } - - return -EINVAL; -} - -static int bma220_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int val, int val2, long mask) -{ - int i; - int ret; - int index = -1; - struct bma220_data *data = iio_priv(indio_dev); - - switch (mask) { - case IIO_CHAN_INFO_SCALE: - for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++) - if (val == bma220_scale_table[i][0] && - val2 == bma220_scale_table[i][1]) { - index = i; - break; - } - if (index < 0) - return -EINVAL; - - mutex_lock(&data->lock); - data->tx_buf[0] = BMA220_REG_RANGE; - data->tx_buf[1] = index; - ret = spi_write(data->spi_device, data->tx_buf, - sizeof(data->tx_buf)); - if (ret < 0) - dev_err(&data->spi_device->dev, - "failed to set measurement range\n"); - mutex_unlock(&data->lock); - - return 0; - } - - return -EINVAL; -} - -static int bma220_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: - *vals = (int *)bma220_scale_table; - *type = IIO_VAL_INT_PLUS_MICRO; - *length = ARRAY_SIZE(bma220_scale_table) * 2; - return IIO_AVAIL_LIST; - default: - return -EINVAL; - } -} - -static const struct iio_info bma220_info = { - .read_raw = bma220_read_raw, - .write_raw = bma220_write_raw, - .read_avail = bma220_read_avail, -}; - -static int bma220_init(struct spi_device *spi) -{ - int ret; - - ret = bma220_read_reg(spi, BMA220_REG_ID); - if (ret != BMA220_CHIP_ID) - return -ENODEV; - - /* Make sure the chip is powered on */ - ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); - if (ret == BMA220_SUSPEND_WAKE) - ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); - if (ret < 0) - return ret; - if (ret == BMA220_SUSPEND_WAKE) - return -EBUSY; - - return 0; -} - -static int bma220_power(struct spi_device *spi, bool up) -{ - int i, ret; - - /** - * The chip can be suspended/woken up by a simple register read. - * So, we need up to 2 register reads of the suspend register - * to make sure that the device is in the desired state. - */ - for (i = 0; i < 2; i++) { - ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); - if (ret < 0) - return ret; - - if (up && ret == BMA220_SUSPEND_SLEEP) - return 0; - - if (!up && ret == BMA220_SUSPEND_WAKE) - return 0; - } - - return -EBUSY; -} - -static void bma220_deinit(void *spi) -{ - bma220_power(spi, false); -} - -static int bma220_probe(struct spi_device *spi) -{ - int ret; - struct iio_dev *indio_dev; - struct bma220_data *data; - - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data)); - if (!indio_dev) - return -ENOMEM; - - data = iio_priv(indio_dev); - data->spi_device = spi; - mutex_init(&data->lock); - - indio_dev->info = &bma220_info; - indio_dev->name = BMA220_DEVICE_NAME; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = bma220_channels; - indio_dev->num_channels = ARRAY_SIZE(bma220_channels); - indio_dev->available_scan_masks = bma220_accel_scan_masks; - - ret = bma220_init(data->spi_device); - if (ret) - return ret; - - ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi); - if (ret) - return ret; - - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, - iio_pollfunc_store_time, - bma220_trigger_handler, NULL); - if (ret < 0) { - dev_err(&spi->dev, "iio triggered buffer setup failed\n"); - return ret; - } - - return devm_iio_device_register(&spi->dev, indio_dev); -} - -static int bma220_suspend(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - - return bma220_power(spi, false); -} - -static int bma220_resume(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - - return bma220_power(spi, true); -} -static DEFINE_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); - static const struct spi_device_id bma220_spi_id[] = { - {"bma220", 0}, + { "bma220", 0 }, { } }; static const struct acpi_device_id bma220_acpi_id[] = { - {"BMA0220", 0}, + { "BMA0220", 0 }, { } }; MODULE_DEVICE_TABLE(spi, bma220_spi_id); -static struct spi_driver bma220_driver = { +static const struct of_device_id bma220_of_spi_match[] = { + { .compatible = "bosch,bma220" }, + { } +}; +MODULE_DEVICE_TABLE(of, bma220_of_spi_match); + +static struct spi_driver bma220_spi_driver = { .driver = { .name = "bma220_spi", .pm = pm_sleep_ptr(&bma220_pm_ops), + .of_match_table = bma220_of_spi_match, .acpi_match_table = bma220_acpi_id, }, - .probe = bma220_probe, + .probe = bma220_spi_probe, .id_table = bma220_spi_id, }; -module_spi_driver(bma220_driver); +module_spi_driver(bma220_spi_driver); MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); -MODULE_DESCRIPTION("BMA220 acceleration sensor driver"); -MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMA220 triaxial acceleration sensor spi driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_BOSCH_BMA220"); diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h index 932358b45f17..b5f3cac51610 100644 --- a/drivers/iio/accel/bma400.h +++ b/drivers/iio/accel/bma400.h @@ -16,31 +16,44 @@ * Read-Only Registers */ +/* Chip ID of BMA 400 devices found in the chip ID register. */ +#define BMA400_ID_REG_VAL 0x90 + /* Status and ID registers */ #define BMA400_CHIP_ID_REG 0x00 #define BMA400_ERR_REG 0x02 #define BMA400_STATUS_REG 0x03 /* Acceleration registers */ -#define BMA400_X_AXIS_LSB_REG 0x04 -#define BMA400_X_AXIS_MSB_REG 0x05 -#define BMA400_Y_AXIS_LSB_REG 0x06 -#define BMA400_Y_AXIS_MSB_REG 0x07 -#define BMA400_Z_AXIS_LSB_REG 0x08 -#define BMA400_Z_AXIS_MSB_REG 0x09 +#define BMA400_ACC_X_LSB_REG 0x04 +#define BMA400_ACC_X_MSB_REG 0x05 +#define BMA400_ACC_Y_LSB_REG 0x06 +#define BMA400_ACC_Y_MSB_REG 0x07 +#define BMA400_ACC_Z_LSB_REG 0x08 +#define BMA400_ACC_Z_MSB_REG 0x09 /* Sensor time registers */ -#define BMA400_SENSOR_TIME0 0x0a -#define BMA400_SENSOR_TIME1 0x0b -#define BMA400_SENSOR_TIME2 0x0c +#define BMA400_SENSOR_TIME0_REG 0x0a +#define BMA400_SENSOR_TIME1_REG 0x0b +#define BMA400_SENSOR_TIME2_REG 0x0c /* Event and interrupt registers */ #define BMA400_EVENT_REG 0x0d + #define BMA400_INT_STAT0_REG 0x0e +#define BMA400_INT_STAT0_GEN1_MASK BIT(2) +#define BMA400_INT_STAT0_GEN2_MASK BIT(3) +#define BMA400_INT_STAT0_DRDY_MASK BIT(7) + #define BMA400_INT_STAT1_REG 0x0f +#define BMA400_INT_STAT1_STEP_INT_MASK GENMASK(9, 8) +#define BMA400_INT_STAT1_S_TAP_MASK BIT(10) +#define BMA400_INT_STAT1_D_TAP_MASK BIT(11) + #define BMA400_INT_STAT2_REG 0x10 -#define BMA400_INT12_MAP_REG 0x23 -#define BMA400_INT_ENG_OVRUN_MSK BIT(4) + +/* Bit present in all INT_STAT registers */ +#define BMA400_INT_STAT_ENG_OVRRUN_MASK BIT(4) /* Temperature register */ #define BMA400_TEMP_DATA_REG 0x11 @@ -55,70 +68,100 @@ #define BMA400_STEP_CNT1_REG 0x16 #define BMA400_STEP_CNT3_REG 0x17 #define BMA400_STEP_STAT_REG 0x18 -#define BMA400_STEP_INT_MSK BIT(0) #define BMA400_STEP_RAW_LEN 0x03 -#define BMA400_STEP_STAT_MASK GENMASK(9, 8) /* * Read-write configuration registers */ -#define BMA400_ACC_CONFIG0_REG 0x19 -#define BMA400_ACC_CONFIG1_REG 0x1a +#define BMA400_ACC_CONFIG0_REG 0x19 +#define BMA400_ACC_CONFIG0_LP_OSR_MASK GENMASK(6, 5) + +#define BMA400_ACC_CONFIG1_REG 0x1a +#define BMA400_ACC_CONFIG1_ODR_MASK GENMASK(3, 0) +#define BMA400_ACC_CONFIG1_ODR_MIN_RAW 0x05 +#define BMA400_ACC_CONFIG1_ODR_LP_RAW 0x06 +#define BMA400_ACC_CONFIG1_ODR_MAX_RAW 0x0b +#define BMA400_ACC_CONFIG1_ODR_MAX_HZ 800 +#define BMA400_ACC_CONFIG1_ODR_MIN_WHOLE_HZ 25 +#define BMA400_ACC_CONFIG1_ODR_MIN_HZ 12 +#define BMA400_ACC_CONFIG1_NP_OSR_MASK GENMASK(5, 4) +#define BMA400_ACC_CONFIG1_ACC_RANGE_MASK GENMASK(7, 6) + #define BMA400_ACC_CONFIG2_REG 0x1b -#define BMA400_CMD_REG 0x7e /* Interrupt registers */ #define BMA400_INT_CONFIG0_REG 0x1f +#define BMA400_INT_CONFIG0_GEN1_MASK BIT(2) +#define BMA400_INT_CONFIG0_GEN2_MASK BIT(3) +#define BMA400_INT_CONFIG0_DRDY_MASK BIT(7) + +enum bma400_generic_intr { + BMA400_GEN1_INTR = 0x1, + BMA400_GEN2_INTR = 0x2, +}; + #define BMA400_INT_CONFIG1_REG 0x20 +#define BMA400_INT_CONFIG1_STEP_INT_MASK BIT(0) +#define BMA400_INT_CONFIG1_S_TAP_MASK BIT(2) +#define BMA400_INT_CONFIG1_D_TAP_MASK BIT(3) + #define BMA400_INT1_MAP_REG 0x21 +#define BMA400_INT12_MAP_REG 0x23 #define BMA400_INT_IO_CTRL_REG 0x24 -#define BMA400_INT_DRDY_MSK BIT(7) - -/* Chip ID of BMA 400 devices found in the chip ID register. */ -#define BMA400_ID_REG_VAL 0x90 - -#define BMA400_LP_OSR_SHIFT 5 -#define BMA400_NP_OSR_SHIFT 4 -#define BMA400_SCALE_SHIFT 6 #define BMA400_TWO_BITS_MASK GENMASK(1, 0) -#define BMA400_LP_OSR_MASK GENMASK(6, 5) -#define BMA400_NP_OSR_MASK GENMASK(5, 4) -#define BMA400_ACC_ODR_MASK GENMASK(3, 0) -#define BMA400_ACC_SCALE_MASK GENMASK(7, 6) - -#define BMA400_ACC_ODR_MIN_RAW 0x05 -#define BMA400_ACC_ODR_LP_RAW 0x06 -#define BMA400_ACC_ODR_MAX_RAW 0x0b - -#define BMA400_ACC_ODR_MAX_HZ 800 -#define BMA400_ACC_ODR_MIN_WHOLE_HZ 25 -#define BMA400_ACC_ODR_MIN_HZ 12 /* Generic interrupts register */ -#define BMA400_GEN1INT_CONFIG0 0x3f -#define BMA400_GEN2INT_CONFIG0 0x4A +#define BMA400_GENINT_CONFIG_REG_BASE 0x3f +#define BMA400_NUM_GENINT_CONFIG_REGS 11 +#define BMA400_GENINT_CONFIG_REG(gen_intr, config_idx) \ + (BMA400_GENINT_CONFIG_REG_BASE + \ + (gen_intr - 1) * BMA400_NUM_GENINT_CONFIG_REGS + \ + (config_idx)) +#define BMA400_GENINT_CONFIG0_HYST_MASK GENMASK(1, 0) +#define BMA400_GENINT_CONFIG0_REF_UPD_MODE_MASK GENMASK(3, 2) +#define BMA400_GENINT_CONFIG0_DATA_SRC_MASK BIT(4) +#define BMA400_GENINT_CONFIG0_X_EN_MASK BIT(5) +#define BMA400_GENINT_CONFIG0_Y_EN_MASK BIT(6) +#define BMA400_GENINT_CONFIG0_Z_EN_MASK BIT(7) + +enum bma400_accel_data_src { + ACCEL_FILT1 = 0x0, + ACCEL_FILT2 = 0x1, +}; + +enum bma400_ref_updt_mode { + BMA400_REF_MANUAL_UPDT_MODE = 0x0, + BMA400_REF_ONETIME_UPDT_MODE = 0x1, + BMA400_REF_EVERYTIME_UPDT_MODE = 0x2, + BMA400_REF_EVERYTIME_LP_UPDT_MODE = 0x3, +}; + #define BMA400_GEN_CONFIG1_OFF 0x01 -#define BMA400_GEN_CONFIG2_OFF 0x02 -#define BMA400_GEN_CONFIG3_OFF 0x03 -#define BMA400_GEN_CONFIG31_OFF 0x04 -#define BMA400_INT_GEN1_MSK BIT(2) -#define BMA400_INT_GEN2_MSK BIT(3) -#define BMA400_GEN_HYST_MSK GENMASK(1, 0) +#define BMA400_GENINT_CONFIG1_AXES_COMB_MASK BIT(0) +#define BMA400_GENINT_CONFIG1_DETCT_CRIT_MASK BIT(1) + +enum bma400_genintr_acceleval_axescomb { + BMA400_EVAL_X_OR_Y_OR_Z = 0x0, + BMA400_EVAL_X_AND_Y_AND_Z = 0x1, +}; + +enum bma400_detect_criterion { + BMA400_DETECT_INACTIVITY = 0x0, + BMA400_DETECT_ACTIVITY = 0x1, +}; /* TAP config registers */ -#define BMA400_TAP_CONFIG 0x57 -#define BMA400_TAP_CONFIG1 0x58 -#define BMA400_S_TAP_MSK BIT(2) -#define BMA400_D_TAP_MSK BIT(3) -#define BMA400_INT_S_TAP_MSK BIT(10) -#define BMA400_INT_D_TAP_MSK BIT(11) -#define BMA400_TAP_SEN_MSK GENMASK(2, 0) -#define BMA400_TAP_TICSTH_MSK GENMASK(1, 0) -#define BMA400_TAP_QUIET_MSK GENMASK(3, 2) -#define BMA400_TAP_QUIETDT_MSK GENMASK(5, 4) +#define BMA400_TAP_CONFIG_REG 0x57 +#define BMA400_TAP_CONFIG_SEN_MASK GENMASK(2, 0) + +#define BMA400_TAP_CONFIG1_REG 0x58 +#define BMA400_TAP_CONFIG1_TICSTH_MASK GENMASK(1, 0) +#define BMA400_TAP_CONFIG1_QUIET_MASK GENMASK(3, 2) +#define BMA400_TAP_CONFIG1_QUIETDT_MASK GENMASK(5, 4) #define BMA400_TAP_TIM_LIST_LEN 4 +#define BMA400_CMD_REG 0x7e /* * BMA400_SCALE_MIN macro value represents m/s^2 for 1 LSB before * converting to micro values for +-2g range. @@ -138,8 +181,8 @@ * To select +-8g = 9577 << 2 = raw value to write is 2. * To select +-16g = 9577 << 3 = raw value to write is 3. */ -#define BMA400_SCALE_MIN 9577 -#define BMA400_SCALE_MAX 76617 +#define BMA400_ACC_SCALE_MIN 9577 +#define BMA400_ACC_SCALE_MAX 76617 extern const struct regmap_config bma400_regmap_config; diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c index 85e23badf733..05f72707f830 100644 --- a/drivers/iio/accel/bma400_core.c +++ b/drivers/iio/accel/bma400_core.c @@ -121,21 +121,56 @@ struct bma400_data { __be16 duration; }; +struct bma400_genintr_info { + enum bma400_generic_intr genintr; + unsigned int intrmask; + enum iio_event_direction dir; + enum bma400_detect_criterion detect_mode; +}; + +/* Lookup struct for determining GEN1/GEN2 based on dir */ +static const struct bma400_genintr_info bma400_genintrs[] = { + [IIO_EV_DIR_RISING] = { + .genintr = BMA400_GEN1_INTR, + .intrmask = BMA400_INT_CONFIG0_GEN1_MASK, + .dir = IIO_EV_DIR_RISING, + .detect_mode = BMA400_DETECT_ACTIVITY, + }, + [IIO_EV_DIR_FALLING] = { + .genintr = BMA400_GEN2_INTR, + .intrmask = BMA400_INT_CONFIG0_GEN2_MASK, + .dir = IIO_EV_DIR_FALLING, + .detect_mode = BMA400_DETECT_INACTIVITY, + } +}; + +static inline const struct bma400_genintr_info * +get_bma400_genintr_info(enum iio_event_direction dir) +{ + switch (dir) { + case IIO_EV_DIR_RISING: + case IIO_EV_DIR_FALLING: + return &bma400_genintrs[dir]; + default: + return NULL; + }; +} + 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_ACC_X_LSB_REG: + case BMA400_ACC_X_MSB_REG: + case BMA400_ACC_Y_LSB_REG: + case BMA400_ACC_Y_MSB_REG: + case BMA400_ACC_Z_LSB_REG: + case BMA400_ACC_Z_MSB_REG: + case BMA400_SENSOR_TIME0_REG: + case BMA400_SENSOR_TIME1_REG: + case BMA400_SENSOR_TIME2_REG: case BMA400_EVENT_REG: case BMA400_INT_STAT0_REG: case BMA400_INT_STAT1_REG: @@ -159,15 +194,15 @@ 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_ACC_X_LSB_REG: + case BMA400_ACC_X_MSB_REG: + case BMA400_ACC_Y_LSB_REG: + case BMA400_ACC_Y_MSB_REG: + case BMA400_ACC_Z_LSB_REG: + case BMA400_ACC_Z_MSB_REG: + case BMA400_SENSOR_TIME0_REG: + case BMA400_SENSOR_TIME1_REG: + case BMA400_SENSOR_TIME2_REG: case BMA400_EVENT_REG: case BMA400_INT_STAT0_REG: case BMA400_INT_STAT1_REG: @@ -275,11 +310,11 @@ static ssize_t in_accel_gesture_tap_maxtomin_time_show(struct device *dev, struct bma400_data *data = iio_priv(indio_dev); int ret, reg_val, raw, vals[2]; - ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1, ®_val); + ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1_REG, ®_val); if (ret) return ret; - raw = FIELD_GET(BMA400_TAP_TICSTH_MSK, reg_val); + raw = FIELD_GET(BMA400_TAP_CONFIG1_TICSTH_MASK, reg_val); vals[0] = 0; vals[1] = tap_max2min_time[raw]; @@ -302,9 +337,9 @@ static ssize_t in_accel_gesture_tap_maxtomin_time_store(struct device *dev, 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)); + ret = regmap_update_bits(data->regmap, BMA400_TAP_CONFIG1_REG, + BMA400_TAP_CONFIG1_TICSTH_MASK, + FIELD_PREP(BMA400_TAP_CONFIG1_TICSTH_MASK, raw)); if (ret) return ret; @@ -449,13 +484,13 @@ static int bma400_get_accel_reg(struct bma400_data *data, switch (chan->channel2) { case IIO_MOD_X: - lsb_reg = BMA400_X_AXIS_LSB_REG; + lsb_reg = BMA400_ACC_X_LSB_REG; break; case IIO_MOD_Y: - lsb_reg = BMA400_Y_AXIS_LSB_REG; + lsb_reg = BMA400_ACC_Y_LSB_REG; break; case IIO_MOD_Z: - lsb_reg = BMA400_Z_AXIS_LSB_REG; + lsb_reg = BMA400_ACC_Z_LSB_REG; break; default: dev_err(data->dev, "invalid axis channel modifier\n"); @@ -475,8 +510,8 @@ static int bma400_get_accel_reg(struct bma400_data *data, 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) + *val = BMA400_ACC_CONFIG1_ODR_MAX_HZ >> (BMA400_ACC_CONFIG1_ODR_MAX_RAW - raw); + if (raw > BMA400_ACC_CONFIG1_ODR_MIN_RAW) *val2 = 0; else *val2 = 500000; @@ -494,7 +529,7 @@ static int bma400_get_accel_output_data_rate(struct bma400_data *data) * 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, + bma400_output_data_rate_from_raw(BMA400_ACC_CONFIG1_ODR_LP_RAW, &data->sample_freq.hz, &data->sample_freq.uhz); return 0; @@ -507,9 +542,9 @@ static int bma400_get_accel_output_data_rate(struct bma400_data *data) if (ret) goto error; - odr = val & BMA400_ACC_ODR_MASK; - if (odr < BMA400_ACC_ODR_MIN_RAW || - odr > BMA400_ACC_ODR_MAX_RAW) { + odr = val & BMA400_ACC_CONFIG1_ODR_MASK; + if (odr < BMA400_ACC_CONFIG1_ODR_MIN_RAW || + odr > BMA400_ACC_CONFIG1_ODR_MAX_RAW) { ret = -EINVAL; goto error; } @@ -539,19 +574,19 @@ static int bma400_set_accel_output_data_rate(struct bma400_data *data, unsigned int val; int ret; - if (hz >= BMA400_ACC_ODR_MIN_WHOLE_HZ) { - if (uhz || hz > BMA400_ACC_ODR_MAX_HZ) + if (hz >= BMA400_ACC_CONFIG1_ODR_MIN_WHOLE_HZ) { + if (uhz || hz > BMA400_ACC_CONFIG1_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) + if (hz >> idx != BMA400_ACC_CONFIG1_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; + idx += BMA400_ACC_CONFIG1_ODR_MIN_RAW + 1; + } else if (hz == BMA400_ACC_CONFIG1_ODR_MIN_HZ && uhz == 500000) { + idx = BMA400_ACC_CONFIG1_ODR_MIN_RAW; } else { return -EINVAL; } @@ -561,7 +596,7 @@ static int bma400_set_accel_output_data_rate(struct bma400_data *data, return ret; /* preserve the range and normal mode osr */ - odr = (~BMA400_ACC_ODR_MASK & val) | idx; + odr = (~BMA400_ACC_CONFIG1_ODR_MASK & val) | idx; ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, odr); if (ret) @@ -592,7 +627,7 @@ static int bma400_get_accel_oversampling_ratio(struct bma400_data *data) return ret; } - osr = (val & BMA400_LP_OSR_MASK) >> BMA400_LP_OSR_SHIFT; + osr = FIELD_GET(BMA400_ACC_CONFIG0_LP_OSR_MASK, val); data->oversampling_ratio = osr; return 0; @@ -603,7 +638,7 @@ static int bma400_get_accel_oversampling_ratio(struct bma400_data *data) return ret; } - osr = (val & BMA400_NP_OSR_MASK) >> BMA400_NP_OSR_SHIFT; + osr = FIELD_GET(BMA400_ACC_CONFIG1_NP_OSR_MASK, val); data->oversampling_ratio = osr; return 0; @@ -637,8 +672,8 @@ static int bma400_set_accel_oversampling_ratio(struct bma400_data *data, return ret; ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG, - (acc_config & ~BMA400_LP_OSR_MASK) | - (val << BMA400_LP_OSR_SHIFT)); + (acc_config & ~BMA400_ACC_CONFIG0_LP_OSR_MASK) | + FIELD_PREP(BMA400_ACC_CONFIG0_LP_OSR_MASK, val)); if (ret) { dev_err(data->dev, "Failed to write out OSR\n"); return ret; @@ -653,8 +688,8 @@ static int bma400_set_accel_oversampling_ratio(struct bma400_data *data, return ret; ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, - (acc_config & ~BMA400_NP_OSR_MASK) | - (val << BMA400_NP_OSR_SHIFT)); + (acc_config & ~BMA400_ACC_CONFIG1_NP_OSR_MASK) | + FIELD_PREP(BMA400_ACC_CONFIG1_NP_OSR_MASK, val)); if (ret) { dev_err(data->dev, "Failed to write out OSR\n"); return ret; @@ -679,7 +714,7 @@ static int bma400_accel_scale_to_raw(struct bma400_data *data, /* Note this works because BMA400_SCALE_MIN is odd */ raw = __ffs(val); - if (val >> raw != BMA400_SCALE_MIN) + if (val >> raw != BMA400_ACC_SCALE_MIN) return -EINVAL; return raw; @@ -695,11 +730,11 @@ static int bma400_get_accel_scale(struct bma400_data *data) if (ret) return ret; - raw_scale = (val & BMA400_ACC_SCALE_MASK) >> BMA400_SCALE_SHIFT; + raw_scale = FIELD_GET(BMA400_ACC_CONFIG1_ACC_RANGE_MASK, val); if (raw_scale > BMA400_TWO_BITS_MASK) return -EINVAL; - data->scale = BMA400_SCALE_MIN << raw_scale; + data->scale = BMA400_ACC_SCALE_MIN << raw_scale; return 0; } @@ -719,8 +754,8 @@ static int bma400_set_accel_scale(struct bma400_data *data, unsigned int val) return raw; ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, - (acc_config & ~BMA400_ACC_SCALE_MASK) | - (raw << BMA400_SCALE_SHIFT)); + (acc_config & ~BMA400_ACC_CONFIG1_ACC_RANGE_MASK) | + FIELD_PREP(BMA400_ACC_CONFIG1_ACC_RANGE_MASK, raw)); if (ret) return ret; @@ -786,8 +821,8 @@ static int bma400_enable_steps(struct bma400_data *data, int 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)); + BMA400_INT_CONFIG1_STEP_INT_MASK, + FIELD_PREP(BMA400_INT_CONFIG1_STEP_INT_MASK, val ? 1 : 0)); if (ret) return ret; data->steps_enabled = val; @@ -826,7 +861,7 @@ static void bma400_init_tables(void) 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; + bma400_scales[i + 1] = BMA400_ACC_SCALE_MIN << raw; } } @@ -1063,7 +1098,7 @@ static int bma400_write_raw(struct iio_dev *indio_dev, return ret; case IIO_CHAN_INFO_SCALE: if (val != 0 || - val2 < BMA400_SCALE_MIN || val2 > BMA400_SCALE_MAX) + val2 < BMA400_ACC_SCALE_MIN || val2 > BMA400_ACC_SCALE_MAX) return -EINVAL; mutex_lock(&data->mutex); @@ -1114,16 +1149,16 @@ static int bma400_read_event_config(struct iio_dev *indio_dev, case IIO_ACCEL: switch (dir) { case IIO_EV_DIR_RISING: - return FIELD_GET(BMA400_INT_GEN1_MSK, + return FIELD_GET(BMA400_INT_CONFIG0_GEN1_MASK, data->generic_event_en); case IIO_EV_DIR_FALLING: - return FIELD_GET(BMA400_INT_GEN2_MSK, + return FIELD_GET(BMA400_INT_CONFIG0_GEN2_MASK, data->generic_event_en); case IIO_EV_DIR_SINGLETAP: - return FIELD_GET(BMA400_S_TAP_MSK, + return FIELD_GET(BMA400_INT_CONFIG1_S_TAP_MASK, data->tap_event_en_bitmask); case IIO_EV_DIR_DOUBLETAP: - return FIELD_GET(BMA400_D_TAP_MSK, + return FIELD_GET(BMA400_INT_CONFIG1_D_TAP_MASK, data->tap_event_en_bitmask); default: return -EINVAL; @@ -1146,8 +1181,8 @@ static int bma400_steps_event_enable(struct bma400_data *data, int state) return ret; ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG, - BMA400_STEP_INT_MSK, - FIELD_PREP(BMA400_STEP_INT_MSK, + BMA400_INT_CONFIG1_STEP_INT_MASK, + FIELD_PREP(BMA400_INT_CONFIG1_STEP_INT_MASK, state)); if (ret) return ret; @@ -1155,63 +1190,68 @@ static int bma400_steps_event_enable(struct bma400_data *data, int state) return 0; } -static int bma400_activity_event_en(struct bma400_data *data, - enum iio_event_direction dir, - int state) +static int bma400_generic_event_en(struct bma400_data *data, + enum iio_event_direction dir, + int state) { - int ret, reg, msk, value; - int field_value = 0; + int ret; + unsigned int intrmask, regval; + enum bma400_generic_intr genintr; + enum bma400_detect_criterion detect_criterion; + const struct bma400_genintr_info *bma400_genintr; - 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: + bma400_genintr = get_bma400_genintr_info(dir); + if (!bma400_genintr) return -EINVAL; - } - /* Enabling all axis for interrupt evaluation */ - ret = regmap_write(data->regmap, reg, 0xF8); + genintr = bma400_genintr->genintr; + detect_criterion = bma400_genintr->detect_mode; + intrmask = bma400_genintr->intrmask; + + /* + * Enabling all axis for interrupt evaluation + * Acc_filt2 is recommended as data source in datasheet (Section 4.7) + */ + ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 0), + BMA400_GENINT_CONFIG0_X_EN_MASK | + BMA400_GENINT_CONFIG0_Y_EN_MASK | + BMA400_GENINT_CONFIG0_Z_EN_MASK| + FIELD_PREP(BMA400_GENINT_CONFIG0_DATA_SRC_MASK, ACCEL_FILT2)| + FIELD_PREP(BMA400_GENINT_CONFIG0_REF_UPD_MODE_MASK, + BMA400_REF_EVERYTIME_UPDT_MODE)); if (ret) return ret; /* OR combination of all axis for interrupt evaluation */ - ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG1_OFF, value); + regval = FIELD_PREP(BMA400_GENINT_CONFIG1_AXES_COMB_MASK, BMA400_EVAL_X_OR_Y_OR_Z) | + FIELD_PREP(BMA400_GENINT_CONFIG1_DETCT_CRIT_MASK, detect_criterion); + ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 1), regval); if (ret) return ret; - /* Initial value to avoid interrupts while enabling*/ - ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG2_OFF, 0x0A); + /* + * Initial value to avoid interrupts while enabling + * Value is in units of 8mg/lsb, i.e. effective val is val * 8mg/lsb + */ + ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 2), 0x0A); if (ret) return ret; /* Initial duration value to avoid interrupts while enabling*/ - ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG31_OFF, 0x0F); + ret = regmap_write(data->regmap, BMA400_GENINT_CONFIG_REG(genintr, 4), 0x0F); if (ret) return ret; - ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, msk, - field_value); + regval = state ? intrmask : 0; + ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, intrmask, regval); if (ret) return ret; - ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, msk, - field_value); + ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, intrmask, regval); if (ret) return ret; - set_mask_bits(&data->generic_event_en, msk, field_value); + set_mask_bits(&data->generic_event_en, intrmask, regval); return 0; } @@ -1240,21 +1280,21 @@ static int bma400_tap_event_en(struct bma400_data *data, } ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG, - BMA400_S_TAP_MSK, - FIELD_PREP(BMA400_S_TAP_MSK, state)); + BMA400_INT_CONFIG1_S_TAP_MASK, + FIELD_PREP(BMA400_INT_CONFIG1_S_TAP_MASK, 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)); + mask = BMA400_INT_CONFIG1_S_TAP_MASK; + set_mask_bits(&field_value, BMA400_INT_CONFIG1_S_TAP_MASK, + FIELD_PREP(BMA400_INT_CONFIG1_S_TAP_MASK, 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)); + mask = BMA400_INT_CONFIG1_D_TAP_MASK; + set_mask_bits(&field_value, BMA400_INT_CONFIG1_D_TAP_MASK, + FIELD_PREP(BMA400_INT_CONFIG1_D_TAP_MASK, state)); break; default: return -EINVAL; @@ -1303,7 +1343,7 @@ static int bma400_write_event_config(struct iio_dev *indio_dev, switch (type) { case IIO_EV_TYPE_MAG: mutex_lock(&data->mutex); - ret = bma400_activity_event_en(data, dir, state); + ret = bma400_generic_event_en(data, dir, state); mutex_unlock(&data->mutex); return ret; case IIO_EV_TYPE_GESTURE: @@ -1336,18 +1376,6 @@ static int bma400_write_event_config(struct iio_dev *indio_dev, } } -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, @@ -1356,22 +1384,25 @@ static int bma400_read_event_value(struct iio_dev *indio_dev, int *val, int *val2) { struct bma400_data *data = iio_priv(indio_dev); - int ret, reg, reg_val, raw; + int ret, reg_val, raw; + enum bma400_generic_intr genintr; + const struct bma400_genintr_info *bma400_genintr; if (chan->type != IIO_ACCEL) return -EINVAL; switch (type) { case IIO_EV_TYPE_MAG: - reg = get_gen_config_reg(dir); - if (reg < 0) + bma400_genintr = get_bma400_genintr_info(dir); + if (!bma400_genintr) return -EINVAL; + genintr = bma400_genintr->genintr; *val2 = 0; switch (info) { case IIO_EV_INFO_VALUE: ret = regmap_read(data->regmap, - reg + BMA400_GEN_CONFIG2_OFF, + BMA400_GENINT_CONFIG_REG(genintr, 2), val); if (ret) return ret; @@ -1379,7 +1410,7 @@ static int bma400_read_event_value(struct iio_dev *indio_dev, case IIO_EV_INFO_PERIOD: mutex_lock(&data->mutex); ret = regmap_bulk_read(data->regmap, - reg + BMA400_GEN_CONFIG3_OFF, + BMA400_GENINT_CONFIG_REG(genintr, 3), &data->duration, sizeof(data->duration)); if (ret) { @@ -1390,10 +1421,12 @@ static int bma400_read_event_value(struct iio_dev *indio_dev, mutex_unlock(&data->mutex); return IIO_VAL_INT; case IIO_EV_INFO_HYSTERESIS: - ret = regmap_read(data->regmap, reg, val); + ret = regmap_read(data->regmap, + BMA400_GENINT_CONFIG_REG(genintr, 0), + val); if (ret) return ret; - *val = FIELD_GET(BMA400_GEN_HYST_MSK, *val); + *val = FIELD_GET(BMA400_GENINT_CONFIG0_HYST_MASK, *val); return IIO_VAL_INT; default: return -EINVAL; @@ -1401,30 +1434,30 @@ static int bma400_read_event_value(struct iio_dev *indio_dev, case IIO_EV_TYPE_GESTURE: switch (info) { case IIO_EV_INFO_VALUE: - ret = regmap_read(data->regmap, BMA400_TAP_CONFIG, + ret = regmap_read(data->regmap, BMA400_TAP_CONFIG_REG, ®_val); if (ret) return ret; - *val = FIELD_GET(BMA400_TAP_SEN_MSK, reg_val); + *val = FIELD_GET(BMA400_TAP_CONFIG_SEN_MASK, reg_val); return IIO_VAL_INT; case IIO_EV_INFO_RESET_TIMEOUT: - ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1, + ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1_REG, ®_val); if (ret) return ret; - raw = FIELD_GET(BMA400_TAP_QUIET_MSK, reg_val); + raw = FIELD_GET(BMA400_TAP_CONFIG1_QUIET_MASK, 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, + ret = regmap_read(data->regmap, BMA400_TAP_CONFIG1_REG, ®_val); if (ret) return ret; - raw = FIELD_GET(BMA400_TAP_QUIETDT_MSK, reg_val); + raw = FIELD_GET(BMA400_TAP_CONFIG1_QUIETDT_MASK, reg_val); *val = 0; *val2 = double_tap2_min_delay[raw]; return IIO_VAL_INT_PLUS_MICRO; @@ -1444,16 +1477,19 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, int val, int val2) { struct bma400_data *data = iio_priv(indio_dev); - int reg, ret, raw; + int ret, raw; + enum bma400_generic_intr genintr; + const struct bma400_genintr_info *bma400_genintr; if (chan->type != IIO_ACCEL) return -EINVAL; switch (type) { case IIO_EV_TYPE_MAG: - reg = get_gen_config_reg(dir); - if (reg < 0) + bma400_genintr = get_bma400_genintr_info(dir); + if (!bma400_genintr) return -EINVAL; + genintr = bma400_genintr->genintr; switch (info) { case IIO_EV_INFO_VALUE: @@ -1461,7 +1497,7 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, return -EINVAL; return regmap_write(data->regmap, - reg + BMA400_GEN_CONFIG2_OFF, + BMA400_GENINT_CONFIG_REG(genintr, 2), val); case IIO_EV_INFO_PERIOD: if (val < 1 || val > 65535) @@ -1470,7 +1506,7 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, mutex_lock(&data->mutex); put_unaligned_be16(val, &data->duration); ret = regmap_bulk_write(data->regmap, - reg + BMA400_GEN_CONFIG3_OFF, + BMA400_GENINT_CONFIG_REG(genintr, 3), &data->duration, sizeof(data->duration)); mutex_unlock(&data->mutex); @@ -1479,9 +1515,10 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, if (val < 0 || val > 3) return -EINVAL; - return regmap_update_bits(data->regmap, reg, - BMA400_GEN_HYST_MSK, - FIELD_PREP(BMA400_GEN_HYST_MSK, + return regmap_update_bits(data->regmap, + BMA400_GENINT_CONFIG_REG(genintr, 0), + BMA400_GENINT_CONFIG0_HYST_MASK, + FIELD_PREP(BMA400_GENINT_CONFIG0_HYST_MASK, val)); default: return -EINVAL; @@ -1493,9 +1530,9 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, return -EINVAL; return regmap_update_bits(data->regmap, - BMA400_TAP_CONFIG, - BMA400_TAP_SEN_MSK, - FIELD_PREP(BMA400_TAP_SEN_MSK, + BMA400_TAP_CONFIG_REG, + BMA400_TAP_CONFIG_SEN_MASK, + FIELD_PREP(BMA400_TAP_CONFIG_SEN_MASK, val)); case IIO_EV_INFO_RESET_TIMEOUT: raw = usec_to_tapreg_raw(val2, tap_reset_timeout); @@ -1503,9 +1540,9 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, return -EINVAL; return regmap_update_bits(data->regmap, - BMA400_TAP_CONFIG1, - BMA400_TAP_QUIET_MSK, - FIELD_PREP(BMA400_TAP_QUIET_MSK, + BMA400_TAP_CONFIG1_REG, + BMA400_TAP_CONFIG1_QUIET_MASK, + FIELD_PREP(BMA400_TAP_CONFIG1_QUIET_MASK, raw)); case IIO_EV_INFO_TAP2_MIN_DELAY: raw = usec_to_tapreg_raw(val2, double_tap2_min_delay); @@ -1513,9 +1550,9 @@ static int bma400_write_event_value(struct iio_dev *indio_dev, return -EINVAL; return regmap_update_bits(data->regmap, - BMA400_TAP_CONFIG1, - BMA400_TAP_QUIETDT_MSK, - FIELD_PREP(BMA400_TAP_QUIETDT_MSK, + BMA400_TAP_CONFIG1_REG, + BMA400_TAP_CONFIG1_QUIETDT_MASK, + FIELD_PREP(BMA400_TAP_CONFIG1_QUIETDT_MASK, raw)); default: return -EINVAL; @@ -1533,14 +1570,14 @@ static int bma400_data_rdy_trigger_set_state(struct iio_trigger *trig, int ret; ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, - BMA400_INT_DRDY_MSK, - FIELD_PREP(BMA400_INT_DRDY_MSK, state)); + BMA400_INT_CONFIG0_DRDY_MASK, + FIELD_PREP(BMA400_INT_CONFIG0_DRDY_MASK, 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)); + BMA400_INT_CONFIG0_DRDY_MASK, + FIELD_PREP(BMA400_INT_CONFIG0_DRDY_MASK, state)); } static const unsigned long bma400_avail_scan_masks[] = { @@ -1578,7 +1615,7 @@ static irqreturn_t bma400_trigger_handler(int irq, void *p) 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, + ret = regmap_bulk_read(data->regmap, BMA400_ACC_X_LSB_REG, &data->buffer.buff, sizeof(data->buffer.buff)); if (ret) goto unlock_err; @@ -1628,13 +1665,13 @@ static irqreturn_t bma400_interrupt(int irq, void *private) * 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))) { + if (FIELD_GET(BMA400_INT_STAT_ENG_OVRRUN_MASK, 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))) + if (FIELD_GET(BMA400_INT_STAT1_S_TAP_MASK, le16_to_cpu(data->status))) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, @@ -1642,7 +1679,7 @@ static irqreturn_t bma400_interrupt(int irq, void *private) IIO_EV_DIR_SINGLETAP), timestamp); - if (FIELD_GET(BMA400_INT_D_TAP_MSK, le16_to_cpu(data->status))) + if (FIELD_GET(BMA400_INT_STAT1_D_TAP_MASK, le16_to_cpu(data->status))) iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, @@ -1650,10 +1687,10 @@ static irqreturn_t bma400_interrupt(int irq, void *private) IIO_EV_DIR_DOUBLETAP), timestamp); - if (FIELD_GET(BMA400_INT_GEN1_MSK, le16_to_cpu(data->status))) + if (FIELD_GET(BMA400_INT_STAT0_GEN1_MASK, le16_to_cpu(data->status))) ev_dir = IIO_EV_DIR_RISING; - if (FIELD_GET(BMA400_INT_GEN2_MSK, le16_to_cpu(data->status))) + if (FIELD_GET(BMA400_INT_STAT0_GEN2_MASK, le16_to_cpu(data->status))) ev_dir = IIO_EV_DIR_FALLING; if (ev_dir != IIO_EV_DIR_NONE) { @@ -1664,7 +1701,7 @@ static irqreturn_t bma400_interrupt(int irq, void *private) timestamp); } - if (FIELD_GET(BMA400_STEP_STAT_MASK, le16_to_cpu(data->status))) { + if (FIELD_GET(BMA400_INT_STAT1_STEP_INT_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, @@ -1686,7 +1723,7 @@ static irqreturn_t bma400_interrupt(int irq, void *private) } } - if (FIELD_GET(BMA400_INT_DRDY_MSK, le16_to_cpu(data->status))) { + if (FIELD_GET(BMA400_INT_STAT0_DRDY_MASK, le16_to_cpu(data->status))) { mutex_unlock(&data->mutex); iio_trigger_poll_nested(data->trig); return IRQ_HANDLED; |
