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 mutex fetch_lock; /* lock for a single measurement fetch */
132 unsigned int vdd_uV;
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 /* temp -= 0.222 * VDD */
225 temp -= 222 * (data->vdd_uV / MILLI);
226
227 *val = div_s64(temp, MILLI);
228
229 return IIO_VAL_INT;
230 default:
231 return -EINVAL;
232 }
233 }
234
si7210_set_scale(struct si7210_data * data,unsigned int scale)235 static int si7210_set_scale(struct si7210_data *data, unsigned int scale)
236 {
237 s8 *a_otp_values;
238 int ret;
239
240 if (scale == 20)
241 a_otp_values = data->scale_20_a;
242 else if (scale == 200)
243 a_otp_values = data->scale_200_a;
244 else
245 return -EINVAL;
246
247 guard(mutex)(&data->fetch_lock);
248
249 /* Write the registers 0xCA - 0xCC */
250 ret = regmap_bulk_write(data->regmap, SI7210_REG_A0, a_otp_values, 3);
251 if (ret)
252 return ret;
253
254 /* Write the registers 0xCE - 0xD0 */
255 ret = regmap_bulk_write(data->regmap, SI7210_REG_A3, &a_otp_values[3], 3);
256 if (ret)
257 return ret;
258
259 data->curr_scale = scale;
260
261 return 0;
262 }
263
si7210_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)264 static int si7210_write_raw(struct iio_dev *indio_dev,
265 struct iio_chan_spec const *chan,
266 int val, int val2, long mask)
267 {
268 struct si7210_data *data = iio_priv(indio_dev);
269 unsigned int scale;
270
271 switch (mask) {
272 case IIO_CHAN_INFO_SCALE:
273 if (val == 0 && val2 == 12500)
274 scale = 20;
275 else if (val == 0 && val2 == 125000)
276 scale = 200;
277 else
278 return -EINVAL;
279
280 return si7210_set_scale(data, scale);
281 default:
282 return -EINVAL;
283 }
284 }
285
si7210_read_otpreg_val(struct si7210_data * data,unsigned int otpreg,u8 * val)286 static int si7210_read_otpreg_val(struct si7210_data *data, unsigned int otpreg, u8 *val)
287 {
288 int ret;
289 unsigned int otpdata;
290
291 ret = regmap_write(data->regmap, SI7210_REG_OTP_ADDR, otpreg);
292 if (ret)
293 return ret;
294
295 ret = regmap_update_bits(data->regmap, SI7210_REG_OTP_CTRL,
296 SI7210_MASK_OTP_READ_EN, SI7210_MASK_OTP_READ_EN);
297 if (ret)
298 return ret;
299
300 ret = regmap_read(data->regmap, SI7210_REG_OTP_DATA, &otpdata);
301 if (ret)
302 return ret;
303
304 *val = otpdata;
305
306 return 0;
307 }
308
309 /*
310 * According to the datasheet, the primary method to wake up a
311 * device is to send an empty write. However this is not feasible
312 * using the current API so we use the other method i.e. read a single
313 * byte. The device should respond with 0xFF.
314 */
si7210_device_wake(struct si7210_data * data)315 static int si7210_device_wake(struct si7210_data *data)
316 {
317 int ret;
318
319 ret = i2c_smbus_read_byte(data->client);
320 if (ret < 0)
321 return ret;
322
323 if (ret != 0xFF)
324 return -EIO;
325
326 return 0;
327 }
328
si7210_device_init(struct si7210_data * data)329 static int si7210_device_init(struct si7210_data *data)
330 {
331 int ret;
332 unsigned int i;
333
334 ret = si7210_device_wake(data);
335 if (ret)
336 return ret;
337
338 fsleep(1000);
339
340 ret = si7210_read_otpreg_val(data, SI7210_OTPREG_TMP_GAIN, &data->temp_gain);
341 if (ret)
342 return ret;
343
344 ret = si7210_read_otpreg_val(data, SI7210_OTPREG_TMP_OFF, &data->temp_offset);
345 if (ret)
346 return ret;
347
348 for (i = 0; i < A_REGS_COUNT; i++) {
349 ret = si7210_read_otpreg_val(data, a20_otp_regs[i], &data->scale_20_a[i]);
350 if (ret)
351 return ret;
352 }
353
354 for (i = 0; i < A_REGS_COUNT; i++) {
355 ret = si7210_read_otpreg_val(data, a200_otp_regs[i], &data->scale_200_a[i]);
356 if (ret)
357 return ret;
358 }
359
360 ret = regmap_update_bits(data->regmap, SI7210_REG_ARAUTOINC,
361 SI7210_MASK_ARAUTOINC, SI7210_MASK_ARAUTOINC);
362 if (ret)
363 return ret;
364
365 return si7210_set_scale(data, 20);
366 }
367
368 static const struct iio_info si7210_info = {
369 .read_raw = si7210_read_raw,
370 .write_raw = si7210_write_raw,
371 };
372
si7210_probe(struct i2c_client * client)373 static int si7210_probe(struct i2c_client *client)
374 {
375 struct si7210_data *data;
376 struct iio_dev *indio_dev;
377 int ret;
378
379 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
380 if (!indio_dev)
381 return -ENOMEM;
382
383 data = iio_priv(indio_dev);
384 data->client = client;
385
386 ret = devm_mutex_init(&client->dev, &data->fetch_lock);
387 if (ret)
388 return ret;
389
390 data->regmap = devm_regmap_init_i2c(client, &si7210_regmap_conf);
391 if (IS_ERR(data->regmap))
392 return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
393 "failed to register regmap\n");
394
395 ret = devm_regulator_get_enable_read_voltage(&client->dev, "vdd");
396 if (ret < 0)
397 return dev_err_probe(&client->dev, ret,
398 "Failed to get vdd regulator\n");
399 data->vdd_uV = ret;
400
401 indio_dev->name = dev_name(&client->dev);
402 indio_dev->modes = INDIO_DIRECT_MODE;
403 indio_dev->info = &si7210_info;
404 indio_dev->channels = si7210_channels;
405 indio_dev->num_channels = ARRAY_SIZE(si7210_channels);
406
407 ret = si7210_device_init(data);
408 if (ret)
409 return dev_err_probe(&client->dev, ret,
410 "device initialization failed\n");
411
412 return devm_iio_device_register(&client->dev, indio_dev);
413 }
414
415 static const struct i2c_device_id si7210_id[] = {
416 { "si7210" },
417 { }
418 };
419 MODULE_DEVICE_TABLE(i2c, si7210_id);
420
421 static const struct of_device_id si7210_dt_ids[] = {
422 { .compatible = "silabs,si7210" },
423 { }
424 };
425 MODULE_DEVICE_TABLE(of, si7210_dt_ids);
426
427 static struct i2c_driver si7210_driver = {
428 .driver = {
429 .name = "si7210",
430 .of_match_table = si7210_dt_ids,
431 },
432 .probe = si7210_probe,
433 .id_table = si7210_id,
434 };
435 module_i2c_driver(si7210_driver);
436
437 MODULE_AUTHOR("Antoni Pokusinski <apokusinski01@gmail.com>");
438 MODULE_DESCRIPTION("Silicon Labs Si7210 Hall Effect sensor I2C driver");
439 MODULE_LICENSE("GPL");
440