* [PATCH 0/10] iio: accel: BMA220 improvements
@ 2025-09-01 19:47 Petre Rodan
2025-09-01 19:47 ` [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements Petre Rodan
` (9 more replies)
0 siblings, 10 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Conor Dooley
Series of patches that switch the driver to the regmap API, add i2c
connectivity, tap/low-g/high-g/slope event detection and a large number
of sysfs mappings while keeping backward compatibility.
Tested in I2C and SPI modes with two different sensors.
Petre Rodan (10):
dt-bindings: iio: accel: bosch,BMA220 improvements
iio: accel: BMA220 split original spi driver
iio: accel: BMA220 migrate to regmap SPI
iio: accel: BMA220 add i2c module
iio: accel: BMA220 make use of the watchdog functionality
iio: accel: BMA220 add LPF cut-off frequency mapping
iio: accel: BMA220 add debugfs reg access
iio: accel: BMA220 add events
iio: accel: BMA220 add event attrs
iio: accel: BMA220 add maintainer
.../bindings/iio/accel/bosch,bma220.yaml | 20 +-
MAINTAINERS | 7 +
drivers/iio/accel/Kconfig | 18 +-
drivers/iio/accel/Makefile | 4 +-
drivers/iio/accel/bma220.h | 21 +
drivers/iio/accel/bma220_core.c | 1551 +++++++++++++++++
drivers/iio/accel/bma220_i2c.c | 62 +
drivers/iio/accel/bma220_spi.c | 313 +---
8 files changed, 1702 insertions(+), 294 deletions(-)
create mode 100644 drivers/iio/accel/bma220.h
create mode 100644 drivers/iio/accel/bma220_core.c
create mode 100644 drivers/iio/accel/bma220_i2c.c
--
2.49.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-02 5:57 ` Krzysztof Kozlowski
2025-09-01 19:47 ` [PATCH 02/10] iio: accel: BMA220 split original spi driver Petre Rodan
` (8 subsequent siblings)
9 siblings, 1 reply; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Conor Dooley, Krzysztof Kozlowski
- fix title typo
- add optional watchdog setting that recovers the sensor from a stuck-low
SDA condition
- set correct SPI phase and polarity
- interrupt on rising edge. the level-based interrupt that is being
replaced was not actually implemented in the driver.
This set of changes should not negatively affect existing users.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
.../bindings/iio/accel/bosch,bma220.yaml | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml b/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml
index ec643de031a3..f71b2320b010 100644
--- a/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml
+++ b/Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/iio/accel/bosch,bma220.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Bosch BMA220 Trixial Acceleration Sensor
+title: Bosch BMA220 Triaxial Acceleration Sensor
maintainers:
- Jonathan Cameron <Jonathan.Cameron@huawei.com>
@@ -20,6 +20,20 @@ properties:
interrupts:
maxItems: 1
+ bosch,watchdog:
+ description:
+ In order to prevent the built-in I2C slave to lock-up the I2C bus, a
+ watchdog timer is introduced. The WDT observes internal I2C signals and
+ resets the I2C interface if the bus is locked-up by the BMA220.
+ 0 - off
+ 1 - 1ms
+ 2 - 10ms
+ enum: [0, 1, 2]
+ $ref: /schemas/types.yaml#/definitions/uint32
+
+ spi-cpha: true
+ spi-cpol: true
+
vdda-supply: true
vddd-supply: true
vddio-supply: true
@@ -44,8 +58,10 @@ examples:
compatible = "bosch,bma220";
reg = <0>;
spi-max-frequency = <2500000>;
+ spi-cpol;
+ spi-cpha;
interrupt-parent = <&gpio0>;
- interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
};
...
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 02/10] iio: accel: BMA220 split original spi driver
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
2025-09-01 19:47 ` [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 03/10] iio: accel: BMA220 migrate to regmap API Petre Rodan
` (7 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Split original driver from bma220_spi.c into bma220_core.c and bma220.h
with a minimal number of changes in preparation for the next patches.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/Kconfig | 9 +-
drivers/iio/accel/Makefile | 3 +-
drivers/iio/accel/bma220.h | 17 ++
drivers/iio/accel/bma220_core.c | 310 ++++++++++++++++++++++++++++++++
drivers/iio/accel/bma220_spi.c | 309 ++-----------------------------
5 files changed, 354 insertions(+), 294 deletions(-)
create mode 100644 drivers/iio/accel/bma220.h
create mode 100644 drivers/iio/accel/bma220_core.c
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 8c3f7cf55d5f..2cc3075e2688 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -218,15 +218,20 @@ config BMA180
config BMA220
tristate "Bosch BMA220 3-Axis Accelerometer Driver"
- depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+ 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_spi if SPI is enabled.
+
+config BMA220_SPI
+ tristate
+ 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..56a9f848f7f9 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -25,7 +25,8 @@ 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_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/bma220.h b/drivers/iio/accel/bma220.h
new file mode 100644
index 000000000000..0606cf478f5f
--- /dev/null
+++ b/drivers/iio/accel/bma220.h
@@ -0,0 +1,17 @@
+/* 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/iio/iio.h>
+
+extern const struct dev_pm_ops bma220_pm_ops;
+
+int bma220_common_probe(struct spi_device *dev);
+
+#endif
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
new file mode 100644
index 000000000000..60fd35637d2d
--- /dev/null
+++ b/drivers/iio/accel/bma220_core.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * BMA220 Digital triaxial acceleration sensor driver
+ *
+ * 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/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>
+
+#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)
+{
+ 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;
+
+ 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);
+
+ 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 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);
+}
+
+int bma220_common_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);
+}
+EXPORT_SYMBOL_NS(bma220_common_probe, "IIO_BOSCH_BMA220");
+
+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);
+}
+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_spi.c b/drivers/iio/accel/bma220_spi.c
index 01592eebf05b..be8348ad0a93 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -5,8 +5,8 @@
* Copyright (c) 2016,2020 Intel Corporation.
*/
-#include <linux/bits.h>
-#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/errno.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -14,295 +14,14 @@
#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>
-#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
+#include "bma220.h"
-#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)
-{
- 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;
-
- 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);
-
- 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 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)
+static int bma220_spi_probe(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;
+ return bma220_common_probe(spi);
}
-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},
{ }
@@ -314,17 +33,25 @@ static const struct acpi_device_id bma220_acpi_id[] = {
};
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");
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 03/10] iio: accel: BMA220 migrate to regmap API
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
2025-09-01 19:47 ` [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements Petre Rodan
2025-09-01 19:47 ` [PATCH 02/10] iio: accel: BMA220 split original spi driver Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 04/10] iio: accel: BMA220 add i2c module Petre Rodan
` (6 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Switch to regmap API.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/Kconfig | 2 +
drivers/iio/accel/bma220.h | 5 +-
drivers/iio/accel/bma220_core.c | 417 ++++++++++++++++++++++++++------
drivers/iio/accel/bma220_spi.c | 12 +-
4 files changed, 354 insertions(+), 82 deletions(-)
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 2cc3075e2688..9b6c35b75948 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -218,6 +218,7 @@ config BMA180
config BMA220
tristate "Bosch BMA220 3-Axis Accelerometer Driver"
+ select REGMAP
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select BMA220_SPI if SPI
@@ -231,6 +232,7 @@ config BMA220
config BMA220_SPI
tristate
+ select REGMAP_SPI
depends on BMA220
config BMA400
diff --git a/drivers/iio/accel/bma220.h b/drivers/iio/accel/bma220.h
index 0606cf478f5f..5eefa9749d33 100644
--- a/drivers/iio/accel/bma220.h
+++ b/drivers/iio/accel/bma220.h
@@ -8,10 +8,13 @@
#ifndef _BMA220_H
#define _BMA220_H
+#include <linux/regmap.h>
+
#include <linux/iio/iio.h>
+extern const struct regmap_config bma220_spi_regmap_config;
extern const struct dev_pm_ops bma220_pm_ops;
-int bma220_common_probe(struct spi_device *dev);
+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
index 60fd35637d2d..e6dac2e1cf4d 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -3,31 +3,133 @@
* 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/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/types.h>
-#include <linux/spi/spi.h>
-#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
+#include "bma220.h"
+
+/*
+ * Read-Only Registers
+ */
+
+/* ID registers */
#define BMA220_REG_ID 0x00
+#define BMA220_REG_REVISION_ID 0x01
+
+/* Acceleration registers */
#define BMA220_REG_ACCEL_X 0x02
#define BMA220_REG_ACCEL_Y 0x03
#define BMA220_REG_ACCEL_Z 0x04
+
+/*
+ * Read-write configuration registers
+ */
+#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_TT_FILT_MSK BIT(7)
+#define BMA220_REG_CONF4 0x09
+#define BMA220_SLOPE_DUR_MSK GENMASK(1, 0)
+#define BMA220_SLOPE_TH_MSK GENMASK(5, 2)
+#define BMA220_SLOPE_FILT_MSK BIT(6)
+#define BMA220_ORIENT_EX_MSK BIT(7)
+#define BMA220_REG_CONF5 0x0a
+#define BMA220_TT_SAMP_MSK GENMASK(1, 0)
+#define BMA220_ORIENT_BLOCKING_MSK GENMASK(3, 2)
+#define BMA220_TIP_EN_MSK BIT(4)
+
+/*
+ * Read-only interrupt flags
+ */
+#define BMA220_REG_IF0 0x0b
+/* interrupt flags */
+#define BMA220_IF_HIGH_SIGN BIT(0)
+#define BMA220_IF_HIGH_FIRST_Z BIT(1)
+#define BMA220_IF_HIGH_FIRST_Y BIT(2)
+#define BMA220_IF_HIGH_FIRST_X BIT(3)
+#define BMA220_IF_ORIENT_INT BIT(7)
+
+#define BMA220_REG_IF1 0x0c
+/* interrupt flags */
+#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)
+
+/*
+ * Read-write interrupt enable configuration registers
+ */
+#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_ORIENT_MSK BIT(6)
+#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_LATCH_MAX 0x7
+#define BMA220_INT_RST_MSK BIT(7)
+#define BMA220_INT_LATCH_LEN 8
+#define BMA220_REG_IE2 0x0f
+
+/*
+ * Read-write configuration registers
+ */
+#define BMA220_REG_FILTER 0x10
#define BMA220_REG_RANGE 0x11
+#define BMA220_REG_WDT 0x17
+#define BMA220_WDT_MASK GENMASK(2, 1)
+#define BMA220_WDT_OFF 0x0
+#define BMA220_WDT_1MS BIT(1)
+#define BMA220_WDT_10MS GENMASK(1, 0)
+/*
+ * Read-only state change registers
+ */
#define BMA220_REG_SUSPEND 0x18
+#define BMA220_REG_SOFTRESET 0x19
#define BMA220_CHIP_ID 0xDD
-#define BMA220_READ_MASK BIT(7)
#define BMA220_RANGE_MASK GENMASK(1, 0)
+#define BMA220_FILTER_MASK GENMASK(3, 0)
#define BMA220_SUSPEND_SLEEP 0xFF
#define BMA220_SUSPEND_WAKE 0x00
@@ -61,14 +163,16 @@ static const int bma220_scale_table[][2] = {
};
struct bma220_data {
- struct spi_device *spi_device;
+ struct device *dev;
+ struct regmap *regmap;
struct mutex lock;
+ u8 range_idx;
+ struct iio_trigger *trig;
struct {
s8 chans[3];
/* Ensure timestamp is naturally aligned. */
aligned_s64 timestamp;
- } scan;
- u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN);
+ } scan __aligned(IIO_DMA_MINALIGN);
};
static const struct iio_chan_spec bma220_channels[] = {
@@ -78,35 +182,81 @@ static const struct iio_chan_spec bma220_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3),
};
-static inline int bma220_read_reg(struct spi_device *spi, u8 reg)
-{
- 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 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;
+ }
+}
+
+static bool bma220_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ /* Don't cache any registers. */
+ return true;
+}
+
+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_MAPLE,
+ .writeable_reg = bma220_is_writable_reg,
+ .volatile_reg = bma220_is_volatile_reg,
+};
+EXPORT_SYMBOL_NS(bma220_spi_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);
+
+ guard(mutex)(&data->lock);
+ 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);
- 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);
+ ret = regmap_bulk_read(data->regmap, BMA220_REG_ACCEL_X,
+ &data->scan.chans,
+ sizeof(data->scan.chans));
if (ret < 0)
- goto err;
+ return IRQ_NONE;
iio_push_to_buffers_with_ts(indio_dev, &data->scan, sizeof(data->scan),
- pf->timestamp);
-err:
- mutex_unlock(&data->lock);
+ iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
@@ -117,59 +267,66 @@ static int bma220_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
int ret;
- u8 range_idx;
+ u8 index;
+ unsigned int reg;
struct bma220_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = bma220_read_reg(data->spi_device, chan->address);
+ ret = regmap_read(data->regmap, chan->address, ®);
if (ret < 0)
return -EINVAL;
- *val = sign_extend32(ret >> chan->scan_type.shift,
+ *val = sign_extend32(reg >> 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];
+ index = data->range_idx;
+ *val = bma220_scale_table[index][0];
+ *val2 = bma220_scale_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
+static int bma220_find_match(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_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);
+ guard(mutex)(&data->lock);
+
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;
- }
+ index = bma220_find_match(bma220_scale_table,
+ ARRAY_SIZE(bma220_scale_table),
+ val, val2);
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));
+ ret = regmap_update_bits(data->regmap, BMA220_REG_RANGE,
+ BMA220_RANGE_MASK,
+ FIELD_PREP(BMA220_RANGE_MASK, index));
if (ret < 0)
- dev_err(&data->spi_device->dev,
+ dev_err(data->dev,
"failed to set measurement range\n");
- mutex_unlock(&data->lock);
+ data->range_idx = index;
return 0;
}
@@ -199,69 +356,150 @@ static const struct iio_info bma220_info = {
.read_avail = bma220_read_avail,
};
-static int bma220_init(struct spi_device *spi)
+static int bma220_reset(struct bma220_data *data, bool up)
{
- int ret;
+ int i, ret;
+ unsigned int val;
- ret = bma220_read_reg(spi, BMA220_REG_ID);
- if (ret != BMA220_CHIP_ID)
- return -ENODEV;
+ guard(mutex)(&data->lock);
- /* 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;
+ /**
+ * 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;
- return 0;
+ if (up && (val == BMA220_SUSPEND_SLEEP))
+ return 0;
+
+ if (!up && (val == BMA220_SUSPEND_WAKE))
+ return 0;
+ }
+
+ return -EBUSY;
}
-static int bma220_power(struct spi_device *spi, bool up)
+static int bma220_power(struct bma220_data *data, bool up)
{
int i, ret;
+ unsigned int val;
+ guard(mutex)(&data->lock);
/**
* 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);
+ ret = regmap_read(data->regmap, BMA220_REG_SUSPEND, &val);
if (ret < 0)
return ret;
- if (up && ret == BMA220_SUSPEND_SLEEP)
+ if (up && (val == BMA220_SUSPEND_SLEEP))
return 0;
- if (!up && ret == BMA220_SUSPEND_WAKE)
+ if (!up && (val == BMA220_SUSPEND_WAKE))
return 0;
}
return -EBUSY;
}
-static void bma220_deinit(void *spi)
+static int bma220_init(struct bma220_data *data)
+{
+ int ret;
+ unsigned int val;
+ static const char * const regulator_names[] = { "vddd", "vddio", "vdda" };
+
+ ret = devm_regulator_bulk_get_enable(data->dev,
+ ARRAY_SIZE(regulator_names),
+ regulator_names);
+ if (ret)
+ return dev_err_probe(data->dev, ret, "Failed to get regulators\n");
+
+ /* Try to read chip_id register. It must return 0xdd. */
+ ret = regmap_read(data->regmap, BMA220_REG_ID, &val);
+ if (ret) {
+ dev_err(data->dev, "Failed to read chip id register\n");
+ return ret;
+ }
+
+ if (val != BMA220_CHIP_ID)
+ return -ENODEV;
+
+ ret = bma220_power(data, true);
+ if (ret) {
+ dev_err(data->dev, "Failed to power-on chip\n");
+ return ret;
+ }
+
+ ret = bma220_reset(data, true);
+ if (ret) {
+ dev_err(data->dev, "Failed to soft reset chip\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void bma220_deinit(void *data_ptr)
{
- bma220_power(spi, false);
+ struct bma220_data *data = data_ptr;
+ int ret;
+
+ ret = bma220_power(data, false);
+ if (ret)
+ dev_warn(data->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 rv;
+ u8 bma220_reg_if[2];
+
+ guard(mutex)(&data->lock);
+ rv = regmap_bulk_read(data->regmap, BMA220_REG_IF0, bma220_reg_if,
+ sizeof(bma220_reg_if));
+ if (rv)
+ return IRQ_NONE;
+
+ if (FIELD_GET(BMA220_IF_DRDY, bma220_reg_if[1])) {
+ iio_trigger_poll_nested(data->trig);
+ goto done;
+ }
+
+done:
+
+ return IRQ_HANDLED;
}
-int bma220_common_probe(struct spi_device *spi)
+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(&spi->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- data->spi_device = spi;
- mutex_init(&data->lock);
+ data->regmap = regmap;
+ data->dev = dev;
+
+ ret = bma220_init(data);
+ if (ret)
+ return ret;
+ mutex_init(&data->lock);
indio_dev->info = &bma220_info;
indio_dev->name = BMA220_DEVICE_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
@@ -269,38 +507,59 @@ int bma220_common_probe(struct spi_device *spi)
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;
+ 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(data->dev, data->trig);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "iio trigger register fail\n");
+ indio_dev->trig = iio_trigger_get(data->trig);
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ &bma220_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "request irq %d failed\n", irq);
+ }
- ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi);
+ ret = devm_add_action_or_reset(data->dev, bma220_deinit, data);
if (ret)
return ret;
- ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
- iio_pollfunc_store_time,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
bma220_trigger_handler, NULL);
if (ret < 0) {
- dev_err(&spi->dev, "iio triggered buffer setup failed\n");
+ dev_err(dev, "iio triggered buffer setup failed\n");
return ret;
}
- return devm_iio_device_register(&spi->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS(bma220_common_probe, "IIO_BOSCH_BMA220");
static int bma220_suspend(struct device *dev)
{
- struct spi_device *spi = to_spi_device(dev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct bma220_data *data = iio_priv(indio_dev);
- return bma220_power(spi, false);
+ return bma220_power(data, false);
}
static int bma220_resume(struct device *dev)
{
- struct spi_device *spi = to_spi_device(dev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct bma220_data *data = iio_priv(indio_dev);
- return bma220_power(spi, true);
+ return bma220_power(data, true);
}
EXPORT_NS_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume,
IIO_BOSCH_BMA220);
diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c
index be8348ad0a93..00e3fba9436d 100644
--- a/drivers/iio/accel/bma220_spi.c
+++ b/drivers/iio/accel/bma220_spi.c
@@ -9,17 +9,25 @@
#include <linux/errno.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 "bma220.h"
static int bma220_spi_probe(struct spi_device *spi)
{
- return bma220_common_probe(spi);
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &bma220_spi_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&spi->dev, "failed to create regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return bma220_common_probe(&spi->dev, regmap, spi->irq);
}
static const struct spi_device_id bma220_spi_id[] = {
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 04/10] iio: accel: BMA220 add i2c module
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (2 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 03/10] iio: accel: BMA220 migrate to regmap API Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 05/10] iio: accel: BMA220 make use of the watchdog functionality Petre Rodan
` (5 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Add i2c module.
Note that the kernel module transparently shifts all register addresses
1 bit to the left, so all functions will operate based on the SPI memory
map.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/Kconfig | 9 ++++-
drivers/iio/accel/Makefile | 1 +
drivers/iio/accel/bma220.h | 1 +
drivers/iio/accel/bma220_core.c | 19 ++++++++++
drivers/iio/accel/bma220_i2c.c | 62 +++++++++++++++++++++++++++++++++
5 files changed, 91 insertions(+), 1 deletion(-)
create mode 100644 drivers/iio/accel/bma220_i2c.c
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 9b6c35b75948..b3c5b0b7a406 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -221,6 +221,7 @@ config BMA220
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
@@ -228,7 +229,13 @@ config BMA220
To compile this driver as a module, choose M here: the
module will be called bma220_core and you will also get
- bma220_spi if SPI is enabled.
+ 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
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index 56a9f848f7f9..fa440a859283 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_ADXL380_I2C) += adxl380_i2c.o
obj-$(CONFIG_ADXL380_SPI) += adxl380_spi.o
obj-$(CONFIG_BMA180) += bma180.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
diff --git a/drivers/iio/accel/bma220.h b/drivers/iio/accel/bma220.h
index 5eefa9749d33..ae4b74514629 100644
--- a/drivers/iio/accel/bma220.h
+++ b/drivers/iio/accel/bma220.h
@@ -13,6 +13,7 @@
#include <linux/iio/iio.h>
extern const struct regmap_config bma220_spi_regmap_config;
+extern const struct regmap_config bma220_i2c_regmap_config;
extern const struct dev_pm_ops bma220_pm_ops;
int bma220_common_probe(struct device *dev, struct regmap *regmap, int irq);
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index e6dac2e1cf4d..fae84823d52b 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -225,6 +225,25 @@ const struct regmap_config bma220_spi_regmap_config = {
};
EXPORT_SYMBOL_NS(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_MAPLE,
+ .writeable_reg = bma220_is_writable_reg,
+ .volatile_reg = bma220_is_volatile_reg,
+};
+EXPORT_SYMBOL_NS(bma220_i2c_regmap_config, "IIO_BOSCH_BMA220");
+
static int bma220_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
diff --git a/drivers/iio/accel/bma220_i2c.c b/drivers/iio/accel/bma220_i2c.c
new file mode 100644
index 000000000000..8a1644aac287
--- /dev/null
+++ b/drivers/iio/accel/bma220_i2c.c
@@ -0,0 +1,62 @@
+// 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/device.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#include <linux/iio/iio.h>
+
+#include "bma220.h"
+
+static int bma220_i2c_probe(struct i2c_client *client)
+{
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_i2c(client, &bma220_i2c_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "failed to create regmap\n");
+ return PTR_ERR(regmap);
+ }
+
+ return bma220_common_probe(&client->dev, regmap, client->irq);
+}
+
+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");
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 05/10] iio: accel: BMA220 make use of the watchdog functionality
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (3 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 04/10] iio: accel: BMA220 add i2c module Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 06/10] iio: accel: BMA220 add LPF cut-off frequency mapping Petre Rodan
` (4 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Sometimes the sensor gets stuck and enters a condition in which it pulls
SDA low, thus making the entire i2c bus unusable.
The optional bosch,watchdog property mitigates this problem by clearing
the condition after a period of 1 or 10ms.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/bma220_core.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index fae84823d52b..86347cf8ab1e 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -158,6 +158,12 @@ enum bma220_axis {
AXIS_Z,
};
+enum bma220_prop_wdt {
+ BMA220_PROP_WDT_OFF,
+ BMA220_PROP_WDT_1MS,
+ BMA220_PROP_WDT_10MS,
+};
+
static const int bma220_scale_table[][2] = {
{0, 623000}, {1, 248000}, {2, 491000}, {4, 983000},
};
@@ -428,10 +434,17 @@ static int bma220_power(struct bma220_data *data, bool up)
return -EBUSY;
}
+static int bma220_wdt(struct bma220_data *data, const u8 val)
+{
+ return regmap_update_bits(data->regmap, BMA220_REG_WDT, BMA220_WDT_MASK,
+ FIELD_PREP(BMA220_WDT_MASK, val));
+}
+
static int bma220_init(struct bma220_data *data)
{
int ret;
unsigned int val;
+ u32 watchdog;
static const char * const regulator_names[] = { "vddd", "vddio", "vdda" };
ret = devm_regulator_bulk_get_enable(data->dev,
@@ -462,6 +475,25 @@ static int bma220_init(struct bma220_data *data)
return ret;
}
+ ret = device_property_read_u32(data->dev, "bosch,watchdog", &watchdog);
+ if (!ret) {
+ switch (watchdog) {
+ case BMA220_PROP_WDT_1MS:
+ ret = bma220_wdt(data, BMA220_WDT_1MS);
+ break;
+ case BMA220_PROP_WDT_10MS:
+ ret = bma220_wdt(data, BMA220_WDT_10MS);
+ break;
+ default:
+ ret = bma220_wdt(data, BMA220_WDT_OFF);
+ break;
+ }
+ if (ret) {
+ dev_err(data->dev, "Failed to set watchdog\n");
+ return ret;
+ }
+ }
+
return 0;
}
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 06/10] iio: accel: BMA220 add LPF cut-off frequency mapping
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (4 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 05/10] iio: accel: BMA220 make use of the watchdog functionality Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 07/10] iio: accel: BMA220 add debugfs reg access Petre Rodan
` (3 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
- add mapping for the low pass filter cut-off frequency.
- make valid values visible for both the cut-off frequency and the scale.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/bma220_core.c | 60 ++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index 86347cf8ab1e..e60acd62cf96 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -4,6 +4,15 @@
*
* Copyright (c) 2016,2020 Intel Corporation.
* Copyright (c) 2025 Petre Rodan <petre.rodan@subdimension.ro>
+ *
+ *
+ * Device register to IIO ABI mapping:
+ *
+ * Register | IIO ABI (sysfs) | valid values
+ * --------------------------+--------------------------------+---------------
+ * scale (range) | in_accel_scale | see _available
+ * cut-off freq (filt_config)| in_accel_filter_low_pass_... | see _available
+ * ---------------------------------------------------------------------------
*/
#include <linux/bits.h>
@@ -135,13 +144,23 @@
#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), \
+ .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', \
@@ -172,6 +191,7 @@ struct bma220_data {
struct device *dev;
struct regmap *regmap;
struct mutex lock;
+ u8 lpf_3db_freq_idx;
u8 range_idx;
struct iio_trigger *trig;
struct {
@@ -188,6 +208,18 @@ static const struct iio_chan_spec bma220_channels[] = {
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[][2] = {
+ [BMA220_COF_1000HZ] = {1000, 0},
+ [BMA220_COF_500HZ] = {500, 0},
+ [BMA220_COF_250HZ] = {250, 0},
+ [BMA220_COF_125HZ] = {125, 0},
+ [BMA220_COF_64HZ] = {64, 0},
+ [BMA220_COF_32HZ] = {32, 0},
+};
+
static const unsigned long bma220_accel_scan_masks[] = {
BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
0
@@ -309,6 +341,11 @@ static int bma220_read_raw(struct iio_dev *indio_dev,
*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][0];
+ *val2 = bma220_lpf_3db_freq_hz_table[index][1];
+ return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
@@ -353,6 +390,22 @@ static int bma220_write_raw(struct iio_dev *indio_dev,
"failed to set measurement range\n");
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, val2);
+ 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)
+ dev_err(data->dev,
+ "failed to set low pass filter\n");
+ data->lpf_3db_freq_idx = index;
+
return 0;
}
@@ -370,6 +423,11 @@ static int bma220_read_avail(struct iio_dev *indio_dev,
*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_PLUS_MICRO;
+ *length = ARRAY_SIZE(bma220_lpf_3db_freq_hz_table) * 2;
+ return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 07/10] iio: accel: BMA220 add debugfs reg access
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (5 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 06/10] iio: accel: BMA220 add LPF cut-off frequency mapping Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 08/10] iio: accel: BMA220 add events Petre Rodan
` (2 subsequent siblings)
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Allow read/write access to sensor registers for use in unit-tests.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/bma220_core.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index e60acd62cf96..41889cdcef76 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -433,10 +433,21 @@ static int bma220_read_avail(struct iio_dev *indio_dev,
}
}
+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)
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 08/10] iio: accel: BMA220 add events
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (6 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 07/10] iio: accel: BMA220 add debugfs reg access Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 09/10] iio: accel: BMA220 add event attrs Petre Rodan
2025-09-01 19:47 ` [PATCH 10/10] iio: accel: BMA220 add maintainer Petre Rodan
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Add events for tap detection and low-g, high-g, slope conditions.
Ignored the 80-column rule for readability.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/bma220_core.c | 686 ++++++++++++++++++++++++++++++++
1 file changed, 686 insertions(+)
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index 41889cdcef76..c8da6cc2eaf3 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -13,6 +13,37 @@
* scale (range) | in_accel_scale | see _available
* cut-off freq (filt_config)| in_accel_filter_low_pass_... | see _available
* ---------------------------------------------------------------------------
+ *
+ * Events:
+ * Register | IIO ABI (sysfs) | valid values
+ * --------------------------+-----------------------------------+------------
+ * high-g detection | |
+ * enable/disable irq | in_accel_*_thresh_rising_en | 0/1
+ * threshold (high_th) | in_accel_thresh_rising_value | 0-15
+ * hysteresis (high_hy) | in_accel_thresh_rising_hysteresis | 0-3
+ * duration (high_dur) | in_accel_thresh_rising_period | 0-63
+ * low-g detection | |
+ * enable/disable irq | in_accel_*_thresh_falling_en | 0/1
+ * threshold (low_th) | in_accel_thresh_falling_value | 0-15
+ * hysteresis (low_hy) | in_accel_thresh_falling_hysteresis| 0-3
+ * duration (low_dur) | in_accel_thresh_falling_period | 0-63
+ * slope detection | |
+ * enable/disable irq | in_accel_*_thresh_either_en | 0/1
+ * threshold (slope_th) | in_accel_thresh_either_value | 0-15
+ * duration (slope_dur) | in_accel_thresh_either_period | 0-3
+ * tap sensing | |
+ * enable/disable singletap| in_accel_*_gesture_singletap_en | 0/1 [2]
+ * enable/disable doubletap| in_accel_*_gesture_doubletap_en | 0/1 [2]
+ * threshold (tt_th) | in_accel_gesture_singletap_value | 0-15
+ * duration (tt_dur) | in_accel_gesture_doubletap_period | see [1]
+ * ----------------------------------------------------------------------------
+ *
+ * [1] The event related sysfs interface provides and expects raw register values
+ * (unshifted bitfields) based on the chip specifications.
+ * [2] Do not mix singletap and doubletap interrupt enable flags.
+ *
+ * To be on the safe side do not enable two or more concurrent interrupt events
+ * of different types.
*/
#include <linux/bits.h>
@@ -151,6 +182,48 @@
#define BMA220_COF_64HZ 0x4
#define BMA220_COF_32HZ 0x5
+#define BMA220_TAP_TYPE_DOUBLE 0x0
+#define BMA220_TAP_TYPE_SINGLE 0x1
+
+static const struct iio_event_spec bma220_events[] = {
+ {
+ .type = IIO_EV_TYPE_GESTURE,
+ .dir = IIO_EV_DIR_SINGLETAP,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE)
+ },
+ {
+ .type = IIO_EV_TYPE_GESTURE,
+ .dir = IIO_EV_DIR_DOUBLETAP,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD),
+ },
+};
+
#define BMA220_ACCEL_CHANNEL(index, reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
@@ -162,6 +235,8 @@
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE) |\
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \
.scan_index = index, \
+ .event_spec = bma220_events, \
+ .num_event_specs = ARRAY_SIZE(bma220_events), \
.scan_type = { \
.sign = 's', \
.realbits = 6, \
@@ -193,6 +268,7 @@ struct bma220_data {
struct mutex lock;
u8 lpf_3db_freq_idx;
u8 range_idx;
+ u8 tap_type;
struct iio_trigger *trig;
struct {
s8 chans[3];
@@ -299,6 +375,12 @@ static const struct iio_trigger_ops bma220_trigger_ops = {
.validate_device = &iio_trigger_validate_own_device,
};
+static int bma220_reset_int(struct bma220_data *data)
+{
+ return regmap_update_bits(data->regmap, BMA220_REG_IE1, BMA220_INT_RST_MSK,
+ FIELD_PREP(BMA220_INT_RST_MSK, 1));
+}
+
static irqreturn_t bma220_trigger_handler(int irq, void *p)
{
int ret;
@@ -433,6 +515,564 @@ static int bma220_read_avail(struct iio_dev *indio_dev,
}
}
+static int bma220_is_tap_en(struct bma220_data *data,
+ enum iio_modifier axis,
+ int type,
+ bool *en)
+{
+ unsigned int reg_val, val;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMA220_REG_IE0, ®_val);
+ if (ret)
+ return ret;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ *en = FIELD_GET(BMA220_INT_EN_TAP_X_MSK, reg_val);
+ break;
+ case IIO_MOD_Y:
+ *en = FIELD_GET(BMA220_INT_EN_TAP_Y_MSK, reg_val);
+ break;
+ case IIO_MOD_Z:
+ *en = FIELD_GET(BMA220_INT_EN_TAP_Z_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (*en) {
+ ret = regmap_read(data->regmap, BMA220_REG_CONF5, ®_val);
+ if (ret)
+ return ret;
+ val = FIELD_GET(BMA220_TIP_EN_MSK, reg_val);
+ data->tap_type = val;
+/*
+ * the tip_en reg_flag - if '1' it enables SingleTap, '0' DoubleTap
+ * truth table for the logic below, *en has to be switched to 0 in two cases:
+ * ST DT reg_val *en
+ * 1 0 0 (DT) 0
+ * 1 0 1 (ST) 1
+ * 0 1 0 (DT) 1
+ * 0 1 1 (ST) 0
+ */
+ if ((type == IIO_EV_DIR_DOUBLETAP) && val)
+ *en = false;
+ else if ((type == IIO_EV_DIR_SINGLETAP) && !val)
+ *en = false;
+ }
+
+ return 0;
+}
+
+static int bma220_is_slope_en(struct bma220_data *data,
+ enum iio_modifier axis,
+ bool *en)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMA220_REG_IE0, ®_val);
+ if (ret)
+ return ret;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ *en = FIELD_GET(BMA220_INT_EN_SLOPE_X_MSK, reg_val);
+ break;
+ case IIO_MOD_Y:
+ *en = FIELD_GET(BMA220_INT_EN_SLOPE_Y_MSK, reg_val);
+ break;
+ case IIO_MOD_Z:
+ *en = FIELD_GET(BMA220_INT_EN_SLOPE_Z_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bma220_is_high_en(struct bma220_data *data,
+ enum iio_modifier axis,
+ bool *en)
+{
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMA220_REG_IE1, ®_val);
+ if (ret)
+ return ret;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ *en = FIELD_GET(BMA220_INT_EN_HIGH_X_MSK, reg_val);
+ break;
+ case IIO_MOD_Y:
+ *en = FIELD_GET(BMA220_INT_EN_HIGH_Y_MSK, reg_val);
+ break;
+ case IIO_MOD_Z:
+ *en = FIELD_GET(BMA220_INT_EN_HIGH_Z_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bma220_set_tap_en(struct bma220_data *data,
+ enum iio_modifier axis,
+ int type,
+ bool en)
+{
+ unsigned int flags = BMA220_TAP_TYPE_DOUBLE;
+ int ret;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE0,
+ BMA220_INT_EN_TAP_X_MSK,
+ FIELD_PREP(BMA220_INT_EN_TAP_X_MSK, en));
+ break;
+ case IIO_MOD_Y:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE0,
+ BMA220_INT_EN_TAP_Y_MSK,
+ FIELD_PREP(BMA220_INT_EN_TAP_Y_MSK, en));
+ break;
+ case IIO_MOD_Z:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE0,
+ BMA220_INT_EN_TAP_Z_MSK,
+ FIELD_PREP(BMA220_INT_EN_TAP_Z_MSK, en));
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret)
+ return ret;
+
+ /* tip_en must be 1 to select singletap detection */
+ if (type == IIO_EV_DIR_SINGLETAP)
+ flags = BMA220_TAP_TYPE_SINGLE;
+
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF5,
+ BMA220_TIP_EN_MSK,
+ FIELD_PREP(BMA220_TIP_EN_MSK, flags));
+ if (ret)
+ return ret;
+
+ data->tap_type = flags;
+
+ return 0;
+}
+
+static int bma220_set_slope_en(struct bma220_data *data,
+ enum iio_modifier axis,
+ bool en)
+{
+ int ret;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE0,
+ BMA220_INT_EN_SLOPE_X_MSK,
+ FIELD_PREP(BMA220_INT_EN_SLOPE_X_MSK, en));
+ break;
+ case IIO_MOD_Y:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE0,
+ BMA220_INT_EN_SLOPE_Y_MSK,
+ FIELD_PREP(BMA220_INT_EN_SLOPE_Y_MSK, en));
+ break;
+ case IIO_MOD_Z:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE0,
+ BMA220_INT_EN_SLOPE_Z_MSK,
+ FIELD_PREP(BMA220_INT_EN_SLOPE_Z_MSK, en));
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int bma220_set_high_en(struct bma220_data *data,
+ enum iio_modifier axis,
+ bool en)
+{
+ int ret;
+
+ switch (axis) {
+ case IIO_MOD_X:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE1,
+ BMA220_INT_EN_HIGH_X_MSK,
+ FIELD_PREP(BMA220_INT_EN_HIGH_X_MSK, en));
+ break;
+ case IIO_MOD_Y:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE1,
+ BMA220_INT_EN_HIGH_Y_MSK,
+ FIELD_PREP(BMA220_INT_EN_HIGH_Y_MSK, en));
+ break;
+ case IIO_MOD_Z:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE1,
+ BMA220_INT_EN_HIGH_Z_MSK,
+ FIELD_PREP(BMA220_INT_EN_HIGH_Z_MSK, en));
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+// find out if the event is enabled
+static int bma220_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 bma220_data *data = iio_priv(indio_dev);
+ bool int_en;
+ int ret;
+ unsigned int reg_val, val;
+
+ guard(mutex)(&data->lock);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (dir) {
+ case IIO_EV_DIR_SINGLETAP:
+ ret = bma220_is_tap_en(data, chan->channel2,
+ IIO_EV_DIR_SINGLETAP, &int_en);
+ if (ret)
+ return ret;
+ return int_en;
+ case IIO_EV_DIR_DOUBLETAP:
+ ret = bma220_is_tap_en(data, chan->channel2,
+ IIO_EV_DIR_DOUBLETAP, &int_en);
+ if (ret)
+ return ret;
+ return int_en;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_TYPE_THRESH:
+ switch (dir) {
+ case IIO_EV_DIR_EITHER:
+ ret = bma220_is_slope_en(data, chan->channel2, &int_en);
+ if (ret)
+ return ret;
+ return int_en;
+ case IIO_EV_DIR_RISING:
+ ret = bma220_is_high_en(data, chan->channel2, &int_en);
+ if (ret)
+ return ret;
+ return int_en;
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_read(data->regmap, BMA220_REG_IE1,
+ ®_val);
+ if (ret)
+ return ret;
+ val = FIELD_GET(BMA220_INT_EN_LOW_MSK, reg_val);
+ return val;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+// set if the event is enabled
+static int bma220_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ struct bma220_data *data = iio_priv(indio_dev);
+ int ret = 0;
+
+ guard(mutex)(&data->lock);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (dir) {
+ case IIO_EV_DIR_SINGLETAP:
+ ret = bma220_set_tap_en(data, chan->channel2,
+ IIO_EV_DIR_SINGLETAP, state);
+ break;
+ case IIO_EV_DIR_DOUBLETAP:
+ ret = bma220_set_tap_en(data, chan->channel2,
+ IIO_EV_DIR_DOUBLETAP, state);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_TYPE_THRESH:
+ switch (dir) {
+ case IIO_EV_DIR_EITHER:
+ ret = bma220_set_slope_en(data, chan->channel2, state);
+ break;
+ case IIO_EV_DIR_RISING:
+ ret = bma220_set_high_en(data, chan->channel2, state);
+ break;
+ case IIO_EV_DIR_FALLING:
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE1,
+ BMA220_INT_EN_LOW_MSK,
+ FIELD_PREP(BMA220_INT_EN_LOW_MSK, state));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return bma220_reset_int(data);
+}
+
+static int bma220_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct bma220_data *data = iio_priv(indio_dev);
+ unsigned int reg_val;
+ int ret;
+
+ guard(mutex)(&data->lock);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF3, ®_val);
+ *val = FIELD_GET(BMA220_TT_TH_MSK, reg_val);
+ break;
+ case IIO_EV_INFO_PERIOD:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF3, ®_val);
+ *val = FIELD_GET(BMA220_TT_DUR_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_TYPE_THRESH:
+ switch (dir) {
+ case IIO_EV_DIR_EITHER:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF4,
+ ®_val);
+ *val = FIELD_GET(BMA220_SLOPE_TH_MSK, reg_val);
+ break;
+ case IIO_EV_INFO_PERIOD:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF4,
+ ®_val);
+ *val = FIELD_GET(BMA220_SLOPE_DUR_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_DIR_RISING:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF1,
+ ®_val);
+ *val = FIELD_GET(BMA220_HIGH_TH_MSK, reg_val);
+ break;
+ case IIO_EV_INFO_PERIOD:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF0,
+ ®_val);
+ *val = FIELD_GET(BMA220_HIGH_DUR_MSK, reg_val);
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF0,
+ ®_val);
+ *val = FIELD_GET(BMA220_HIGH_HY_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_DIR_FALLING:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF1,
+ ®_val);
+ *val = FIELD_GET(BMA220_LOW_TH_MSK, reg_val);
+ break;
+ case IIO_EV_INFO_PERIOD:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF2,
+ ®_val);
+ *val = FIELD_GET(BMA220_LOW_DUR_MSK, reg_val);
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF2,
+ ®_val);
+ *val = FIELD_GET(BMA220_LOW_HY_MSK, reg_val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+}
+
+static int bma220_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct bma220_data *data = iio_priv(indio_dev);
+ int ret;
+
+ guard(mutex)(&data->lock);
+
+ switch (type) {
+ case IIO_EV_TYPE_GESTURE:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (!FIELD_FIT(BMA220_TT_TH_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF3,
+ BMA220_TT_TH_MSK,
+ FIELD_PREP(BMA220_TT_TH_MSK, val));
+ break;
+ case IIO_EV_INFO_PERIOD:
+ if (!FIELD_FIT(BMA220_TT_DUR_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF3,
+ BMA220_TT_DUR_MSK,
+ FIELD_PREP(BMA220_TT_DUR_MSK, val));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_TYPE_THRESH:
+ switch (dir) {
+ case IIO_EV_DIR_EITHER:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (!FIELD_FIT(BMA220_SLOPE_TH_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF4,
+ BMA220_SLOPE_TH_MSK,
+ FIELD_PREP(BMA220_SLOPE_TH_MSK, val));
+ break;
+ case IIO_EV_INFO_PERIOD:
+ if (!FIELD_FIT(BMA220_SLOPE_DUR_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF4,
+ BMA220_SLOPE_DUR_MSK,
+ FIELD_PREP(BMA220_SLOPE_DUR_MSK, val));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_DIR_RISING:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (!FIELD_FIT(BMA220_HIGH_TH_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF1,
+ BMA220_HIGH_TH_MSK,
+ FIELD_PREP(BMA220_HIGH_TH_MSK, val));
+ break;
+ case IIO_EV_INFO_PERIOD:
+ if (!FIELD_FIT(BMA220_HIGH_DUR_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF0,
+ BMA220_HIGH_DUR_MSK,
+ FIELD_PREP(BMA220_HIGH_DUR_MSK, val));
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ if (!FIELD_FIT(BMA220_HIGH_HY_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF0,
+ BMA220_HIGH_HY_MSK,
+ FIELD_PREP(BMA220_HIGH_HY_MSK, val));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_EV_DIR_FALLING:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ if (!FIELD_FIT(BMA220_LOW_TH_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF1,
+ BMA220_LOW_TH_MSK,
+ FIELD_PREP(BMA220_LOW_TH_MSK, val));
+ break;
+ case IIO_EV_INFO_PERIOD:
+ if (!FIELD_FIT(BMA220_LOW_DUR_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF2,
+ BMA220_LOW_DUR_MSK,
+ FIELD_PREP(BMA220_LOW_DUR_MSK, val));
+ break;
+ case IIO_EV_INFO_HYSTERESIS:
+ if (!FIELD_FIT(BMA220_LOW_HY_MSK, val))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap,
+ BMA220_REG_CONF2,
+ BMA220_LOW_HY_MSK,
+ FIELD_PREP(BMA220_LOW_HY_MSK, val));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int bma220_reg_access(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
@@ -447,6 +1087,10 @@ static const struct iio_info bma220_info = {
.read_raw = bma220_read_raw,
.write_raw = bma220_write_raw,
.read_avail = bma220_read_avail,
+ .read_event_config = bma220_read_event_config,
+ .write_event_config = bma220_write_event_config,
+ .read_event_value = bma220_read_event_value,
+ .write_event_value = bma220_write_event_value,
.debugfs_reg_access = &bma220_reg_access,
};
@@ -563,6 +1207,8 @@ static int bma220_init(struct bma220_data *data)
}
}
+ data->tap_type = BMA220_TAP_TYPE_DOUBLE;
+
return 0;
}
@@ -584,6 +1230,7 @@ static irqreturn_t bma220_irq_handler(int irq, void *private)
struct bma220_data *data = iio_priv(indio_dev);
int rv;
u8 bma220_reg_if[2];
+ s64 timestamp = iio_get_time_ns(indio_dev);
guard(mutex)(&data->lock);
rv = regmap_bulk_read(data->regmap, BMA220_REG_IF0, bma220_reg_if,
@@ -596,6 +1243,45 @@ static irqreturn_t bma220_irq_handler(int irq, void *private)
goto done;
}
+ if (FIELD_GET(BMA220_IF_HIGH, bma220_reg_if[1]))
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ timestamp);
+ if (FIELD_GET(BMA220_IF_LOW, bma220_reg_if[1]))
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ timestamp);
+ if (FIELD_GET(BMA220_IF_SLOPE, bma220_reg_if[1]))
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ if (FIELD_GET(BMA220_IF_TT, bma220_reg_if[1])) {
+
+ if (data->tap_type == BMA220_TAP_TYPE_SINGLE)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_GESTURE,
+ IIO_EV_DIR_SINGLETAP),
+ timestamp);
+ else
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
+ IIO_MOD_X_OR_Y_OR_Z,
+ IIO_EV_TYPE_GESTURE,
+ IIO_EV_DIR_DOUBLETAP),
+ timestamp);
+ }
+
done:
return IRQ_HANDLED;
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 09/10] iio: accel: BMA220 add event attrs
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (7 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 08/10] iio: accel: BMA220 add events Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
2025-09-01 19:47 ` [PATCH 10/10] iio: accel: BMA220 add maintainer Petre Rodan
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Add event attributes not directly covered by the IIO API.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
drivers/iio/accel/bma220_core.c | 178 +++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 1 deletion(-)
diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c
index c8da6cc2eaf3..7a1064b408bb 100644
--- a/drivers/iio/accel/bma220_core.c
+++ b/drivers/iio/accel/bma220_core.c
@@ -31,11 +31,18 @@
* enable/disable irq | in_accel_*_thresh_either_en | 0/1
* threshold (slope_th) | in_accel_thresh_either_value | 0-15
* duration (slope_dur) | in_accel_thresh_either_period | 0-3
+ * filter (slope_filt) | in_accel_slope_filt | 0/1
+ * orientation | |
+ * mounting (orient_ex) | in_accel_orient_ex | 0/1
+ * blocking | in_accel_orient_blocking | see [1]
* tap sensing | |
* enable/disable singletap| in_accel_*_gesture_singletap_en | 0/1 [2]
* enable/disable doubletap| in_accel_*_gesture_doubletap_en | 0/1 [2]
* threshold (tt_th) | in_accel_gesture_singletap_value | 0-15
* duration (tt_dur) | in_accel_gesture_doubletap_period | see [1]
+ * sample cnt (tt_samp) | in_accel_gesture_tap_sample_cnt | see [1]
+ * filter (tt_filt) | in_accel_gesture_tap_filt | 0/1
+ * latch time (lat_int) | in_accel_latch_time | see [1]
* ----------------------------------------------------------------------------
*
* [1] The event related sysfs interface provides and expects raw register values
@@ -269,6 +276,7 @@ struct bma220_data {
u8 lpf_3db_freq_idx;
u8 range_idx;
u8 tap_type;
+ bool irq_needs_clear_if;
struct iio_trigger *trig;
struct {
s8 chans[3];
@@ -1083,7 +1091,167 @@ static int bma220_reg_access(struct iio_dev *indio_dev, unsigned int reg,
return regmap_write(data->regmap, reg, writeval);
}
+/* Event related attributes not directly covered by the IIO API */
+enum bma220_attributes {
+ BMA220_ATTR_TT_FILT,
+ BMA220_ATTR_TT_SAMP,
+ BMA220_ATTR_SLOPE_FILT,
+ BMA220_ATTR_ORIENT_EX,
+ BMA220_ATTR_ORIENT_BLOCKING,
+ BMA220_ATTR_LATCH_TIME,
+};
+
+static ssize_t event_attr_reg_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bma220_data *data = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+ int ret = -EINVAL;
+ unsigned int reg_val, flags;
+
+ guard(mutex)(&data->lock);
+
+ switch (iattr->address) {
+ case BMA220_ATTR_TT_FILT:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF3, ®_val);
+ flags = FIELD_GET(BMA220_TT_FILT_MSK, reg_val);
+ break;
+ case BMA220_ATTR_TT_SAMP:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF5, ®_val);
+ flags = FIELD_GET(BMA220_TT_SAMP_MSK, reg_val);
+ break;
+ case BMA220_ATTR_SLOPE_FILT:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF4, ®_val);
+ flags = FIELD_GET(BMA220_SLOPE_FILT_MSK, reg_val);
+ break;
+ case BMA220_ATTR_ORIENT_EX:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF4, ®_val);
+ flags = FIELD_GET(BMA220_ORIENT_EX_MSK, reg_val);
+ break;
+ case BMA220_ATTR_ORIENT_BLOCKING:
+ ret = regmap_read(data->regmap, BMA220_REG_CONF5, ®_val);
+ flags = FIELD_GET(BMA220_ORIENT_BLOCKING_MSK, reg_val);
+ break;
+ case BMA220_ATTR_LATCH_TIME:
+ ret = regmap_read(data->regmap, BMA220_REG_IE1, ®_val);
+ flags = FIELD_GET(BMA220_INT_LATCH_MSK, reg_val);
+ break;
+ }
+
+ if (ret)
+ return ret;
+ return sysfs_emit(buf, "%d\n", flags);
+}
+
+static ssize_t event_attr_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct bma220_data *data = iio_priv(dev_to_iio_dev(dev));
+ struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+ int ret = -EINVAL;
+ int value;
+
+ if (kstrtoint(buf, 0, &value))
+ return -EINVAL;
+
+ guard(mutex)(&data->lock);
+
+ switch (iattr->address) {
+ case BMA220_ATTR_TT_FILT:
+ if (!FIELD_FIT(BMA220_TT_FILT_MSK, value))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF3,
+ BMA220_TT_FILT_MSK,
+ FIELD_PREP(BMA220_TT_FILT_MSK, value));
+ break;
+ case BMA220_ATTR_TT_SAMP:
+ if (!FIELD_FIT(BMA220_TT_SAMP_MSK, value))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF5,
+ BMA220_TT_SAMP_MSK,
+ FIELD_PREP(BMA220_TT_SAMP_MSK, value));
+ break;
+ case BMA220_ATTR_SLOPE_FILT:
+ if (!FIELD_FIT(BMA220_SLOPE_FILT_MSK, value))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF4,
+ BMA220_SLOPE_FILT_MSK,
+ FIELD_PREP(BMA220_SLOPE_FILT_MSK, value));
+ break;
+ case BMA220_ATTR_ORIENT_EX:
+ if (!FIELD_FIT(BMA220_ORIENT_EX_MSK, value))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF4,
+ BMA220_ORIENT_EX_MSK,
+ FIELD_PREP(BMA220_ORIENT_EX_MSK, value));
+ break;
+ case BMA220_ATTR_ORIENT_BLOCKING:
+ if (!FIELD_FIT(BMA220_ORIENT_BLOCKING_MSK, value))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_CONF5,
+ BMA220_ORIENT_BLOCKING_MSK,
+ FIELD_PREP(BMA220_ORIENT_BLOCKING_MSK,
+ value));
+ break;
+ case BMA220_ATTR_LATCH_TIME:
+ if (!FIELD_FIT(BMA220_INT_LATCH_MSK, value))
+ return -EINVAL;
+ ret = regmap_update_bits(data->regmap, BMA220_REG_IE1,
+ BMA220_INT_LATCH_MSK,
+ FIELD_PREP(BMA220_INT_LATCH_MSK, value));
+ if (value == BMA220_INT_LATCH_MAX)
+ data->irq_needs_clear_if = true;
+ break;
+ }
+
+ if (ret < 0)
+ return -EINVAL;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(in_accel_gesture_tap_filt, 0644,
+ event_attr_reg_show, event_attr_reg_store,
+ BMA220_ATTR_TT_FILT);
+
+static IIO_DEVICE_ATTR(in_accel_gesture_tap_sample_cnt, 0644,
+ event_attr_reg_show, event_attr_reg_store,
+ BMA220_ATTR_TT_SAMP);
+
+static IIO_DEVICE_ATTR(in_accel_thresh_either_filt, 0644,
+ event_attr_reg_show, event_attr_reg_store,
+ BMA220_ATTR_SLOPE_FILT);
+
+static IIO_DEVICE_ATTR(in_accel_orient_ex, 0644,
+ event_attr_reg_show, event_attr_reg_store,
+ BMA220_ATTR_ORIENT_EX);
+
+static IIO_DEVICE_ATTR(in_accel_orient_blocking, 0644,
+ event_attr_reg_show, event_attr_reg_store,
+ BMA220_ATTR_ORIENT_BLOCKING);
+
+static IIO_DEVICE_ATTR(in_accel_latch_time, 0644,
+ event_attr_reg_show, event_attr_reg_store,
+ BMA220_ATTR_LATCH_TIME);
+
+static struct attribute *bma220_event_attributes[] = {
+ &iio_dev_attr_in_accel_gesture_tap_filt.dev_attr.attr,
+ &iio_dev_attr_in_accel_gesture_tap_sample_cnt.dev_attr.attr,
+ &iio_dev_attr_in_accel_thresh_either_filt.dev_attr.attr,
+ &iio_dev_attr_in_accel_orient_ex.dev_attr.attr,
+ &iio_dev_attr_in_accel_orient_blocking.dev_attr.attr,
+ &iio_dev_attr_in_accel_latch_time.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group bma220_event_attribute_group = {
+ .attrs = bma220_event_attributes,
+};
+
static const struct iio_info bma220_info = {
+ .event_attrs = &bma220_event_attribute_group,
.read_raw = bma220_read_raw,
.write_raw = bma220_write_raw,
.read_avail = bma220_read_avail,
@@ -1207,6 +1375,7 @@ static int bma220_init(struct bma220_data *data)
}
}
+ data->irq_needs_clear_if = false;
data->tap_type = BMA220_TAP_TYPE_DOUBLE;
return 0;
@@ -1228,7 +1397,7 @@ 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 rv;
+ int rv, ret;
u8 bma220_reg_if[2];
s64 timestamp = iio_get_time_ns(indio_dev);
@@ -1283,6 +1452,13 @@ static irqreturn_t bma220_irq_handler(int irq, void *private)
}
done:
+ if (data->irq_needs_clear_if) {
+ ret = bma220_reset_int(data);
+ if (ret)
+ dev_warn(data->dev,
+ "Failed to clear interrupt flag (%pe)\n",
+ ERR_PTR(ret));
+ }
return IRQ_HANDLED;
}
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 10/10] iio: accel: BMA220 add maintainer
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
` (8 preceding siblings ...)
2025-09-01 19:47 ` [PATCH 09/10] iio: accel: BMA220 add event attrs Petre Rodan
@ 2025-09-01 19:47 ` Petre Rodan
9 siblings, 0 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-01 19:47 UTC (permalink / raw)
To: linux-iio, linux-kernel
Cc: Petre Rodan, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko
Add myself as maintainer of this driver.
Signed-off-by: Petre Rodan <petre.rodan@subdimension.ro>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index af1c8d2bfb3d..dd94505fb9a0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4402,6 +4402,13 @@ F: include/net/bond*
F: include/uapi/linux/if_bonding.h
F: tools/testing/selftests/drivers/net/bonding/
+BOSCH SENSORTEC BMA220 ACCELEROMETER IIO DRIVER
+M: Petre Rodan <petre.rodan@subdimension.ro>
+L: linux-iio@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml
+F: drivers/iio/accel/bma220*
+
BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
M: Dan Robertson <dan@dlrobertson.com>
L: linux-iio@vger.kernel.org
--
2.49.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements
2025-09-01 19:47 ` [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements Petre Rodan
@ 2025-09-02 5:57 ` Krzysztof Kozlowski
2025-09-02 16:02 ` Petre Rodan
0 siblings, 1 reply; 15+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-02 5:57 UTC (permalink / raw)
To: Petre Rodan, linux-iio, linux-kernel
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Rob Herring, Conor Dooley, Krzysztof Kozlowski
On 01/09/2025 21:47, Petre Rodan wrote:
> - fix title typo
> - add optional watchdog setting that recovers the sensor from a stuck-low
> SDA condition
> - set correct SPI phase and polarity
> - interrupt on rising edge. the level-based interrupt that is being
Cleanup and new features must never be mixed together.
<form letter>
Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.
Tools like b4 or scripts/get_maintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, instead use mainline) or work on fork of kernel
(don't, instead use mainline). Just use b4 and everything should be
fine, although remember about `b4 prep --auto-to-cc` if you added new
patches to the patchset.
You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time.
Please kindly resend and include all necessary To/Cc entries.
</form letter>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements
2025-09-02 5:57 ` Krzysztof Kozlowski
@ 2025-09-02 16:02 ` Petre Rodan
2025-09-02 16:14 ` David Lechner
2025-09-02 19:22 ` Krzysztof Kozlowski
0 siblings, 2 replies; 15+ messages in thread
From: Petre Rodan @ 2025-09-02 16:02 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: linux-iio, linux-kernel, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Conor Dooley,
Krzysztof Kozlowski
[-- Attachment #1: Type: text/plain, Size: 1460 bytes --]
hello,
On Tue, Sep 02, 2025 at 07:57:03AM +0200, Krzysztof Kozlowski wrote:
> <form letter>
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
I'm using the bleeding edge togreg branch of the iio tree, git pulled yesterday.
I indeed missed devicetree@ while manually copy-pasting from get_maintainer.pl on the bindings patch. I wish that script would provide a valid rfc822 email header instead of it's current verbose output.
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time.
the patch set had gone thru multiple static scans, unit tests, checkpatch.pl and the dt_binding_check on my end.
since devicetree@ is not emailed with driver code, I will still wait for any feedback to the driver part of my submission, I guess.
> > - fix title typo
> > - add optional watchdog setting that recovers the sensor from a stuck-low
> > SDA condition
> > - set correct SPI phase and polarity
> > - interrupt on rising edge. the level-based interrupt that is being
>
> Cleanup and new features must never be mixed together.
ok I will split up all the bindings changes in the next revision.
best regards.
peter
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements
2025-09-02 16:02 ` Petre Rodan
@ 2025-09-02 16:14 ` David Lechner
2025-09-02 19:22 ` Krzysztof Kozlowski
1 sibling, 0 replies; 15+ messages in thread
From: David Lechner @ 2025-09-02 16:14 UTC (permalink / raw)
To: Petre Rodan, Krzysztof Kozlowski
Cc: linux-iio, linux-kernel, Jonathan Cameron, Nuno Sá,
Andy Shevchenko, Rob Herring, Conor Dooley, Krzysztof Kozlowski
On 9/2/25 11:02 AM, Petre Rodan wrote:
>
> hello,
>
> On Tue, Sep 02, 2025 at 07:57:03AM +0200, Krzysztof Kozlowski wrote:
>> <form letter>
>> Please use scripts/get_maintainers.pl to get a list of necessary people
>> and lists to CC. It might happen, that command when run on an older
>> kernel, gives you outdated entries. Therefore please be sure you base
>> your patches on recent Linux kernel.
>
> I'm using the bleeding edge togreg branch of the iio tree, git pulled yesterday.
> I indeed missed devicetree@ while manually copy-pasting from get_maintainer.pl on the bindings patch. I wish that script would provide a valid rfc822 email header instead of it's current verbose output.
>
IIRC, the --no-rolestats option will fix that.
Suggest to use b4 or other tools to automate this.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements
2025-09-02 16:02 ` Petre Rodan
2025-09-02 16:14 ` David Lechner
@ 2025-09-02 19:22 ` Krzysztof Kozlowski
1 sibling, 0 replies; 15+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-02 19:22 UTC (permalink / raw)
To: Petre Rodan
Cc: linux-iio, linux-kernel, Jonathan Cameron, David Lechner,
Nuno Sá, Andy Shevchenko, Rob Herring, Conor Dooley,
Krzysztof Kozlowski
On 02/09/2025 18:02, Petre Rodan wrote:
>
> hello,
>
> On Tue, Sep 02, 2025 at 07:57:03AM +0200, Krzysztof Kozlowski wrote:
>> <form letter>
>> Please use scripts/get_maintainers.pl to get a list of necessary people
>> and lists to CC. It might happen, that command when run on an older
>> kernel, gives you outdated entries. Therefore please be sure you base
>> your patches on recent Linux kernel.
>
> I'm using the bleeding edge togreg branch of the iio tree, git pulled yesterday.
> I indeed missed devicetree@ while manually copy-pasting from get_maintainer.pl on the bindings patch. I wish that script would provide a valid rfc822 email header instead of it's current verbose output.
Recommended is to use b4. Simple wrapper like git_send_email() also
would work:
https://lore.kernel.org/all/?q=git_send_email
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2025-09-02 19:22 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-01 19:47 [PATCH 0/10] iio: accel: BMA220 improvements Petre Rodan
2025-09-01 19:47 ` [PATCH 01/10] dt-bindings: iio: accel: bosch,BMA220 improvements Petre Rodan
2025-09-02 5:57 ` Krzysztof Kozlowski
2025-09-02 16:02 ` Petre Rodan
2025-09-02 16:14 ` David Lechner
2025-09-02 19:22 ` Krzysztof Kozlowski
2025-09-01 19:47 ` [PATCH 02/10] iio: accel: BMA220 split original spi driver Petre Rodan
2025-09-01 19:47 ` [PATCH 03/10] iio: accel: BMA220 migrate to regmap API Petre Rodan
2025-09-01 19:47 ` [PATCH 04/10] iio: accel: BMA220 add i2c module Petre Rodan
2025-09-01 19:47 ` [PATCH 05/10] iio: accel: BMA220 make use of the watchdog functionality Petre Rodan
2025-09-01 19:47 ` [PATCH 06/10] iio: accel: BMA220 add LPF cut-off frequency mapping Petre Rodan
2025-09-01 19:47 ` [PATCH 07/10] iio: accel: BMA220 add debugfs reg access Petre Rodan
2025-09-01 19:47 ` [PATCH 08/10] iio: accel: BMA220 add events Petre Rodan
2025-09-01 19:47 ` [PATCH 09/10] iio: accel: BMA220 add event attrs Petre Rodan
2025-09-01 19:47 ` [PATCH 10/10] iio: accel: BMA220 add maintainer Petre Rodan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).