xref: /linux/drivers/iio/magnetometer/mmc5983.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * MMC5983 - MEMSIC 3-axis Magnetic Sensor
4  *
5  * Copyright (c) 2026, Vlad Kulikov <vlad.kulikov.c@gmail.com>
6  *
7  * IIO driver for MMC5983
8  */
9 
10 #include <linux/array_size.h>
11 #include <linux/bits.h>
12 #include <linux/cleanup.h>
13 #include <linux/delay.h>
14 #include <linux/dev_printk.h>
15 #include <linux/err.h>
16 #include <linux/i2c.h>
17 #include <linux/iio/iio.h>
18 #include <linux/module.h>
19 #include <linux/mutex.h>
20 #include <linux/regmap.h>
21 #include <linux/time.h>
22 #include <linux/types.h>
23 
24 #define MMC5983_REG_XOUT0	0x00
25 #define MMC5983_REG_XOUT1	0x01
26 #define MMC5983_REG_YOUT0	0x02
27 #define MMC5983_REG_YOUT1	0x03
28 #define MMC5983_REG_ZOUT0	0x04
29 #define MMC5983_REG_ZOUT1	0x05
30 #define MMC5983_REG_XYZOUT2	0x06
31 
32 #define MMC5983_REG_STATUS	0x08
33 
34 #define MMC5983_REG_CTRL0	0x09
35 #define MMC5983_REG_CTRL1	0x0A
36 #define MMC5983_REG_CTRL2	0x0B
37 #define MMC5983_REG_CTRL3	0x0C
38 
39 #define MMC5983_REG_ID		0x2F
40 
41 #define MMC5983_PRODUCT_ID	0x30
42 
43 #define MMC5983_STATUS_MEAS_M_DONE_BIT	BIT(0)
44 #define MMC5983_STATUS_OTP_RD_DONE_BIT	BIT(4)
45 
46 #define MMC5983_CTRL0_TM_M_BIT		BIT(0)
47 #define MMC5983_CTRL0_SET_BIT		BIT(3)
48 #define MMC5983_CTRL0_RESET_BIT		BIT(4)
49 #define MMC5983_CTRL0_OTP_RD_BIT	BIT(6)
50 
51 #define MMC5983_CTRL1_SW_RST_BIT	BIT(7)
52 
53 enum mmc5983_axis {
54 	MMC5983_AXIS_X,
55 	MMC5983_AXIS_Y,
56 	MMC5983_AXIS_Z,
57 };
58 
59 struct mmc5983_data {
60 	struct regmap *regmap;
61 	/* Protects chip access during SET/RESET measurement sequence */
62 	struct mutex mutex;
63 };
64 
65 #define MMC5983_CHANNEL(_axis) { \
66 	.type = IIO_MAGN, \
67 	.modified = 1, \
68 	.channel2 = IIO_MOD_##_axis, \
69 	.address = MMC5983_AXIS_##_axis, \
70 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
71 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
72 }
73 
74 static const struct iio_chan_spec mmc5983_channels[] = {
75 	MMC5983_CHANNEL(X),
76 	MMC5983_CHANNEL(Y),
77 	MMC5983_CHANNEL(Z),
78 };
79 
80 static int mmc5983_pulse_coil(struct mmc5983_data *data, unsigned int coil_bit)
81 {
82 	int ret;
83 
84 	ret = regmap_write(data->regmap, MMC5983_REG_CTRL0, coil_bit);
85 	if (ret)
86 		return ret;
87 
88 	/*
89 	 * Datasheet page 15: SET/RESET coil pulse is 500 ns.
90 	 * Vendor sample code waits 500 us before the next operation.
91 	 */
92 	fsleep(500);
93 
94 	return 0;
95 }
96 
97 static int mmc5983_take_measurement(struct mmc5983_data *data, int m[3])
98 {
99 	unsigned int status;
100 	u8 buf[7];
101 	int ret;
102 
103 	ret = regmap_write(data->regmap, MMC5983_REG_CTRL0,
104 			   MMC5983_CTRL0_TM_M_BIT);
105 	if (ret)
106 		return ret;
107 
108 	/*
109 	 * Datasheet page 15: measurement time is 8 ms at BW=00 (default,
110 	 * slowest setting). Use a 50 ms timeout for margin.
111 	 */
112 	ret = regmap_read_poll_timeout(data->regmap, MMC5983_REG_STATUS,
113 				       status,
114 				       status & MMC5983_STATUS_MEAS_M_DONE_BIT,
115 				       10 * USEC_PER_MSEC,
116 				       50 * USEC_PER_MSEC);
117 	if (ret)
118 		return ret;
119 
120 	ret = regmap_bulk_read(data->regmap, MMC5983_REG_XOUT0, buf,
121 			       sizeof(buf));
122 	if (ret)
123 		return ret;
124 
125 	m[0] = (buf[0] << 10) | (buf[1] << 2) | ((buf[6] >> 6) & 0x3);
126 	m[1] = (buf[2] << 10) | (buf[3] << 2) | ((buf[6] >> 4) & 0x3);
127 	m[2] = (buf[4] << 10) | (buf[5] << 2) | ((buf[6] >> 2) & 0x3);
128 
129 	return 0;
130 }
131 
132 static int mmc5983_read_raw(struct iio_dev *indio_dev,
133 			     const struct iio_chan_spec *chan, int *val,
134 			     int *val2, long mask)
135 {
136 	struct mmc5983_data *data = iio_priv(indio_dev);
137 	int m1[3], m2[3];
138 	int ret;
139 
140 	switch (mask) {
141 	case IIO_CHAN_INFO_RAW: {
142 		guard(mutex)(&data->mutex);
143 
144 		/* SET: magnetize sensor elements in forward direction */
145 		ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT);
146 		if (ret)
147 			return ret;
148 
149 		ret = mmc5983_take_measurement(data, m1);
150 		if (ret)
151 			return ret;
152 
153 		/* RESET: magnetize sensor elements in reverse direction */
154 		ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT);
155 		if (ret)
156 			return ret;
157 
158 		ret = mmc5983_take_measurement(data, m2);
159 		if (ret)
160 			return ret;
161 
162 		*val = (m1[chan->address] - m2[chan->address]) / 2;
163 		return IIO_VAL_INT;
164 	}
165 	case IIO_CHAN_INFO_SCALE:
166 		*val = 0;
167 		*val2 = 61035;
168 		return IIO_VAL_INT_PLUS_NANO;
169 	default:
170 		return -EINVAL;
171 	}
172 }
173 
174 static const struct iio_info mmc5983_info = {
175 	.read_raw = mmc5983_read_raw,
176 };
177 
178 static bool mmc5983_is_writeable_reg(struct device *dev, unsigned int reg)
179 {
180 	switch (reg) {
181 	case MMC5983_REG_CTRL0:
182 	case MMC5983_REG_CTRL1:
183 	case MMC5983_REG_CTRL2:
184 	case MMC5983_REG_CTRL3:
185 		return true;
186 	default:
187 		return false;
188 	}
189 }
190 
191 static bool mmc5983_is_readable_reg(struct device *dev, unsigned int reg)
192 {
193 	switch (reg) {
194 	case MMC5983_REG_XOUT0:
195 	case MMC5983_REG_XOUT1:
196 	case MMC5983_REG_YOUT0:
197 	case MMC5983_REG_YOUT1:
198 	case MMC5983_REG_ZOUT0:
199 	case MMC5983_REG_ZOUT1:
200 	case MMC5983_REG_XYZOUT2:
201 	case MMC5983_REG_STATUS:
202 	case MMC5983_REG_CTRL0:
203 	case MMC5983_REG_CTRL1:
204 	case MMC5983_REG_CTRL2:
205 	case MMC5983_REG_CTRL3:
206 	case MMC5983_REG_ID:
207 		return true;
208 	default:
209 		return false;
210 	}
211 }
212 
213 static bool mmc5983_is_volatile_reg(struct device *dev, unsigned int reg)
214 {
215 	switch (reg) {
216 	case MMC5983_REG_XOUT0:
217 	case MMC5983_REG_XOUT1:
218 	case MMC5983_REG_YOUT0:
219 	case MMC5983_REG_YOUT1:
220 	case MMC5983_REG_ZOUT0:
221 	case MMC5983_REG_ZOUT1:
222 	case MMC5983_REG_XYZOUT2:
223 	case MMC5983_REG_STATUS:
224 	case MMC5983_REG_CTRL0:
225 	case MMC5983_REG_CTRL1:
226 		return true;
227 	default:
228 		return false;
229 	}
230 }
231 
232 static const struct regmap_config mmc5983_regmap_config = {
233 	.name = "mmc5983_regmap",
234 	.reg_bits = 8,
235 	.val_bits = 8,
236 	.max_register = MMC5983_REG_ID,
237 	.writeable_reg = mmc5983_is_writeable_reg,
238 	.readable_reg = mmc5983_is_readable_reg,
239 	.volatile_reg = mmc5983_is_volatile_reg,
240 };
241 
242 static int mmc5983_init(struct mmc5983_data *data)
243 {
244 	struct regmap *regmap = data->regmap;
245 	struct device *dev = regmap_get_device(regmap);
246 	unsigned int reg_id, status;
247 	int ret;
248 
249 	ret = regmap_read(regmap, MMC5983_REG_ID, &reg_id);
250 	if (ret)
251 		return dev_err_probe(dev, ret, "Error reading product id\n");
252 
253 	if (reg_id != MMC5983_PRODUCT_ID)
254 		dev_info(dev, "unexpected product id 0x%02x\n", reg_id);
255 
256 	ret = regmap_write(regmap, MMC5983_REG_CTRL1, MMC5983_CTRL1_SW_RST_BIT);
257 	if (ret)
258 		return ret;
259 
260 	/* Datasheet page 15: power-on time after SW_RST is 10 ms */
261 	fsleep(10 * USEC_PER_MSEC);
262 
263 	ret = regmap_write(regmap, MMC5983_REG_CTRL0, MMC5983_CTRL0_OTP_RD_BIT);
264 	if (ret)
265 		return ret;
266 
267 	/*
268 	 * Datasheet page 15: OTP read completes and self-clears. No separate
269 	 * OTP refresh timeout is specified, so use the 10 ms power-on time as
270 	 * a conservative upper bound.
271 	 */
272 	ret = regmap_read_poll_timeout(regmap, MMC5983_REG_STATUS, status,
273 				       status & MMC5983_STATUS_OTP_RD_DONE_BIT,
274 				       USEC_PER_MSEC,
275 				       10 * USEC_PER_MSEC);
276 	if (ret)
277 		return ret;
278 
279 	/* SET: magnetize sensor elements in forward direction */
280 	ret = mmc5983_pulse_coil(data, MMC5983_CTRL0_SET_BIT);
281 	if (ret)
282 		return ret;
283 
284 	/* RESET: magnetize sensor elements in reverse direction */
285 	return mmc5983_pulse_coil(data, MMC5983_CTRL0_RESET_BIT);
286 }
287 
288 static int mmc5983_probe(struct i2c_client *i2c)
289 {
290 	struct device *dev = &i2c->dev;
291 	struct mmc5983_data *data;
292 	struct iio_dev *indio_dev;
293 	int ret;
294 
295 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
296 	if (!indio_dev)
297 		return -ENOMEM;
298 
299 	data = iio_priv(indio_dev);
300 
301 	ret = devm_mutex_init(dev, &data->mutex);
302 	if (ret)
303 		return ret;
304 
305 	data->regmap = devm_regmap_init_i2c(i2c, &mmc5983_regmap_config);
306 	if (IS_ERR(data->regmap))
307 		return dev_err_probe(dev, PTR_ERR(data->regmap),
308 				     "failed to allocate register map\n");
309 
310 	indio_dev->info = &mmc5983_info;
311 	indio_dev->modes = INDIO_DIRECT_MODE;
312 	indio_dev->name = "mmc5983";
313 	indio_dev->channels = mmc5983_channels;
314 	indio_dev->num_channels = ARRAY_SIZE(mmc5983_channels);
315 
316 	ret = mmc5983_init(data);
317 	if (ret)
318 		return dev_err_probe(dev, ret, "mmc5983 chip init failed\n");
319 
320 	return devm_iio_device_register(dev, indio_dev);
321 }
322 
323 static const struct of_device_id mmc5983_of_match[] = {
324 	{ .compatible = "memsic,mmc5983" },
325 	{ }
326 };
327 MODULE_DEVICE_TABLE(of, mmc5983_of_match);
328 
329 static const struct i2c_device_id mmc5983_id[] = {
330 	{ .name = "mmc5983" },
331 	{ }
332 };
333 MODULE_DEVICE_TABLE(i2c, mmc5983_id);
334 
335 static struct i2c_driver mmc5983_driver = {
336 	.driver = {
337 		.name = "mmc5983",
338 		.of_match_table = mmc5983_of_match,
339 	},
340 	.probe = mmc5983_probe,
341 	.id_table = mmc5983_id,
342 };
343 module_i2c_driver(mmc5983_driver);
344 
345 MODULE_AUTHOR("Vladislav Kulikov <vlad.kulikov.c@gmail.com>");
346 MODULE_DESCRIPTION("MEMSIC MMC5983 magnetic sensor driver");
347 MODULE_LICENSE("GPL");
348