xref: /linux/drivers/iio/magnetometer/si7210.c (revision d2c9a99135da931377240942d44f3dea104cedb8)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Silicon Labs Si7210 Hall Effect sensor driver
4  *
5  * Copyright (c) 2024 Antoni Pokusinski <apokusinski01@gmail.com>
6  *
7  * Datasheet:
8  *  https://www.silabs.com/documents/public/data-sheets/si7210-datasheet.pdf
9  */
10 
11 #include <linux/array_size.h>
12 #include <linux/bitfield.h>
13 #include <linux/bits.h>
14 #include <linux/cleanup.h>
15 #include <linux/err.h>
16 #include <linux/i2c.h>
17 #include <linux/iio/iio.h>
18 #include <linux/math64.h>
19 #include <linux/mutex.h>
20 #include <linux/regmap.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/types.h>
23 #include <linux/units.h>
24 #include <asm/byteorder.h>
25 
26 /* Registers offsets and masks */
27 #define SI7210_REG_DSPSIGM	0xC1
28 #define SI7210_REG_DSPSIGL	0xC2
29 
30 #define SI7210_MASK_DSPSIGSEL	GENMASK(2, 0)
31 #define SI7210_REG_DSPSIGSEL	0xC3
32 
33 #define SI7210_MASK_STOP	BIT(1)
34 #define SI7210_MASK_ONEBURST	BIT(2)
35 #define SI7210_REG_POWER_CTRL	0xC4
36 
37 #define SI7210_MASK_ARAUTOINC	BIT(0)
38 #define SI7210_REG_ARAUTOINC	0xC5
39 
40 #define SI7210_REG_A0		0xCA
41 #define SI7210_REG_A1		0xCB
42 #define SI7210_REG_A2		0xCC
43 #define SI7210_REG_A3		0xCE
44 #define SI7210_REG_A4		0xCF
45 #define SI7210_REG_A5		0xD0
46 
47 #define SI7210_REG_OTP_ADDR	0xE1
48 #define SI7210_REG_OTP_DATA	0xE2
49 
50 #define SI7210_MASK_OTP_READ_EN	BIT(1)
51 #define SI7210_REG_OTP_CTRL	0xE3
52 
53 /* OTP data registers offsets */
54 #define SI7210_OTPREG_TMP_OFF	0x1D
55 #define SI7210_OTPREG_TMP_GAIN	0x1E
56 
57 #define SI7210_OTPREG_A0_20	0x21
58 #define SI7210_OTPREG_A1_20	0x22
59 #define SI7210_OTPREG_A2_20	0x23
60 #define SI7210_OTPREG_A3_20	0x24
61 #define SI7210_OTPREG_A4_20	0x25
62 #define SI7210_OTPREG_A5_20	0x26
63 
64 #define SI7210_OTPREG_A0_200	0x27
65 #define SI7210_OTPREG_A1_200	0x28
66 #define SI7210_OTPREG_A2_200	0x29
67 #define SI7210_OTPREG_A3_200	0x2A
68 #define SI7210_OTPREG_A4_200	0x2B
69 #define SI7210_OTPREG_A5_200	0x2C
70 
71 #define A_REGS_COUNT 6
72 
73 static const unsigned int a20_otp_regs[A_REGS_COUNT] = {
74 	SI7210_OTPREG_A0_20, SI7210_OTPREG_A1_20, SI7210_OTPREG_A2_20,
75 	SI7210_OTPREG_A3_20, SI7210_OTPREG_A4_20, SI7210_OTPREG_A5_20,
76 };
77 
78 static const unsigned int a200_otp_regs[A_REGS_COUNT] = {
79 	SI7210_OTPREG_A0_200, SI7210_OTPREG_A1_200, SI7210_OTPREG_A2_200,
80 	SI7210_OTPREG_A3_200, SI7210_OTPREG_A4_200, SI7210_OTPREG_A5_200,
81 };
82 
83 static const struct regmap_range si7210_read_reg_ranges[] = {
84 	regmap_reg_range(SI7210_REG_DSPSIGM, SI7210_REG_ARAUTOINC),
85 	regmap_reg_range(SI7210_REG_A0, SI7210_REG_A2),
86 	regmap_reg_range(SI7210_REG_A3, SI7210_REG_A5),
87 	regmap_reg_range(SI7210_REG_OTP_ADDR, SI7210_REG_OTP_CTRL),
88 };
89 
90 static const struct regmap_access_table si7210_readable_regs = {
91 	.yes_ranges = si7210_read_reg_ranges,
92 	.n_yes_ranges = ARRAY_SIZE(si7210_read_reg_ranges),
93 };
94 
95 static const struct regmap_range si7210_write_reg_ranges[] = {
96 	regmap_reg_range(SI7210_REG_DSPSIGSEL, SI7210_REG_ARAUTOINC),
97 	regmap_reg_range(SI7210_REG_A0, SI7210_REG_A2),
98 	regmap_reg_range(SI7210_REG_A3, SI7210_REG_A5),
99 	regmap_reg_range(SI7210_REG_OTP_ADDR, SI7210_REG_OTP_CTRL),
100 };
101 
102 static const struct regmap_access_table si7210_writeable_regs = {
103 	.yes_ranges = si7210_write_reg_ranges,
104 	.n_yes_ranges = ARRAY_SIZE(si7210_write_reg_ranges),
105 };
106 
107 static const struct regmap_range si7210_volatile_reg_ranges[] = {
108 	regmap_reg_range(SI7210_REG_DSPSIGM, SI7210_REG_DSPSIGL),
109 	regmap_reg_range(SI7210_REG_POWER_CTRL, SI7210_REG_POWER_CTRL),
110 };
111 
112 static const struct regmap_access_table si7210_volatile_regs = {
113 	.yes_ranges = si7210_volatile_reg_ranges,
114 	.n_yes_ranges = ARRAY_SIZE(si7210_volatile_reg_ranges),
115 };
116 
117 static const struct regmap_config si7210_regmap_conf = {
118 	.reg_bits = 8,
119 	.val_bits = 8,
120 	.max_register = SI7210_REG_OTP_CTRL,
121 
122 	.rd_table = &si7210_readable_regs,
123 	.wr_table = &si7210_writeable_regs,
124 	.volatile_table = &si7210_volatile_regs,
125 };
126 
127 struct si7210_data {
128 	struct regmap *regmap;
129 	struct i2c_client *client;
130 	struct mutex fetch_lock; /* lock for a single measurement fetch */
131 	unsigned int vdd_uV;
132 	s8 temp_offset;
133 	s8 temp_gain;
134 	s8 scale_20_a[A_REGS_COUNT];
135 	s8 scale_200_a[A_REGS_COUNT];
136 	u8 curr_scale;
137 };
138 
139 static const struct iio_chan_spec si7210_channels[] = {
140 	{
141 		.type = IIO_MAGN,
142 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
143 			BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
144 	}, {
145 		.type = IIO_TEMP,
146 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
147 	},
148 };
149 
si7210_fetch_measurement(struct si7210_data * data,struct iio_chan_spec const * chan,u16 * buf)150 static int si7210_fetch_measurement(struct si7210_data *data,
151 				    struct iio_chan_spec const *chan,
152 				    u16 *buf)
153 {
154 	u8 dspsigsel = chan->type == IIO_MAGN ? 0 : 1;
155 	int ret;
156 	__be16 result;
157 
158 	guard(mutex)(&data->fetch_lock);
159 
160 	ret = regmap_update_bits(data->regmap, SI7210_REG_DSPSIGSEL,
161 				 SI7210_MASK_DSPSIGSEL, dspsigsel);
162 	if (ret)
163 		return ret;
164 
165 	ret = regmap_update_bits(data->regmap, SI7210_REG_POWER_CTRL,
166 				 SI7210_MASK_ONEBURST | SI7210_MASK_STOP,
167 				 SI7210_MASK_ONEBURST & ~SI7210_MASK_STOP);
168 	if (ret)
169 		return ret;
170 
171 	/*
172 	 * Read the contents of the
173 	 * registers containing the result: DSPSIGM, DSPSIGL
174 	 */
175 	ret = regmap_bulk_read(data->regmap, SI7210_REG_DSPSIGM,
176 			       &result, sizeof(result));
177 	if (ret)
178 		return ret;
179 
180 	*buf = be16_to_cpu(result);
181 
182 	return 0;
183 }
184 
si7210_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)185 static int si7210_read_raw(struct iio_dev *indio_dev,
186 			   struct iio_chan_spec const *chan,
187 			   int *val, int *val2, long mask)
188 {
189 	struct si7210_data *data = iio_priv(indio_dev);
190 	long long temp;
191 	u16 dspsig;
192 	int ret;
193 
194 	switch (mask) {
195 	case IIO_CHAN_INFO_RAW:
196 		ret = si7210_fetch_measurement(data, chan, &dspsig);
197 		if (ret)
198 			return ret;
199 
200 		*val = dspsig & GENMASK(14, 0);
201 		return IIO_VAL_INT;
202 	case IIO_CHAN_INFO_SCALE:
203 		*val = 0;
204 		if (data->curr_scale == 20)
205 			*val2 = 12500;
206 		else /* data->curr_scale == 200 */
207 			*val2 = 125000;
208 		return IIO_VAL_INT_PLUS_MICRO;
209 	case IIO_CHAN_INFO_OFFSET:
210 		*val = -16384;
211 		return IIO_VAL_INT;
212 	case IIO_CHAN_INFO_PROCESSED:
213 		ret = si7210_fetch_measurement(data, chan, &dspsig);
214 		if (ret)
215 			return ret;
216 
217 		/* temp = 32 * Dspsigm[6:0] + (Dspsigl[7:0] >> 3) */
218 		temp = FIELD_GET(GENMASK(14, 3), dspsig);
219 		temp = div_s64(-383 * temp * temp, 100) + 160940 * temp - 279800000;
220 		temp *= (1 + (data->temp_gain / 2048));
221 		temp += (int)(MICRO / 16) * data->temp_offset;
222 
223 		/* temp -= 0.222 * VDD */
224 		temp -= 222 * (data->vdd_uV / MILLI);
225 
226 		*val = div_s64(temp, MILLI);
227 
228 		return IIO_VAL_INT;
229 	default:
230 		return -EINVAL;
231 	}
232 }
233 
si7210_set_scale(struct si7210_data * data,unsigned int scale)234 static int si7210_set_scale(struct si7210_data *data, unsigned int scale)
235 {
236 	s8 *a_otp_values;
237 	int ret;
238 
239 	if (scale == 20)
240 		a_otp_values = data->scale_20_a;
241 	else if (scale == 200)
242 		a_otp_values = data->scale_200_a;
243 	else
244 		return -EINVAL;
245 
246 	guard(mutex)(&data->fetch_lock);
247 
248 	/* Write the registers 0xCA - 0xCC */
249 	ret = regmap_bulk_write(data->regmap, SI7210_REG_A0, a_otp_values, 3);
250 	if (ret)
251 		return ret;
252 
253 	/* Write the registers 0xCE - 0xD0 */
254 	ret = regmap_bulk_write(data->regmap, SI7210_REG_A3, &a_otp_values[3], 3);
255 	if (ret)
256 		return ret;
257 
258 	data->curr_scale = scale;
259 
260 	return 0;
261 }
262 
si7210_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)263 static int si7210_write_raw(struct iio_dev *indio_dev,
264 			    struct iio_chan_spec const *chan,
265 			    int val, int val2, long mask)
266 {
267 	struct si7210_data *data = iio_priv(indio_dev);
268 	unsigned int scale;
269 
270 	switch (mask) {
271 	case IIO_CHAN_INFO_SCALE:
272 		if (val == 0 && val2 == 12500)
273 			scale = 20;
274 		else if (val == 0 && val2 == 125000)
275 			scale = 200;
276 		else
277 			return -EINVAL;
278 
279 		return si7210_set_scale(data, scale);
280 	default:
281 		return -EINVAL;
282 	}
283 }
284 
si7210_read_otpreg_val(struct si7210_data * data,unsigned int otpreg,u8 * val)285 static int si7210_read_otpreg_val(struct si7210_data *data, unsigned int otpreg, u8 *val)
286 {
287 	int ret;
288 	unsigned int otpdata;
289 
290 	ret = regmap_write(data->regmap, SI7210_REG_OTP_ADDR, otpreg);
291 	if (ret)
292 		return ret;
293 
294 	ret = regmap_update_bits(data->regmap, SI7210_REG_OTP_CTRL,
295 				 SI7210_MASK_OTP_READ_EN, SI7210_MASK_OTP_READ_EN);
296 	if (ret)
297 		return ret;
298 
299 	ret = regmap_read(data->regmap, SI7210_REG_OTP_DATA, &otpdata);
300 	if (ret)
301 		return ret;
302 
303 	*val = otpdata;
304 
305 	return 0;
306 }
307 
308 /*
309  * According to the datasheet, the primary method to wake up a
310  * device is to send an empty write. However this is not feasible
311  * using the current API so we use the other method i.e. read a single
312  * byte. The device should respond with 0xFF.
313  */
si7210_device_wake(struct si7210_data * data)314 static int si7210_device_wake(struct si7210_data *data)
315 {
316 	int ret;
317 
318 	ret = i2c_smbus_read_byte(data->client);
319 	if (ret < 0)
320 		return ret;
321 
322 	if (ret != 0xFF)
323 		return -EIO;
324 
325 	return 0;
326 }
327 
si7210_device_init(struct si7210_data * data)328 static int si7210_device_init(struct si7210_data *data)
329 {
330 	int ret;
331 	unsigned int i;
332 
333 	ret = si7210_device_wake(data);
334 	if (ret)
335 		return ret;
336 
337 	fsleep(1000);
338 
339 	ret = si7210_read_otpreg_val(data, SI7210_OTPREG_TMP_GAIN, &data->temp_gain);
340 	if (ret)
341 		return ret;
342 
343 	ret = si7210_read_otpreg_val(data, SI7210_OTPREG_TMP_OFF, &data->temp_offset);
344 	if (ret)
345 		return ret;
346 
347 	for (i = 0; i < A_REGS_COUNT; i++) {
348 		ret = si7210_read_otpreg_val(data, a20_otp_regs[i], &data->scale_20_a[i]);
349 		if (ret)
350 			return ret;
351 	}
352 
353 	for (i = 0; i < A_REGS_COUNT; i++) {
354 		ret = si7210_read_otpreg_val(data, a200_otp_regs[i], &data->scale_200_a[i]);
355 		if (ret)
356 			return ret;
357 	}
358 
359 	ret = regmap_update_bits(data->regmap, SI7210_REG_ARAUTOINC,
360 				 SI7210_MASK_ARAUTOINC, SI7210_MASK_ARAUTOINC);
361 	if (ret)
362 		return ret;
363 
364 	return si7210_set_scale(data, 20);
365 }
366 
367 static const struct iio_info si7210_info = {
368 	.read_raw = si7210_read_raw,
369 	.write_raw = si7210_write_raw,
370 };
371 
si7210_probe(struct i2c_client * client)372 static int si7210_probe(struct i2c_client *client)
373 {
374 	struct si7210_data *data;
375 	struct iio_dev *indio_dev;
376 	int ret;
377 
378 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
379 	if (!indio_dev)
380 		return -ENOMEM;
381 
382 	data = iio_priv(indio_dev);
383 	data->client = client;
384 
385 	ret = devm_mutex_init(&client->dev, &data->fetch_lock);
386 	if (ret)
387 		return ret;
388 
389 	data->regmap = devm_regmap_init_i2c(client, &si7210_regmap_conf);
390 	if (IS_ERR(data->regmap))
391 		return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
392 				     "failed to register regmap\n");
393 
394 	ret = devm_regulator_get_enable_read_voltage(&client->dev, "vdd");
395 	if (ret < 0)
396 		return dev_err_probe(&client->dev, ret,
397 				     "Failed to get vdd regulator\n");
398 	data->vdd_uV = ret;
399 
400 	indio_dev->name = dev_name(&client->dev);
401 	indio_dev->modes = INDIO_DIRECT_MODE;
402 	indio_dev->info = &si7210_info;
403 	indio_dev->channels = si7210_channels;
404 	indio_dev->num_channels = ARRAY_SIZE(si7210_channels);
405 
406 	ret = si7210_device_init(data);
407 	if (ret)
408 		return dev_err_probe(&client->dev, ret,
409 				     "device initialization failed\n");
410 
411 	return devm_iio_device_register(&client->dev, indio_dev);
412 }
413 
414 static const struct i2c_device_id si7210_id[] = {
415 	{ .name = "si7210" },
416 	{ }
417 };
418 MODULE_DEVICE_TABLE(i2c, si7210_id);
419 
420 static const struct of_device_id si7210_dt_ids[] = {
421 	{ .compatible = "silabs,si7210" },
422 	{ }
423 };
424 MODULE_DEVICE_TABLE(of, si7210_dt_ids);
425 
426 static struct i2c_driver si7210_driver = {
427 	.driver = {
428 		.name = "si7210",
429 		.of_match_table = si7210_dt_ids,
430 	},
431 	.probe = si7210_probe,
432 	.id_table = si7210_id,
433 };
434 module_i2c_driver(si7210_driver);
435 
436 MODULE_AUTHOR("Antoni Pokusinski <apokusinski01@gmail.com>");
437 MODULE_DESCRIPTION("Silicon Labs Si7210 Hall Effect sensor I2C driver");
438 MODULE_LICENSE("GPL");
439