* [PATCH v4 0/2] Add I2C driver for Bosch BMI270 IMU @ 2024-09-12 21:07 Alex Lanzano 2024-09-12 21:07 ` [PATCH v4 1/2] dt-bindings: iio: imu: add bmi270 bindings Alex Lanzano 2024-09-12 21:07 ` [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu Alex Lanzano 0 siblings, 2 replies; 5+ messages in thread From: Alex Lanzano @ 2024-09-12 21:07 UTC (permalink / raw) To: Alex Lanzano, Jonathan Cameron, Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jagath Jog J, Nuno Sa, Ramona Gradinariu Cc: linux-kernel-mentees, skhan, Jonathan Cameron, linux-iio, devicetree, linux-kernel Add basic I2C support for the Bosch BMI270 IMU. References: https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi270/ Signed-off-by: Alex Lanzano <lanzano.alex@gmail.com> --- Changes in v4: - Include linux/bitfield.h to bmi270_core.c - Add comments documenting sleep functions - Increase configuration delay to be inline with datasheet Changes in v3: - Remove code pertaining to buffer / triggered buffer - Move register definitions from struct to defines - Add bit mask defines for registers and replace hardcoded values - Create macros for accel and gryo channels - Code style cleanup Changes in v2: - Remove spi example in binding documentation - Add more properties to i2c example in binding documentation --- Alex Lanzano (2): dt-bindings: iio: imu: add bmi270 bindings iio: imu: Add i2c driver for bmi270 imu .../bindings/iio/imu/bosch,bmi270.yaml | 77 ++++++ MAINTAINERS | 7 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/bmi270/Kconfig | 21 ++ drivers/iio/imu/bmi270/Makefile | 6 + drivers/iio/imu/bmi270/bmi270.h | 62 +++++ drivers/iio/imu/bmi270/bmi270_core.c | 258 ++++++++++++++++++ drivers/iio/imu/bmi270/bmi270_i2c.c | 48 ++++ 9 files changed, 481 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml create mode 100644 drivers/iio/imu/bmi270/Kconfig create mode 100644 drivers/iio/imu/bmi270/Makefile create mode 100644 drivers/iio/imu/bmi270/bmi270.h create mode 100644 drivers/iio/imu/bmi270/bmi270_core.c create mode 100644 drivers/iio/imu/bmi270/bmi270_i2c.c -- 2.46.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 1/2] dt-bindings: iio: imu: add bmi270 bindings 2024-09-12 21:07 [PATCH v4 0/2] Add I2C driver for Bosch BMI270 IMU Alex Lanzano @ 2024-09-12 21:07 ` Alex Lanzano 2024-09-12 21:07 ` [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu Alex Lanzano 1 sibling, 0 replies; 5+ messages in thread From: Alex Lanzano @ 2024-09-12 21:07 UTC (permalink / raw) To: Alex Lanzano, Jonathan Cameron, Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jagath Jog J, Nuno Sa, Ramona Gradinariu Cc: linux-kernel-mentees, skhan, Krzysztof Kozlowski, Jonathan Cameron, linux-iio, devicetree, linux-kernel Add device tree bindings for the bmi270 IMU Signed-off-by: Alex Lanzano <lanzano.alex@gmail.com> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> --- .../bindings/iio/imu/bosch,bmi270.yaml | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml new file mode 100644 index 000000000000..792d1483af3c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi270.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,bmi270.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bosch BMI270 6-Axis IMU + +maintainers: + - Alex Lanzano <lanzano.alex@gmail.com> + +description: | + BMI270 is a 6-axis inertial measurement unit that can measure acceleration and + angular velocity. The sensor also supports configurable interrupt events such + as motion, step counter, and wrist motion gestures. The sensor can communicate + I2C or SPI. + https://www.bosch-sensortec.com/products/motion-sensors/imus/bmi270/ + +properties: + compatible: + const: bosch,bmi270 + + 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 pins 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: + - | + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imu@68 { + compatible = "bosch,bmi270"; + reg = <0x68>; + vdd-supply = <&vdd>; + vddio-supply = <&vddio>; + interrupt-parent = <&gpio1>; + interrupts = <16 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT1"; + }; + }; -- 2.46.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu 2024-09-12 21:07 [PATCH v4 0/2] Add I2C driver for Bosch BMI270 IMU Alex Lanzano 2024-09-12 21:07 ` [PATCH v4 1/2] dt-bindings: iio: imu: add bmi270 bindings Alex Lanzano @ 2024-09-12 21:07 ` Alex Lanzano 2024-09-14 13:27 ` Jonathan Cameron 1 sibling, 1 reply; 5+ messages in thread From: Alex Lanzano @ 2024-09-12 21:07 UTC (permalink / raw) To: Alex Lanzano, Jonathan Cameron, Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jagath Jog J, Ramona Gradinariu, Nuno Sa Cc: linux-kernel-mentees, skhan, Jonathan Cameron, linux-iio, devicetree, linux-kernel Add initial i2c support for the Bosch BMI270 6-axis IMU. Provides raw read access to acceleration and angle velocity measurements via iio channels. Device configuration requires firmware provided by Bosch and is requested and load from userspace. Signed-off-by: Alex Lanzano <lanzano.alex@gmail.com> --- MAINTAINERS | 7 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/bmi270/Kconfig | 21 +++ drivers/iio/imu/bmi270/Makefile | 6 + drivers/iio/imu/bmi270/bmi270.h | 62 +++++++ drivers/iio/imu/bmi270/bmi270_core.c | 258 +++++++++++++++++++++++++++ drivers/iio/imu/bmi270/bmi270_i2c.c | 48 +++++ 8 files changed, 404 insertions(+) create mode 100644 drivers/iio/imu/bmi270/Kconfig create mode 100644 drivers/iio/imu/bmi270/Makefile create mode 100644 drivers/iio/imu/bmi270/bmi270.h create mode 100644 drivers/iio/imu/bmi270/bmi270_core.c create mode 100644 drivers/iio/imu/bmi270/bmi270_i2c.c diff --git a/MAINTAINERS b/MAINTAINERS index dd4588838d90..faf109ae60eb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3928,6 +3928,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: drivers/iio/accel/bma400* +BOSCH SENSORTEC BMI270 IMU IIO DRIVER +M: Alex Lanzano <lanzano.alex@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/imu/bosch,bmi270.yaml +F: drivers/iio/imu/bmi270/ + BOSCH SENSORTEC BMI323 IMU IIO DRIVER M: Jagath Jog J <jagathjog1996@gmail.com> L: linux-iio@vger.kernel.org diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 782fb80e44c2..489dd898830b 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -53,6 +53,7 @@ config ADIS16480 ADIS16485, ADIS16488 inertial sensors. source "drivers/iio/imu/bmi160/Kconfig" +source "drivers/iio/imu/bmi270/Kconfig" source "drivers/iio/imu/bmi323/Kconfig" source "drivers/iio/imu/bno055/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 7e2d7d5c3b7b..79f83ea6f644 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -15,6 +15,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += bmi160/ +obj-y += bmi270/ obj-y += bmi323/ obj-y += bno055/ diff --git a/drivers/iio/imu/bmi270/Kconfig b/drivers/iio/imu/bmi270/Kconfig new file mode 100644 index 000000000000..3f7b4ac30f00 --- /dev/null +++ b/drivers/iio/imu/bmi270/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# BMI270 IMU driver +# + +config BMI270 + tristate + select IIO_BUFFER + +config BMI270_I2C + tristate "Bosch BMI270 I2C driver" + depends on I2C + select BMI270 + select REGMAP_I2C + help + Enable support for the Bosch BMI270 6-Axis IMU connected to I2C + interface. + + This driver can also be built as a module. If so, the module will be + called bmi270_i2c. + diff --git a/drivers/iio/imu/bmi270/Makefile b/drivers/iio/imu/bmi270/Makefile new file mode 100644 index 000000000000..ab4acaaee6d2 --- /dev/null +++ b/drivers/iio/imu/bmi270/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for Bosch BMI270 IMU +# +obj-$(CONFIG_BMI270) += bmi270_core.o +obj-$(CONFIG_BMI270_I2C) += bmi270_i2c.o diff --git a/drivers/iio/imu/bmi270/bmi270.h b/drivers/iio/imu/bmi270/bmi270.h new file mode 100644 index 000000000000..4af4098d8e82 --- /dev/null +++ b/drivers/iio/imu/bmi270/bmi270.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef BMI270_H_ +#define BMI270_H_ + +#include <linux/iio/iio.h> + +#define BMI270_CHIP_ID_REG 0x00 +#define BMI270_CHIP_ID_VAL 0x24 +#define BMI270_CHIP_ID_MSK GENMASK(7, 0) + +#define BMI270_ACCEL_X_REG 0x0c +#define BMI270_ANG_VEL_X_REG 0x12 + +#define BMI270_INTERNAL_STATUS_REG 0x21 +#define BMI270_INTERNAL_STATUS_MSG_MSK GENMASK(3, 0) +#define BMI270_INTERNAL_STATUS_MSG_INIT_OK 0x01 + +#define BMI270_INTERNAL_STATUS_AXES_REMAP_ERR_MSK BIT(5) +#define BMI270_INTERNAL_STATUS_ODR_50HZ_ERR_MSK BIT(6) + +#define BMI270_ACC_CONF_REG 0x40 +#define BMI270_ACC_CONF_ODR_MSK GENMASK(3, 0) +#define BMI270_ACC_CONF_ODR_100HZ 0x08 +#define BMI270_ACC_CONF_BWP_MSK GENMASK(6, 4) +#define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 +#define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) + +#define BMI270_GYR_CONF_REG 0x42 +#define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) +#define BMI270_GYR_CONF_ODR_200HZ 0x09 +#define BMI270_GYR_CONF_BWP_MSK GENMASK(5, 4) +#define BMI270_GYR_CONF_BWP_NORMAL_MODE 0x02 +#define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) +#define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) + +#define BMI270_INIT_CTRL_REG 0x59 +#define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) + +#define BMI270_INIT_DATA_REG 0x5e + +#define BMI270_PWR_CONF_REG 0x7c +#define BMI270_PWR_CONF_ADV_PWR_SAVE_MSK BIT(0) +#define BMI270_PWR_CONF_FIFO_WKUP_MSK BIT(1) +#define BMI270_PWR_CONF_FUP_EN_MSK BIT(2) + +#define BMI270_PWR_CTRL_REG 0x7d +#define BMI270_PWR_CTRL_AUX_EN_MSK BIT(0) +#define BMI270_PWR_CTRL_GYR_EN_MSK BIT(1) +#define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) +#define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) + +struct bmi270_data { + struct device *dev; + struct regmap *regmap; +}; + +extern const struct regmap_config bmi270_regmap_config; + +int bmi270_core_probe(struct device *dev, struct regmap *regmap); + +#endif /* BMI270_H_ */ diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c new file mode 100644 index 000000000000..319e5601d9e7 --- /dev/null +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include <linux/firmware.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/bitfield.h> + +#include "bmi270.h" + +#define BMI270_INIT_DATA_FILE "bmi270-init-data.fw" + +enum bmi270_scan { + BMI270_SCAN_ACCEL_X, + BMI270_SCAN_ACCEL_Y, + BMI270_SCAN_ACCEL_Z, + BMI270_SCAN_GYRO_X, + BMI270_SCAN_GYRO_Y, + BMI270_SCAN_GYRO_Z, +}; + +const struct regmap_config bmi270_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; +EXPORT_SYMBOL_NS_GPL(bmi270_regmap_config, IIO_BMI270); + +static int bmi270_get_data(struct bmi270_data *bmi270_device, + int chan_type, int axis, int *val) +{ + __le16 sample; + int reg; + int ret; + + switch (chan_type) { + case IIO_ACCEL: + reg = BMI270_ACCEL_X_REG + (axis - IIO_MOD_X) * sizeof(sample); + break; + case IIO_ANGL_VEL: + reg = BMI270_ANG_VEL_X_REG + (axis - IIO_MOD_X) * sizeof(sample); + break; + default: + return -EINVAL; + } + + ret = regmap_bulk_read(bmi270_device->regmap, reg, &sample, sizeof(sample)); + if (ret) + return ret; + + *val = sign_extend32(le16_to_cpu(sample), 15); + + return 0; +} + +static int bmi270_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + struct bmi270_data *bmi270_device = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = bmi270_get_data(bmi270_device, chan->type, chan->channel2, val); + if (ret) + return ret; + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static const struct iio_info bmi270_info = { + .read_raw = bmi270_read_raw, +}; + +#define BMI270_ACCEL_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ +} + +#define BMI270_ANG_VEL_CHANNEL(_axis) { \ + .type = IIO_ANGL_VEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ +} + +static const struct iio_chan_spec bmi270_channels[] = { + BMI270_ACCEL_CHANNEL(X), + BMI270_ACCEL_CHANNEL(Y), + BMI270_ACCEL_CHANNEL(Z), + BMI270_ANG_VEL_CHANNEL(X), + BMI270_ANG_VEL_CHANNEL(Y), + BMI270_ANG_VEL_CHANNEL(Z) +}; + +static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) +{ + int chip_id; + int ret; + struct device *dev = bmi270_device->dev; + struct regmap *regmap = bmi270_device->regmap; + + ret = regmap_read(regmap, BMI270_CHIP_ID_REG, &chip_id); + if (ret) + return dev_err_probe(dev, ret, "Failed to read chip id"); + + if (chip_id != BMI270_CHIP_ID_VAL) + return dev_err_probe(dev, -ENODEV, "Invalid chip id 0x%x", chip_id); + + return 0; +} + +static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device) +{ + int ret; + int status = 0; + const struct firmware *init_data; + struct device *dev = bmi270_device->dev; + struct regmap *regmap = bmi270_device->regmap; + + ret = regmap_clear_bits(regmap, BMI270_PWR_CONF_REG, BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to write power configuration"); + + /* After disabling advanced power save, all registers are accessible after a 450us delay + * This delay is specified in table A of the datasheet. + */ + usleep_range(450, 1000); + + ret = regmap_clear_bits(regmap, BMI270_INIT_CTRL_REG, BMI270_INIT_CTRL_LOAD_DONE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to prepare device to load init data"); + + ret = request_firmware(&init_data, BMI270_INIT_DATA_FILE, dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to load init data file"); + + ret = regmap_bulk_write(regmap, BMI270_INIT_DATA_REG, + init_data->data, init_data->size); + release_firmware(init_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to write init data"); + + ret = regmap_set_bits(regmap, BMI270_INIT_CTRL_REG, BMI270_INIT_CTRL_LOAD_DONE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to stop device initialization"); + + /* Wait at least 140ms for the device to complete configuration. + * This delay is specified in table C of the datasheet. + */ + usleep_range(140000, 160000); + + ret = regmap_read(regmap, BMI270_INTERNAL_STATUS_REG, &status); + if (ret) + return dev_err_probe(dev, ret, "Failed to read internal status"); + + if (status != BMI270_INTERNAL_STATUS_MSG_INIT_OK) + return dev_err_probe(dev, -ENODEV, "Device failed to initialize"); + + return 0; +} + +static int bmi270_configure_imu(struct bmi270_data *bmi270_device) +{ + int ret; + struct device *dev = bmi270_device->dev; + struct regmap *regmap = bmi270_device->regmap; + + ret = regmap_set_bits(regmap, BMI270_PWR_CTRL_REG, + BMI270_PWR_CTRL_AUX_EN_MSK | + BMI270_PWR_CTRL_GYR_EN_MSK | + BMI270_PWR_CTRL_ACCEL_EN_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable accelerometer and gyroscope"); + + ret = regmap_set_bits(regmap, BMI270_ACC_CONF_REG, + FIELD_PREP(BMI270_ACC_CONF_ODR_MSK, + BMI270_ACC_CONF_ODR_100HZ) | + FIELD_PREP(BMI270_ACC_CONF_BWP_MSK, + BMI270_ACC_CONF_BWP_NORMAL_MODE) | + BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to configure accelerometer"); + + ret = regmap_set_bits(regmap, BMI270_GYR_CONF_REG, + FIELD_PREP(BMI270_GYR_CONF_ODR_MSK, + BMI270_GYR_CONF_ODR_200HZ) | + FIELD_PREP(BMI270_GYR_CONF_BWP_MSK, + BMI270_GYR_CONF_BWP_NORMAL_MODE) | + BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to configure gyroscope"); + + /* Enable FIFO_WKUP, Disable ADV_PWR_SAVE and FUP_EN */ + ret = regmap_write(regmap, BMI270_PWR_CONF_REG, + BMI270_PWR_CONF_FIFO_WKUP_MSK); + if (ret) + return dev_err_probe(dev, ret, "Failed to set power configuration"); + + return 0; +} + +static int bmi270_chip_init(struct bmi270_data *bmi270_device) +{ + int ret; + + ret = bmi270_validate_chip_id(bmi270_device); + if (ret) + return ret; + + ret = bmi270_write_calibration_data(bmi270_device); + if (ret) + return ret; + + return bmi270_configure_imu(bmi270_device); +} + +int bmi270_core_probe(struct device *dev, struct regmap *regmap) +{ + int ret; + struct bmi270_data *bmi270_device; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(struct bmi270_data *)); + if (!indio_dev) + return -ENOMEM; + + bmi270_device = iio_priv(indio_dev); + bmi270_device->dev = dev; + bmi270_device->regmap = regmap; + + ret = bmi270_chip_init(bmi270_device); + if (ret) + return ret; + + indio_dev->channels = bmi270_channels; + indio_dev->num_channels = ARRAY_SIZE(bmi270_channels); + indio_dev->name = "bmi270"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmi270_info; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_NS_GPL(bmi270_core_probe, IIO_BMI270); + +MODULE_AUTHOR("Alex Lanzano"); +MODULE_DESCRIPTION("BMI270 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c new file mode 100644 index 000000000000..f70dee2d8a64 --- /dev/null +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> + +#include "bmi270.h" + +static int bmi270_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + struct device *dev = &client->dev; + + regmap = devm_regmap_init_i2c(client, &bmi270_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init i2c regmap"); + + return bmi270_core_probe(dev, regmap); +} + +static const struct i2c_device_id bmi270_i2c_id[] = { + { "bmi270", 0 }, + { } +}; + +static const struct of_device_id bmi270_of_match[] = { + { .compatible = "bosch,bmi270" }, + { } +}; + +static struct i2c_driver bmi270_i2c_driver = { + .driver = { + .name = "bmi270_i2c", + .of_match_table = bmi270_of_match, + }, + .probe = bmi270_i2c_probe, + .id_table = bmi270_i2c_id, +}; +module_i2c_driver(bmi270_i2c_driver); + +MODULE_AUTHOR("Alex Lanzano"); +MODULE_DESCRIPTION("BMI270 driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BMI270); -- 2.46.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu 2024-09-12 21:07 ` [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu Alex Lanzano @ 2024-09-14 13:27 ` Jonathan Cameron 2024-09-14 19:36 ` Alex Lanzano 0 siblings, 1 reply; 5+ messages in thread From: Jonathan Cameron @ 2024-09-14 13:27 UTC (permalink / raw) To: Alex Lanzano Cc: Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jagath Jog J, Ramona Gradinariu, Nuno Sa, linux-kernel-mentees, skhan, Jonathan Cameron, linux-iio, devicetree, linux-kernel On Thu, 12 Sep 2024 17:07:19 -0400 Alex Lanzano <lanzano.alex@gmail.com> wrote: > Add initial i2c support for the Bosch BMI270 6-axis IMU. > Provides raw read access to acceleration and angle velocity measurements > via iio channels. Device configuration requires firmware provided by > Bosch and is requested and load from userspace. > > Signed-off-by: Alex Lanzano <lanzano.alex@gmail.com> Hi Alex, A bunch of fairly minor stuff so I've just tweaked it whilst applying rather than wasting time on going around again. I also changed a few line wraps to keep lines a bit shorter. Where it doesn't hurt readability 80 chars is still my preference for IIO. The diff of the tweaks I made is as follows. Shout if I messed anything up! Thanks, Jonathan diff --git a/drivers/iio/imu/bmi270/bmi270.h b/drivers/iio/imu/bmi270/bmi270.h index 4af4098d8e82..608b29ea58a3 100644 --- a/drivers/iio/imu/bmi270/bmi270.h +++ b/drivers/iio/imu/bmi270/bmi270.h @@ -3,53 +3,9 @@ #ifndef BMI270_H_ #define BMI270_H_ -#include <linux/iio/iio.h> - -#define BMI270_CHIP_ID_REG 0x00 -#define BMI270_CHIP_ID_VAL 0x24 -#define BMI270_CHIP_ID_MSK GENMASK(7, 0) - -#define BMI270_ACCEL_X_REG 0x0c -#define BMI270_ANG_VEL_X_REG 0x12 - -#define BMI270_INTERNAL_STATUS_REG 0x21 -#define BMI270_INTERNAL_STATUS_MSG_MSK GENMASK(3, 0) -#define BMI270_INTERNAL_STATUS_MSG_INIT_OK 0x01 - -#define BMI270_INTERNAL_STATUS_AXES_REMAP_ERR_MSK BIT(5) -#define BMI270_INTERNAL_STATUS_ODR_50HZ_ERR_MSK BIT(6) - -#define BMI270_ACC_CONF_REG 0x40 -#define BMI270_ACC_CONF_ODR_MSK GENMASK(3, 0) -#define BMI270_ACC_CONF_ODR_100HZ 0x08 -#define BMI270_ACC_CONF_BWP_MSK GENMASK(6, 4) -#define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 -#define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) - -#define BMI270_GYR_CONF_REG 0x42 -#define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) -#define BMI270_GYR_CONF_ODR_200HZ 0x09 -#define BMI270_GYR_CONF_BWP_MSK GENMASK(5, 4) -#define BMI270_GYR_CONF_BWP_NORMAL_MODE 0x02 -#define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) -#define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) - -#define BMI270_INIT_CTRL_REG 0x59 -#define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) - -#define BMI270_INIT_DATA_REG 0x5e - -#define BMI270_PWR_CONF_REG 0x7c -#define BMI270_PWR_CONF_ADV_PWR_SAVE_MSK BIT(0) -#define BMI270_PWR_CONF_FIFO_WKUP_MSK BIT(1) -#define BMI270_PWR_CONF_FUP_EN_MSK BIT(2) - -#define BMI270_PWR_CTRL_REG 0x7d -#define BMI270_PWR_CTRL_AUX_EN_MSK BIT(0) -#define BMI270_PWR_CTRL_GYR_EN_MSK BIT(1) -#define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) -#define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) +#include <linux/regmap.h> +struct device; struct bmi270_data { struct device *dev; struct regmap *regmap; iff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c index 319e5601d9e7..8e45343d6472 100644 --- a/drivers/iio/imu/bmi270/bmi270_core.c +++ b/drivers/iio/imu/bmi270/bmi270_core.c @@ -1,14 +1,60 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +#include <linux/bitfield.h> #include <linux/firmware.h> #include <linux/i2c.h> -#include <linux/iio/iio.h> #include <linux/module.h> #include <linux/regmap.h> -#include <linux/bitfield.h> + +#include <linux/iio/iio.h> #include "bmi270.h" +#define BMI270_CHIP_ID_REG 0x00 +#define BMI270_CHIP_ID_VAL 0x24 +#define BMI270_CHIP_ID_MSK GENMASK(7, 0) + +#define BMI270_ACCEL_X_REG 0x0c +#define BMI270_ANG_VEL_X_REG 0x12 + +#define BMI270_INTERNAL_STATUS_REG 0x21 +#define BMI270_INTERNAL_STATUS_MSG_MSK GENMASK(3, 0) +#define BMI270_INTERNAL_STATUS_MSG_INIT_OK 0x01 + +#define BMI270_INTERNAL_STATUS_AXES_REMAP_ERR_MSK BIT(5) +#define BMI270_INTERNAL_STATUS_ODR_50HZ_ERR_MSK BIT(6) + +#define BMI270_ACC_CONF_REG 0x40 +#define BMI270_ACC_CONF_ODR_MSK GENMASK(3, 0) +#define BMI270_ACC_CONF_ODR_100HZ 0x08 +#define BMI270_ACC_CONF_BWP_MSK GENMASK(6, 4) +#define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 +#define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) + +#define BMI270_GYR_CONF_REG 0x42 +#define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) +#define BMI270_GYR_CONF_ODR_200HZ 0x09 +#define BMI270_GYR_CONF_BWP_MSK GENMASK(5, 4) +#define BMI270_GYR_CONF_BWP_NORMAL_MODE 0x02 +#define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) +#define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) + +#define BMI270_INIT_CTRL_REG 0x59 +#define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) + +#define BMI270_INIT_DATA_REG 0x5e + +#define BMI270_PWR_CONF_REG 0x7c +#define BMI270_PWR_CONF_ADV_PWR_SAVE_MSK BIT(0) +#define BMI270_PWR_CONF_FIFO_WKUP_MSK BIT(1) +#define BMI270_PWR_CONF_FUP_EN_MSK BIT(2) + +#define BMI270_PWR_CTRL_REG 0x7d +#define BMI270_PWR_CTRL_AUX_EN_MSK BIT(0) +#define BMI270_PWR_CTRL_GYR_EN_MSK BIT(1) +#define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) +#define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) + #define BMI270_INIT_DATA_FILE "bmi270-init-data.fw" enum bmi270_scan { @@ -35,10 +81,10 @@ static int bmi270_get_data(struct bmi270_data *bmi270_device, switch (chan_type) { case IIO_ACCEL: - reg = BMI270_ACCEL_X_REG + (axis - IIO_MOD_X) * sizeof(sample); + reg = BMI270_ACCEL_X_REG + (axis - IIO_MOD_X) * 2; break; case IIO_ANGL_VEL: - reg = BMI270_ANG_VEL_X_REG + (axis - IIO_MOD_X) * sizeof(sample); + reg = BMI270_ANG_VEL_X_REG + (axis - IIO_MOD_X) * 2; break; default: return -EINVAL; @@ -82,7 +128,7 @@ static const struct iio_info bmi270_info = { .channel2 = IIO_MOD_##_axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_FREQUENCY), \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ } #define BMI270_ANG_VEL_CHANNEL(_axis) { \ @@ -91,7 +137,7 @@ static const struct iio_info bmi270_info = { .channel2 = IIO_MOD_##_axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_FREQUENCY), \ + BIT(IIO_CHAN_INFO_FREQUENCY), \ } static const struct iio_chan_spec bmi270_channels[] = { @@ -100,7 +146,7 @@ static const struct iio_chan_spec bmi270_channels[] = { BMI270_ACCEL_CHANNEL(Z), BMI270_ANG_VEL_CHANNEL(X), BMI270_ANG_VEL_CHANNEL(Y), - BMI270_ANG_VEL_CHANNEL(Z) + BMI270_ANG_VEL_CHANNEL(Z), }; static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) @@ -115,7 +161,7 @@ static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) return dev_err_probe(dev, ret, "Failed to read chip id"); if (chip_id != BMI270_CHIP_ID_VAL) - return dev_err_probe(dev, -ENODEV, "Invalid chip id 0x%x", chip_id); + dev_info(dev, "Unknown chip id 0x%x", chip_id); return 0; } @@ -128,18 +174,24 @@ static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device) struct device *dev = bmi270_device->dev; struct regmap *regmap = bmi270_device->regmap; - ret = regmap_clear_bits(regmap, BMI270_PWR_CONF_REG, BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); + ret = regmap_clear_bits(regmap, BMI270_PWR_CONF_REG, + BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); if (ret) - return dev_err_probe(dev, ret, "Failed to write power configuration"); + return dev_err_probe(dev, ret, + "Failed to write power configuration"); - /* After disabling advanced power save, all registers are accessible after a 450us delay - * This delay is specified in table A of the datasheet. + /* + * After disabling advanced power save, all registers are accessible + * after a 450us delay. This delay is specified in table A of the + * datasheet. */ usleep_range(450, 1000); - ret = regmap_clear_bits(regmap, BMI270_INIT_CTRL_REG, BMI270_INIT_CTRL_LOAD_DONE_MSK); + ret = regmap_clear_bits(regmap, BMI270_INIT_CTRL_REG, + BMI270_INIT_CTRL_LOAD_DONE_MSK); if (ret) - return dev_err_probe(dev, ret, "Failed to prepare device to load init data"); + return dev_err_probe(dev, ret, + "Failed to prepare device to load init data"); ret = request_firmware(&init_data, BMI270_INIT_DATA_FILE, dev); if (ret) @@ -151,11 +203,14 @@ static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device) if (ret) return dev_err_probe(dev, ret, "Failed to write init data"); - ret = regmap_set_bits(regmap, BMI270_INIT_CTRL_REG, BMI270_INIT_CTRL_LOAD_DONE_MSK); + ret = regmap_set_bits(regmap, BMI270_INIT_CTRL_REG, + BMI270_INIT_CTRL_LOAD_DONE_MSK); if (ret) - return dev_err_probe(dev, ret, "Failed to stop device initialization"); + return dev_err_probe(dev, ret, + "Failed to stop device initialization"); - /* Wait at least 140ms for the device to complete configuration. + /* + * Wait at least 140ms for the device to complete configuration. * This delay is specified in table C of the datasheet. */ usleep_range(140000, 160000); @@ -231,7 +286,7 @@ int bmi270_core_probe(struct device *dev, struct regmap *regmap) struct bmi270_data *bmi270_device; struct iio_dev *indio_dev; - indio_dev = devm_iio_device_alloc(dev, sizeof(struct bmi270_data *)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*bmi270_device)); if (!indio_dev) return -ENOMEM; > diff --git a/drivers/iio/imu/bmi270/Makefile b/drivers/iio/imu/bmi270/Makefile > new file mode 100644 > index 000000000000..ab4acaaee6d2 > --- /dev/null > +++ b/drivers/iio/imu/bmi270/Makefile > @@ -0,0 +1,6 @@ > +# SPDX-License-Identifier: GPL-2.0 > +# > +# Makefile for Bosch BMI270 IMU > +# > +obj-$(CONFIG_BMI270) += bmi270_core.o > +obj-$(CONFIG_BMI270_I2C) += bmi270_i2c.o > diff --git a/drivers/iio/imu/bmi270/bmi270.h b/drivers/iio/imu/bmi270/bmi270.h > new file mode 100644 > index 000000000000..4af4098d8e82 > --- /dev/null > +++ b/drivers/iio/imu/bmi270/bmi270.h > @@ -0,0 +1,62 @@ > +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ > + > +#ifndef BMI270_H_ > +#define BMI270_H_ > + > +#include <linux/iio/iio.h> no obvious reason for this. Headers should only include things they need. However you do need some forward definitions for struct device; and an include of regmap.h for the regmap_config. > + > +#define BMI270_CHIP_ID_REG 0x00 > +#define BMI270_CHIP_ID_VAL 0x24 > +#define BMI270_CHIP_ID_MSK GENMASK(7, 0) > + > +#define BMI270_ACCEL_X_REG 0x0c > +#define BMI270_ANG_VEL_X_REG 0x12 > + > +#define BMI270_INTERNAL_STATUS_REG 0x21 > +#define BMI270_INTERNAL_STATUS_MSG_MSK GENMASK(3, 0) > +#define BMI270_INTERNAL_STATUS_MSG_INIT_OK 0x01 > + > +#define BMI270_INTERNAL_STATUS_AXES_REMAP_ERR_MSK BIT(5) > +#define BMI270_INTERNAL_STATUS_ODR_50HZ_ERR_MSK BIT(6) > + > +#define BMI270_ACC_CONF_REG 0x40 > +#define BMI270_ACC_CONF_ODR_MSK GENMASK(3, 0) > +#define BMI270_ACC_CONF_ODR_100HZ 0x08 > +#define BMI270_ACC_CONF_BWP_MSK GENMASK(6, 4) > +#define BMI270_ACC_CONF_BWP_NORMAL_MODE 0x02 > +#define BMI270_ACC_CONF_FILTER_PERF_MSK BIT(7) > + > +#define BMI270_GYR_CONF_REG 0x42 > +#define BMI270_GYR_CONF_ODR_MSK GENMASK(3, 0) > +#define BMI270_GYR_CONF_ODR_200HZ 0x09 > +#define BMI270_GYR_CONF_BWP_MSK GENMASK(5, 4) > +#define BMI270_GYR_CONF_BWP_NORMAL_MODE 0x02 > +#define BMI270_GYR_CONF_NOISE_PERF_MSK BIT(6) > +#define BMI270_GYR_CONF_FILTER_PERF_MSK BIT(7) > + > +#define BMI270_INIT_CTRL_REG 0x59 > +#define BMI270_INIT_CTRL_LOAD_DONE_MSK BIT(0) > + > +#define BMI270_INIT_DATA_REG 0x5e > + > +#define BMI270_PWR_CONF_REG 0x7c > +#define BMI270_PWR_CONF_ADV_PWR_SAVE_MSK BIT(0) > +#define BMI270_PWR_CONF_FIFO_WKUP_MSK BIT(1) > +#define BMI270_PWR_CONF_FUP_EN_MSK BIT(2) > + > +#define BMI270_PWR_CTRL_REG 0x7d > +#define BMI270_PWR_CTRL_AUX_EN_MSK BIT(0) > +#define BMI270_PWR_CTRL_GYR_EN_MSK BIT(1) > +#define BMI270_PWR_CTRL_ACCEL_EN_MSK BIT(2) > +#define BMI270_PWR_CTRL_TEMP_EN_MSK BIT(3) Currently all these defines are just used in the core c file. So I'd move them there for now. We can drag them back into the header if the spi bus driver needs them. > + > +struct bmi270_data { > + struct device *dev; > + struct regmap *regmap; > +}; > + > +extern const struct regmap_config bmi270_regmap_config; > + > +int bmi270_core_probe(struct device *dev, struct regmap *regmap); > + > +#endif /* BMI270_H_ */ > diff --git a/drivers/iio/imu/bmi270/bmi270_core.c b/drivers/iio/imu/bmi270/bmi270_core.c > new file mode 100644 > index 000000000000..319e5601d9e7 > --- /dev/null > +++ b/drivers/iio/imu/bmi270/bmi270_core.c > @@ -0,0 +1,258 @@ > +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > + > +#include <linux/firmware.h> > +#include <linux/i2c.h> > +#include <linux/iio/iio.h> > +#include <linux/module.h> > +#include <linux/regmap.h> > +#include <linux/bitfield.h> > + > +#include "bmi270.h" > + > +#define BMI270_INIT_DATA_FILE "bmi270-init-data.fw" > + > +enum bmi270_scan { > + BMI270_SCAN_ACCEL_X, > + BMI270_SCAN_ACCEL_Y, > + BMI270_SCAN_ACCEL_Z, > + BMI270_SCAN_GYRO_X, > + BMI270_SCAN_GYRO_Y, > + BMI270_SCAN_GYRO_Z, > +}; > + > +const struct regmap_config bmi270_regmap_config = { > + .reg_bits = 8, > + .val_bits = 8, > +}; > +EXPORT_SYMBOL_NS_GPL(bmi270_regmap_config, IIO_BMI270); > + > +static int bmi270_get_data(struct bmi270_data *bmi270_device, > + int chan_type, int axis, int *val) > +{ > + __le16 sample; > + int reg; > + int ret; > + > + switch (chan_type) { > + case IIO_ACCEL: > + reg = BMI270_ACCEL_X_REG + (axis - IIO_MOD_X) * sizeof(sample); > + break; > + case IIO_ANGL_VEL: > + reg = BMI270_ANG_VEL_X_REG + (axis - IIO_MOD_X) * sizeof(sample); This only works because they are 1 byte registers which isn't obvious here So I don't think sizeof(sample) is very useful vs 2. > + break; > + default: > + return -EINVAL; > + } > + > + ret = regmap_bulk_read(bmi270_device->regmap, reg, &sample, sizeof(sample)); > + if (ret) > + return ret; > + > + *val = sign_extend32(le16_to_cpu(sample), 15); > + > + return 0; > +} > + > + > +#define BMI270_ACCEL_CHANNEL(_axis) { \ > + .type = IIO_ACCEL, \ > + .modified = 1, \ > + .channel2 = IIO_MOD_##_axis, \ > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ > + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ > + BIT(IIO_CHAN_INFO_FREQUENCY), \ Probably good to indent this last item by one more tab to help with reability. > +} > + > +#define BMI270_ANG_VEL_CHANNEL(_axis) { \ > + .type = IIO_ANGL_VEL, \ > + .modified = 1, \ > + .channel2 = IIO_MOD_##_axis, \ > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ > + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ > + BIT(IIO_CHAN_INFO_FREQUENCY), \ > +} > +./v4_20240912_lanzano_alex_add_i2c_driver_for_bosch_bmi270_imu.mbx > +static const struct iio_chan_spec bmi270_channels[] = { > + BMI270_ACCEL_CHANNEL(X), > + BMI270_ACCEL_CHANNEL(Y), > + BMI270_ACCEL_CHANNEL(Z), > + BMI270_ANG_VEL_CHANNEL(X), > + BMI270_ANG_VEL_CHANNEL(Y), > + BMI270_ANG_VEL_CHANNEL(Z) Add a trailing comma as we may well have additional channels in future that come after this. > +}; > + > +static int bmi270_validate_chip_id(struct bmi270_data *bmi270_device) > +{ > + int chip_id; > + int ret; > + struct device *dev = bmi270_device->dev; > + struct regmap *regmap = bmi270_device->regmap; > + > + ret = regmap_read(regmap, BMI270_CHIP_ID_REG, &chip_id); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to read chip id"); > + > + if (chip_id != BMI270_CHIP_ID_VAL) > + return dev_err_probe(dev, -ENODEV, "Invalid chip id 0x%x", chip_id); A failure to match on a ID register should not result in a failure to probe. The reason for this is Device tree fallback compatibles. Those allow for a future device that is compatible (it may have a superset of features) with this part to use a dt-binding that includes the compatible for this one despite having a different ID register value. As such this should print an information message to say it's an unknown device ID but return success. > + > + return 0; > +} > + > +static int bmi270_write_calibration_data(struct bmi270_data *bmi270_device) > +{ > + int ret; > + int status = 0; > + const struct firmware *init_data; > + struct device *dev = bmi270_device->dev; > + struct regmap *regmap = bmi270_device->regmap; > + > + ret = regmap_clear_bits(regmap, BMI270_PWR_CONF_REG, BMI270_PWR_CONF_ADV_PWR_SAVE_MSK); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to write power configuration"); > + > + /* After disabling advanced power save, all registers are accessible after a 450us delay All IIO multiline comments are /* * After... > + * This delay is specified in table A of the datasheet. > + */ > + usleep_range(450, 1000); > + > + ret = regmap_clear_bits(regmap, BMI270_INIT_CTRL_REG, BMI270_INIT_CTRL_LOAD_DONE_MSK); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to prepare device to load init data"); > + > + ret = request_firmware(&init_data, BMI270_INIT_DATA_FILE, dev); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to load init data file"); > + > + ret = regmap_bulk_write(regmap, BMI270_INIT_DATA_REG, > + init_data->data, init_data->size); > + release_firmware(init_data); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to write init data"); > + > + ret = regmap_set_bits(regmap, BMI270_INIT_CTRL_REG, BMI270_INIT_CTRL_LOAD_DONE_MSK); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to stop device initialization"); > + > + /* Wait at least 140ms for the device to complete configuration. > + * This delay is specified in table C of the datasheet. > + */ > + usleep_range(140000, 160000); > + > + ret = regmap_read(regmap, BMI270_INTERNAL_STATUS_REG, &status); > + if (ret) > + return dev_err_probe(dev, ret, "Failed to read internal status"); > + > + if (status != BMI270_INTERNAL_STATUS_MSG_INIT_OK) > + return dev_err_probe(dev, -ENODEV, "Device failed to initialize"); > + > + return 0; > +} ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu 2024-09-14 13:27 ` Jonathan Cameron @ 2024-09-14 19:36 ` Alex Lanzano 0 siblings, 0 replies; 5+ messages in thread From: Alex Lanzano @ 2024-09-14 19:36 UTC (permalink / raw) To: Jonathan Cameron Cc: Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jagath Jog J, Ramona Gradinariu, Nuno Sa, linux-kernel-mentees, skhan, Jonathan Cameron, linux-iio, devicetree, linux-kernel On Sat, Sep 14, 2024 at 02:27:34PM GMT, Jonathan Cameron wrote: > On Thu, 12 Sep 2024 17:07:19 -0400 > Alex Lanzano <lanzano.alex@gmail.com> wrote: > > > Add initial i2c support for the Bosch BMI270 6-axis IMU. > > Provides raw read access to acceleration and angle velocity measurements > > via iio channels. Device configuration requires firmware provided by > > Bosch and is requested and load from userspace. > > > > Signed-off-by: Alex Lanzano <lanzano.alex@gmail.com> > > Hi Alex, > > A bunch of fairly minor stuff so I've just tweaked it whilst applying rather > than wasting time on going around again. > > I also changed a few line wraps to keep lines a bit shorter. > Where it doesn't hurt readability 80 chars is still my preference for IIO. > > The diff of the tweaks I made is as follows. Shout if I messed anything up! > Looks good! I agree with all the changes. Thanks again for the review and cleaning it up for me. ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-09-14 19:36 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-09-12 21:07 [PATCH v4 0/2] Add I2C driver for Bosch BMI270 IMU Alex Lanzano 2024-09-12 21:07 ` [PATCH v4 1/2] dt-bindings: iio: imu: add bmi270 bindings Alex Lanzano 2024-09-12 21:07 ` [PATCH v4 2/2] iio: imu: Add i2c driver for bmi270 imu Alex Lanzano 2024-09-14 13:27 ` Jonathan Cameron 2024-09-14 19:36 ` Alex Lanzano
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).