summaryrefslogtreecommitdiff
path: root/drivers/iio/accel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-11-04 08:21:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2021-11-04 08:21:47 -0700
commit5c904c66ed4e86c31ac7c033b64274cebed04e0e (patch)
tree769d366c5e61ffa45d5d8a99c61ae9d5ea39a0a0 /drivers/iio/accel
parent5cd4dc44b8a0f656100e3b6916cf73b1623299eb (diff)
parent536de747bc48262225889a533db6650731ab25d3 (diff)
downloadlinux-5c904c66ed4e86c31ac7c033b64274cebed04e0e.tar.gz
Merge tag 'char-misc-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here is the big set of char and misc and other tiny driver subsystem updates for 5.16-rc1. Loads of things in here, all of which have been in linux-next for a while with no reported problems (except for one called out below.) Included are: - habanana labs driver updates, including dma_buf usage, reviewed and acked by the dma_buf maintainers - iio driver update (going through this tree not staging as they really do not belong going through that tree anymore) - counter driver updates - hwmon driver updates that the counter drivers needed, acked by the hwmon maintainer - xillybus driver updates - binder driver updates - extcon driver updates - dma_buf module namespaces added (will cause a build error in arm64 for allmodconfig, but that change is on its way through the drm tree) - lkdtm driver updates - pvpanic driver updates - phy driver updates - virt acrn and nitr_enclaves driver updates - smaller char and misc driver updates" * tag 'char-misc-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (386 commits) comedi: dt9812: fix DMA buffers on stack comedi: ni_usb6501: fix NULL-deref in command paths arm64: errata: Enable TRBE workaround for write to out-of-range address arm64: errata: Enable workaround for TRBE overwrite in FILL mode coresight: trbe: Work around write to out of range coresight: trbe: Make sure we have enough space coresight: trbe: Add a helper to determine the minimum buffer size coresight: trbe: Workaround TRBE errata overwrite in FILL mode coresight: trbe: Add infrastructure for Errata handling coresight: trbe: Allow driver to choose a different alignment coresight: trbe: Decouple buffer base from the hardware base coresight: trbe: Add a helper to pad a given buffer area coresight: trbe: Add a helper to calculate the trace generated coresight: trbe: Defer the probe on offline CPUs coresight: trbe: Fix incorrect access of the sink specific data coresight: etm4x: Add ETM PID for Kryo-5XX coresight: trbe: Prohibit trace before disabling TRBE coresight: trbe: End the AUX handle on truncation coresight: trbe: Do not truncate buffer on IRQ coresight: trbe: Fix handling of spurious interrupts ...
Diffstat (limited to 'drivers/iio/accel')
-rw-r--r--drivers/iio/accel/Kconfig62
-rw-r--r--drivers/iio/accel/Makefile6
-rw-r--r--drivers/iio/accel/adxl313.h54
-rw-r--r--drivers/iio/accel/adxl313_core.c332
-rw-r--r--drivers/iio/accel/adxl313_i2c.c66
-rw-r--r--drivers/iio/accel/adxl313_spi.c92
-rw-r--r--drivers/iio/accel/adxl355.h21
-rw-r--r--drivers/iio/accel/adxl355_core.c765
-rw-r--r--drivers/iio/accel/adxl355_i2c.c62
-rw-r--r--drivers/iio/accel/adxl355_spi.c65
-rw-r--r--drivers/iio/accel/adxl372.c1
-rw-r--r--drivers/iio/accel/bma400.h2
-rw-r--r--drivers/iio/accel/bma400_core.c7
-rw-r--r--drivers/iio/accel/bma400_i2c.c4
-rw-r--r--drivers/iio/accel/bma400_spi.c4
-rw-r--r--drivers/iio/accel/bmc150-accel-core.c5
-rw-r--r--drivers/iio/accel/bmc150-accel-i2c.c4
-rw-r--r--drivers/iio/accel/bmc150-accel-spi.c4
-rw-r--r--drivers/iio/accel/bmc150-accel.h2
-rw-r--r--drivers/iio/accel/bmi088-accel-core.c4
-rw-r--r--drivers/iio/accel/bmi088-accel-spi.c4
-rw-r--r--drivers/iio/accel/bmi088-accel.h2
-rw-r--r--drivers/iio/accel/fxls8962af-core.c347
-rw-r--r--drivers/iio/accel/kxsd9-i2c.c4
-rw-r--r--drivers/iio/accel/kxsd9-spi.c4
-rw-r--r--drivers/iio/accel/kxsd9.c4
-rw-r--r--drivers/iio/accel/kxsd9.h2
-rw-r--r--drivers/iio/accel/mma7455.h2
-rw-r--r--drivers/iio/accel/mma7455_core.c4
-rw-r--r--drivers/iio/accel/mma7455_i2c.c4
-rw-r--r--drivers/iio/accel/mma7455_spi.c4
-rw-r--r--drivers/iio/accel/mma7660.c2
-rw-r--r--drivers/iio/accel/sca3000.c3
-rw-r--r--drivers/iio/accel/st_accel_core.c31
-rw-r--r--drivers/iio/accel/st_accel_i2c.c23
-rw-r--r--drivers/iio/accel/st_accel_spi.c23
36 files changed, 1918 insertions, 107 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index a0e9061f6d6b..49587c992a6d 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -30,6 +30,35 @@ config ADIS16209
To compile this driver as a module, say M here: the module will be
called adis16209.
+config ADXL313
+ tristate
+
+config ADXL313_I2C
+ tristate "Analog Devices ADXL313 3-Axis Digital Accelerometer I2C Driver"
+ depends on I2C
+ select ADXL313
+ select REGMAP_I2C
+ help
+ Say Y here if you want to build i2c support for the Analog Devices
+ ADXL313 3-axis digital accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called adxl313_i2c and you will also get adxl313_core
+ for the core module.
+
+config ADXL313_SPI
+ tristate "Analog Devices ADXL313 3-Axis Digital Accelerometer SPI Driver"
+ depends on SPI
+ select ADXL313
+ select REGMAP_SPI
+ help
+ Say Y here if you want to build spi support for the Analog Devices
+ ADXL313 3-axis digital accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called adxl313_spi and you will also get adxl313_core
+ for the core module.
+
config ADXL345
tristate
@@ -61,6 +90,39 @@ config ADXL345_SPI
will be called adxl345_spi and you will also get adxl345_core
for the core module.
+config ADXL355
+ tristate
+
+config ADXL355_I2C
+ tristate "Analog Devices ADXL355 3-Axis Digital Accelerometer I2C Driver"
+ depends on I2C
+ select ADXL355
+ select REGMAP_I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say Y here if you want to build i2c support for the Analog Devices
+ ADXL355 3-axis digital accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called adxl355_i2c and you will also get adxl355_core
+ for the core module.
+
+config ADXL355_SPI
+ tristate "Analog Devices ADXL355 3-Axis Digital Accelerometer SPI Driver"
+ depends on SPI
+ select ADXL355
+ select REGMAP_SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say Y here if you want to build spi support for the Analog Devices
+ ADXL355 3-axis digital accelerometer.
+
+ To compile this driver as a module, choose M here: the module
+ will be called adxl355_spi and you will also get adxl355_core
+ for the core module.
+
config ADXL372
tristate
select IIO_BUFFER
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 89280e823bcd..d03e2f6bba08 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -6,9 +6,15 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ADIS16201) += adis16201.o
obj-$(CONFIG_ADIS16209) += adis16209.o
+obj-$(CONFIG_ADXL313) += adxl313_core.o
+obj-$(CONFIG_ADXL313_I2C) += adxl313_i2c.o
+obj-$(CONFIG_ADXL313_SPI) += adxl313_spi.o
obj-$(CONFIG_ADXL345) += adxl345_core.o
obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o
obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
+obj-$(CONFIG_ADXL355) += adxl355_core.o
+obj-$(CONFIG_ADXL355_I2C) += adxl355_i2c.o
+obj-$(CONFIG_ADXL355_SPI) += adxl355_spi.o
obj-$(CONFIG_ADXL372) += adxl372.o
obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
diff --git a/drivers/iio/accel/adxl313.h b/drivers/iio/accel/adxl313.h
new file mode 100644
index 000000000000..4415f2fc07e1
--- /dev/null
+++ b/drivers/iio/accel/adxl313.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ADXL313 3-Axis Digital Accelerometer
+ *
+ * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>
+ */
+
+#ifndef _ADXL313_H_
+#define _ADXL313_H_
+
+/* ADXL313 register definitions */
+#define ADXL313_REG_DEVID0 0x00
+#define ADXL313_REG_DEVID1 0x01
+#define ADXL313_REG_PARTID 0x02
+#define ADXL313_REG_XID 0x04
+#define ADXL313_REG_SOFT_RESET 0x18
+#define ADXL313_REG_OFS_AXIS(index) (0x1E + (index))
+#define ADXL313_REG_THRESH_ACT 0x24
+#define ADXL313_REG_ACT_INACT_CTL 0x27
+#define ADXL313_REG_BW_RATE 0x2C
+#define ADXL313_REG_POWER_CTL 0x2D
+#define ADXL313_REG_INT_MAP 0x2F
+#define ADXL313_REG_DATA_FORMAT 0x31
+#define ADXL313_REG_DATA_AXIS(index) (0x32 + ((index) * 2))
+#define ADXL313_REG_FIFO_CTL 0x38
+#define ADXL313_REG_FIFO_STATUS 0x39
+
+#define ADXL313_DEVID0 0xAD
+#define ADXL313_DEVID1 0x1D
+#define ADXL313_PARTID 0xCB
+#define ADXL313_SOFT_RESET 0x52
+
+#define ADXL313_RATE_MSK GENMASK(3, 0)
+#define ADXL313_RATE_BASE 6
+
+#define ADXL313_POWER_CTL_MSK GENMASK(3, 2)
+#define ADXL313_MEASUREMENT_MODE BIT(3)
+
+#define ADXL313_RANGE_MSK GENMASK(1, 0)
+#define ADXL313_RANGE_4G 3
+
+#define ADXL313_FULL_RES BIT(3)
+#define ADXL313_SPI_3WIRE BIT(6)
+#define ADXL313_I2C_DISABLE BIT(6)
+
+extern const struct regmap_access_table adxl313_readable_regs_table;
+
+extern const struct regmap_access_table adxl313_writable_regs_table;
+
+int adxl313_core_probe(struct device *dev,
+ struct regmap *regmap,
+ const char *name,
+ int (*setup)(struct device *, struct regmap *));
+#endif /* _ADXL313_H_ */
diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c
new file mode 100644
index 000000000000..0d243341f1a7
--- /dev/null
+++ b/drivers/iio/accel/adxl313_core.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADXL313 3-Axis Digital Accelerometer
+ *
+ * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
+ */
+
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adxl313.h"
+
+static const struct regmap_range adxl313_readable_reg_range[] = {
+ regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_XID),
+ regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
+ regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
+ regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
+ regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS),
+};
+
+const struct regmap_access_table adxl313_readable_regs_table = {
+ .yes_ranges = adxl313_readable_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range),
+};
+EXPORT_SYMBOL_GPL(adxl313_readable_regs_table);
+
+static const struct regmap_range adxl313_writable_reg_range[] = {
+ regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
+ regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
+ regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
+ regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP),
+ regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT),
+ regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL),
+};
+
+const struct regmap_access_table adxl313_writable_regs_table = {
+ .yes_ranges = adxl313_writable_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range),
+};
+EXPORT_SYMBOL_GPL(adxl313_writable_regs_table);
+
+struct adxl313_data {
+ struct regmap *regmap;
+ struct mutex lock; /* lock to protect transf_buf */
+ __le16 transf_buf ____cacheline_aligned;
+};
+
+static const int adxl313_odr_freqs[][2] = {
+ [0] = { 6, 250000 },
+ [1] = { 12, 500000 },
+ [2] = { 25, 0 },
+ [3] = { 50, 0 },
+ [4] = { 100, 0 },
+ [5] = { 200, 0 },
+ [6] = { 400, 0 },
+ [7] = { 800, 0 },
+ [8] = { 1600, 0 },
+ [9] = { 3200, 0 },
+};
+
+#define ADXL313_ACCEL_CHANNEL(index, axis) { \
+ .type = IIO_ACCEL, \
+ .address = index, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_type = { \
+ .realbits = 13, \
+ }, \
+}
+
+static const struct iio_chan_spec adxl313_channels[] = {
+ ADXL313_ACCEL_CHANNEL(0, X),
+ ADXL313_ACCEL_CHANNEL(1, Y),
+ ADXL313_ACCEL_CHANNEL(2, Z),
+};
+
+static int adxl313_set_odr(struct adxl313_data *data,
+ unsigned int freq1, unsigned int freq2)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(adxl313_odr_freqs); i++) {
+ if (adxl313_odr_freqs[i][0] == freq1 &&
+ adxl313_odr_freqs[i][1] == freq2)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(adxl313_odr_freqs))
+ return -EINVAL;
+
+ return regmap_update_bits(data->regmap, ADXL313_REG_BW_RATE,
+ ADXL313_RATE_MSK,
+ FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i));
+}
+
+static int adxl313_read_axis(struct adxl313_data *data,
+ struct iio_chan_spec const *chan)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = regmap_bulk_read(data->regmap,
+ ADXL313_REG_DATA_AXIS(chan->address),
+ &data->transf_buf, sizeof(data->transf_buf));
+ if (ret)
+ goto unlock_ret;
+
+ ret = le16_to_cpu(data->transf_buf);
+
+unlock_ret:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int adxl313_read_freq_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_SAMP_FREQ:
+ *vals = (const int *)adxl313_odr_freqs;
+ *length = ARRAY_SIZE(adxl313_odr_freqs) * 2;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl313_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct adxl313_data *data = iio_priv(indio_dev);
+ unsigned int regval;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = adxl313_read_axis(data, chan);
+ if (ret < 0)
+ return ret;
+
+ *val = sign_extend32(ret, chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * Scale for any g range is given in datasheet as
+ * 1024 LSB/g = 0.0009765625 * 9.80665 = 0.009576806640625 m/s^2
+ */
+ *val = 0;
+ *val2 = 9576806;
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ ret = regmap_read(data->regmap,
+ ADXL313_REG_OFS_AXIS(chan->address), &regval);
+ if (ret)
+ return ret;
+
+ /*
+ * 8-bit resolution at +/- 0.5g, that is 4x accel data scale
+ * factor at full resolution
+ */
+ *val = sign_extend32(regval, 7) * 4;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(data->regmap, ADXL313_REG_BW_RATE, &regval);
+ if (ret)
+ return ret;
+
+ ret = FIELD_GET(ADXL313_RATE_MSK, regval) - ADXL313_RATE_BASE;
+ *val = adxl313_odr_freqs[ret][0];
+ *val2 = adxl313_odr_freqs[ret][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl313_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct adxl313_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ /*
+ * 8-bit resolution at +/- 0.5g, that is 4x accel data scale
+ * factor at full resolution
+ */
+ if (clamp_val(val, -128 * 4, 127 * 4) != val)
+ return -EINVAL;
+
+ return regmap_write(data->regmap,
+ ADXL313_REG_OFS_AXIS(chan->address),
+ val / 4);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return adxl313_set_odr(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info adxl313_info = {
+ .read_raw = adxl313_read_raw,
+ .write_raw = adxl313_write_raw,
+ .read_avail = adxl313_read_freq_avail,
+};
+
+static int adxl313_setup(struct device *dev, struct adxl313_data *data,
+ int (*setup)(struct device *, struct regmap *))
+{
+ unsigned int regval;
+ int ret;
+
+ /* Ensures the device is in a consistent state after start up */
+ ret = regmap_write(data->regmap, ADXL313_REG_SOFT_RESET,
+ ADXL313_SOFT_RESET);
+ if (ret)
+ return ret;
+
+ if (setup) {
+ ret = setup(dev, data->regmap);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_read(data->regmap, ADXL313_REG_DEVID0, &regval);
+ if (ret)
+ return ret;
+
+ if (regval != ADXL313_DEVID0) {
+ dev_err(dev, "Invalid manufacturer ID: 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(data->regmap, ADXL313_REG_DEVID1, &regval);
+ if (ret)
+ return ret;
+
+ if (regval != ADXL313_DEVID1) {
+ dev_err(dev, "Invalid mems ID: 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(data->regmap, ADXL313_REG_PARTID, &regval);
+ if (ret)
+ return ret;
+
+ if (regval != ADXL313_PARTID) {
+ dev_err(dev, "Invalid device ID: 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ /* Sets the range to +/- 4g */
+ ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT,
+ ADXL313_RANGE_MSK,
+ FIELD_PREP(ADXL313_RANGE_MSK, ADXL313_RANGE_4G));
+ if (ret)
+ return ret;
+
+ /* Enables full resolution */
+ ret = regmap_update_bits(data->regmap, ADXL313_REG_DATA_FORMAT,
+ ADXL313_FULL_RES, ADXL313_FULL_RES);
+ if (ret)
+ return ret;
+
+ /* Enables measurement mode */
+ return regmap_update_bits(data->regmap, ADXL313_REG_POWER_CTL,
+ ADXL313_POWER_CTL_MSK,
+ ADXL313_MEASUREMENT_MODE);
+}
+
+/**
+ * adxl313_core_probe() - probe and setup for adxl313 accelerometer
+ * @dev: Driver model representation of the device
+ * @regmap: Register map of the device
+ * @name: Device name buffer reference
+ * @setup: Setup routine to be executed right before the standard device
+ * setup, can also be set to NULL if not required
+ *
+ * Return: 0 on success, negative errno on error cases
+ */
+int adxl313_core_probe(struct device *dev,
+ struct regmap *regmap,
+ const char *name,
+ int (*setup)(struct device *, struct regmap *))
+{
+ struct adxl313_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->regmap = regmap;
+ mutex_init(&data->lock);
+
+ indio_dev->name = name;
+ indio_dev->info = &adxl313_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = adxl313_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adxl313_channels);
+
+ ret = adxl313_setup(dev, data, setup);
+ if (ret) {
+ dev_err(dev, "ADXL313 setup failed\n");
+ return ret;
+ }
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_GPL(adxl313_core_probe);
+
+MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");
+MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c
new file mode 100644
index 000000000000..82e9fb2db1e6
--- /dev/null
+++ b/drivers/iio/accel/adxl313_i2c.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADXL313 3-Axis Digital Accelerometer
+ *
+ * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
+ */
+
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adxl313.h"
+
+static const struct regmap_config adxl313_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .rd_table = &adxl313_readable_regs_table,
+ .wr_table = &adxl313_writable_regs_table,
+ .max_register = 0x39,
+};
+
+static int adxl313_i2c_probe(struct i2c_client *client)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &adxl313_i2c_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ return adxl313_core_probe(&client->dev, regmap, client->name, NULL);
+}
+
+static const struct i2c_device_id adxl313_i2c_id[] = {
+ { "adxl313" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, adxl313_i2c_id);
+
+static const struct of_device_id adxl313_of_match[] = {
+ { .compatible = "adi,adxl313" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, adxl313_of_match);
+
+static struct i2c_driver adxl313_i2c_driver = {
+ .driver = {
+ .name = "adxl313_i2c",
+ .of_match_table = adxl313_of_match,
+ },
+ .probe_new = adxl313_i2c_probe,
+ .id_table = adxl313_i2c_id,
+};
+
+module_i2c_driver(adxl313_i2c_driver);
+
+MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");
+MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c
new file mode 100644
index 000000000000..a6162f36ef52
--- /dev/null
+++ b/drivers/iio/accel/adxl313_spi.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADXL313 3-Axis Digital Accelerometer
+ *
+ * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
+ */
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "adxl313.h"
+
+static const struct regmap_config adxl313_spi_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .rd_table = &adxl313_readable_regs_table,
+ .wr_table = &adxl313_writable_regs_table,
+ .max_register = 0x39,
+ /* Setting bits 7 and 6 enables multiple-byte read */
+ .read_flag_mask = BIT(7) | BIT(6),
+};
+
+static int adxl313_spi_setup(struct device *dev, struct regmap *regmap)
+{
+ struct spi_device *spi = container_of(dev, struct spi_device, dev);
+ int ret;
+
+ if (spi->mode & SPI_3WIRE) {
+ ret = regmap_write(regmap, ADXL313_REG_DATA_FORMAT,
+ ADXL313_SPI_3WIRE);
+ if (ret)
+ return ret;
+ }
+
+ return regmap_update_bits(regmap, ADXL313_REG_POWER_CTL,
+ ADXL313_I2C_DISABLE, ADXL313_I2C_DISABLE);
+}
+
+static int adxl313_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap *regmap;
+ int ret;
+
+ spi->mode |= SPI_MODE_3;
+ ret = spi_setup(spi);
+ if (ret)
+ return ret;
+
+ regmap = devm_regmap_init_spi(spi, &adxl313_spi_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ return adxl313_core_probe(&spi->dev, regmap, id->name,
+ &adxl313_spi_setup);
+}
+
+static const struct spi_device_id adxl313_spi_id[] = {
+ { "adxl313" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(spi, adxl313_spi_id);
+
+static const struct of_device_id adxl313_of_match[] = {
+ { .compatible = "adi,adxl313" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, adxl313_of_match);
+
+static struct spi_driver adxl313_spi_driver = {
+ .driver = {
+ .name = "adxl313_spi",
+ .of_match_table = adxl313_of_match,
+ },
+ .probe = adxl313_spi_probe,
+ .id_table = adxl313_spi_id,
+};
+
+module_spi_driver(adxl313_spi_driver);
+
+MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");
+MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl355.h b/drivers/iio/accel/adxl355.h
new file mode 100644
index 000000000000..6dd49b13e4fd
--- /dev/null
+++ b/drivers/iio/accel/adxl355.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ADXL355 3-Axis Digital Accelerometer
+ *
+ * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
+ */
+
+#ifndef _ADXL355_H_
+#define _ADXL355_H_
+
+#include <linux/regmap.h>
+
+struct device;
+
+extern const struct regmap_access_table adxl355_readable_regs_tbl;
+extern const struct regmap_access_table adxl355_writeable_regs_tbl;
+
+int adxl355_core_probe(struct device *dev, struct regmap *regmap,
+ const char *name);
+
+#endif /* _ADXL355_H_ */
diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c
new file mode 100644
index 000000000000..4f485909f459
--- /dev/null
+++ b/drivers/iio/accel/adxl355_core.c
@@ -0,0 +1,765 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADXL355 3-Axis Digital Accelerometer IIO core driver
+ *
+ * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
+ *
+ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/adxl354_adxl355.pdf
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/limits.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <asm/unaligned.h>
+
+#include "adxl355.h"
+
+/* ADXL355 Register Definitions */
+#define ADXL355_DEVID_AD_REG 0x00
+#define ADXL355_DEVID_MST_REG 0x01
+#define ADXL355_PARTID_REG 0x02
+#define ADXL355_STATUS_REG 0x04
+#define ADXL355_FIFO_ENTRIES_REG 0x05
+#define ADXL355_TEMP2_REG 0x06
+#define ADXL355_XDATA3_REG 0x08
+#define ADXL355_YDATA3_REG 0x0B
+#define ADXL355_ZDATA3_REG 0x0E
+#define ADXL355_FIFO_DATA_REG 0x11
+#define ADXL355_OFFSET_X_H_REG 0x1E
+#define ADXL355_OFFSET_Y_H_REG 0x20
+#define ADXL355_OFFSET_Z_H_REG 0x22
+#define ADXL355_ACT_EN_REG 0x24
+#define ADXL355_ACT_THRESH_H_REG 0x25
+#define ADXL355_ACT_THRESH_L_REG 0x26
+#define ADXL355_ACT_COUNT_REG 0x27
+#define ADXL355_FILTER_REG 0x28
+#define ADXL355_FILTER_ODR_MSK GENMASK(3, 0)
+#define ADXL355_FILTER_HPF_MSK GENMASK(6, 4)
+#define ADXL355_FIFO_SAMPLES_REG 0x29
+#define ADXL355_INT_MAP_REG 0x2A
+#define ADXL355_SYNC_REG 0x2B
+#define ADXL355_RANGE_REG 0x2C
+#define ADXL355_POWER_CTL_REG 0x2D
+#define ADXL355_POWER_CTL_MODE_MSK GENMASK(1, 0)
+#define ADXL355_POWER_CTL_DRDY_MSK BIT(2)
+#define ADXL355_SELF_TEST_REG 0x2E
+#define ADXL355_RESET_REG 0x2F
+
+#define ADXL355_DEVID_AD_VAL 0xAD
+#define ADXL355_DEVID_MST_VAL 0x1D
+#define ADXL355_PARTID_VAL 0xED
+#define ADXL355_RESET_CODE 0x52
+
+#define MEGA 1000000UL
+#define TERA 1000000000000ULL
+
+static const struct regmap_range adxl355_read_reg_range[] = {
+ regmap_reg_range(ADXL355_DEVID_AD_REG, ADXL355_FIFO_DATA_REG),
+ regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_SELF_TEST_REG),
+};
+
+const struct regmap_access_table adxl355_readable_regs_tbl = {
+ .yes_ranges = adxl355_read_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(adxl355_read_reg_range),
+};
+EXPORT_SYMBOL_GPL(adxl355_readable_regs_tbl);
+
+static const struct regmap_range adxl355_write_reg_range[] = {
+ regmap_reg_range(ADXL355_OFFSET_X_H_REG, ADXL355_RESET_REG),
+};
+
+const struct regmap_access_table adxl355_writeable_regs_tbl = {
+ .yes_ranges = adxl355_write_reg_range,
+ .n_yes_ranges = ARRAY_SIZE(adxl355_write_reg_range),
+};
+EXPORT_SYMBOL_GPL(adxl355_writeable_regs_tbl);
+
+enum adxl355_op_mode {
+ ADXL355_MEASUREMENT,
+ ADXL355_STANDBY,
+ ADXL355_TEMP_OFF,
+};
+
+enum adxl355_odr {
+ ADXL355_ODR_4000HZ,
+ ADXL355_ODR_2000HZ,
+ ADXL355_ODR_1000HZ,
+ ADXL355_ODR_500HZ,
+ ADXL355_ODR_250HZ,
+ ADXL355_ODR_125HZ,
+ ADXL355_ODR_62_5HZ,
+ ADXL355_ODR_31_25HZ,
+ ADXL355_ODR_15_625HZ,
+ ADXL355_ODR_7_813HZ,
+ ADXL355_ODR_3_906HZ,
+};
+
+enum adxl355_hpf_3db {
+ ADXL355_HPF_OFF,
+ ADXL355_HPF_24_7,
+ ADXL355_HPF_6_2084,
+ ADXL355_HPF_1_5545,
+ ADXL355_HPF_0_3862,
+ ADXL355_HPF_0_0954,
+ ADXL355_HPF_0_0238,
+};
+
+static const int adxl355_odr_table[][2] = {
+ [0] = {4000, 0},
+ [1] = {2000, 0},
+ [2] = {1000, 0},
+ [3] = {500, 0},
+ [4] = {250, 0},
+ [5] = {125, 0},
+ [6] = {62, 500000},
+ [7] = {31, 250000},
+ [8] = {15, 625000},
+ [9] = {7, 813000},
+ [10] = {3, 906000},
+};
+
+static const int adxl355_hpf_3db_multipliers[] = {
+ 0,
+ 247000,
+ 62084,
+ 15545,
+ 3862,
+ 954,
+ 238,
+};
+
+enum adxl355_chans {
+ chan_x, chan_y, chan_z,
+};
+
+struct adxl355_chan_info {
+ u8 data_reg;
+ u8 offset_reg;
+};
+
+static const struct adxl355_chan_info adxl355_chans[] = {
+ [chan_x] = {
+ .data_reg = ADXL355_XDATA3_REG,
+ .offset_reg = ADXL355_OFFSET_X_H_REG
+ },
+ [chan_y] = {
+ .data_reg = ADXL355_YDATA3_REG,
+ .offset_reg = ADXL355_OFFSET_Y_H_REG
+ },
+ [chan_z] = {
+ .data_reg = ADXL355_ZDATA3_REG,
+ .offset_reg = ADXL355_OFFSET_Z_H_REG
+ },
+};
+
+struct adxl355_data {
+ struct regmap *regmap;
+ struct device *dev;
+ struct mutex lock; /* lock to protect op_mode */
+ enum adxl355_op_mode op_mode;
+ enum adxl355_odr odr;
+ enum adxl355_hpf_3db hpf_3db;
+ int calibbias[3];
+ int adxl355_hpf_3db_table[7][2];
+ struct iio_trigger *dready_trig;
+ union {
+ u8 transf_buf[3];
+ struct {
+ u8 buf[14];
+ s64 ts;
+ } buffer;
+ } ____cacheline_aligned;
+};
+
+static int adxl355_set_op_mode(struct adxl355_data *data,
+ enum adxl355_op_mode op_mode)
+{
+ int ret;
+
+ if (data->op_mode == op_mode)
+ return 0;
+
+ ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
+ ADXL355_POWER_CTL_MODE_MSK, op_mode);
+ if (ret)
+ return ret;
+
+ data->op_mode = op_mode;
+
+ return ret;
+}
+
+static int adxl355_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct adxl355_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+ ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
+ ADXL355_POWER_CTL_DRDY_MSK,
+ FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK,
+ state ? 0 : 1));
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static void adxl355_fill_3db_frequency_table(struct adxl355_data *data)
+{
+ u32 multiplier;
+ u64 div, rem;
+ u64 odr;
+ int i;
+
+ odr = mul_u64_u32_shr(adxl355_odr_table[data->odr][0], MEGA, 0) +
+ adxl355_odr_table[data->odr][1];
+
+ for (i = 0; i < ARRAY_SIZE(adxl355_hpf_3db_multipliers); i++) {
+ multiplier = adxl355_hpf_3db_multipliers[i];
+ div = div64_u64_rem(mul_u64_u32_shr(odr, multiplier, 0),
+ TERA * 100, &rem);
+
+ data->adxl355_hpf_3db_table[i][0] = div;
+ data->adxl355_hpf_3db_table[i][1] = div_u64(rem, MEGA * 100);
+ }
+}
+
+static int adxl355_setup(struct adxl355_data *data)
+{
+ unsigned int regval;
+ int ret;
+
+ ret = regmap_read(data->regmap, ADXL355_DEVID_AD_REG, &regval);
+ if (ret)
+ return ret;
+
+ if (regval != ADXL355_DEVID_AD_VAL) {
+ dev_err(data->dev, "Invalid ADI ID 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(data->regmap, ADXL355_DEVID_MST_REG, &regval);
+ if (ret)
+ return ret;
+
+ if (regval != ADXL355_DEVID_MST_VAL) {
+ dev_err(data->dev, "Invalid MEMS ID 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(data->regmap, ADXL355_PARTID_REG, &regval);
+ if (ret)
+ return ret;
+
+ if (regval != ADXL355_PARTID_VAL) {
+ dev_err(data->dev, "Invalid DEV ID 0x%02x\n", regval);
+ return -ENODEV;
+ }
+
+ /*
+ * Perform a software reset to make sure the device is in a consistent
+ * state after start-up.
+ */
+ ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG,
+ ADXL355_POWER_CTL_DRDY_MSK,
+ FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 1));
+ if (ret)
+ return ret;
+
+ adxl355_fill_3db_frequency_table(data);
+
+ return adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+}
+
+static int adxl355_get_temp_data(struct adxl355_data *data, u8 addr)
+{
+ return regmap_bulk_read(data->regmap, addr, data->transf_buf, 2);
+}
+
+static int adxl355_read_axis(struct adxl355_data *data, u8 addr)
+{
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, addr, data->transf_buf,
+ ARRAY_SIZE(data->transf_buf));
+ if (ret)
+ return ret;
+
+ return get_unaligned_be24(data->transf_buf);
+}
+
+static int adxl355_find_match(const int (*freq_tbl)[2], const int n,
+ const int val, const int val2)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ if (freq_tbl[i][0] == val && freq_tbl[i][1] == val2)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int adxl355_set_odr(struct adxl355_data *data,
+ enum adxl355_odr odr)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ if (data->odr == odr) {
+ mutex_unlock(&data->lock);
+ return 0;
+ }
+
+ ret = adxl355_set_op_mode(data, ADXL355_STANDBY);
+ if (ret)
+ goto err_unlock;
+
+ ret = regmap_update_bits(data->regmap, ADXL355_FILTER_REG,
+ ADXL355_FILTER_ODR_MSK,
+ FIELD_PREP(ADXL355_FILTER_ODR_MSK, odr));
+ if (ret)
+ goto err_set_opmode;
+
+ data->odr = odr;
+ adxl355_fill_3db_frequency_table(data);
+
+ ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+ if (ret)
+ goto err_set_opmode;
+
+ mutex_unlock(&data->lock);
+ return 0;
+
+err_set_opmode:
+ adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+err_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int adxl355_set_hpf_3db(struct adxl355_data *data,
+ enum adxl355_hpf_3db hpf)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ if (data->hpf_3db == hpf) {
+ mutex_unlock(&data->lock);
+ return 0;
+ }
+
+ ret = adxl355_set_op_mode(data, ADXL355_STANDBY);
+ if (ret)
+ goto err_unlock;
+
+ ret = regmap_update_bits(data->regmap, ADXL355_FILTER_REG,
+ ADXL355_FILTER_HPF_MSK,
+ FIELD_PREP(ADXL355_FILTER_HPF_MSK, hpf));
+ if (ret)
+ goto err_set_opmode;
+
+ data->hpf_3db = hpf;
+
+ ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+ if (ret)
+ goto err_set_opmode;
+
+ mutex_unlock(&data->lock);
+ return 0;
+
+err_set_opmode:
+ adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+err_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int adxl355_set_calibbias(struct adxl355_data *data,
+ enum adxl355_chans chan, int calibbias)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = adxl355_set_op_mode(data, ADXL355_STANDBY);
+ if (ret)
+ goto err_unlock;
+
+ put_unaligned_be16(calibbias, data->transf_buf);
+ ret = regmap_bulk_write(data->regmap,
+ adxl355_chans[chan].offset_reg,
+ data->transf_buf, 2);
+ if (ret)
+ goto err_set_opmode;
+
+ data->calibbias[chan] = calibbias;
+
+ ret = adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+ if (ret)
+ goto err_set_opmode;
+
+ mutex_unlock(&data->lock);
+ return 0;
+
+err_set_opmode:
+ adxl355_set_op_mode(data, ADXL355_MEASUREMENT);
+err_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int adxl355_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct adxl355_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_TEMP:
+ ret = adxl355_get_temp_data(data, chan->address);
+ if (ret < 0)
+ return ret;
+ *val = get_unaligned_be16(data->transf_buf);
+
+ return IIO_VAL_INT;
+ case IIO_ACCEL:
+ ret = adxl355_read_axis(data, adxl355_chans[
+ chan->address].data_reg);
+ if (ret < 0)
+ return ret;
+ *val = sign_extend32(ret >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ /*
+ * The datasheet defines an intercept of 1885 LSB at 25 degC
+ * and a slope of -9.05 LSB/C. The following formula can be used
+ * to find the temperature:
+ * Temp = ((RAW - 1885)/(-9.05)) + 25 but this doesn't follow
+ * the format of the IIO which is Temp = (RAW + OFFSET) * SCALE.
+ * Hence using some rearranging we get the scale as -110.497238
+ * and offset as -2111.25.
+ */
+ case IIO_TEMP:
+ *val = -110;
+ *val2 = 497238;
+ return IIO_VAL_INT_PLUS_MICRO;
+ /*
+ * At +/- 2g with 20-bit resolution, scale is given in datasheet
+ * as 3.9ug/LSB = 0.0000039 * 9.80665 = 0.00003824593 m/s^2.
+ */
+ case IIO_ACCEL:
+ *val = 0;
+ *val2 = 38245;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ *val = -2111;
+ *val2 = 250000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *val = sign_extend32(data->calibbias[chan->address], 15);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = adxl355_odr_table[data->odr][0];
+ *val2 = adxl355_odr_table[data->odr][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
+ *val = data->adxl355_hpf_3db_table[data->hpf_3db][0];
+ *val2 = data->adxl355_hpf_3db_table[data->hpf_3db][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl355_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct adxl355_data *data = iio_priv(indio_dev);
+ int odr_idx, hpf_idx, calibbias;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ odr_idx = adxl355_find_match(adxl355_odr_table,
+ ARRAY_SIZE(adxl355_odr_table),
+ val, val2);
+ if (odr_idx < 0)
+ return odr_idx;
+
+ return adxl355_set_odr(data, odr_idx);
+ case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
+ hpf_idx = adxl355_find_match(data->adxl355_hpf_3db_table,
+ ARRAY_SIZE(data->adxl355_hpf_3db_table),
+ val, val2);
+ if (hpf_idx < 0)
+ return hpf_idx;
+
+ return adxl355_set_hpf_3db(data, hpf_idx);
+ case IIO_CHAN_INFO_CALIBBIAS:
+ calibbias = clamp_t(int, val, S16_MIN, S16_MAX);
+
+ return adxl355_set_calibbias(data, chan->address, calibbias);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int adxl355_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct adxl355_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = (const int *)adxl355_odr_table;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ /* Values are stored in a 2D matrix */
+ *length = ARRAY_SIZE(adxl355_odr_table) * 2;
+
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
+ *vals = (const int *)data->adxl355_hpf_3db_table;
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ /* Values are stored in a 2D matrix */
+ *length = ARRAY_SIZE(data->adxl355_hpf_3db_table) * 2;
+
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const unsigned long adxl355_avail_scan_masks[] = {
+ GENMASK(3, 0),
+ 0
+};
+
+static const struct iio_info adxl355_info = {
+ .read_raw = adxl355_read_raw,
+ .write_raw = adxl355_write_raw,
+ .read_avail = &adxl355_read_avail,
+};
+
+static const struct iio_trigger_ops adxl355_trigger_ops = {
+ .set_trigger_state = &adxl355_data_rdy_trigger_set_state,
+ .validate_device = &iio_trigger_validate_own_device,
+};
+
+static irqreturn_t adxl355_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct adxl355_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ /*
+ * data->buffer is used both for triggered buffer support
+ * and read/write_raw(), hence, it has to be zeroed here before usage.
+ */
+ data->buffer.buf[0] = 0;
+
+ /*
+ * The acceleration data is 24 bits and big endian. It has to be saved
+ * in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer.
+ * The buf array is 14 bytes as it includes 3x4=12 bytes for
+ * accelaration data of x, y, and z axis. It also includes 2 bytes for
+ * temperature data.
+ */
+ ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG,
+ &data->buffer.buf[1], 3);
+ if (ret)
+ goto out_unlock_notify;
+
+ ret = regmap_bulk_read(data->regmap, ADXL355_YDATA3_REG,
+ &data->buffer.buf[5], 3);
+ if (ret)
+ goto out_unlock_notify;
+
+ ret = regmap_bulk_read(data->regmap, ADXL355_ZDATA3_REG,
+ &data->buffer.buf[9], 3);
+ if (ret)
+ goto out_unlock_notify;
+
+ ret = regmap_bulk_read(data->regmap, ADXL355_TEMP2_REG,
+ &data->buffer.buf[12], 2);
+ if (ret)
+ goto out_unlock_notify;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer,
+ pf->timestamp);
+
+out_unlock_notify:
+ mutex_unlock(&data->lock);
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+#define ADXL355_ACCEL_CHANNEL(index, reg, axis) { \
+ .type = IIO_ACCEL, \
+ .address = reg, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_##axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_CALIBBIAS), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+ BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 20, \
+ .storagebits = 32, \
+ .shift = 4, \
+ .endianness = IIO_BE, \
+ } \
+}
+
+static const struct iio_chan_spec adxl355_channels[] = {
+ ADXL355_ACCEL_CHANNEL(0, chan_x, X),
+ ADXL355_ACCEL_CHANNEL(1, chan_y, Y),
+ ADXL355_ACCEL_CHANNEL(2, chan_z, Z),
+ {
+ .type = IIO_TEMP,
+ .address = ADXL355_TEMP2_REG,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .scan_index = 3,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 12,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq)
+{
+ struct adxl355_data *data = iio_priv(indio_dev);
+ int ret;
+
+ data->dready_trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!data->dready_trig)
+ return -ENOMEM;
+
+ data->dready_trig->ops = &adxl355_trigger_ops;
+ iio_trigger_set_drvdata(data->dready_trig, indio_dev);
+
+ ret = devm_request_irq(data->dev, irq,
+ &iio_trigger_generic_data_rdy_poll,
+ IRQF_ONESHOT, "adxl355_irq", data->dready_trig);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "request irq %d failed\n",
+ irq);
+
+ ret = devm_iio_trigger_register(data->dev, data->dready_trig);
+ if (ret) {
+ dev_err(data->dev, "iio trigger register failed\n");
+ return ret;
+ }
+
+ indio_dev->trig = iio_trigger_get(data->dready_trig);
+
+ return 0;
+}
+
+int adxl355_core_probe(struct device *dev, struct regmap *regmap,
+ const char *name)
+{
+ struct adxl355_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+ int irq;
+
+ 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;
+ data->op_mode = ADXL355_STANDBY;
+ mutex_init(&data->lock);
+
+ indio_dev->name = name;
+ indio_dev->info = &adxl355_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = adxl355_channels;
+ indio_dev->num_channels = ARRAY_SIZE(adxl355_channels);
+ indio_dev->available_scan_masks = adxl355_avail_scan_masks;
+
+ ret = adxl355_setup(data);
+ if (ret) {
+ dev_err(dev, "ADXL355 setup failed\n");
+ return ret;
+ }
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &adxl355_trigger_handler, NULL);
+ if (ret) {
+ dev_err(dev, "iio triggered buffer setup failed\n");
+ return ret;
+ }
+
+ /*
+ * TODO: Would be good to move it to the generic version.
+ */
+ irq = of_irq_get_byname(dev->of_node, "DRDY");
+ if (irq > 0) {
+ ret = adxl355_probe_trigger(indio_dev, irq);
+ if (ret)
+ return ret;
+ }
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_GPL(adxl355_core_probe);
+
+MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>");
+MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c
new file mode 100644
index 000000000000..5a987bda9060
--- /dev/null
+++ b/drivers/iio/accel/adxl355_i2c.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADXL355 3-Axis Digital Accelerometer I2C driver
+ *
+ * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+
+#include "adxl355.h"
+
+static const struct regmap_config adxl355_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x2F,
+ .rd_table = &adxl355_readable_regs_tbl,
+ .wr_table = &adxl355_writeable_regs_tbl,
+};
+
+static int adxl355_i2c_probe(struct i2c_client *client)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &adxl355_i2c_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
+ PTR_ERR(regmap));
+
+ return PTR_ERR(regmap);
+ }
+
+ return adxl355_core_probe(&client->dev, regmap, client->name);
+}
+
+static const struct i2c_device_id adxl355_i2c_id[] = {
+ { "adxl355", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adxl355_i2c_id);
+
+static const struct of_device_id adxl355_of_match[] = {
+ { .compatible = "adi,adxl355" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adxl355_of_match);
+
+static struct i2c_driver adxl355_i2c_driver = {
+ .driver = {
+ .name = "adxl355_i2c",
+ .of_match_table = adxl355_of_match,
+ },
+ .probe_new = adxl355_i2c_probe,
+ .id_table = adxl355_i2c_id,
+};
+module_i2c_driver(adxl355_i2c_driver);
+
+MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>");
+MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer I2C driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c
new file mode 100644
index 000000000000..fb225aeb56e3
--- /dev/null
+++ b/drivers/iio/accel/adxl355_spi.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ADXL355 3-Axis Digital Accelerometer SPI driver
+ *
+ * Copyright (c) 2021 Puranjay Mohan <puranjay12@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "adxl355.h"
+
+static const struct regmap_config adxl355_spi_regmap_config = {
+ .reg_bits = 7,
+ .pad_bits = 1,
+ .val_bits = 8,
+ .read_flag_mask = BIT(0),
+ .max_register = 0x2F,
+ .rd_table = &adxl355_readable_regs_tbl,
+ .wr_table = &adxl355_writeable_regs_tbl,
+};
+
+static int adxl355_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &adxl355_spi_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "Error initializing spi regmap: %ld\n",
+ PTR_ERR(regmap));
+
+ return PTR_ERR(regmap);
+ }
+
+ return adxl355_core_probe(&spi->dev, regmap, id->name);
+}
+
+static const struct spi_device_id adxl355_spi_id[] = {
+ { "adxl355", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, adxl355_spi_id);
+
+static const struct of_device_id adxl355_of_match[] = {
+ { .compatible = "adi,adxl355" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adxl355_of_match);
+
+static struct spi_driver adxl355_spi_driver = {
+ .driver = {
+ .name = "adxl355_spi",
+ .of_match_table = adxl355_of_match,
+ },
+ .probe = adxl355_spi_probe,
+ .id_table = adxl355_spi_id,
+};
+module_spi_driver(adxl355_spi_driver);
+
+MODULE_AUTHOR("Puranjay Mohan <puranjay12@gmail.com>");
+MODULE_DESCRIPTION("ADXL355 3-Axis Digital Accelerometer SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
index fc9592407717..758952584f8c 100644
--- a/drivers/iio/accel/adxl372.c
+++ b/drivers/iio/accel/adxl372.c
@@ -1214,6 +1214,7 @@ int adxl372_probe(struct device *dev, struct regmap *regmap,
ret = devm_iio_triggered_buffer_setup_ext(dev,
indio_dev, NULL,
adxl372_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
&adxl372_buffer_ops,
adxl372_fifo_attributes);
if (ret < 0)
diff --git a/drivers/iio/accel/bma400.h b/drivers/iio/accel/bma400.h
index 5ad10db9819f..c4c8d74155c2 100644
--- a/drivers/iio/accel/bma400.h
+++ b/drivers/iio/accel/bma400.h
@@ -94,6 +94,6 @@ extern const struct regmap_config bma400_regmap_config;
int bma400_probe(struct device *dev, struct regmap *regmap, const char *name);
-int bma400_remove(struct device *dev);
+void bma400_remove(struct device *dev);
#endif
diff --git a/drivers/iio/accel/bma400_core.c b/drivers/iio/accel/bma400_core.c
index 21520e022a21..fd2647b728d3 100644
--- a/drivers/iio/accel/bma400_core.c
+++ b/drivers/iio/accel/bma400_core.c
@@ -828,7 +828,7 @@ int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
}
EXPORT_SYMBOL(bma400_probe);
-int bma400_remove(struct device *dev)
+void bma400_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bma400_data *data = iio_priv(indio_dev);
@@ -838,12 +838,13 @@ int bma400_remove(struct device *dev)
ret = bma400_set_power_mode(data, POWER_MODE_SLEEP);
mutex_unlock(&data->mutex);
+ if (ret)
+ dev_warn(dev, "Failed to put device into sleep mode (%pe)\n", ERR_PTR(ret));
+
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
iio_device_unregister(indio_dev);
-
- return ret;
}
EXPORT_SYMBOL(bma400_remove);
diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c
index 9dcb7cc9996e..f50df5310beb 100644
--- a/drivers/iio/accel/bma400_i2c.c
+++ b/drivers/iio/accel/bma400_i2c.c
@@ -29,7 +29,9 @@ static int bma400_i2c_probe(struct i2c_client *client,
static int bma400_i2c_remove(struct i2c_client *client)
{
- return bma400_remove(&client->dev);
+ bma400_remove(&client->dev);
+
+ return 0;
}
static const struct i2c_device_id bma400_i2c_ids[] = {
diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c
index 7c2825904e08..9f622e37477b 100644
--- a/drivers/iio/accel/bma400_spi.c
+++ b/drivers/iio/accel/bma400_spi.c
@@ -89,7 +89,9 @@ static int bma400_spi_probe(struct spi_device *spi)
static int bma400_spi_remove(struct spi_device *spi)
{
- return bma400_remove(&spi->dev);
+ bma400_remove(&spi->dev);
+
+ return 0;
}
static const struct spi_device_id bma400_spi_ids[] = {
diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c
index e8693a42ad46..b0678c351e82 100644
--- a/drivers/iio/accel/bmc150-accel-core.c
+++ b/drivers/iio/accel/bmc150-accel-core.c
@@ -1734,6 +1734,7 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
ret = iio_triggered_buffer_setup_ext(indio_dev,
&iio_pollfunc_store_time,
bmc150_accel_trigger_handler,
+ IIO_BUFFER_DIRECTION_IN,
&bmc150_accel_buffer_ops,
fifo_attrs);
if (ret < 0) {
@@ -1799,7 +1800,7 @@ err_disable_regulators:
}
EXPORT_SYMBOL_GPL(bmc150_accel_core_probe);
-int bmc150_accel_core_remove(struct device *dev)
+void bmc150_accel_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmc150_accel_data *data = iio_priv(indio_dev);
@@ -1819,8 +1820,6 @@ int bmc150_accel_core_remove(struct device *dev)
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
-
- return 0;
}
EXPORT_SYMBOL_GPL(bmc150_accel_core_remove);
diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c
index 88bd8a25f142..9e52df9a8f07 100644
--- a/drivers/iio/accel/bmc150-accel-i2c.c
+++ b/drivers/iio/accel/bmc150-accel-i2c.c
@@ -213,7 +213,9 @@ static int bmc150_accel_remove(struct i2c_client *client)
{
bmc150_acpi_dual_accel_remove(client);
- return bmc150_accel_core_remove(&client->dev);
+ bmc150_accel_core_remove(&client->dev);
+
+ return 0;
}
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c
index 191e312dc91a..11559567cb39 100644
--- a/drivers/iio/accel/bmc150-accel-spi.c
+++ b/drivers/iio/accel/bmc150-accel-spi.c
@@ -37,7 +37,9 @@ static int bmc150_accel_probe(struct spi_device *spi)
static int bmc150_accel_remove(struct spi_device *spi)
{
- return bmc150_accel_core_remove(&spi->dev);
+ bmc150_accel_core_remove(&spi->dev);
+
+ return 0;
}
static const struct acpi_device_id bmc150_accel_acpi_match[] = {
diff --git a/drivers/iio/accel/bmc150-accel.h b/drivers/iio/accel/bmc150-accel.h
index 1bb5023e8ed9..7775c5edaeef 100644
--- a/drivers/iio/accel/bmc150-accel.h
+++ b/drivers/iio/accel/bmc150-accel.h
@@ -88,7 +88,7 @@ struct bmc150_accel_data {
int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
enum bmc150_type type, const char *name,
bool block_supported);
-int bmc150_accel_core_remove(struct device *dev);
+void bmc150_accel_core_remove(struct device *dev);
extern const struct dev_pm_ops bmc150_accel_pm_ops;
extern const struct regmap_config bmc150_regmap_conf;
diff --git a/drivers/iio/accel/bmi088-accel-core.c b/drivers/iio/accel/bmi088-accel-core.c
index a06dae5c971d..d74465214feb 100644
--- a/drivers/iio/accel/bmi088-accel-core.c
+++ b/drivers/iio/accel/bmi088-accel-core.c
@@ -536,7 +536,7 @@ int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap,
EXPORT_SYMBOL_GPL(bmi088_accel_core_probe);
-int bmi088_accel_core_remove(struct device *dev)
+void bmi088_accel_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmi088_accel_data *data = iio_priv(indio_dev);
@@ -546,8 +546,6 @@ int bmi088_accel_core_remove(struct device *dev)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
bmi088_accel_power_down(data);
-
- return 0;
}
EXPORT_SYMBOL_GPL(bmi088_accel_core_remove);
diff --git a/drivers/iio/accel/bmi088-accel-spi.c b/drivers/iio/accel/bmi088-accel-spi.c
index dd1e3f6cf211..758ad2f12896 100644
--- a/drivers/iio/accel/bmi088-accel-spi.c
+++ b/drivers/iio/accel/bmi088-accel-spi.c
@@ -58,7 +58,9 @@ static int bmi088_accel_probe(struct spi_device *spi)
static int bmi088_accel_remove(struct spi_device *spi)
{
- return bmi088_accel_core_remove(&spi->dev);
+ bmi088_accel_core_remove(&spi->dev);
+
+ return 0;
}
static const struct spi_device_id bmi088_accel_id[] = {
diff --git a/drivers/iio/accel/bmi088-accel.h b/drivers/iio/accel/bmi088-accel.h
index 5c25f16b672c..5d40c7cf1cbc 100644
--- a/drivers/iio/accel/bmi088-accel.h
+++ b/drivers/iio/accel/bmi088-accel.h
@@ -13,6 +13,6 @@ extern const struct dev_pm_ops bmi088_accel_pm_ops;
int bmi088_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
const char *name, bool block_supported);
-int bmi088_accel_core_remove(struct device *dev);
+void bmi088_accel_core_remove(struct device *dev);
#endif /* BMI088_ACCEL_H */
diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c
index f41db9e0249a..32989d91b982 100644
--- a/drivers/iio/accel/fxls8962af-core.c
+++ b/drivers/iio/accel/fxls8962af-core.c
@@ -22,6 +22,7 @@
#include <linux/regmap.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
@@ -30,6 +31,7 @@
#define FXLS8962AF_INT_STATUS 0x00
#define FXLS8962AF_INT_STATUS_SRC_BOOT BIT(0)
+#define FXLS8962AF_INT_STATUS_SRC_SDCD_OT BIT(4)
#define FXLS8962AF_INT_STATUS_SRC_BUF BIT(5)
#define FXLS8962AF_INT_STATUS_SRC_DRDY BIT(7)
#define FXLS8962AF_TEMP_OUT 0x01
@@ -73,6 +75,7 @@
#define FXLS8962AF_ASLP_COUNT_LSB 0x1e
#define FXLS8962AF_INT_EN 0x20
+#define FXLS8962AF_INT_EN_SDCD_OT_EN BIT(5)
#define FXLS8962AF_INT_EN_BUF_EN BIT(6)
#define FXLS8962AF_INT_PIN_SEL 0x21
#define FXLS8962AF_INT_PIN_SEL_MASK GENMASK(7, 0)
@@ -96,9 +99,21 @@
#define FXLS8962AF_ORIENT_THS_REG 0x2c
#define FXLS8962AF_SDCD_INT_SRC1 0x2d
+#define FXLS8962AF_SDCD_INT_SRC1_X_OT BIT(5)
+#define FXLS8962AF_SDCD_INT_SRC1_X_POL BIT(4)
+#define FXLS8962AF_SDCD_INT_SRC1_Y_OT BIT(3)
+#define FXLS8962AF_SDCD_INT_SRC1_Y_POL BIT(2)
+#define FXLS8962AF_SDCD_INT_SRC1_Z_OT BIT(1)
+#define FXLS8962AF_SDCD_INT_SRC1_Z_POL BIT(0)
#define FXLS8962AF_SDCD_INT_SRC2 0x2e
#define FXLS8962AF_SDCD_CONFIG1 0x2f
+#define FXLS8962AF_SDCD_CONFIG1_Z_OT_EN BIT(3)
+#define FXLS8962AF_SDCD_CONFIG1_Y_OT_EN BIT(4)
+#define FXLS8962AF_SDCD_CONFIG1_X_OT_EN BIT(5)
+#define FXLS8962AF_SDCD_CONFIG1_OT_ELE BIT(7)
#define FXLS8962AF_SDCD_CONFIG2 0x30
+#define FXLS8962AF_SDCD_CONFIG2_SDCD_EN BIT(7)
+#define FXLS8962AF_SC2_REF_UPDM_AC GENMASK(6, 5)
#define FXLS8962AF_SDCD_OT_DBCNT 0x31
#define FXLS8962AF_SDCD_WT_DBCNT 0x32
#define FXLS8962AF_SDCD_LTHS_LSB 0x33
@@ -151,7 +166,11 @@ struct fxls8962af_data {
} scan;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
struct iio_mount_matrix orientation;
+ int irq;
u8 watermark;
+ u8 enable_event;
+ u16 lower_thres;
+ u16 upper_thres;
};
const struct regmap_config fxls8962af_regmap_conf = {
@@ -238,7 +257,7 @@ static int fxls8962af_get_out(struct fxls8962af_data *data,
}
ret = regmap_bulk_read(data->regmap, chan->address,
- &raw_val, (chan->scan_type.storagebits / 8));
+ &raw_val, sizeof(data->lower_thres));
if (!is_active)
fxls8962af_power_off(data);
@@ -451,6 +470,15 @@ static int fxls8962af_write_raw(struct iio_dev *indio_dev,
}
}
+static int fxls8962af_event_setup(struct fxls8962af_data *data, int state)
+{
+ /* Enable wakeup interrupt */
+ int mask = FXLS8962AF_INT_EN_SDCD_OT_EN;
+ int value = state ? mask : 0;
+
+ return regmap_update_bits(data->regmap, FXLS8962AF_INT_EN, mask, value);
+}
+
static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
@@ -463,6 +491,217 @@ static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
return 0;
}
+static int __fxls8962af_set_thresholds(struct fxls8962af_data *data,
+ const struct iio_chan_spec *chan,
+ enum iio_event_direction dir,
+ int val)
+{
+ switch (dir) {
+ case IIO_EV_DIR_FALLING:
+ data->lower_thres = val;
+ return regmap_bulk_write(data->regmap, FXLS8962AF_SDCD_LTHS_LSB,
+ &data->lower_thres, sizeof(data->lower_thres));
+ case IIO_EV_DIR_RISING:
+ data->upper_thres = val;
+ return regmap_bulk_write(data->regmap, FXLS8962AF_SDCD_UTHS_LSB,
+ &data->upper_thres, sizeof(data->upper_thres));
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ switch (dir) {
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_bulk_read(data->regmap, FXLS8962AF_SDCD_LTHS_LSB,
+ &data->lower_thres, sizeof(data->lower_thres));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(data->lower_thres, chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ case IIO_EV_DIR_RISING:
+ ret = regmap_bulk_read(data->regmap, FXLS8962AF_SDCD_UTHS_LSB,
+ &data->upper_thres, sizeof(data->upper_thres));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(data->upper_thres, chan->scan_type.realbits - 1);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int fxls8962af_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ int ret, val_masked;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ if (val < -2048 || val > 2047)
+ return -EINVAL;
+
+ if (data->enable_event)
+ return -EBUSY;
+
+ val_masked = val & GENMASK(11, 0);
+ if (fxls8962af_is_active(data)) {
+ ret = fxls8962af_standby(data);
+ if (ret)
+ return ret;
+
+ ret = __fxls8962af_set_thresholds(data, chan, dir, val_masked);
+ if (ret)
+ return ret;
+
+ return fxls8962af_active(data);
+ } else {
+ return __fxls8962af_set_thresholds(data, chan, dir, val_masked);
+ }
+}
+
+static int
+fxls8962af_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ return !!(FXLS8962AF_SDCD_CONFIG1_X_OT_EN & data->enable_event);
+ case IIO_MOD_Y:
+ return !!(FXLS8962AF_SDCD_CONFIG1_Y_OT_EN & data->enable_event);
+ case IIO_MOD_Z:
+ return !!(FXLS8962AF_SDCD_CONFIG1_Z_OT_EN & data->enable_event);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int
+fxls8962af_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ u8 enable_event, enable_bits;
+ int ret, value;
+
+ if (type != IIO_EV_TYPE_THRESH)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ enable_bits = FXLS8962AF_SDCD_CONFIG1_X_OT_EN;
+ break;
+ case IIO_MOD_Y:
+ enable_bits = FXLS8962AF_SDCD_CONFIG1_Y_OT_EN;
+ break;
+ case IIO_MOD_Z:
+ enable_bits = FXLS8962AF_SDCD_CONFIG1_Z_OT_EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (state)
+ enable_event = data->enable_event | enable_bits;
+ else
+ enable_event = data->enable_event & ~enable_bits;
+
+ if (data->enable_event == enable_event)
+ return 0;
+
+ ret = fxls8962af_standby(data);
+ if (ret)
+ return ret;
+
+ /* Enable events */
+ value = enable_event | FXLS8962AF_SDCD_CONFIG1_OT_ELE;
+ ret = regmap_write(data->regmap, FXLS8962AF_SDCD_CONFIG1, value);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable update of SDCD_REF_X/Y/Z values with the current decimated and
+ * trimmed X/Y/Z acceleration input data. This allows for acceleration
+ * slope detection with Data(n) to Data(n–1) always used as the input
+ * to the window comparator.
+ */
+ value = enable_event ?
+ FXLS8962AF_SDCD_CONFIG2_SDCD_EN | FXLS8962AF_SC2_REF_UPDM_AC :
+ 0x00;
+ ret = regmap_write(data->regmap, FXLS8962AF_SDCD_CONFIG2, value);
+ if (ret)
+ return ret;
+
+ ret = fxls8962af_event_setup(data, state);
+ if (ret)
+ return ret;
+
+ data->enable_event = enable_event;
+
+ if (data->enable_event) {
+ fxls8962af_active(data);
+ ret = fxls8962af_power_on(data);
+ } else {
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Not in buffered mode so disable power */
+ ret = fxls8962af_power_off(data);
+
+ iio_device_release_direct_mode(indio_dev);
+ }
+
+ return ret;
+}
+
+static const struct iio_event_spec fxls8962af_event[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE),
+ },
+};
+
#define FXLS8962AF_CHANNEL(axis, reg, idx) { \
.type = IIO_ACCEL, \
.address = reg, \
@@ -481,6 +720,8 @@ static int fxls8962af_set_watermark(struct iio_dev *indio_dev, unsigned val)
.shift = 4, \
.endianness = IIO_BE, \
}, \
+ .event_spec = fxls8962af_event, \
+ .num_event_specs = ARRAY_SIZE(fxls8962af_event), \
}
#define FXLS8962AF_TEMP_CHANNEL { \
@@ -522,6 +763,10 @@ static const struct iio_info fxls8962af_info = {
.read_raw = &fxls8962af_read_raw,
.write_raw = &fxls8962af_write_raw,
.write_raw_get_fmt = fxls8962af_write_raw_get_fmt,
+ .read_event_value = fxls8962af_read_event,
+ .write_event_value = fxls8962af_write_event,
+ .read_event_config = fxls8962af_read_event_config,
+ .write_event_config = fxls8962af_write_event_config,
.read_avail = fxls8962af_read_avail,
.hwfifo_set_watermark = fxls8962af_set_watermark,
};
@@ -605,7 +850,8 @@ static int fxls8962af_buffer_predisable(struct iio_dev *indio_dev)
ret = __fxls8962af_fifo_set_mode(data, false);
- fxls8962af_active(data);
+ if (data->enable_event)
+ fxls8962af_active(data);
return ret;
}
@@ -614,7 +860,10 @@ static int fxls8962af_buffer_postdisable(struct iio_dev *indio_dev)
{
struct fxls8962af_data *data = iio_priv(indio_dev);
- return fxls8962af_power_off(data);
+ if (!data->enable_event)
+ fxls8962af_power_off(data);
+
+ return 0;
}
static const struct iio_buffer_setup_ops fxls8962af_buffer_ops = {
@@ -725,6 +974,45 @@ static int fxls8962af_fifo_flush(struct iio_dev *indio_dev)
return count;
}
+static int fxls8962af_event_interrupt(struct iio_dev *indio_dev)
+{
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+ s64 ts = iio_get_time_ns(indio_dev);
+ unsigned int reg;
+ u64 ev_code;
+ int ret;
+
+ ret = regmap_read(data->regmap, FXLS8962AF_SDCD_INT_SRC1, &reg);
+ if (ret)
+ return ret;
+
+ if (reg & FXLS8962AF_SDCD_INT_SRC1_X_OT) {
+ ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_X_POL ?
+ IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
+ IIO_EV_TYPE_THRESH, ev_code), ts);
+ }
+
+ if (reg & FXLS8962AF_SDCD_INT_SRC1_Y_OT) {
+ ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Y_POL ?
+ IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
+ IIO_EV_TYPE_THRESH, ev_code), ts);
+ }
+
+ if (reg & FXLS8962AF_SDCD_INT_SRC1_Z_OT) {
+ ev_code = reg & FXLS8962AF_SDCD_INT_SRC1_Z_POL ?
+ IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X,
+ IIO_EV_TYPE_THRESH, ev_code), ts);
+ }
+
+ return 0;
+}
+
static irqreturn_t fxls8962af_interrupt(int irq, void *p)
{
struct iio_dev *indio_dev = p;
@@ -744,6 +1032,14 @@ static irqreturn_t fxls8962af_interrupt(int irq, void *p)
return IRQ_HANDLED;
}
+ if (reg & FXLS8962AF_INT_STATUS_SRC_SDCD_OT) {
+ ret = fxls8962af_event_interrupt(indio_dev);
+ if (ret < 0)
+ return IRQ_NONE;
+
+ return IRQ_HANDLED;
+ }
+
return IRQ_NONE;
}
@@ -861,6 +1157,7 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
+ data->irq = irq;
ret = iio_read_mount_matrix(dev, &data->orientation);
if (ret)
@@ -930,6 +1227,9 @@ int fxls8962af_core_probe(struct device *dev, struct regmap *regmap, int irq)
if (ret)
return ret;
+ if (device_property_read_bool(dev, "wakeup-source"))
+ device_init_wakeup(dev, true);
+
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(fxls8962af_core_probe);
@@ -955,9 +1255,46 @@ static int __maybe_unused fxls8962af_runtime_resume(struct device *dev)
return fxls8962af_active(data);
}
+static int __maybe_unused fxls8962af_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (device_may_wakeup(dev) && data->enable_event) {
+ enable_irq_wake(data->irq);
+
+ /*
+ * Disable buffer, as the buffer is so small the device will wake
+ * almost immediately.
+ */
+ if (iio_buffer_enabled(indio_dev))
+ fxls8962af_buffer_predisable(indio_dev);
+ } else {
+ fxls8962af_runtime_suspend(dev);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused fxls8962af_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct fxls8962af_data *data = iio_priv(indio_dev);
+
+ if (device_may_wakeup(dev) && data->enable_event) {
+ disable_irq_wake(data->irq);
+
+ if (iio_buffer_enabled(indio_dev))
+ fxls8962af_buffer_postenable(indio_dev);
+ } else {
+ fxls8962af_runtime_resume(dev);
+ }
+
+ return 0;
+}
+
const struct dev_pm_ops fxls8962af_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(fxls8962af_suspend, fxls8962af_resume)
SET_RUNTIME_PM_OPS(fxls8962af_runtime_suspend,
fxls8962af_runtime_resume, NULL)
};
diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c
index b580d605f848..274b41a6e603 100644
--- a/drivers/iio/accel/kxsd9-i2c.c
+++ b/drivers/iio/accel/kxsd9-i2c.c
@@ -34,7 +34,9 @@ static int kxsd9_i2c_probe(struct i2c_client *i2c,
static int kxsd9_i2c_remove(struct i2c_client *client)
{
- return kxsd9_common_remove(&client->dev);
+ kxsd9_common_remove(&client->dev);
+
+ return 0;
}
static const struct of_device_id kxsd9_of_match[] = {
diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c
index 7971ec1eeb7e..441e6b764281 100644
--- a/drivers/iio/accel/kxsd9-spi.c
+++ b/drivers/iio/accel/kxsd9-spi.c
@@ -34,7 +34,9 @@ static int kxsd9_spi_probe(struct spi_device *spi)
static int kxsd9_spi_remove(struct spi_device *spi)
{
- return kxsd9_common_remove(&spi->dev);
+ kxsd9_common_remove(&spi->dev);
+
+ return 0;
}
static const struct spi_device_id kxsd9_spi_id[] = {
diff --git a/drivers/iio/accel/kxsd9.c b/drivers/iio/accel/kxsd9.c
index bf7ed9e7d00f..2faf85ca996e 100644
--- a/drivers/iio/accel/kxsd9.c
+++ b/drivers/iio/accel/kxsd9.c
@@ -478,7 +478,7 @@ err_power_down:
}
EXPORT_SYMBOL(kxsd9_common_probe);
-int kxsd9_common_remove(struct device *dev)
+void kxsd9_common_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct kxsd9_state *st = iio_priv(indio_dev);
@@ -489,8 +489,6 @@ int kxsd9_common_remove(struct device *dev)
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
kxsd9_power_down(st);
-
- return 0;
}
EXPORT_SYMBOL(kxsd9_common_remove);
diff --git a/drivers/iio/accel/kxsd9.h b/drivers/iio/accel/kxsd9.h
index 5e3ca212f5be..c04dbfa4e0d0 100644
--- a/drivers/iio/accel/kxsd9.h
+++ b/drivers/iio/accel/kxsd9.h
@@ -8,6 +8,6 @@
int kxsd9_common_probe(struct device *dev,
struct regmap *map,
const char *name);
-int kxsd9_common_remove(struct device *dev);
+void kxsd9_common_remove(struct device *dev);
extern const struct dev_pm_ops kxsd9_dev_pm_ops;
diff --git a/drivers/iio/accel/mma7455.h b/drivers/iio/accel/mma7455.h
index 4e3fa988f690..1fcc4b64b3af 100644
--- a/drivers/iio/accel/mma7455.h
+++ b/drivers/iio/accel/mma7455.h
@@ -11,6 +11,6 @@ extern const struct regmap_config mma7455_core_regmap;
int mma7455_core_probe(struct device *dev, struct regmap *regmap,
const char *name);
-int mma7455_core_remove(struct device *dev);
+void mma7455_core_remove(struct device *dev);
#endif
diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c
index 922bd38ff6ea..777c6c384b09 100644
--- a/drivers/iio/accel/mma7455_core.c
+++ b/drivers/iio/accel/mma7455_core.c
@@ -294,7 +294,7 @@ int mma7455_core_probe(struct device *dev, struct regmap *regmap,
}
EXPORT_SYMBOL_GPL(mma7455_core_probe);
-int mma7455_core_remove(struct device *dev)
+void mma7455_core_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct mma7455_data *mma7455 = iio_priv(indio_dev);
@@ -304,8 +304,6 @@ int mma7455_core_remove(struct device *dev)
regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
MMA7455_MCTL_MODE_STANDBY);
-
- return 0;
}
EXPORT_SYMBOL_GPL(mma7455_core_remove);
diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c
index cddeaa9e230a..8a5256516f9f 100644
--- a/drivers/iio/accel/mma7455_i2c.c
+++ b/drivers/iio/accel/mma7455_i2c.c
@@ -28,7 +28,9 @@ static int mma7455_i2c_probe(struct i2c_client *i2c,
static int mma7455_i2c_remove(struct i2c_client *i2c)
{
- return mma7455_core_remove(&i2c->dev);
+ mma7455_core_remove(&i2c->dev);
+
+ return 0;
}
static const struct i2c_device_id mma7455_i2c_ids[] = {
diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c
index eb82cdfa8abc..ecf690692dcc 100644
--- a/drivers/iio/accel/mma7455_spi.c
+++ b/drivers/iio/accel/mma7455_spi.c
@@ -24,7 +24,9 @@ static int mma7455_spi_probe(struct spi_device *spi)
static int mma7455_spi_remove(struct spi_device *spi)
{
- return mma7455_core_remove(&spi->dev);
+ mma7455_core_remove(&spi->dev);
+
+ return 0;
}
static const struct spi_device_id mma7455_spi_ids[] = {
diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c
index 47f5cd66e996..cd6cdf2c51b0 100644
--- a/drivers/iio/accel/mma7660.c
+++ b/drivers/iio/accel/mma7660.c
@@ -254,7 +254,7 @@ static const struct of_device_id mma7660_of_match[] = {
};
MODULE_DEVICE_TABLE(of, mma7660_of_match);
-static const struct acpi_device_id mma7660_acpi_id[] = {
+static const struct acpi_device_id __maybe_unused mma7660_acpi_id[] = {
{"MMA7660", 0},
{}
};
diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c
index cb753a43533c..c6b75308148a 100644
--- a/drivers/iio/accel/sca3000.c
+++ b/drivers/iio/accel/sca3000.c
@@ -731,8 +731,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
return ret;
}
*val = (be16_to_cpup((__be16 *)st->rx) >> 3) & 0x1FFF;
- *val = ((*val) << (sizeof(*val) * 8 - 13)) >>
- (sizeof(*val) * 8 - 13);
+ *val = sign_extend32(*val, 12);
} else {
/* get the temperature when available */
ret = sca3000_read_data_short(st,
diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c
index f1e6ec380667..31ea19d0ba71 100644
--- a/drivers/iio/accel/st_accel_core.c
+++ b/drivers/iio/accel/st_accel_core.c
@@ -1210,7 +1210,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev)
};
- adev = ACPI_COMPANION(adata->dev);
+ adev = ACPI_COMPANION(indio_dev->dev.parent);
if (!adev)
return 0;
@@ -1334,7 +1334,8 @@ EXPORT_SYMBOL(st_accel_get_settings);
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
- struct st_sensors_platform_data *pdata = dev_get_platdata(adata->dev);
+ struct device *parent = indio_dev->dev.parent;
+ struct st_sensors_platform_data *pdata = dev_get_platdata(parent);
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -1354,7 +1355,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
*/
err = apply_acpi_orientation(indio_dev);
if (err) {
- err = iio_read_mount_matrix(adata->dev, &adata->mount_matrix);
+ err = iio_read_mount_matrix(parent, &adata->mount_matrix);
if (err)
return err;
}
@@ -1380,32 +1381,10 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
return err;
}
- err = iio_device_register(indio_dev);
- if (err)
- goto st_accel_device_register_error;
-
- dev_info(&indio_dev->dev, "registered accelerometer %s\n",
- indio_dev->name);
-
- return 0;
-
-st_accel_device_register_error:
- if (adata->irq > 0)
- st_sensors_deallocate_trigger(indio_dev);
- return err;
+ return devm_iio_device_register(parent, indio_dev);
}
EXPORT_SYMBOL(st_accel_common_probe);
-void st_accel_common_remove(struct iio_dev *indio_dev)
-{
- struct st_sensor_data *adata = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
- if (adata->irq > 0)
- st_sensors_deallocate_trigger(indio_dev);
-}
-EXPORT_SYMBOL(st_accel_common_remove);
-
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics accelerometers driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c
index f711756e41e3..c0ce78eebad9 100644
--- a/drivers/iio/accel/st_accel_i2c.c
+++ b/drivers/iio/accel/st_accel_i2c.c
@@ -177,27 +177,7 @@ static int st_accel_i2c_probe(struct i2c_client *client)
if (ret)
return ret;
- ret = st_accel_common_probe(indio_dev);
- if (ret < 0)
- goto st_accel_power_off;
-
- return 0;
-
-st_accel_power_off:
- st_sensors_power_disable(indio_dev);
-
- return ret;
-}
-
-static int st_accel_i2c_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
- st_sensors_power_disable(indio_dev);
-
- st_accel_common_remove(indio_dev);
-
- return 0;
+ return st_accel_common_probe(indio_dev);
}
static struct i2c_driver st_accel_driver = {
@@ -207,7 +187,6 @@ static struct i2c_driver st_accel_driver = {
.acpi_match_table = ACPI_PTR(st_accel_acpi_match),
},
.probe_new = st_accel_i2c_probe,
- .remove = st_accel_i2c_remove,
.id_table = st_accel_id_table,
};
module_i2c_driver(st_accel_driver);
diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c
index bb45d9ff95b8..b74a1c6d03de 100644
--- a/drivers/iio/accel/st_accel_spi.c
+++ b/drivers/iio/accel/st_accel_spi.c
@@ -127,27 +127,7 @@ static int st_accel_spi_probe(struct spi_device *spi)
if (err)
return err;
- err = st_accel_common_probe(indio_dev);
- if (err < 0)
- goto st_accel_power_off;
-
- return 0;
-
-st_accel_power_off:
- st_sensors_power_disable(indio_dev);
-
- return err;
-}
-
-static int st_accel_spi_remove(struct spi_device *spi)
-{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
-
- st_sensors_power_disable(indio_dev);
-
- st_accel_common_remove(indio_dev);
-
- return 0;
+ return st_accel_common_probe(indio_dev);
}
static const struct spi_device_id st_accel_id_table[] = {
@@ -177,7 +157,6 @@ static struct spi_driver st_accel_driver = {
.of_match_table = st_accel_of_match,
},
.probe = st_accel_spi_probe,
- .remove = st_accel_spi_remove,
.id_table = st_accel_id_table,
};
module_spi_driver(st_accel_driver);