diff options
Diffstat (limited to 'SOURCES/rog-ally-gyro-fix.patch')
-rw-r--r-- | SOURCES/rog-ally-gyro-fix.patch | 2847 |
1 files changed, 0 insertions, 2847 deletions
diff --git a/SOURCES/rog-ally-gyro-fix.patch b/SOURCES/rog-ally-gyro-fix.patch index fc02fe0..b5f57cc 100644 --- a/SOURCES/rog-ally-gyro-fix.patch +++ b/SOURCES/rog-ally-gyro-fix.patch @@ -1,2850 +1,3 @@ -Add devicetree description document for Bosch BMI323, a 6-Axis IMU. - -Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com> -Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> ---- - .../bindings/iio/imu/bosch,bmi323.yaml | 77 +++++++++++++++++++ - 1 file changed, 77 insertions(+) - create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml - -diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml -new file mode 100644 -index 000000000000..64ef26e19669 ---- /dev/null -+++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml -@@ -0,0 +1,77 @@ -+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/iio/imu/bosch,bmi323.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Bosch BMI323 6-Axis IMU -+ -+maintainers: -+ - Jagath Jog J <jagathjog1996@gmail.com> -+ -+description: -+ BMI323 is a 6-axis inertial measurement unit that supports acceleration and -+ gyroscopic measurements with hardware fifo buffering. Sensor also provides -+ events information such as motion, steps, orientation, single and double -+ tap detection. -+ -+properties: -+ compatible: -+ const: bosch,bmi323 -+ -+ reg: -+ maxItems: 1 -+ -+ vdd-supply: true -+ vddio-supply: true -+ -+ interrupts: -+ minItems: 1 -+ maxItems: 2 -+ -+ interrupt-names: -+ minItems: 1 -+ maxItems: 2 -+ items: -+ enum: -+ - INT1 -+ - INT2 -+ -+ drive-open-drain: -+ description: -+ set if the specified interrupt pin should be configured as -+ open drain. If not set, defaults to push-pull. -+ -+ mount-matrix: -+ description: -+ an optional 3x3 mounting rotation matrix. -+ -+required: -+ - compatible -+ - reg -+ - vdd-supply -+ - vddio-supply -+ -+allOf: -+ - $ref: /schemas/spi/spi-peripheral-props.yaml# -+ -+unevaluatedProperties: false -+ -+examples: -+ - | -+ // Example for I2C -+ #include <dt-bindings/interrupt-controller/irq.h> -+ i2c { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ imu@68 { -+ compatible = "bosch,bmi323"; -+ reg = <0x68>; -+ vddio-supply = <&vddio>; -+ vdd-supply = <&vdd>; -+ interrupt-parent = <&gpio1>; -+ interrupts = <29 IRQ_TYPE_EDGE_RISING>; -+ interrupt-names = "INT1"; -+ }; -+ }; -From: Jagath Jog J <jagathjog1996@gmail.com> -To: jic23@kernel.org, andriy.shevchenko@linux.intel.com, - lars@metafoo.de, robh+dt@kernel.org, - krzysztof.kozlowski+dt@linaro.org -Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org, - linux-kernel@vger.kernel.org -Subject: [RFC 2/2] iio: imu: Add driver for BMI323 IMU -Date: Mon, 18 Sep 2023 13:33:14 +0530 [thread overview] -Message-ID: <20230918080314.11959-3-jagathjog1996@gmail.com> (raw) -In-Reply-To: <20230918080314.11959-1-jagathjog1996@gmail.com> - -The Bosch BMI323 is a 6-axis low-power IMU that provide measurements for -acceleration, angular rate, and temperature. This sensor includes -motion-triggered interrupt features, such as a step counter, tap detection, -and activity/inactivity interrupt capabilities. - -The driver supports various functionalities, including data ready, FIFO -data handling, and events such as tap detection, step counting, and -activity interrupts. - -Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com> ---- - MAINTAINERS | 7 + - drivers/iio/imu/Kconfig | 1 + - drivers/iio/imu/Makefile | 1 + - drivers/iio/imu/bmi323/Kconfig | 33 + - drivers/iio/imu/bmi323/Makefile | 7 + - drivers/iio/imu/bmi323/bmi323.h | 209 +++ - drivers/iio/imu/bmi323/bmi323_core.c | 2139 +++++++++++++++++++++++ - drivers/iio/imu/bmi323/bmi323_i2c.c | 121 ++ - drivers/iio/imu/bmi323/bmi323_spi.c | 92 + - 10 files changed, 2628 insertions(+) - create mode 100644 drivers/iio/imu/bmi323/Kconfig - create mode 100644 drivers/iio/imu/bmi323/Makefile - create mode 100644 drivers/iio/imu/bmi323/bmi323.h - create mode 100644 drivers/iio/imu/bmi323/bmi323_core.c - create mode 100644 drivers/iio/imu/bmi323/bmi323_i2c.c - create mode 100644 drivers/iio/imu/bmi323/bmi323_spi.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index 4e07c032d06a..47ca415212a7 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -3636,6 +3636,13 @@ - F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml - F: drivers/iio/accel/bma400* - -+BOSCH SENSORTEC BMI323 IMU IIO DRIVER -+M: Jagath Jog J <jagathjog1996@gmail.com> -+L: linux-iio@vger.kernel.org -+S: Maintained -+F: Documentation/devicetree/bindings/iio/imu/bosch,bma400.yaml -+F: drivers/iio/imu/bmi323/ -+ - BPF JIT for ARM - M: Russell King <linux@armlinux.org.uk> - M: Puranjay Mohan <puranjay12@gmail.com> -diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig -index c2f97629e9cd..6c9a85294bc1 100644 ---- a/drivers/iio/imu/Kconfig -+++ b/drivers/iio/imu/Kconfig -@@ -54,6 +54,7 @@ config ADIS16480 - - source "drivers/iio/imu/bmi160/Kconfig" - source "drivers/iio/imu/bno055/Kconfig" -+source "drivers/iio/imu/bmi323/Kconfig" - - config FXOS8700 - tristate -diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile -index 6eb612034722..627406476357 100644 ---- a/drivers/iio/imu/Makefile -+++ b/drivers/iio/imu/Makefile -@@ -16,6 +16,7 @@ obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o - - obj-y += bmi160/ - obj-y += bno055/ -+obj-y += bmi323/ - - obj-$(CONFIG_FXOS8700) += fxos8700_core.o - obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o -diff --git a/drivers/iio/imu/bmi323/Kconfig b/drivers/iio/imu/bmi323/Kconfig -new file mode 100644 -index 000000000000..ab37b285393c ---- /dev/null -+++ b/drivers/iio/imu/bmi323/Kconfig -@@ -0,0 +1,33 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# BMI323 IMU driver -+# -+ -+config BMI323 -+ tristate -+ select IIO_BUFFER -+ select IIO_TRIGGERED_BUFFER -+ -+config BMI323_I2C -+ tristate "Bosch BMI323 I2C driver" -+ depends on I2C -+ select BMI323 -+ select REGMAP_I2C -+ help -+ Enable support for the Bosch BMI323 6-Axis IMU connected to I2C -+ interface. -+ -+ This driver can also be built as a module. If so, the module will be -+ called bmi323_i2c. -+ -+config BMI323_SPI -+ tristate "Bosch BMI323 SPI driver" -+ depends on SPI -+ select BMI323 -+ select REGMAP_SPI -+ help -+ Enable support for the Bosch BMI323 6-Axis IMU connected to SPI -+ interface. -+ -+ This driver can also be built as a module. If so, the module will be -+ called bmi323_spi. -diff --git a/drivers/iio/imu/bmi323/Makefile b/drivers/iio/imu/bmi323/Makefile -new file mode 100644 -index 000000000000..a6a6dc0207c9 ---- /dev/null -+++ b/drivers/iio/imu/bmi323/Makefile -@@ -0,0 +1,7 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# -+# Makefile for Bosch BMI323 IMU -+# -+obj-$(CONFIG_BMI323) += bmi323_core.o -+obj-$(CONFIG_BMI323_I2C) += bmi323_i2c.o -+obj-$(CONFIG_BMI323_SPI) += bmi323_spi.o -diff --git a/drivers/iio/imu/bmi323/bmi323.h b/drivers/iio/imu/bmi323/bmi323.h -new file mode 100644 -index 000000000000..dff126d41658 ---- /dev/null -+++ b/drivers/iio/imu/bmi323/bmi323.h -@@ -0,0 +1,209 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * IIO driver for Bosch BMI323 6-Axis IMU -+ * -+ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> -+ */ -+ -+#ifndef _BMI323_H_ -+#define _BMI323_H_ -+ -+#include <linux/bits.h> -+#include <linux/regmap.h> -+#include <linux/units.h> -+ -+#define BMI323_I2C_DUMMY 2 -+#define BMI323_SPI_DUMMY 1 -+ -+/* Register map */ -+ -+#define BMI323_CHIP_ID_REG 0x00 -+#define BMI323_CHIP_ID_VAL 0x0043 -+#define BMI323_CHIP_ID_MSK GENMASK(7, 0) -+#define BMI323_ERR_REG 0x01 -+#define BMI323_STATUS_REG 0x02 -+#define BMI323_STATUS_POR_MSK BIT(0) -+ -+/* Accelero/Gyro/Temp data registers */ -+#define BMI323_ACCEL_X_REG 0x03 -+#define BMI323_GYRO_X_REG 0x06 -+#define BMI323_TEMP_REG 0x09 -+#define BMI323_ALL_CHAN_MSK GENMASK(5, 0) -+ -+/* Status registers */ -+#define BMI323_STATUS_INT1_REG 0x0D -+#define BMI323_STATUS_INT2_REG 0x0E -+#define BMI323_STATUS_NOMOTION_MSK BIT(0) -+#define BMI323_STATUS_MOTION_MSK BIT(1) -+#define BMI323_STATUS_STP_WTR_MSK BIT(5) -+#define BMI323_STATUS_TAP_MSK BIT(8) -+#define BMI323_STATUS_ERROR_MSK BIT(10) -+#define BMI323_STATUS_TMP_DRDY_MSK BIT(11) -+#define BMI323_STATUS_GYR_DRDY_MSK BIT(12) -+#define BMI323_STATUS_ACC_DRDY_MSK BIT(13) -+#define BMI323_STATUS_ACC_GYR_DRDY_MSK GENMASK(13, 12) -+#define BMI323_STATUS_FIFO_WTRMRK_MSK BIT(14) -+#define BMI323_STATUS_FIFO_FULL_MSK BIT(15) -+ -+/* Feature registers */ -+#define BMI323_FEAT_IO0_REG 0x10 -+#define BMI323_FEAT_IO0_XYZ_NOMOTION_MSK GENMASK(2, 0) -+#define BMI323_FEAT_IO0_XYZ_MOTION_MSK GENMASK(5, 3) -+#define BMI323_FEAT_XYZ_MSK GENMASK(2, 0) -+#define BMI323_FEAT_IO0_STP_CNT_MSK BIT(9) -+#define BMI323_FEAT_IO0_S_TAP_MSK BIT(12) -+#define BMI323_FEAT_IO0_D_TAP_MSK BIT(13) -+#define BMI323_FEAT_IO1_REG 0x11 -+#define BMI323_FEAT_IO1_ERR_MSK GENMASK(3, 0) -+#define BMI323_FEAT_IO2_REG 0x12 -+#define BMI323_FEAT_IO_STATUS_REG 0x14 -+#define BMI323_FEAT_IO_STATUS_MSK BIT(0) -+#define BMI323_FEAT_ENG_POLL 2000 -+#define BMI323_FEAT_ENG_TIMEOUT 10000 -+ -+/* FIFO registers */ -+#define BMI323_FIFO_FILL_LEVEL_REG 0x15 -+#define BMI323_FIFO_DATA_REG 0x16 -+ -+/* Accelero/Gyro config registers */ -+#define BMI323_ACC_CONF_REG 0x20 -+#define BMI323_GYRO_CONF_REG 0x21 -+#define BMI323_ACC_GYRO_CONF_MODE_MSK GENMASK(14, 12) -+#define BMI323_ACC_GYRO_CONF_ODR_MSK GENMASK(3, 0) -+#define BMI323_ACC_GYRO_CONF_SCL_MSK GENMASK(6, 4) -+#define BMI323_ACC_GYRO_CONF_BW_MSK BIT(7) -+#define BMI323_ACC_GYRO_CONF_AVG_MSK GENMASK(10, 8) -+ -+/* FIFO registers */ -+#define BMI323_FIFO_WTRMRK_REG 0x35 -+#define BMI323_FIFO_CONF_REG 0x36 -+#define BMI323_FIFO_CONF_STP_FUL_MSK BIT(0) -+#define BMI323_FIFO_CONF_ACC_GYR_EN_MSK GENMASK(10, 9) -+#define BMI323_FIFO_ACC_GYR_MSK GENMASK(1, 0) -+#define BMI323_FIFO_CTRL_REG 0x37 -+#define BMI323_FIFO_FLUSH_MSK BIT(0) -+ -+/* Interrupt pin config registers */ -+#define BMI323_IO_INT_CTR_REG 0x38 -+#define BMI323_IO_INT1_LVL_MSK BIT(0) -+#define BMI323_IO_INT1_OD_MSK BIT(1) -+#define BMI323_IO_INT1_OP_EN_MSK BIT(2) -+#define BMI323_IO_INT1_LVL_OD_OP_MSK GENMASK(2, 0) -+#define BMI323_IO_INT2_LVL_MSK BIT(8) -+#define BMI323_IO_INT2_OD_MSK BIT(9) -+#define BMI323_IO_INT2_OP_EN_MSK BIT(10) -+#define BMI323_IO_INT2_LVL_OD_OP_MSK GENMASK(10, 8) -+#define BMI323_IO_INT_CONF_REG 0x39 -+#define BMI323_IO_INT_LTCH_MSK BIT(0) -+#define BMI323_INT_MAP1_REG 0x3A -+#define BMI323_INT_MAP2_REG 0x3B -+#define BMI323_NOMOTION_MSK GENMASK(1, 0) -+#define BMI323_MOTION_MSK GENMASK(3, 2) -+#define BMI323_STEP_CNT_MSK GENMASK(11, 10) -+#define BMI323_TAP_MSK GENMASK(1, 0) -+#define BMI323_TMP_DRDY_MSK GENMASK(7, 6) -+#define BMI323_GYR_DRDY_MSK GENMASK(9, 8) -+#define BMI323_ACC_DRDY_MSK GENMASK(11, 10) -+#define BMI323_FIFO_WTRMRK_MSK GENMASK(13, 12) -+#define BMI323_FIFO_FULL_MSK GENMASK(15, 14) -+ -+/* Feature registers */ -+#define BMI323_FEAT_CTRL_REG 0x40 -+#define BMI323_FEAT_ENG_EN_MSK BIT(0) -+#define BMI323_FEAT_DATA_ADDR 0x41 -+#define BMI323_FEAT_DATA_TX 0x42 -+#define BMI323_FEAT_DATA_STATUS 0x43 -+#define BMI323_FEAT_DATA_TX_RDY_MSK BIT(1) -+#define BMI323_FEAT_EVNT_EXT_REG 0x47 -+#define BMI323_FEAT_EVNT_EXT_S_MSK BIT(3) -+#define BMI323_FEAT_EVNT_EXT_D_MSK BIT(4) -+ -+#define BMI323_CMD_REG 0x7E -+#define BMI323_RST_VAL 0xDEAF -+#define BMI323_CFG_RES_REG 0x7F -+ -+/* Extended registers */ -+#define BMI323_GEN_SET1_REG 0x02 -+#define BMI323_GEN_SET1_MODE_MSK BIT(0) -+#define BMI323_GEN_HOLD_DUR_MSK GENMASK(4, 1) -+ -+/* Any Motion/No Motion config registers */ -+#define BMI323_ANYMO1_REG 0x05 -+#define BMI323_NOMO1_REG 0x08 -+#define BMI323_MO2_OFFSET 0x01 -+#define BMI323_MO3_OFFSET 0x02 -+#define BMI323_MO1_REF_UP_MSK BIT(12) -+#define BMI323_MO1_SLOPE_TH_MSK GENMASK(11, 0) -+#define BMI323_MO2_HYSTR_MSK GENMASK(9, 0) -+#define BMI323_MO3_DURA_MSK GENMASK(12, 0) -+ -+/* Step counter config registers */ -+#define BMI323_STEP_SC1_REG 0x10 -+#define BMI323_STEP_SC1_WTRMRK_MSK GENMASK(9, 0) -+#define BMI323_STEP_SC1_RST_CNT_MSK BIT(10) -+#define BMI323_STEP_SC1_REG 0x10 -+#define BMI323_STEP_LEN 2 -+ -+/* Tap gesture config registers */ -+#define BMI323_TAP1_REG 0x1E -+#define BMI323_TAP1_AXIS_SEL_MSK GENMASK(1, 0) -+#define BMI323_AXIS_XYZ_MSK GENMASK(1, 0) -+#define BMI323_TAP1_TIMOUT_MSK BIT(2) -+#define BMI323_TAP1_MAX_PEAKS_MSK GENMASK(5, 3) -+#define BMI323_TAP1_MODE_MSK GENMASK(7, 6) -+#define BMI323_TAP2_REG 0x1F -+#define BMI323_TAP2_THRES_MSK GENMASK(9, 0) -+#define BMI323_TAP2_MAX_DUR_MSK GENMASK(15, 10) -+#define BMI323_TAP3_REG 0x20 -+#define BMI323_TAP3_QUIET_TIM_MSK GENMASK(15, 12) -+#define BMI323_TAP3_QT_BW_TAP_MSK GENMASK(11, 8) -+#define BMI323_TAP3_QT_AFT_GES_MSK GENMASK(15, 12) -+ -+#define BMI323_MOTION_THRES_SCALE 512 -+#define BMI323_MOTION_HYSTR_SCALE 512 -+#define BMI323_MOTION_DURAT_SCALE 50 -+#define BMI323_TAP_THRES_SCALE 512 -+#define BMI323_DUR_BW_TAP_SCALE 200 -+#define BMI323_QUITE_TIM_GES_SCALE 25 -+#define BMI323_MAX_GES_DUR_SCALE 25 -+ -+/* -+ * The formula to calculate temperature in C. -+ * See datasheet section 6.1.1, Register Map Overview -+ * -+ * T_C = (temp_raw / 512) + 23 -+ */ -+#define BMI323_TEMP_OFFSET 11776 -+#define BMI323_TEMP_SCALE 1953125 -+ -+/* -+ * The BMI323 features a FIFO with a capacity of 2048 bytes. Each frame -+ * consists of accelerometer (X, Y, Z) data and gyroscope (X, Y, Z) data, -+ * totaling 6 words or 12 bytes. The FIFO buffer can hold a total of -+ * 170 frames. -+ * -+ * If a watermark interrupt is configured for 170 frames, the interrupt will -+ * trigger when the FIFO reaches 169 frames, so limit the maximum watermark -+ * level to 169 frames. In terms of data, 169 frames would equal 1014 bytes, -+ * which is approximately 2 frames before the FIFO reaches its full capacity. -+ * See datasheet section 5.7.3 FIFO Buffer Interrupts -+ */ -+#define BMI323_BYTES_PER_SAMPLE 2 -+#define BMI323_FIFO_LENGTH_IN_BYTES 2048 -+#define BMI323_FIFO_FRAME_LENGTH 6 -+#define BMI323_FIFO_FULL_IN_FRAMES \ -+ ((BMI323_FIFO_LENGTH_IN_BYTES / \ -+ (BMI323_BYTES_PER_SAMPLE * BMI323_FIFO_FRAME_LENGTH)) - 1) -+#define BMI323_FIFO_FULL_IN_WORDS \ -+ (BMI323_FIFO_FULL_IN_FRAMES * BMI323_FIFO_FRAME_LENGTH) -+ -+#define BMI323_INT_MICRO_TO_RAW(val, val2, scale) ((val) * (scale) + \ -+ ((val2) * (scale)) / MEGA) -+ -+#define BMI323_RAW_TO_MICRO(raw, scale) ((((raw) % (scale)) * MEGA) / scale) -+ -+struct device; -+int bmi323_core_probe(struct device *dev); -+extern const struct regmap_config bmi323_regmap_config; -+ -+#endif -diff --git a/drivers/iio/imu/bmi323/bmi323_core.c b/drivers/iio/imu/bmi323/bmi323_core.c -new file mode 100644 -index 000000000000..0bd5dedd9a63 ---- /dev/null -+++ b/drivers/iio/imu/bmi323/bmi323_core.c -@@ -0,0 +1,2139 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * IIO core driver for Bosch BMI323 6-Axis IMU. -+ * -+ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> -+ * -+ * Datasheet: https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi323-ds000.pdf -+ */ -+ -+#include <linux/bitfield.h> -+#include <linux/cleanup.h> -+#include <linux/device.h> -+#include <linux/interrupt.h> -+#include <linux/minmax.h> -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/property.h> -+#include <linux/regmap.h> -+#include <linux/regulator/consumer.h> -+#include <linux/units.h> -+ -+#include <asm/unaligned.h> -+ -+#include <linux/iio/buffer.h> -+#include <linux/iio/events.h> -+#include <linux/iio/iio.h> -+#include <linux/iio/sysfs.h> -+#include <linux/iio/trigger.h> -+#include <linux/iio/trigger_consumer.h> -+#include <linux/iio/triggered_buffer.h> -+ -+#include "bmi323.h" -+ -+enum bmi323_sensor_type { -+ BMI323_ACCEL, -+ BMI323_GYRO, -+ BMI323_SENSORS_CNT, -+}; -+ -+enum bmi323_opr_mode { -+ ACC_GYRO_MODE_DISABLE = 0x00, -+ GYRO_DRIVE_MODE_ENABLED = 0x01, -+ ACC_GYRO_MODE_DUTYCYCLE = 0x03, -+ ACC_GYRO_MODE_CONTINOUS = 0x04, -+ ACC_GYRO_MODE_HIGH_PERF = 0x07, -+}; -+ -+enum bmi323_state { -+ BMI323_IDLE, -+ BMI323_BUFFER_DRDY_TRIGGERED, -+ BMI323_BUFFER_FIFO, -+}; -+ -+enum bmi323_irq_pin { -+ BMI323_IRQ_DISABLED, -+ BMI323_IRQ_INT1, -+ BMI323_IRQ_INT2, -+}; -+ -+enum bmi323_3db_bw { -+ BMI323_BW_ODR_BY_2, -+ BMI323_BW_ODR_BY_4, -+}; -+ -+enum bmi323_scan { -+ BMI323_ACCEL_X, -+ BMI323_ACCEL_Y, -+ BMI323_ACCEL_Z, -+ BMI323_GYRO_X, -+ BMI323_GYRO_Y, -+ BMI323_GYRO_Z, -+ BMI323_CHAN_MAX -+}; -+ -+struct bmi323_hw { -+ u8 data; -+ u8 config; -+ const int (*scale_table)[2]; -+ int scale_table_len; -+}; -+ -+/* -+ * The accelerometer supports +-2G/4G/8G/16G ranges, and the resolution of -+ * each sample is 16 bits, signed. -+ * At +-8G the scale can calculated by -+ * ((8 + 8) * 9.80665 / (2^16 - 1)) * 10^6 = 2394.23819 scale in micro -+ * -+ */ -+static const int bmi323_accel_scale[][2] = { -+ { 0, 598 }, -+ { 0, 1197 }, -+ { 0, 2394 }, -+ { 0, 4788 }, -+}; -+ -+static const int bmi323_gyro_scale[][2] = { -+ { 0, 66 }, -+ { 0, 133 }, -+ { 0, 266 }, -+ { 0, 532 }, -+ { 0, 1065 }, -+}; -+ -+static const int bmi323_accel_gyro_avrg[] = {0, 2, 4, 8, 16, 32, 64}; -+ -+static const struct bmi323_hw bmi323_hw[2] = { -+ [BMI323_ACCEL] = { -+ .data = BMI323_ACCEL_X_REG, -+ .config = BMI323_ACC_CONF_REG, -+ .scale_table = bmi323_accel_scale, -+ .scale_table_len = ARRAY_SIZE(bmi323_accel_scale), -+ }, -+ [BMI323_GYRO] = { -+ .data = BMI323_GYRO_X_REG, -+ .config = BMI323_GYRO_CONF_REG, -+ .scale_table = bmi323_gyro_scale, -+ .scale_table_len = ARRAY_SIZE(bmi323_gyro_scale), -+ }, -+}; -+ -+struct bmi323_data { -+ struct device *dev; -+ struct regmap *regmap; -+ struct iio_mount_matrix orientation; -+ enum bmi323_irq_pin irq_pin; -+ struct iio_trigger *trig; -+ bool drdy_trigger_enabled; -+ enum bmi323_state state; -+ s64 fifo_tstamp, old_fifo_tstamp; -+ u32 odrns[BMI323_SENSORS_CNT]; -+ u32 odrhz[BMI323_SENSORS_CNT]; -+ unsigned int feature_events; -+ -+ /* -+ * Lock to protect the members of device's private data from concurrent -+ * access and also to serialize the access of extended registers. -+ * See bmi323_write_ext_reg(..) for more info. -+ */ -+ struct mutex mutex; -+ int watermark; -+ __le16 fifo_buff[BMI323_FIFO_FULL_IN_WORDS] __aligned(IIO_DMA_MINALIGN); -+ struct { -+ __le16 channels[BMI323_CHAN_MAX]; -+ s64 ts __aligned(8); -+ } buffer; -+ __le16 steps_count[BMI323_STEP_LEN]; -+}; -+ -+static const struct iio_mount_matrix * -+bmi323_get_mount_matrix(const struct iio_dev *idev, -+ const struct iio_chan_spec *chan) -+{ -+ struct bmi323_data *data = iio_priv(idev); -+ -+ return &data->orientation; -+} -+ -+static const struct iio_chan_spec_ext_info bmi323_ext_info[] = { -+ IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, bmi323_get_mount_matrix), -+ { } -+}; -+ -+static const struct iio_event_spec bmi323_step_wtrmrk_event = { -+ .type = IIO_EV_TYPE_CHANGE, -+ .dir = IIO_EV_DIR_NONE, -+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | -+ BIT(IIO_EV_INFO_VALUE), -+}; -+ -+static const struct iio_event_spec bmi323_accel_event[] = { -+ { -+ .type = IIO_EV_TYPE_MAG, -+ .dir = IIO_EV_DIR_FALLING, -+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | -+ BIT(IIO_EV_INFO_PERIOD) | -+ BIT(IIO_EV_INFO_HYSTERESIS) | -+ BIT(IIO_EV_INFO_ENABLE), -+ }, -+ { -+ .type = IIO_EV_TYPE_MAG, -+ .dir = IIO_EV_DIR_RISING, -+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | -+ BIT(IIO_EV_INFO_PERIOD) | -+ BIT(IIO_EV_INFO_HYSTERESIS) | -+ BIT(IIO_EV_INFO_ENABLE), -+ }, -+ { -+ .type = IIO_EV_TYPE_GESTURE, -+ .dir = IIO_EV_DIR_SINGLETAP, -+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | -+ BIT(IIO_EV_INFO_VALUE) | -+ BIT(IIO_EV_INFO_RESET_TIMEOUT), -+ }, -+ { -+ .type = IIO_EV_TYPE_GESTURE, -+ .dir = IIO_EV_DIR_DOUBLETAP, -+ .mask_shared_by_type = BIT(IIO_EV_INFO_ENABLE) | -+ BIT(IIO_EV_INFO_VALUE) | -+ BIT(IIO_EV_INFO_RESET_TIMEOUT) | -+ BIT(IIO_EV_INFO_TAP2_MIN_DELAY), -+ }, -+}; -+ -+#define BMI323_ACCEL_CHANNEL(_type, _axis, _index) { \ -+ .type = _type, \ -+ .modified = 1, \ -+ .channel2 = IIO_MOD_##_axis, \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .info_mask_shared_by_type_available = \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .scan_index = _index, \ -+ .scan_type = { \ -+ .sign = 's', \ -+ .realbits = 16, \ -+ .storagebits = 16, \ -+ .endianness = IIO_LE, \ -+ }, \ -+ .ext_info = bmi323_ext_info, \ -+ .event_spec = bmi323_accel_event, \ -+ .num_event_specs = ARRAY_SIZE(bmi323_accel_event), \ -+} -+ -+#define BMI323_GYRO_CHANNEL(_type, _axis, _index) { \ -+ .type = _type, \ -+ .modified = 1, \ -+ .channel2 = IIO_MOD_##_axis, \ -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ -+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .info_mask_shared_by_type_available = \ -+ BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ -+ BIT(IIO_CHAN_INFO_SCALE) | \ -+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ -+ .scan_index = _index, \ -+ .scan_type = { \ -+ .sign = 's', \ -+ .realbits = 16, \ -+ .storagebits = 16, \ -+ .endianness = IIO_LE, \ -+ }, \ -+ .ext_info = bmi323_ext_info, \ -+} -+ -+static const struct iio_chan_spec bmi323_channels[] = { -+ BMI323_ACCEL_CHANNEL(IIO_ACCEL, X, BMI323_ACCEL_X), -+ BMI323_ACCEL_CHANNEL(IIO_ACCEL, Y, BMI323_ACCEL_Y), -+ BMI323_ACCEL_CHANNEL(IIO_ACCEL, Z, BMI323_ACCEL_Z), -+ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, X, BMI323_GYRO_X), -+ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, Y, BMI323_GYRO_Y), -+ BMI323_GYRO_CHANNEL(IIO_ANGL_VEL, Z, BMI323_GYRO_Z), -+ { -+ .type = IIO_TEMP, -+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | -+ BIT(IIO_CHAN_INFO_OFFSET) | -+ BIT(IIO_CHAN_INFO_SCALE), -+ .scan_index = -1, -+ }, -+ { -+ .type = IIO_STEPS, -+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | -+ BIT(IIO_CHAN_INFO_ENABLE), -+ .scan_index = -1, -+ .event_spec = &bmi323_step_wtrmrk_event, -+ .num_event_specs = 1, -+ -+ }, -+ IIO_CHAN_SOFT_TIMESTAMP(BMI323_CHAN_MAX), -+}; -+ -+static const int bmi323_acc_gyro_odr[][2] = { -+ { 0, 781250 }, -+ { 1, 562500 }, -+ { 3, 125000 }, -+ { 6, 250000 }, -+ { 12, 500000 }, -+ { 25, 0 }, -+ { 50, 0 }, -+ { 100, 0 }, -+ { 200, 0 }, -+ { 400, 0 }, -+ { 800, 0 }, -+}; -+ -+static const int bmi323_acc_gyro_odrns[] = { -+ 1280 * MEGA, -+ 640 * MEGA, -+ 320 * MEGA, -+ 160 * MEGA, -+ 80 * MEGA, -+ 40 * MEGA, -+ 20 * MEGA, -+ 10 * MEGA, -+ 5 * MEGA, -+ 2500 * KILO, -+ 1250 * KILO, -+}; -+ -+static enum bmi323_sensor_type bmi323_iio_to_sensor(enum iio_chan_type iio_type) -+{ -+ switch (iio_type) { -+ case IIO_ACCEL: -+ return BMI323_ACCEL; -+ case IIO_ANGL_VEL: -+ return BMI323_GYRO; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_set_mode(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, -+ enum bmi323_opr_mode mode) -+{ -+ guard(mutex)(&data->mutex); -+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, -+ BMI323_ACC_GYRO_CONF_MODE_MSK, -+ FIELD_PREP(BMI323_ACC_GYRO_CONF_MODE_MSK, -+ mode)); -+} -+ -+/* -+ * When writing data to extended register there must be no communication to -+ * any other register before write transaction is complete. -+ * See datasheet section 6.2 Extended Register Map Description. -+ */ -+static int bmi323_write_ext_reg(struct bmi323_data *data, unsigned int ext_addr, -+ unsigned int ext_data) -+{ -+ int ret, feature_status; -+ -+ ret = regmap_read(data->regmap, BMI323_FEAT_DATA_STATUS, -+ &feature_status); -+ if (ret) -+ return ret; -+ -+ if (!FIELD_GET(BMI323_FEAT_DATA_TX_RDY_MSK, feature_status)) -+ return -EBUSY; -+ -+ ret = regmap_write(data->regmap, BMI323_FEAT_DATA_ADDR, ext_addr); -+ if (ret) -+ return ret; -+ -+ return regmap_write(data->regmap, BMI323_FEAT_DATA_TX, ext_data); -+} -+ -+/* -+ * When reading data from extended register there must be no communication to -+ * any other register before read transaction is complete. -+ * See datasheet section 6.2 Extended Register Map Description. -+ */ -+static int bmi323_read_ext_reg(struct bmi323_data *data, unsigned int ext_addr, -+ unsigned int *ext_data) -+{ -+ int ret, feature_status; -+ -+ ret = regmap_read(data->regmap, BMI323_FEAT_DATA_STATUS, -+ &feature_status); -+ if (ret) -+ return ret; -+ -+ if (!FIELD_GET(BMI323_FEAT_DATA_TX_RDY_MSK, feature_status)) -+ return -EBUSY; -+ -+ ret = regmap_write(data->regmap, BMI323_FEAT_DATA_ADDR, ext_addr); -+ if (ret) -+ return ret; -+ -+ return regmap_read(data->regmap, BMI323_FEAT_DATA_TX, ext_data); -+} -+ -+static int bmi323_update_ext_reg(struct bmi323_data *data, -+ unsigned int ext_addr, -+ unsigned int mask, unsigned int ext_data) -+{ -+ unsigned int value; -+ int ret; -+ -+ ret = bmi323_read_ext_reg(data, ext_addr, &value); -+ if (ret) -+ return ret; -+ -+ set_mask_bits(&value, mask, ext_data); -+ -+ return bmi323_write_ext_reg(data, ext_addr, value); -+} -+ -+static int bmi323_get_error_status(struct bmi323_data *data) -+{ -+ int error, ret; -+ -+ guard(mutex)(&data->mutex); -+ ret = regmap_read(data->regmap, BMI323_ERR_REG, &error); -+ if (ret) -+ return ret; -+ -+ if (error) -+ dev_err(data->dev, "Sensor error 0x%x\n", error); -+ -+ return error; -+} -+ -+static int bmi323_feature_engine_events(struct bmi323_data *data, -+ const unsigned int event_mask, -+ bool state) -+{ -+ unsigned int value; -+ int ret; -+ -+ ret = regmap_read(data->regmap, BMI323_FEAT_IO0_REG, &value); -+ if (ret) -+ return ret; -+ -+ /* Register must be cleared before changing an active config */ -+ ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, 0); -+ if (ret) -+ return ret; -+ -+ if (state) -+ value |= event_mask; -+ else -+ value &= ~event_mask; -+ -+ ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, value); -+ if (ret) -+ return ret; -+ -+ return regmap_write(data->regmap, BMI323_FEAT_IO_STATUS_REG, -+ BMI323_FEAT_IO_STATUS_MSK); -+} -+ -+static int bmi323_step_wtrmrk_en(struct bmi323_data *data, int state) -+{ -+ enum bmi323_irq_pin step_irq; -+ int ret; -+ -+ guard(mutex)(&data->mutex); -+ if (!FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, data->feature_events)) -+ return -EINVAL; -+ -+ if (state) -+ step_irq = data->irq_pin; -+ else -+ step_irq = BMI323_IRQ_DISABLED; -+ -+ ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, -+ BMI323_STEP_SC1_WTRMRK_MSK, -+ FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK, -+ state ? 1 : 0)); -+ if (ret) -+ return ret; -+ -+ return regmap_update_bits(data->regmap, BMI323_INT_MAP1_REG, -+ BMI323_STEP_CNT_MSK, -+ FIELD_PREP(BMI323_STEP_CNT_MSK, step_irq)); -+} -+ -+static int bmi323_motion_config_reg(enum iio_event_direction dir) -+{ -+ switch (dir) { -+ case IIO_EV_DIR_RISING: -+ return BMI323_ANYMO1_REG; -+ case IIO_EV_DIR_FALLING: -+ return BMI323_NOMO1_REG; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_motion_event_en(struct bmi323_data *data, -+ enum iio_event_direction dir, int state) -+{ -+ unsigned int state_value = state ? BMI323_FEAT_XYZ_MSK : 0; -+ int config, ret, msk, raw, field_value; -+ enum bmi323_irq_pin motion_irq; -+ int irq_msk, irq_field_val; -+ -+ if (state) -+ motion_irq = data->irq_pin; -+ else -+ motion_irq = BMI323_IRQ_DISABLED; -+ -+ switch (dir) { -+ case IIO_EV_DIR_RISING: -+ msk = BMI323_FEAT_IO0_XYZ_MOTION_MSK; -+ raw = 512; -+ config = BMI323_ANYMO1_REG; -+ irq_msk = BMI323_MOTION_MSK; -+ irq_field_val = FIELD_PREP(BMI323_MOTION_MSK, motion_irq); -+ field_value = FIELD_PREP(BMI323_FEAT_IO0_XYZ_MOTION_MSK, -+ state_value); -+ break; -+ case IIO_EV_DIR_FALLING: -+ msk = BMI323_FEAT_IO0_XYZ_NOMOTION_MSK; -+ raw = 0; -+ config = BMI323_NOMO1_REG; -+ irq_msk = BMI323_NOMOTION_MSK; -+ irq_field_val = FIELD_PREP(BMI323_NOMOTION_MSK, motion_irq); -+ field_value = FIELD_PREP(BMI323_FEAT_IO0_XYZ_NOMOTION_MSK, -+ state_value); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ guard(mutex)(&data->mutex); -+ ret = bmi323_feature_engine_events(data, msk, state); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_update_ext_reg(data, config, -+ BMI323_MO1_REF_UP_MSK, -+ FIELD_PREP(BMI323_MO1_REF_UP_MSK, 0)); -+ if (ret) -+ return ret; -+ -+ /* Set initial value to avoid interrupts while enabling*/ -+ ret = bmi323_update_ext_reg(data, config, -+ BMI323_MO1_SLOPE_TH_MSK, -+ FIELD_PREP(BMI323_MO1_SLOPE_TH_MSK, raw)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP1_REG, irq_msk, -+ irq_field_val); -+ if (ret) -+ return ret; -+ -+ set_mask_bits(&data->feature_events, msk, field_value); -+ -+ return 0; -+} -+ -+static int bmi323_tap_event_en(struct bmi323_data *data, -+ enum iio_event_direction dir, int state) -+{ -+ enum bmi323_irq_pin tap_irq; -+ int ret, tap_enabled; -+ -+ guard(mutex)(&data->mutex); -+ -+ if (data->odrhz[BMI323_ACCEL] < 200) { -+ dev_err(data->dev, "Invalid accelrometer parameter\n"); -+ return -EINVAL; -+ } -+ -+ switch (dir) { -+ case IIO_EV_DIR_SINGLETAP: -+ ret = bmi323_feature_engine_events(data, -+ BMI323_FEAT_IO0_S_TAP_MSK, -+ state); -+ if (ret) -+ return ret; -+ -+ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_S_TAP_MSK, -+ FIELD_PREP(BMI323_FEAT_IO0_S_TAP_MSK, state)); -+ break; -+ case IIO_EV_DIR_DOUBLETAP: -+ ret = bmi323_feature_engine_events(data, -+ BMI323_FEAT_IO0_D_TAP_MSK, -+ state); -+ if (ret) -+ return ret; -+ -+ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_D_TAP_MSK, -+ FIELD_PREP(BMI323_FEAT_IO0_D_TAP_MSK, state)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ tap_enabled = FIELD_GET(BMI323_FEAT_IO0_S_TAP_MSK | -+ BMI323_FEAT_IO0_D_TAP_MSK, -+ data->feature_events); -+ -+ if (tap_enabled) -+ tap_irq = data->irq_pin; -+ else -+ tap_irq = BMI323_IRQ_DISABLED; -+ -+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, -+ BMI323_TAP_MSK, -+ FIELD_PREP(BMI323_TAP_MSK, tap_irq)); -+ if (ret) -+ return ret; -+ -+ if (!state) -+ return 0; -+ -+ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG, -+ BMI323_TAP1_MAX_PEAKS_MSK, -+ FIELD_PREP(BMI323_TAP1_MAX_PEAKS_MSK, -+ 0x04)); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG, -+ BMI323_TAP1_AXIS_SEL_MSK, -+ FIELD_PREP(BMI323_TAP1_AXIS_SEL_MSK, -+ BMI323_AXIS_XYZ_MSK)); -+ if (ret) -+ return ret; -+ -+ return bmi323_update_ext_reg(data, BMI323_TAP1_REG, -+ BMI323_TAP1_TIMOUT_MSK, -+ FIELD_PREP(BMI323_TAP1_TIMOUT_MSK, -+ 0)); -+} -+ -+static ssize_t in_accel_gesture_tap_wait_dur_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct bmi323_data *data = iio_priv(indio_dev); -+ unsigned int reg_value, raw; -+ int ret, val[2]; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = bmi323_read_ext_reg(data, BMI323_TAP2_REG, ®_value); -+ if (ret) -+ return ret; -+ } -+ -+ raw = FIELD_GET(BMI323_TAP2_MAX_DUR_MSK, reg_value); -+ val[0] = raw / BMI323_MAX_GES_DUR_SCALE; -+ val[1] = BMI323_RAW_TO_MICRO(raw, BMI323_MAX_GES_DUR_SCALE); -+ -+ return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, ARRAY_SIZE(val), -+ val); -+} -+ -+static ssize_t in_accel_gesture_tap_wait_dur_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, size_t len) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct bmi323_data *data = iio_priv(indio_dev); -+ int ret, val_int, val_fract, raw; -+ -+ ret = iio_str_to_fixpoint(buf, 100000, &val_int, &val_fract); -+ if (ret) -+ return ret; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val_int, val_fract, -+ BMI323_MAX_GES_DUR_SCALE); -+ if (!in_range(raw, 0, 64)) -+ return -EINVAL; -+ -+ guard(mutex)(&data->mutex); -+ ret = bmi323_update_ext_reg(data, BMI323_TAP2_REG, -+ BMI323_TAP2_MAX_DUR_MSK, -+ FIELD_PREP(BMI323_TAP2_MAX_DUR_MSK, raw)); -+ if (ret) -+ return ret; -+ -+ return len; -+} -+ -+/* -+ * Maximum duration from first tap within the second tap is expected to happen. -+ * This timeout is applicable only if gesture_tap_wait_timeout is enabled. -+ */ -+static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_wait_dur, 0); -+ -+static ssize_t in_accel_gesture_tap_wait_timeout_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct bmi323_data *data = iio_priv(indio_dev); -+ unsigned int reg_value, raw; -+ int ret; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = bmi323_read_ext_reg(data, BMI323_TAP1_REG, ®_value); -+ if (ret) -+ return ret; -+ } -+ -+ raw = FIELD_GET(BMI323_TAP1_TIMOUT_MSK, reg_value); -+ -+ return iio_format_value(buf, IIO_VAL_INT, 1, &raw); -+} -+ -+static ssize_t in_accel_gesture_tap_wait_timeout_store(struct device *dev, -+ struct device_attribute *attr, -+ const char *buf, -+ size_t len) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct bmi323_data *data = iio_priv(indio_dev); -+ bool val; -+ int ret; -+ -+ ret = kstrtobool(buf, &val); -+ if (ret) -+ return ret; -+ -+ guard(mutex)(&data->mutex); -+ ret = bmi323_update_ext_reg(data, BMI323_TAP1_REG, -+ BMI323_TAP1_TIMOUT_MSK, -+ FIELD_PREP(BMI323_TAP1_TIMOUT_MSK, val)); -+ if (ret) -+ return ret; -+ -+ return len; -+} -+ -+/* Enable/disable gesture confirmation with wait time */ -+static IIO_DEVICE_ATTR_RW(in_accel_gesture_tap_wait_timeout, 0); -+ -+static IIO_CONST_ATTR(in_accel_gesture_tap_wait_dur_available, -+ "[0.0 0.04 2.52]"); -+ -+static IIO_CONST_ATTR(in_accel_gesture_doubletap_tap2_min_delay_available, -+ "[0.005 0.005 0.075]"); -+ -+static IIO_CONST_ATTR(in_accel_gesture_tap_reset_timeout_available, -+ "[0.04 0.04 0.6]"); -+ -+static IIO_CONST_ATTR(in_accel_gesture_tap_value_available, "[0.0 0.002 1.99]"); -+ -+static IIO_CONST_ATTR(in_accel_mag_value_available, "[0.0 0.002 7.99]"); -+ -+static IIO_CONST_ATTR(in_accel_mag_period_available, "[0.0 0.02 162.0]"); -+ -+static IIO_CONST_ATTR(in_accel_mag_hysteresis_available, "[0.0 0.002 1.99]"); -+ -+static struct attribute *bmi323_event_attributes[] = { -+ &iio_const_attr_in_accel_gesture_tap_value_available.dev_attr.attr, -+ &iio_const_attr_in_accel_gesture_tap_reset_timeout_available.dev_attr.attr, -+ &iio_const_attr_in_accel_gesture_doubletap_tap2_min_delay_available.dev_attr.attr, -+ &iio_const_attr_in_accel_gesture_tap_wait_dur_available.dev_attr.attr, -+ &iio_dev_attr_in_accel_gesture_tap_wait_timeout.dev_attr.attr, -+ &iio_dev_attr_in_accel_gesture_tap_wait_dur.dev_attr.attr, -+ &iio_const_attr_in_accel_mag_value_available.dev_attr.attr, -+ &iio_const_attr_in_accel_mag_period_available.dev_attr.attr, -+ &iio_const_attr_in_accel_mag_hysteresis_available.dev_attr.attr, -+ NULL -+}; -+ -+static const struct attribute_group bmi323_event_attribute_group = { -+ .attrs = bmi323_event_attributes, -+}; -+ -+static int bmi323_write_event_config(struct iio_dev *indio_dev, -+ const struct iio_chan_spec *chan, -+ enum iio_event_type type, -+ enum iio_event_direction dir, int state) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ -+ switch (type) { -+ case IIO_EV_TYPE_MAG: -+ return bmi323_motion_event_en(data, dir, state); -+ case IIO_EV_TYPE_GESTURE: -+ return bmi323_tap_event_en(data, dir, state); -+ case IIO_EV_TYPE_CHANGE: -+ return bmi323_step_wtrmrk_en(data, state); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_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 bmi323_data *data = iio_priv(indio_dev); -+ int ret, value, reg_val; -+ -+ guard(mutex)(&data->mutex); -+ -+ switch (chan->type) { -+ case IIO_ACCEL: -+ switch (dir) { -+ case IIO_EV_DIR_SINGLETAP: -+ ret = FIELD_GET(BMI323_FEAT_IO0_S_TAP_MSK, -+ data->feature_events); -+ break; -+ case IIO_EV_DIR_DOUBLETAP: -+ ret = FIELD_GET(BMI323_FEAT_IO0_D_TAP_MSK, -+ data->feature_events); -+ break; -+ case IIO_EV_DIR_RISING: -+ value = FIELD_GET(BMI323_FEAT_IO0_XYZ_MOTION_MSK, -+ data->feature_events); -+ ret = value ? 1 : 0; -+ break; -+ case IIO_EV_DIR_FALLING: -+ value = FIELD_GET(BMI323_FEAT_IO0_XYZ_NOMOTION_MSK, -+ data->feature_events); -+ ret = value ? 1 : 0; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+ case IIO_STEPS: -+ ret = regmap_read(data->regmap, BMI323_INT_MAP1_REG, ®_val); -+ if (ret) -+ return ret; -+ -+ return FIELD_GET(BMI323_STEP_CNT_MSK, reg_val) ? 1 : 0; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_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 bmi323_data *data = iio_priv(indio_dev); -+ unsigned int raw; -+ int reg; -+ -+ guard(mutex)(&data->mutex); -+ -+ switch (type) { -+ case IIO_EV_TYPE_GESTURE: -+ switch (info) { -+ case IIO_EV_INFO_VALUE: -+ if (!in_range(val, 0, 2)) -+ return -EINVAL; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val, val2, -+ BMI323_TAP_THRES_SCALE); -+ -+ return bmi323_update_ext_reg(data, BMI323_TAP2_REG, -+ BMI323_TAP2_THRES_MSK, -+ FIELD_PREP(BMI323_TAP2_THRES_MSK, -+ raw)); -+ case IIO_EV_INFO_RESET_TIMEOUT: -+ if (val || !in_range(val2, 40000, 560001)) -+ return -EINVAL; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val, val2, -+ BMI323_QUITE_TIM_GES_SCALE); -+ -+ return bmi323_update_ext_reg(data, BMI323_TAP3_REG, -+ BMI323_TAP3_QT_AFT_GES_MSK, -+ FIELD_PREP(BMI323_TAP3_QT_AFT_GES_MSK, -+ raw)); -+ case IIO_EV_INFO_TAP2_MIN_DELAY: -+ if (val || !in_range(val2, 5000, 70001)) -+ return -EINVAL; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val, val2, -+ BMI323_DUR_BW_TAP_SCALE); -+ -+ return bmi323_update_ext_reg(data, BMI323_TAP3_REG, -+ BMI323_TAP3_QT_BW_TAP_MSK, -+ FIELD_PREP(BMI323_TAP3_QT_BW_TAP_MSK, -+ raw)); -+ default: -+ return -EINVAL; -+ } -+ case IIO_EV_TYPE_MAG: -+ reg = bmi323_motion_config_reg(dir); -+ if (reg < 0) -+ return -EINVAL; -+ -+ switch (info) { -+ case IIO_EV_INFO_VALUE: -+ if (!in_range(val, 0, 8)) -+ return -EINVAL; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val, val2, -+ BMI323_MOTION_THRES_SCALE); -+ -+ return bmi323_update_ext_reg(data, reg, -+ BMI323_MO1_SLOPE_TH_MSK, -+ FIELD_PREP(BMI323_MO1_SLOPE_TH_MSK, -+ raw)); -+ case IIO_EV_INFO_PERIOD: -+ if (!in_range(val, 0, 163)) -+ return -EINVAL; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val, val2, -+ BMI323_MOTION_DURAT_SCALE); -+ -+ return bmi323_update_ext_reg(data, -+ reg + BMI323_MO3_OFFSET, -+ BMI323_MO3_DURA_MSK, -+ FIELD_PREP(BMI323_MO3_DURA_MSK, -+ raw)); -+ case IIO_EV_INFO_HYSTERESIS: -+ if (!in_range(val, 0, 2)) -+ return -EINVAL; -+ -+ raw = BMI323_INT_MICRO_TO_RAW(val, val2, -+ BMI323_MOTION_HYSTR_SCALE); -+ -+ return bmi323_update_ext_reg(data, -+ reg + BMI323_MO2_OFFSET, -+ BMI323_MO2_HYSTR_MSK, -+ FIELD_PREP(BMI323_MO2_HYSTR_MSK, -+ raw)); -+ default: -+ return -EINVAL; -+ } -+ case IIO_EV_TYPE_CHANGE: -+ if (!in_range(val, 0, 20461)) -+ return -EINVAL; -+ -+ raw = val / 20; -+ return bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, -+ BMI323_STEP_SC1_WTRMRK_MSK, -+ FIELD_PREP(BMI323_STEP_SC1_WTRMRK_MSK, -+ raw)); -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_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 bmi323_data *data = iio_priv(indio_dev); -+ unsigned int raw, reg_value; -+ int ret, reg; -+ -+ guard(mutex)(&data->mutex); -+ -+ switch (type) { -+ case IIO_EV_TYPE_GESTURE: -+ switch (info) { -+ case IIO_EV_INFO_VALUE: -+ ret = bmi323_read_ext_reg(data, BMI323_TAP2_REG, -+ ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_TAP2_THRES_MSK, reg_value); -+ *val = raw / BMI323_TAP_THRES_SCALE; -+ *val2 = BMI323_RAW_TO_MICRO(raw, BMI323_TAP_THRES_SCALE); -+ return IIO_VAL_INT_PLUS_MICRO; -+ case IIO_EV_INFO_RESET_TIMEOUT: -+ ret = bmi323_read_ext_reg(data, BMI323_TAP3_REG, -+ ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_TAP3_QT_AFT_GES_MSK, reg_value); -+ *val = 0; -+ *val2 = BMI323_RAW_TO_MICRO(raw, -+ BMI323_QUITE_TIM_GES_SCALE); -+ return IIO_VAL_INT_PLUS_MICRO; -+ case IIO_EV_INFO_TAP2_MIN_DELAY: -+ ret = bmi323_read_ext_reg(data, BMI323_TAP3_REG, -+ ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_TAP3_QT_BW_TAP_MSK, reg_value); -+ *val = 0; -+ *val2 = BMI323_RAW_TO_MICRO(raw, -+ BMI323_DUR_BW_TAP_SCALE); -+ return IIO_VAL_INT_PLUS_MICRO; -+ default: -+ return -EINVAL; -+ } -+ case IIO_EV_TYPE_MAG: -+ reg = bmi323_motion_config_reg(dir); -+ if (reg < 0) -+ return -EINVAL; -+ -+ switch (info) { -+ case IIO_EV_INFO_VALUE: -+ ret = bmi323_read_ext_reg(data, reg, ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_MO1_SLOPE_TH_MSK, reg_value); -+ *val = raw / BMI323_MOTION_THRES_SCALE; -+ *val2 = BMI323_RAW_TO_MICRO(raw, -+ BMI323_MOTION_THRES_SCALE); -+ return IIO_VAL_INT_PLUS_MICRO; -+ case IIO_EV_INFO_PERIOD: -+ ret = bmi323_read_ext_reg(data, -+ reg + BMI323_MO3_OFFSET, -+ ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_MO3_DURA_MSK, reg_value); -+ *val = raw / BMI323_MOTION_DURAT_SCALE; -+ *val2 = BMI323_RAW_TO_MICRO(raw, -+ BMI323_MOTION_DURAT_SCALE); -+ return IIO_VAL_INT_PLUS_MICRO; -+ case IIO_EV_INFO_HYSTERESIS: -+ ret = bmi323_read_ext_reg(data, -+ reg + BMI323_MO2_OFFSET, -+ ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_MO2_HYSTR_MSK, reg_value); -+ *val = raw / BMI323_MOTION_HYSTR_SCALE; -+ *val2 = BMI323_RAW_TO_MICRO(raw, -+ BMI323_MOTION_HYSTR_SCALE); -+ return IIO_VAL_INT_PLUS_MICRO; -+ default: -+ return -EINVAL; -+ } -+ case IIO_EV_TYPE_CHANGE: -+ ret = bmi323_read_ext_reg(data, BMI323_STEP_SC1_REG, -+ ®_value); -+ if (ret) -+ return ret; -+ -+ raw = FIELD_GET(BMI323_STEP_SC1_WTRMRK_MSK, reg_value); -+ *val = raw * 20; -+ return IIO_VAL_INT; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int __bmi323_fifo_flush(struct iio_dev *indio_dev) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ int i, ret, fifo_lvl, frame_count, bit, index; -+ __le16 *frame, *pchannels; -+ u64 sample_period; -+ s64 tstamp; -+ -+ guard(mutex)(&data->mutex); -+ ret = regmap_read(data->regmap, BMI323_FIFO_FILL_LEVEL_REG, &fifo_lvl); -+ if (ret) -+ return ret; -+ -+ fifo_lvl = min(fifo_lvl, BMI323_FIFO_FULL_IN_WORDS); -+ -+ frame_count = fifo_lvl / BMI323_FIFO_FRAME_LENGTH; -+ if (!frame_count) -+ return -EINVAL; -+ -+ if (fifo_lvl % BMI323_FIFO_FRAME_LENGTH) -+ dev_warn(data->dev, "Bad FIFO alignment\n"); -+ -+ /* -+ * Approximate timestamps for each of the sample based on the sampling -+ * frequency, timestamp for last sample and number of samples. -+ */ -+ if (data->old_fifo_tstamp) { -+ sample_period = data->fifo_tstamp - data->old_fifo_tstamp; -+ do_div(sample_period, frame_count); -+ } else { -+ sample_period = data->odrns[BMI323_ACCEL]; -+ } -+ -+ tstamp = data->fifo_tstamp - (frame_count - 1) * sample_period; -+ -+ ret = regmap_noinc_read(data->regmap, BMI323_FIFO_DATA_REG, -+ &data->fifo_buff[0], -+ fifo_lvl * BMI323_BYTES_PER_SAMPLE); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < frame_count; i++) { -+ frame = &data->fifo_buff[i * BMI323_FIFO_FRAME_LENGTH]; -+ pchannels = &data->buffer.channels[0]; -+ -+ index = 0; -+ for_each_set_bit(bit, indio_dev->active_scan_mask, -+ BMI323_CHAN_MAX) -+ pchannels[index++] = frame[bit]; -+ -+ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, -+ tstamp); -+ -+ tstamp += sample_period; -+ } -+ -+ return frame_count; -+} -+ -+static int bmi323_set_watermark(struct iio_dev *indio_dev, unsigned int val) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ -+ val = min(val, (u32)BMI323_FIFO_FULL_IN_FRAMES); -+ -+ guard(mutex)(&data->mutex); -+ data->watermark = val; -+ -+ return 0; -+} -+ -+static int bmi323_fifo_disable(struct bmi323_data *data) -+{ -+ int ret; -+ -+ guard(mutex)(&data->mutex); -+ ret = regmap_write(data->regmap, BMI323_FIFO_CONF_REG, 0); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, -+ BMI323_FIFO_WTRMRK_MSK, -+ FIELD_PREP(BMI323_FIFO_WTRMRK_MSK, 0)); -+ if (ret) -+ return ret; -+ -+ data->fifo_tstamp = 0; -+ data->state = BMI323_IDLE; -+ -+ return 0; -+} -+ -+static int bmi323_buffer_predisable(struct iio_dev *indio_dev) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ -+ if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED) -+ return 0; -+ -+ return bmi323_fifo_disable(data); -+} -+ -+static int bmi323_update_watermark(struct bmi323_data *data) -+{ -+ int wtrmrk; -+ -+ wtrmrk = data->watermark * BMI323_FIFO_FRAME_LENGTH; -+ -+ return regmap_write(data->regmap, BMI323_FIFO_WTRMRK_REG, wtrmrk); -+} -+ -+static int bmi323_fifo_enable(struct bmi323_data *data) -+{ -+ int ret; -+ -+ guard(mutex)(&data->mutex); -+ ret = regmap_update_bits(data->regmap, BMI323_FIFO_CONF_REG, -+ BMI323_FIFO_CONF_ACC_GYR_EN_MSK, -+ FIELD_PREP(BMI323_FIFO_CONF_ACC_GYR_EN_MSK, -+ BMI323_FIFO_ACC_GYR_MSK)); -+ if (ret) -+ return ret; -+ -+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, -+ BMI323_FIFO_WTRMRK_MSK, -+ FIELD_PREP(BMI323_FIFO_WTRMRK_MSK, -+ data->irq_pin)); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_update_watermark(data); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(data->regmap, BMI323_FIFO_CTRL_REG, -+ BMI323_FIFO_FLUSH_MSK); -+ if (ret) -+ return ret; -+ -+ data->state = BMI323_BUFFER_FIFO; -+ -+ return 0; -+} -+ -+static int bmi323_buffer_preenable(struct iio_dev *indio_dev) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ -+ guard(mutex)(&data->mutex); -+ /* -+ * When the ODR of the accelerometer and gyroscope do not match, the -+ * maximum ODR value between the accelerometer and gyroscope is used -+ * for FIFO and the signal with lower ODR will insert dummy frame. -+ * So allow buffer read only when ODR's of accelero and gyro are equal. -+ * See datasheet section 5.7 "FIFO Data Buffering". -+ */ -+ if (data->odrns[BMI323_ACCEL] != data->odrns[BMI323_GYRO]) { -+ dev_err(data->dev, "Accelero and Gyro ODR doesn't match\n"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int bmi323_buffer_postenable(struct iio_dev *indio_dev) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ -+ if (iio_device_get_current_mode(indio_dev) == INDIO_BUFFER_TRIGGERED) -+ return 0; -+ -+ return bmi323_fifo_enable(data); -+} -+ -+static ssize_t hwfifo_watermark_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct bmi323_data *data = iio_priv(indio_dev); -+ int wm; -+ -+ scoped_guard(mutex, &data->mutex) -+ wm = data->watermark; -+ -+ return sysfs_emit(buf, "%d\n", wm); -+} -+static IIO_DEVICE_ATTR_RO(hwfifo_watermark, 0); -+ -+static ssize_t hwfifo_enabled_show(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct iio_dev *indio_dev = dev_to_iio_dev(dev); -+ struct bmi323_data *data = iio_priv(indio_dev); -+ bool state; -+ -+ scoped_guard(mutex, &data->mutex) -+ state = data->state == BMI323_BUFFER_FIFO; -+ -+ return sysfs_emit(buf, "%d\n", state); -+} -+static IIO_DEVICE_ATTR_RO(hwfifo_enabled, 0); -+ -+static const struct iio_dev_attr *bmi323_fifo_attributes[] = { -+ &iio_dev_attr_hwfifo_watermark, -+ &iio_dev_attr_hwfifo_enabled, -+ NULL -+}; -+ -+static const struct iio_buffer_setup_ops bmi323_buffer_ops = { -+ .preenable = bmi323_buffer_preenable, -+ .postenable = bmi323_buffer_postenable, -+ .predisable = bmi323_buffer_predisable, -+}; -+ -+static irqreturn_t bmi323_irq_thread_handler(int irq, void *private) -+{ -+ struct iio_dev *indio_dev = private; -+ struct bmi323_data *data = iio_priv(indio_dev); -+ unsigned int status_addr, status, feature_event; -+ s64 timestamp = iio_get_time_ns(indio_dev); -+ int ret; -+ -+ if (data->irq_pin == BMI323_IRQ_INT1) -+ status_addr = BMI323_STATUS_INT1_REG; -+ else -+ status_addr = BMI323_STATUS_INT2_REG; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, status_addr, &status); -+ if (ret) -+ return IRQ_NONE; -+ } -+ -+ if (!status || FIELD_GET(BMI323_STATUS_ERROR_MSK, status)) -+ return IRQ_NONE; -+ -+ if (FIELD_GET(BMI323_STATUS_FIFO_WTRMRK_MSK, status)) { -+ data->old_fifo_tstamp = data->fifo_tstamp; -+ data->fifo_tstamp = iio_get_time_ns(indio_dev); -+ ret = __bmi323_fifo_flush(indio_dev); -+ if (ret < 0) -+ return IRQ_NONE; -+ } -+ -+ if (FIELD_GET(BMI323_STATUS_ACC_GYR_DRDY_MSK, status)) -+ iio_trigger_poll_nested(data->trig); -+ -+ if (FIELD_GET(BMI323_STATUS_MOTION_MSK, status)) -+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, -+ IIO_MOD_X_OR_Y_OR_Z, -+ IIO_EV_TYPE_MAG, -+ IIO_EV_DIR_RISING), -+ timestamp); -+ -+ if (FIELD_GET(BMI323_STATUS_NOMOTION_MSK, status)) -+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, -+ IIO_MOD_X_OR_Y_OR_Z, -+ IIO_EV_TYPE_MAG, -+ IIO_EV_DIR_FALLING), -+ timestamp); -+ -+ if (FIELD_GET(BMI323_STATUS_STP_WTR_MSK, status)) -+ iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_STEPS, 0, -+ IIO_NO_MOD, -+ IIO_EV_TYPE_CHANGE, -+ IIO_EV_DIR_NONE), -+ timestamp); -+ -+ if (FIELD_GET(BMI323_STATUS_TAP_MSK, status)) { -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, -+ BMI323_FEAT_EVNT_EXT_REG, -+ &feature_event); -+ if (ret) -+ return IRQ_NONE; -+ } -+ -+ if (FIELD_GET(BMI323_FEAT_EVNT_EXT_S_MSK, feature_event)) { -+ iio_push_event(indio_dev, -+ IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, -+ IIO_MOD_X_OR_Y_OR_Z, -+ IIO_EV_TYPE_GESTURE, -+ IIO_EV_DIR_SINGLETAP), -+ timestamp); -+ } -+ -+ if (FIELD_GET(BMI323_FEAT_EVNT_EXT_D_MSK, feature_event)) -+ 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); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int bmi323_set_drdy_irq(struct bmi323_data *data, -+ enum bmi323_irq_pin irq_pin) -+{ -+ int ret; -+ -+ ret = regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, -+ BMI323_GYR_DRDY_MSK, -+ FIELD_PREP(BMI323_GYR_DRDY_MSK, irq_pin)); -+ if (ret) -+ return ret; -+ -+ return regmap_update_bits(data->regmap, BMI323_INT_MAP2_REG, -+ BMI323_ACC_DRDY_MSK, -+ FIELD_PREP(BMI323_ACC_DRDY_MSK, irq_pin)); -+} -+ -+static int bmi323_data_rdy_trigger_set_state(struct iio_trigger *trig, -+ bool state) -+{ -+ struct bmi323_data *data = iio_trigger_get_drvdata(trig); -+ enum bmi323_irq_pin irq_pin; -+ -+ guard(mutex)(&data->mutex); -+ -+ if (data->state == BMI323_BUFFER_FIFO) { -+ dev_warn(data->dev, "Can't set trigger when FIFO enabled\n"); -+ return -EBUSY; -+ } -+ -+ if (state) { -+ data->state = BMI323_BUFFER_DRDY_TRIGGERED; -+ irq_pin = data->irq_pin; -+ } else { -+ data->state = BMI323_IDLE; -+ irq_pin = BMI323_IRQ_DISABLED; -+ } -+ -+ return bmi323_set_drdy_irq(data, irq_pin); -+} -+ -+static const struct iio_trigger_ops bmi323_trigger_ops = { -+ .set_trigger_state = &bmi323_data_rdy_trigger_set_state, -+}; -+ -+static irqreturn_t bmi323_trigger_handler(int irq, void *p) -+{ -+ struct iio_poll_func *pf = p; -+ struct iio_dev *indio_dev = pf->indio_dev; -+ struct bmi323_data *data = iio_priv(indio_dev); -+ int ret, bit, index = 0; -+ -+ /* Lock to protect the data->buffer */ -+ guard(mutex)(&data->mutex); -+ -+ if (*indio_dev->active_scan_mask == BMI323_ALL_CHAN_MSK) { -+ ret = regmap_bulk_read(data->regmap, BMI323_ACCEL_X_REG, -+ &data->buffer.channels, -+ ARRAY_SIZE(data->buffer.channels)); -+ if (ret) -+ return IRQ_NONE; -+ } else { -+ for_each_set_bit(bit, indio_dev->active_scan_mask, -+ BMI323_CHAN_MAX) { -+ ret = regmap_raw_read(data->regmap, -+ BMI323_ACCEL_X_REG + bit, -+ &data->buffer.channels[index++], -+ BMI323_BYTES_PER_SAMPLE); -+ if (ret) -+ return IRQ_NONE; -+ } -+ } -+ -+ iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, -+ iio_get_time_ns(indio_dev)); -+ -+ iio_trigger_notify_done(indio_dev->trig); -+ -+ return IRQ_HANDLED; -+} -+ -+static int bmi323_set_average(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, int avg) -+{ -+ int raw = ARRAY_SIZE(bmi323_accel_gyro_avrg); -+ -+ while (raw--) -+ if (avg == bmi323_accel_gyro_avrg[raw]) -+ break; -+ if (raw < 0) -+ return -EINVAL; -+ -+ guard(mutex)(&data->mutex); -+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, -+ BMI323_ACC_GYRO_CONF_AVG_MSK, -+ FIELD_PREP(BMI323_ACC_GYRO_CONF_AVG_MSK, -+ raw)); -+} -+ -+static int bmi323_get_average(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, int *avg) -+{ -+ int ret, value, raw; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, &value); -+ if (ret) -+ return ret; -+ } -+ -+ raw = FIELD_GET(BMI323_ACC_GYRO_CONF_AVG_MSK, value); -+ *avg = bmi323_accel_gyro_avrg[raw]; -+ -+ return IIO_VAL_INT; -+} -+ -+static int bmi323_enable_steps(struct bmi323_data *data, int val) -+{ -+ int ret; -+ -+ guard(mutex)(&data->mutex); -+ if (data->odrhz[BMI323_ACCEL] < 200) { -+ dev_err(data->dev, "Invalid accelrometer parameter\n"); -+ return -EINVAL; -+ } -+ -+ ret = bmi323_feature_engine_events(data, BMI323_FEAT_IO0_STP_CNT_MSK, -+ val ? 1 : 0); -+ if (ret) -+ return ret; -+ -+ set_mask_bits(&data->feature_events, BMI323_FEAT_IO0_STP_CNT_MSK, -+ FIELD_PREP(BMI323_FEAT_IO0_STP_CNT_MSK, val ? 1 : 0)); -+ -+ return 0; -+} -+ -+static int bmi323_read_steps(struct bmi323_data *data, int *val) -+{ -+ int ret; -+ -+ guard(mutex)(&data->mutex); -+ if (!FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, data->feature_events)) -+ return -EINVAL; -+ -+ ret = regmap_bulk_read(data->regmap, BMI323_FEAT_IO2_REG, -+ data->steps_count, -+ ARRAY_SIZE(data->steps_count)); -+ if (ret) -+ return ret; -+ -+ *val = get_unaligned_le32(data->steps_count); -+ -+ return IIO_VAL_INT; -+} -+ -+static int bmi323_read_axis(struct bmi323_data *data, -+ struct iio_chan_spec const *chan, int *val) -+{ -+ enum bmi323_sensor_type sensor; -+ unsigned int value; -+ u8 addr; -+ int ret; -+ -+ ret = bmi323_get_error_status(data); -+ if (ret) -+ return -EINVAL; -+ -+ sensor = bmi323_iio_to_sensor(chan->type); -+ addr = bmi323_hw[sensor].data + (chan->channel2 - IIO_MOD_X); -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, addr, &value); -+ if (ret) -+ return ret; -+ } -+ -+ *val = sign_extend32(value, chan->scan_type.realbits - 1); -+ -+ return IIO_VAL_INT; -+} -+ -+static int bmi323_get_temp_data(struct bmi323_data *data, int *val) -+{ -+ unsigned int value; -+ int ret; -+ -+ ret = bmi323_get_error_status(data); -+ if (ret) -+ return -EINVAL; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, BMI323_TEMP_REG, &value); -+ if (ret) -+ return ret; -+ } -+ -+ *val = sign_extend32(value, 15); -+ -+ return IIO_VAL_INT; -+} -+ -+static int bmi323_get_odr(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, int *odr, int *uodr) -+{ -+ int ret, value, odr_raw; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, &value); -+ if (ret) -+ return ret; -+ } -+ -+ odr_raw = FIELD_GET(BMI323_ACC_GYRO_CONF_ODR_MSK, value); -+ *odr = bmi323_acc_gyro_odr[odr_raw - 1][0]; -+ *uodr = bmi323_acc_gyro_odr[odr_raw - 1][1]; -+ -+ return IIO_VAL_INT_PLUS_MICRO; -+} -+ -+static int bmi323_configure_power_mode(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, -+ int odr_index) -+{ -+ enum bmi323_opr_mode mode; -+ -+ if (bmi323_acc_gyro_odr[odr_index][0] > 25) -+ mode = ACC_GYRO_MODE_CONTINOUS; -+ else -+ mode = ACC_GYRO_MODE_DUTYCYCLE; -+ -+ return bmi323_set_mode(data, sensor, mode); -+} -+ -+static int bmi323_set_odr(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, int odr, int uodr) -+{ -+ int odr_raw, ret; -+ -+ odr_raw = ARRAY_SIZE(bmi323_acc_gyro_odr); -+ -+ while (odr_raw--) -+ if (odr == bmi323_acc_gyro_odr[odr_raw][0] && -+ uodr == bmi323_acc_gyro_odr[odr_raw][1]) -+ break; -+ if (odr_raw < 0) -+ return -EINVAL; -+ -+ ret = bmi323_configure_power_mode(data, sensor, odr_raw); -+ if (ret) -+ return -EINVAL; -+ -+ guard(mutex)(&data->mutex); -+ data->odrhz[sensor] = bmi323_acc_gyro_odr[odr_raw][0]; -+ data->odrns[sensor] = bmi323_acc_gyro_odrns[odr_raw]; -+ -+ odr_raw++; -+ -+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, -+ BMI323_ACC_GYRO_CONF_ODR_MSK, -+ FIELD_PREP(BMI323_ACC_GYRO_CONF_ODR_MSK, -+ odr_raw)); -+} -+ -+static int bmi323_get_scale(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, int *val2) -+{ -+ int ret, value, scale_raw; -+ -+ scoped_guard(mutex, &data->mutex) { -+ ret = regmap_read(data->regmap, bmi323_hw[sensor].config, -+ &value); -+ if (ret) -+ return ret; -+ } -+ -+ scale_raw = FIELD_GET(BMI323_ACC_GYRO_CONF_SCL_MSK, value); -+ *val2 = bmi323_hw[sensor].scale_table[scale_raw][1]; -+ -+ return IIO_VAL_INT_PLUS_MICRO; -+} -+ -+static int bmi323_set_scale(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, int val, int val2) -+{ -+ int scale_raw; -+ -+ scale_raw = bmi323_hw[sensor].scale_table_len; -+ -+ while (scale_raw--) -+ if (val == bmi323_hw[sensor].scale_table[scale_raw][0] && -+ val2 == bmi323_hw[sensor].scale_table[scale_raw][1]) -+ break; -+ if (scale_raw < 0) -+ return -EINVAL; -+ -+ guard(mutex)(&data->mutex); -+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, -+ BMI323_ACC_GYRO_CONF_SCL_MSK, -+ FIELD_PREP(BMI323_ACC_GYRO_CONF_SCL_MSK, -+ scale_raw)); -+} -+ -+static int bmi323_read_avail(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, -+ const int **vals, int *type, int *length, -+ long mask) -+{ -+ enum bmi323_sensor_type sensor; -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ *type = IIO_VAL_INT_PLUS_MICRO; -+ *vals = (const int *)bmi323_acc_gyro_odr; -+ *length = ARRAY_SIZE(bmi323_acc_gyro_odr) * 2; -+ return IIO_AVAIL_LIST; -+ case IIO_CHAN_INFO_SCALE: -+ sensor = bmi323_iio_to_sensor(chan->type); -+ *type = IIO_VAL_INT_PLUS_MICRO; -+ *vals = (const int *)bmi323_hw[sensor].scale_table; -+ *length = bmi323_hw[sensor].scale_table_len * 2; -+ return IIO_AVAIL_LIST; -+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -+ *type = IIO_VAL_INT; -+ *vals = (const int *)bmi323_accel_gyro_avrg; -+ *length = ARRAY_SIZE(bmi323_accel_gyro_avrg); -+ return IIO_AVAIL_LIST; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_write_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, int val, -+ int val2, long mask) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ int ret; -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_set_odr(data, bmi323_iio_to_sensor(chan->type), -+ val, val2); -+ iio_device_release_direct_mode(indio_dev); -+ return ret; -+ case IIO_CHAN_INFO_SCALE: -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_set_scale(data, bmi323_iio_to_sensor(chan->type), -+ val, val2); -+ iio_device_release_direct_mode(indio_dev); -+ return ret; -+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_set_average(data, bmi323_iio_to_sensor(chan->type), -+ val); -+ -+ iio_device_release_direct_mode(indio_dev); -+ return ret; -+ case IIO_CHAN_INFO_ENABLE: -+ return bmi323_enable_steps(data, val); -+ case IIO_CHAN_INFO_PROCESSED: -+ scoped_guard(mutex, &data->mutex) { -+ if (val || !FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, -+ data->feature_events)) -+ return -EINVAL; -+ -+ /* Clear step counter value */ -+ ret = bmi323_update_ext_reg(data, BMI323_STEP_SC1_REG, -+ BMI323_STEP_SC1_RST_CNT_MSK, -+ FIELD_PREP(BMI323_STEP_SC1_RST_CNT_MSK, -+ 1)); -+ } -+ return ret; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int bmi323_read_raw(struct iio_dev *indio_dev, -+ struct iio_chan_spec const *chan, int *val, -+ int *val2, long mask) -+{ -+ struct bmi323_data *data = iio_priv(indio_dev); -+ int ret; -+ -+ switch (mask) { -+ case IIO_CHAN_INFO_PROCESSED: -+ return bmi323_read_steps(data, val); -+ case IIO_CHAN_INFO_RAW: -+ switch (chan->type) { -+ case IIO_ACCEL: -+ case IIO_ANGL_VEL: -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_read_axis(data, chan, val); -+ -+ iio_device_release_direct_mode(indio_dev); -+ return ret; -+ case IIO_TEMP: -+ return bmi323_get_temp_data(data, val); -+ default: -+ return -EINVAL; -+ } -+ case IIO_CHAN_INFO_SAMP_FREQ: -+ return bmi323_get_odr(data, bmi323_iio_to_sensor(chan->type), -+ val, val2); -+ case IIO_CHAN_INFO_SCALE: -+ switch (chan->type) { -+ case IIO_ACCEL: -+ case IIO_ANGL_VEL: -+ *val = 0; -+ return bmi323_get_scale(data, -+ bmi323_iio_to_sensor(chan->type), -+ val2); -+ case IIO_TEMP: -+ *val = BMI323_TEMP_SCALE / MEGA; -+ *val2 = BMI323_TEMP_SCALE % MEGA; -+ return IIO_VAL_INT_PLUS_MICRO; -+ default: -+ return -EINVAL; -+ } -+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -+ return bmi323_get_average(data, -+ bmi323_iio_to_sensor(chan->type), -+ val); -+ case IIO_CHAN_INFO_OFFSET: -+ switch (chan->type) { -+ case IIO_TEMP: -+ *val = BMI323_TEMP_OFFSET; -+ return IIO_VAL_INT; -+ default: -+ return -EINVAL; -+ } -+ case IIO_CHAN_INFO_ENABLE: -+ scoped_guard(mutex, &data->mutex) -+ *val = FIELD_GET(BMI323_FEAT_IO0_STP_CNT_MSK, -+ data->feature_events); -+ return IIO_VAL_INT; -+ default: -+ return -EINVAL; -+ } -+} -+ -+static const struct iio_info bmi323_info = { -+ .read_raw = bmi323_read_raw, -+ .write_raw = bmi323_write_raw, -+ .read_avail = bmi323_read_avail, -+ .hwfifo_set_watermark = bmi323_set_watermark, -+ .write_event_config = bmi323_write_event_config, -+ .read_event_config = bmi323_read_event_config, -+ .write_event_value = bmi323_write_event_value, -+ .read_event_value = bmi323_read_event_value, -+ .event_attrs = &bmi323_event_attribute_group, -+}; -+ -+#define BMI323_SCAN_MASK_ACCEL_3AXIS \ -+ (BIT(BMI323_ACCEL_X) | BIT(BMI323_ACCEL_Y) | BIT(BMI323_ACCEL_Z)) -+ -+#define BMI323_SCAN_MASK_GYRO_3AXIS \ -+ (BIT(BMI323_GYRO_X) | BIT(BMI323_GYRO_Y) | BIT(BMI323_GYRO_Z)) -+ -+static const unsigned long bmi323_avail_scan_masks[] = { -+ /* 3-axis accel */ -+ BMI323_SCAN_MASK_ACCEL_3AXIS, -+ /* 3-axis gyro */ -+ BMI323_SCAN_MASK_GYRO_3AXIS, -+ /* 3-axis accel + 3-axis gyro */ -+ BMI323_SCAN_MASK_ACCEL_3AXIS | BMI323_SCAN_MASK_GYRO_3AXIS, -+ 0 -+}; -+ -+static int bmi323_int_pin_config(struct bmi323_data *data, -+ enum bmi323_irq_pin irq_pin, -+ bool active_high, bool open_drain, bool latch) -+{ -+ unsigned int mask, field_value; -+ int ret; -+ -+ ret = regmap_update_bits(data->regmap, BMI323_IO_INT_CONF_REG, -+ BMI323_IO_INT_LTCH_MSK, -+ FIELD_PREP(BMI323_IO_INT_LTCH_MSK, latch)); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_update_ext_reg(data, BMI323_GEN_SET1_REG, -+ BMI323_GEN_HOLD_DUR_MSK, -+ FIELD_PREP(BMI323_GEN_HOLD_DUR_MSK, 0)); -+ if (ret) -+ return ret; -+ -+ switch (irq_pin) { -+ case BMI323_IRQ_INT1: -+ mask = BMI323_IO_INT1_LVL_OD_OP_MSK; -+ -+ field_value = FIELD_PREP(BMI323_IO_INT1_LVL_MSK, active_high) | -+ FIELD_PREP(BMI323_IO_INT1_OD_MSK, open_drain) | -+ FIELD_PREP(BMI323_IO_INT1_OP_EN_MSK, 1); -+ break; -+ case BMI323_IRQ_INT2: -+ mask = BMI323_IO_INT2_LVL_OD_OP_MSK; -+ -+ field_value = FIELD_PREP(BMI323_IO_INT2_LVL_MSK, active_high) | -+ FIELD_PREP(BMI323_IO_INT2_OD_MSK, open_drain) | -+ FIELD_PREP(BMI323_IO_INT2_OP_EN_MSK, 1); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return regmap_update_bits(data->regmap, BMI323_IO_INT_CTR_REG, mask, -+ field_value); -+} -+ -+static int bmi323_trigger_probe(struct bmi323_data *data, -+ struct iio_dev *indio_dev) -+{ -+ bool open_drain, active_high, latch; -+ struct fwnode_handle *fwnode; -+ enum bmi323_irq_pin irq_pin; -+ int ret, irq, irq_type; -+ struct irq_data *desc; -+ -+ fwnode = dev_fwnode(data->dev); -+ if (!fwnode) -+ return -ENODEV; -+ -+ irq = fwnode_irq_get_byname(fwnode, "INT1"); -+ if (irq > 0) { -+ irq_pin = BMI323_IRQ_INT1; -+ } else { -+ irq = fwnode_irq_get_byname(fwnode, "INT2"); -+ if (irq < 0) -+ return 0; -+ -+ irq_pin = BMI323_IRQ_INT2; -+ } -+ -+ desc = irq_get_irq_data(irq); -+ if (!desc) -+ return dev_err_probe(data->dev, -EINVAL, -+ "Could not find IRQ %d\n", irq); -+ -+ irq_type = irqd_get_trigger_type(desc); -+ switch (irq_type) { -+ case IRQF_TRIGGER_RISING: -+ latch = false; -+ active_high = true; -+ break; -+ case IRQF_TRIGGER_HIGH: -+ latch = true; -+ active_high = true; -+ break; -+ case IRQF_TRIGGER_FALLING: -+ latch = false; -+ active_high = false; -+ break; -+ case IRQF_TRIGGER_LOW: -+ latch = true; -+ active_high = false; -+ break; -+ default: -+ return dev_err_probe(data->dev, -EINVAL, -+ "Invalid interrupt type 0x%x specified\n", -+ irq_type); -+ } -+ -+ open_drain = fwnode_property_read_bool(fwnode, "drive-open-drain"); -+ -+ ret = bmi323_int_pin_config(data, irq_pin, active_high, open_drain, -+ latch); -+ if (ret) -+ return dev_err_probe(data->dev, ret, -+ "Failed to configure irq line\n"); -+ -+ data->trig = devm_iio_trigger_alloc(data->dev, "%s-trig-%d", -+ indio_dev->name, irq_pin); -+ if (!data->trig) -+ return -ENOMEM; -+ -+ data->trig->ops = &bmi323_trigger_ops; -+ iio_trigger_set_drvdata(data->trig, data); -+ -+ ret = devm_request_threaded_irq(data->dev, irq, NULL, -+ bmi323_irq_thread_handler, -+ IRQF_ONESHOT, "bmi323-int", indio_dev); -+ if (ret) -+ return dev_err_probe(data->dev, ret, "Failed to request IRQ\n"); -+ -+ ret = devm_iio_trigger_register(data->dev, data->trig); -+ if (ret) -+ return dev_err_probe(data->dev, ret, -+ "Trigger registration failed\n"); -+ -+ data->irq_pin = irq_pin; -+ -+ return 0; -+} -+ -+static int bmi323_feature_engine_enable(struct bmi323_data *data, bool en) -+{ -+ unsigned int feature_status; -+ int ret; -+ -+ if (!en) -+ return regmap_write(data->regmap, BMI323_FEAT_CTRL_REG, 0); -+ -+ ret = regmap_write(data->regmap, BMI323_FEAT_IO2_REG, 0x012c); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(data->regmap, BMI323_FEAT_IO_STATUS_REG, -+ BMI323_FEAT_IO_STATUS_MSK); -+ if (ret) -+ return ret; -+ -+ ret = regmap_write(data->regmap, BMI323_FEAT_CTRL_REG, -+ BMI323_FEAT_ENG_EN_MSK); -+ if (ret) -+ return ret; -+ -+ /* -+ * It takes around 4 msec to enable the Feature engine, so check -+ * the status of the feature engine every 2 msec for a maximum -+ * of 5 trials. -+ */ -+ ret = regmap_read_poll_timeout(data->regmap, BMI323_FEAT_IO1_REG, -+ feature_status, -+ FIELD_GET(BMI323_FEAT_IO1_ERR_MSK, -+ feature_status) == 1, -+ BMI323_FEAT_ENG_POLL, -+ BMI323_FEAT_ENG_TIMEOUT); -+ if (ret) -+ return dev_err_probe(data->dev, -EINVAL, -+ "Failed to enable feature engine\n"); -+ -+ return 0; -+} -+ -+static void bmi323_disable(void *data_ptr) -+{ -+ struct bmi323_data *data = data_ptr; -+ -+ bmi323_set_mode(data, BMI323_ACCEL, ACC_GYRO_MODE_DISABLE); -+ bmi323_set_mode(data, BMI323_GYRO, ACC_GYRO_MODE_DISABLE); -+} -+ -+static int bmi323_set_bw(struct bmi323_data *data, -+ enum bmi323_sensor_type sensor, enum bmi323_3db_bw bw) -+{ -+ return regmap_update_bits(data->regmap, bmi323_hw[sensor].config, -+ BMI323_ACC_GYRO_CONF_BW_MSK, -+ FIELD_PREP(BMI323_ACC_GYRO_CONF_BW_MSK, bw)); -+} -+ -+static int bmi323_init(struct bmi323_data *data) -+{ -+ int ret, val; -+ -+ /* -+ * Perform soft reset to make sure the device is in a known state after -+ * start up. A delay of 1.5 ms is required after reset. -+ * See datasheet section 5.17 "Soft Reset". -+ */ -+ ret = regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL); -+ if (ret) -+ return ret; -+ -+ usleep_range(1500, 2000); -+ -+ /* -+ * Dummy read is required to enable SPI interface after reset. -+ * See datasheet section 7.2.1 "Protocol Selection". -+ */ -+ regmap_read(data->regmap, BMI323_CHIP_ID_REG, &val); -+ -+ ret = regmap_read(data->regmap, BMI323_STATUS_REG, &val); -+ if (ret) -+ return ret; -+ -+ if (!FIELD_GET(BMI323_STATUS_POR_MSK, val)) -+ return dev_err_probe(data->dev, -EINVAL, -+ "Sensor initialization error\n"); -+ -+ ret = regmap_read(data->regmap, BMI323_CHIP_ID_REG, &val); -+ if (ret) -+ return ret; -+ -+ if (FIELD_GET(BMI323_CHIP_ID_MSK, val) != BMI323_CHIP_ID_VAL) -+ return dev_err_probe(data->dev, -EINVAL, "Chip ID mismatch\n"); -+ -+ ret = bmi323_feature_engine_enable(data, true); -+ if (ret) -+ return ret; -+ -+ ret = regmap_read(data->regmap, BMI323_ERR_REG, &val); -+ if (ret) -+ return ret; -+ -+ if (val) -+ return dev_err_probe(data->dev, -EINVAL, -+ "Sensor power error = 0x%x\n", val); -+ -+ /* -+ * Set the Bandwidth coefficient which defines the 3 dB cutoff -+ * frequency in relation to the ODR. -+ */ -+ ret = bmi323_set_bw(data, BMI323_ACCEL, BMI323_BW_ODR_BY_2); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_set_bw(data, BMI323_GYRO, BMI323_BW_ODR_BY_2); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_set_odr(data, BMI323_ACCEL, 25, 0); -+ if (ret) -+ return ret; -+ -+ ret = bmi323_set_odr(data, BMI323_GYRO, 25, 0); -+ if (ret) -+ return ret; -+ -+ return devm_add_action_or_reset(data->dev, bmi323_disable, data); -+} -+ -+int bmi323_core_probe(struct device *dev) -+{ -+ static const char * const regulator_names[] = { "vdd", "vddio" }; -+ struct iio_dev *indio_dev; -+ struct bmi323_data *data; -+ struct regmap *regmap; -+ int ret; -+ -+ regmap = dev_get_regmap(dev, NULL); -+ if (!regmap) -+ return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n"); -+ -+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); -+ if (!indio_dev) -+ return dev_err_probe(dev, -ENOMEM, -+ "Failed to allocate device\n"); -+ -+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(regulator_names), -+ regulator_names); -+ if (ret) -+ return dev_err_probe(dev, ret, "Failed to enable regulators\n"); -+ -+ data = iio_priv(indio_dev); -+ data->dev = dev; -+ data->regmap = regmap; -+ mutex_init(&data->mutex); -+ -+ ret = bmi323_init(data); -+ if (ret) -+ return -EINVAL; -+ -+ ret = iio_read_mount_matrix(dev, &data->orientation); -+ if (ret) -+ return ret; -+ -+ indio_dev->name = "bmi323-imu"; -+ indio_dev->info = &bmi323_info; -+ indio_dev->channels = bmi323_channels; -+ indio_dev->num_channels = ARRAY_SIZE(bmi323_channels); -+ indio_dev->available_scan_masks = bmi323_avail_scan_masks; -+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; -+ dev_set_drvdata(data->dev, indio_dev); -+ -+ ret = bmi323_trigger_probe(data, indio_dev); -+ if (ret) -+ return -EINVAL; -+ -+ ret = devm_iio_triggered_buffer_setup_ext(data->dev, indio_dev, -+ &iio_pollfunc_store_time, -+ bmi323_trigger_handler, -+ IIO_BUFFER_DIRECTION_IN, -+ &bmi323_buffer_ops, -+ bmi323_fifo_attributes); -+ if (ret) -+ return dev_err_probe(data->dev, ret, -+ "Failed to setup trigger buffer\n"); -+ -+ ret = devm_iio_device_register(data->dev, indio_dev); -+ if (ret) -+ return dev_err_probe(data->dev, ret, -+ "Unable to register iio device\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323); -+ -+MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); -+MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c -new file mode 100644 -index 000000000000..0008e186367d ---- /dev/null -+++ b/drivers/iio/imu/bmi323/bmi323_i2c.c -@@ -0,0 +1,121 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * I2C driver for Bosch BMI323 6-Axis IMU. -+ * -+ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> -+ */ -+ -+#include <linux/i2c.h> -+#include <linux/mod_devicetable.h> -+#include <linux/module.h> -+#include <linux/regmap.h> -+ -+#include "bmi323.h" -+ -+struct bmi323_i2c_priv { -+ struct i2c_client *i2c; -+ u8 i2c_rx_buffer[BMI323_FIFO_LENGTH_IN_BYTES + BMI323_I2C_DUMMY]; -+}; -+ -+/* -+ * From BMI323 datasheet section 4: Notes on the Serial Interface Support. -+ * Each I2C register read operation requires to read two dummy bytes before -+ * the actual payload. -+ */ -+static int bmi323_regmap_i2c_read(void *context, const void *reg_buf, -+ size_t reg_size, void *val_buf, -+ size_t val_size) -+{ -+ struct bmi323_i2c_priv *priv = context; -+ struct i2c_msg msgs[2]; -+ int ret; -+ -+ msgs[0].addr = priv->i2c->addr; -+ msgs[0].flags = priv->i2c->flags; -+ msgs[0].len = reg_size; -+ msgs[0].buf = (u8 *)reg_buf; -+ -+ msgs[1].addr = priv->i2c->addr; -+ msgs[1].len = val_size + BMI323_I2C_DUMMY; -+ msgs[1].buf = priv->i2c_rx_buffer; -+ msgs[1].flags = priv->i2c->flags | I2C_M_RD; -+ -+ ret = i2c_transfer(priv->i2c->adapter, msgs, ARRAY_SIZE(msgs)); -+ if (ret < 0) -+ return -EIO; -+ -+ memcpy(val_buf, priv->i2c_rx_buffer + BMI323_I2C_DUMMY, val_size); -+ -+ return 0; -+} -+ -+static int bmi323_regmap_i2c_write(void *context, const void *data, -+ size_t count) -+{ -+ struct bmi323_i2c_priv *priv = context; -+ u8 reg; -+ -+ reg = *(u8 *)data; -+ return i2c_smbus_write_i2c_block_data(priv->i2c, reg, -+ count - sizeof(u8), -+ data + sizeof(u8)); -+} -+ -+static struct regmap_bus bmi323_regmap_bus = { -+ .read = bmi323_regmap_i2c_read, -+ .write = bmi323_regmap_i2c_write, -+}; -+ -+const struct regmap_config bmi323_i2c_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 16, -+ .max_register = BMI323_CFG_RES_REG, -+ .val_format_endian = REGMAP_ENDIAN_LITTLE, -+}; -+ -+static int bmi323_i2c_probe(struct i2c_client *i2c) -+{ -+ struct device *dev = &i2c->dev; -+ struct bmi323_i2c_priv *priv; -+ struct regmap *regmap; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->i2c = i2c; -+ regmap = devm_regmap_init(dev, &bmi323_regmap_bus, priv, -+ &bmi323_i2c_regmap_config); -+ if (IS_ERR(regmap)) -+ return dev_err_probe(dev, PTR_ERR(regmap), -+ "Failed to initialize I2C Regmap\n"); -+ -+ return bmi323_core_probe(dev); -+} -+ -+static const struct i2c_device_id bmi323_i2c_ids[] = { -+ { "bmi323" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, bmi323_i2c_ids); -+ -+static const struct of_device_id bmi323_of_i2c_match[] = { -+ { .compatible = "bosch,bmi323" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, bmi323_of_i2c_match); -+ -+static struct i2c_driver bmi323_i2c_driver = { -+ .driver = { -+ .name = "bmi323", -+ .of_match_table = bmi323_of_i2c_match, -+ }, -+ .probe = bmi323_i2c_probe, -+ .id_table = bmi323_i2c_ids, -+}; -+module_i2c_driver(bmi323_i2c_driver); -+ -+MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); -+MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS(IIO_BMI323); -diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c -new file mode 100644 -index 000000000000..6dc3352dd714 ---- /dev/null -+++ b/drivers/iio/imu/bmi323/bmi323_spi.c -@@ -0,0 +1,92 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * SPI driver for Bosch BMI323 6-Axis IMU. -+ * -+ * Copyright (C) 2023, Jagath Jog J <jagathjog1996@gmail.com> -+ */ -+ -+#include <linux/mod_devicetable.h> -+#include <linux/module.h> -+#include <linux/regmap.h> -+#include <linux/spi/spi.h> -+ -+#include "bmi323.h" -+ -+/* -+ * From BMI323 datasheet section 4: Notes on the Serial Interface Support. -+ * Each SPI register read operation requires to read one dummy byte before -+ * the actual payload. -+ */ -+static int bmi323_regmap_spi_read(void *context, const void *reg_buf, -+ size_t reg_size, void *val_buf, -+ size_t val_size) -+{ -+ struct spi_device *spi = context; -+ -+ return spi_write_then_read(spi, reg_buf, reg_size, val_buf, val_size); -+} -+ -+static int bmi323_regmap_spi_write(void *context, const void *data, -+ size_t count) -+{ -+ struct spi_device *spi = context; -+ u8 *data_buff = (u8 *)data; -+ -+ data_buff[1] = data_buff[0]; -+ return spi_write(spi, data_buff + 1, count - 1); -+} -+ -+static struct regmap_bus bmi323_regmap_bus = { -+ .read = bmi323_regmap_spi_read, -+ .write = bmi323_regmap_spi_write, -+}; -+ -+const struct regmap_config bmi323_spi_regmap_config = { -+ .reg_bits = 8, -+ .val_bits = 16, -+ .pad_bits = 8, -+ .read_flag_mask = BIT(7), -+ .max_register = BMI323_CFG_RES_REG, -+ .val_format_endian = REGMAP_ENDIAN_LITTLE, -+}; -+ -+static int bmi323_spi_probe(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ struct regmap *regmap; -+ -+ regmap = devm_regmap_init(dev, &bmi323_regmap_bus, dev, -+ &bmi323_spi_regmap_config); -+ if (IS_ERR(regmap)) -+ return dev_err_probe(dev, PTR_ERR(regmap), -+ "Failed to initialize SPI Regmap\n"); -+ -+ return bmi323_core_probe(dev); -+} -+ -+static const struct spi_device_id bmi323_spi_ids[] = { -+ { "bmi323" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(spi, bmi323_spi_ids); -+ -+static const struct of_device_id bmi323_of_spi_match[] = { -+ { .compatible = "bosch,bmi323" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, bmi323_of_spi_match); -+ -+static struct spi_driver bmi323_spi_driver = { -+ .driver = { -+ .name = "bmi323", -+ .of_match_table = bmi323_of_spi_match, -+ }, -+ .probe = bmi323_spi_probe, -+ .id_table = bmi323_spi_ids, -+}; -+module_spi_driver(bmi323_spi_driver); -+ -+MODULE_DESCRIPTION("Bosch BMI323 IMU driver"); -+MODULE_AUTHOR("Jagath Jog J <jagathjog1996@gmail.com>"); -+MODULE_LICENSE("GPL"); -+MODULE_IMPORT_NS(IIO_BMI323); -Make the local structures static within their respective driver files. - -Reported-by: kernel test robot <lkp@intel.com> -Closes: https://lore.kernel.org/oe-kbuild-all/202311070530.qKhLTz1Y-lkp@intel.com/ -Fixes: b512c767e7bc ("iio: imu: Add driver for BMI323 IMU") -Signed-off-by: Jagath Jog J <jagathjog1996@gmail.com> ---- - drivers/iio/imu/bmi323/bmi323_i2c.c | 2 +- - drivers/iio/imu/bmi323/bmi323_spi.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c -index 0008e186367d..20a8001b9956 100644 ---- a/drivers/iio/imu/bmi323/bmi323_i2c.c -+++ b/drivers/iio/imu/bmi323/bmi323_i2c.c -@@ -66,7 +66,7 @@ static struct regmap_bus bmi323_regmap_bus = { - .write = bmi323_regmap_i2c_write, - }; - --const struct regmap_config bmi323_i2c_regmap_config = { -+static const struct regmap_config bmi323_i2c_regmap_config = { - .reg_bits = 8, - .val_bits = 16, - .max_register = BMI323_CFG_RES_REG, -diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c -index 6dc3352dd714..7b1e8127d0dd 100644 ---- a/drivers/iio/imu/bmi323/bmi323_spi.c -+++ b/drivers/iio/imu/bmi323/bmi323_spi.c -@@ -41,7 +41,7 @@ static struct regmap_bus bmi323_regmap_bus = { - .write = bmi323_regmap_spi_write, - }; - --const struct regmap_config bmi323_spi_regmap_config = { -+static const struct regmap_config bmi323_spi_regmap_config = { - .reg_bits = 8, - .val_bits = 16, - .pad_bits = 8, diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 1105918..d665a6e 100644 --- a/drivers/iio/accel/bmc150-accel-core.c |