Skip to content
Snippets Groups Projects
Commit 8a636db3 authored by Jagath Jog J's avatar Jagath Jog J Committed by Jonathan Cameron
Browse files

iio: imu: Add driver for BMI323 IMU


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: default avatarJagath Jog J <jagathjog1996@gmail.com>
Link: https://lore.kernel.org/r/20231013034808.8948-3-jagathjog1996@gmail.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent a0357c08
No related merge requests found
...@@ -2254,3 +2254,21 @@ Description: ...@@ -2254,3 +2254,21 @@ Description:
If a label is defined for this event add that to the event If a label is defined for this event add that to the event
specific attributes. This is useful for userspace to be able to specific attributes. This is useful for userspace to be able to
better identify an individual event. better identify an individual event.
What: /sys/.../events/in_accel_gesture_tap_wait_timeout
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
Enable tap gesture confirmation with timeout.
What: /sys/.../events/in_accel_gesture_tap_wait_dur
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
Timeout value in seconds for tap gesture confirmation.
What: /sys/.../events/in_accel_gesture_tap_wait_dur_available
KernelVersion: 6.7
Contact: linux-iio@vger.kernel.org
Description:
List of available timeout value for tap gesture confirmation.
...@@ -3647,6 +3647,13 @@ S: Maintained ...@@ -3647,6 +3647,13 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
F: drivers/iio/accel/bma400* 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 BPF JIT for ARM
M: Russell King <linux@armlinux.org.uk> M: Russell King <linux@armlinux.org.uk>
M: Puranjay Mohan <puranjay12@gmail.com> M: Puranjay Mohan <puranjay12@gmail.com>
......
...@@ -53,6 +53,7 @@ config ADIS16480 ...@@ -53,6 +53,7 @@ config ADIS16480
ADIS16485, ADIS16488 inertial sensors. ADIS16485, ADIS16488 inertial sensors.
source "drivers/iio/imu/bmi160/Kconfig" source "drivers/iio/imu/bmi160/Kconfig"
source "drivers/iio/imu/bmi323/Kconfig"
source "drivers/iio/imu/bno055/Kconfig" source "drivers/iio/imu/bno055/Kconfig"
config FXOS8700 config FXOS8700
......
...@@ -15,6 +15,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o ...@@ -15,6 +15,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
obj-y += bmi160/ obj-y += bmi160/
obj-y += bmi323/
obj-y += bno055/ obj-y += bno055/
obj-$(CONFIG_FXOS8700) += fxos8700_core.o obj-$(CONFIG_FXOS8700) += fxos8700_core.o
......
# 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.
# 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
/* 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
This diff is collapsed.
// 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);
// 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);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment