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