summaryrefslogtreecommitdiff
path: root/drivers/iio/imu/bmi323/bmi323_i2c.c
blob: 0ba5d69d8329aed0efccad7def00c3af7574a281 (plain)
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
143
// 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 const 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",
		.pm = pm_ptr(&bmi323_core_pm_ops),
		.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);