Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | // 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, }; static 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 acpi_device_id bmi323_acpi_match[] = { /* * The "BOSC0200" identifier used here is not unique to bmi323 devices. * The same "BOSC0200" identifier is found in the ACPI tables of devices * using the bmc150 chip. This creates a conflict with duplicate ACPI * identifiers which multiple drivers want to use. If a non-bmi323 * device starts to load with this "BOSC0200" ACPI match here, then the * chip ID check portion should fail because the chip IDs received (via * i2c) are unique between bmc150 and bmi323 and the driver should * relinquish the device. If and when a different driver (such as * bmc150) starts to load with the "BOSC0200" ACPI match, a short reset * should ensure that the device is not in a bad state during that * driver initialization. This device reset does occur in both the * bmi323 and bmc150 init sequences. */ { "BOSC0200" }, { } }; MODULE_DEVICE_TABLE(acpi, bmi323_acpi_match); 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, .acpi_match_table = bmi323_acpi_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); |