1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * STMicroelectronics sensors core library driver |
4 | * |
5 | * Copyright 2012-2013 STMicroelectronics Inc. |
6 | * |
7 | * Denis Ciocca <denis.ciocca@st.com> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/iio/iio.h> |
15 | #include <linux/mutex.h> |
16 | #include <linux/property.h> |
17 | #include <linux/regulator/consumer.h> |
18 | #include <linux/regmap.h> |
19 | #include <asm/unaligned.h> |
20 | #include <linux/iio/common/st_sensors.h> |
21 | |
22 | #include "st_sensors_core.h" |
23 | |
24 | int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, |
25 | u8 reg_addr, u8 mask, u8 data) |
26 | { |
27 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
28 | |
29 | return regmap_update_bits(map: sdata->regmap, |
30 | reg: reg_addr, mask, val: data << __ffs(mask)); |
31 | } |
32 | |
33 | int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev, |
34 | unsigned reg, unsigned writeval, |
35 | unsigned *readval) |
36 | { |
37 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
38 | int err; |
39 | |
40 | if (!readval) |
41 | return regmap_write(map: sdata->regmap, reg, val: writeval); |
42 | |
43 | err = regmap_read(map: sdata->regmap, reg, val: readval); |
44 | if (err < 0) |
45 | return err; |
46 | |
47 | return 0; |
48 | } |
49 | EXPORT_SYMBOL_NS(st_sensors_debugfs_reg_access, IIO_ST_SENSORS); |
50 | |
51 | static int st_sensors_match_odr(struct st_sensor_settings *sensor_settings, |
52 | unsigned int odr, struct st_sensor_odr_avl *odr_out) |
53 | { |
54 | int i, ret = -EINVAL; |
55 | |
56 | for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) { |
57 | if (sensor_settings->odr.odr_avl[i].hz == 0) |
58 | goto st_sensors_match_odr_error; |
59 | |
60 | if (sensor_settings->odr.odr_avl[i].hz == odr) { |
61 | odr_out->hz = sensor_settings->odr.odr_avl[i].hz; |
62 | odr_out->value = sensor_settings->odr.odr_avl[i].value; |
63 | ret = 0; |
64 | break; |
65 | } |
66 | } |
67 | |
68 | st_sensors_match_odr_error: |
69 | return ret; |
70 | } |
71 | |
72 | int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr) |
73 | { |
74 | int err = 0; |
75 | struct st_sensor_odr_avl odr_out = {0, 0}; |
76 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
77 | |
78 | mutex_lock(&sdata->odr_lock); |
79 | |
80 | if (!sdata->sensor_settings->odr.mask) |
81 | goto unlock_mutex; |
82 | |
83 | err = st_sensors_match_odr(sensor_settings: sdata->sensor_settings, odr, odr_out: &odr_out); |
84 | if (err < 0) |
85 | goto unlock_mutex; |
86 | |
87 | if ((sdata->sensor_settings->odr.addr == |
88 | sdata->sensor_settings->pw.addr) && |
89 | (sdata->sensor_settings->odr.mask == |
90 | sdata->sensor_settings->pw.mask)) { |
91 | if (sdata->enabled == true) { |
92 | err = st_sensors_write_data_with_mask(indio_dev, |
93 | reg_addr: sdata->sensor_settings->odr.addr, |
94 | mask: sdata->sensor_settings->odr.mask, |
95 | data: odr_out.value); |
96 | } else { |
97 | err = 0; |
98 | } |
99 | } else { |
100 | err = st_sensors_write_data_with_mask(indio_dev, |
101 | reg_addr: sdata->sensor_settings->odr.addr, |
102 | mask: sdata->sensor_settings->odr.mask, |
103 | data: odr_out.value); |
104 | } |
105 | if (err >= 0) |
106 | sdata->odr = odr_out.hz; |
107 | |
108 | unlock_mutex: |
109 | mutex_unlock(lock: &sdata->odr_lock); |
110 | |
111 | return err; |
112 | } |
113 | EXPORT_SYMBOL_NS(st_sensors_set_odr, IIO_ST_SENSORS); |
114 | |
115 | static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings, |
116 | unsigned int fs, int *index_fs_avl) |
117 | { |
118 | int i, ret = -EINVAL; |
119 | |
120 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { |
121 | if (sensor_settings->fs.fs_avl[i].num == 0) |
122 | return ret; |
123 | |
124 | if (sensor_settings->fs.fs_avl[i].num == fs) { |
125 | *index_fs_avl = i; |
126 | ret = 0; |
127 | break; |
128 | } |
129 | } |
130 | |
131 | return ret; |
132 | } |
133 | |
134 | static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) |
135 | { |
136 | int err, i = 0; |
137 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
138 | |
139 | if (sdata->sensor_settings->fs.addr == 0) |
140 | return 0; |
141 | |
142 | err = st_sensors_match_fs(sensor_settings: sdata->sensor_settings, fs, index_fs_avl: &i); |
143 | if (err < 0) |
144 | goto st_accel_set_fullscale_error; |
145 | |
146 | err = st_sensors_write_data_with_mask(indio_dev, |
147 | reg_addr: sdata->sensor_settings->fs.addr, |
148 | mask: sdata->sensor_settings->fs.mask, |
149 | data: sdata->sensor_settings->fs.fs_avl[i].value); |
150 | if (err < 0) |
151 | goto st_accel_set_fullscale_error; |
152 | |
153 | sdata->current_fullscale = &sdata->sensor_settings->fs.fs_avl[i]; |
154 | return err; |
155 | |
156 | st_accel_set_fullscale_error: |
157 | dev_err(&indio_dev->dev, "failed to set new fullscale.\n" ); |
158 | return err; |
159 | } |
160 | |
161 | int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable) |
162 | { |
163 | u8 tmp_value; |
164 | int err = -EINVAL; |
165 | bool found = false; |
166 | struct st_sensor_odr_avl odr_out = {0, 0}; |
167 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
168 | |
169 | if (enable) { |
170 | tmp_value = sdata->sensor_settings->pw.value_on; |
171 | if ((sdata->sensor_settings->odr.addr == |
172 | sdata->sensor_settings->pw.addr) && |
173 | (sdata->sensor_settings->odr.mask == |
174 | sdata->sensor_settings->pw.mask)) { |
175 | err = st_sensors_match_odr(sensor_settings: sdata->sensor_settings, |
176 | odr: sdata->odr, odr_out: &odr_out); |
177 | if (err < 0) |
178 | goto set_enable_error; |
179 | tmp_value = odr_out.value; |
180 | found = true; |
181 | } |
182 | err = st_sensors_write_data_with_mask(indio_dev, |
183 | reg_addr: sdata->sensor_settings->pw.addr, |
184 | mask: sdata->sensor_settings->pw.mask, data: tmp_value); |
185 | if (err < 0) |
186 | goto set_enable_error; |
187 | |
188 | sdata->enabled = true; |
189 | |
190 | if (found) |
191 | sdata->odr = odr_out.hz; |
192 | } else { |
193 | err = st_sensors_write_data_with_mask(indio_dev, |
194 | reg_addr: sdata->sensor_settings->pw.addr, |
195 | mask: sdata->sensor_settings->pw.mask, |
196 | data: sdata->sensor_settings->pw.value_off); |
197 | if (err < 0) |
198 | goto set_enable_error; |
199 | |
200 | sdata->enabled = false; |
201 | } |
202 | |
203 | set_enable_error: |
204 | return err; |
205 | } |
206 | EXPORT_SYMBOL_NS(st_sensors_set_enable, IIO_ST_SENSORS); |
207 | |
208 | int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) |
209 | { |
210 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
211 | int err = 0; |
212 | |
213 | if (sdata->sensor_settings->enable_axis.addr) |
214 | err = st_sensors_write_data_with_mask(indio_dev, |
215 | reg_addr: sdata->sensor_settings->enable_axis.addr, |
216 | mask: sdata->sensor_settings->enable_axis.mask, |
217 | data: axis_enable); |
218 | return err; |
219 | } |
220 | EXPORT_SYMBOL_NS(st_sensors_set_axis_enable, IIO_ST_SENSORS); |
221 | |
222 | |
223 | int st_sensors_power_enable(struct iio_dev *indio_dev) |
224 | { |
225 | static const char * const regulator_names[] = { "vdd" , "vddio" }; |
226 | struct device *parent = indio_dev->dev.parent; |
227 | int err; |
228 | |
229 | /* Regulators not mandatory, but if requested we should enable them. */ |
230 | err = devm_regulator_bulk_get_enable(dev: parent, |
231 | ARRAY_SIZE(regulator_names), |
232 | id: regulator_names); |
233 | if (err) |
234 | return dev_err_probe(dev: &indio_dev->dev, err, |
235 | fmt: "unable to enable supplies\n" ); |
236 | |
237 | return 0; |
238 | } |
239 | EXPORT_SYMBOL_NS(st_sensors_power_enable, IIO_ST_SENSORS); |
240 | |
241 | static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, |
242 | struct st_sensors_platform_data *pdata) |
243 | { |
244 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
245 | |
246 | /* Sensor does not support interrupts */ |
247 | if (!sdata->sensor_settings->drdy_irq.int1.addr && |
248 | !sdata->sensor_settings->drdy_irq.int2.addr) { |
249 | if (pdata->drdy_int_pin) |
250 | dev_info(&indio_dev->dev, |
251 | "DRDY on pin INT%d specified, but sensor does not support interrupts\n" , |
252 | pdata->drdy_int_pin); |
253 | return 0; |
254 | } |
255 | |
256 | switch (pdata->drdy_int_pin) { |
257 | case 1: |
258 | if (!sdata->sensor_settings->drdy_irq.int1.mask) { |
259 | dev_err(&indio_dev->dev, |
260 | "DRDY on INT1 not available.\n" ); |
261 | return -EINVAL; |
262 | } |
263 | sdata->drdy_int_pin = 1; |
264 | break; |
265 | case 2: |
266 | if (!sdata->sensor_settings->drdy_irq.int2.mask) { |
267 | dev_err(&indio_dev->dev, |
268 | "DRDY on INT2 not available.\n" ); |
269 | return -EINVAL; |
270 | } |
271 | sdata->drdy_int_pin = 2; |
272 | break; |
273 | default: |
274 | dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n" ); |
275 | return -EINVAL; |
276 | } |
277 | |
278 | if (pdata->open_drain) { |
279 | if (!sdata->sensor_settings->drdy_irq.int1.addr_od && |
280 | !sdata->sensor_settings->drdy_irq.int2.addr_od) |
281 | dev_err(&indio_dev->dev, |
282 | "open drain requested but unsupported.\n" ); |
283 | else |
284 | sdata->int_pin_open_drain = true; |
285 | } |
286 | |
287 | return 0; |
288 | } |
289 | |
290 | static struct st_sensors_platform_data *st_sensors_dev_probe(struct device *dev, |
291 | struct st_sensors_platform_data *defdata) |
292 | { |
293 | struct st_sensors_platform_data *pdata; |
294 | u32 val; |
295 | |
296 | if (!dev_fwnode(dev)) |
297 | return NULL; |
298 | |
299 | pdata = devm_kzalloc(dev, size: sizeof(*pdata), GFP_KERNEL); |
300 | if (!pdata) |
301 | return ERR_PTR(error: -ENOMEM); |
302 | if (!device_property_read_u32(dev, propname: "st,drdy-int-pin" , val: &val) && (val <= 2)) |
303 | pdata->drdy_int_pin = (u8) val; |
304 | else |
305 | pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0; |
306 | |
307 | pdata->open_drain = device_property_read_bool(dev, propname: "drive-open-drain" ); |
308 | |
309 | return pdata; |
310 | } |
311 | |
312 | /** |
313 | * st_sensors_dev_name_probe() - device probe for ST sensor name |
314 | * @dev: driver model representation of the device. |
315 | * @name: device name buffer reference. |
316 | * @len: device name buffer length. |
317 | * |
318 | * In effect this function matches an ID to an internal kernel |
319 | * name for a certain sensor device, so that the rest of the autodetection can |
320 | * rely on that name from this point on. I2C/SPI devices will be renamed |
321 | * to match the internal kernel convention. |
322 | */ |
323 | void st_sensors_dev_name_probe(struct device *dev, char *name, int len) |
324 | { |
325 | const void *match; |
326 | |
327 | match = device_get_match_data(dev); |
328 | if (!match) |
329 | return; |
330 | |
331 | /* The name from the match takes precedence if present */ |
332 | strscpy(name, match, len); |
333 | } |
334 | EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, IIO_ST_SENSORS); |
335 | |
336 | int st_sensors_init_sensor(struct iio_dev *indio_dev, |
337 | struct st_sensors_platform_data *pdata) |
338 | { |
339 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
340 | struct st_sensors_platform_data *of_pdata; |
341 | int err = 0; |
342 | |
343 | mutex_init(&sdata->odr_lock); |
344 | |
345 | /* If OF/DT pdata exists, it will take precedence of anything else */ |
346 | of_pdata = st_sensors_dev_probe(dev: indio_dev->dev.parent, defdata: pdata); |
347 | if (IS_ERR(ptr: of_pdata)) |
348 | return PTR_ERR(ptr: of_pdata); |
349 | if (of_pdata) |
350 | pdata = of_pdata; |
351 | |
352 | if (pdata) { |
353 | err = st_sensors_set_drdy_int_pin(indio_dev, pdata); |
354 | if (err < 0) |
355 | return err; |
356 | } |
357 | |
358 | err = st_sensors_set_enable(indio_dev, false); |
359 | if (err < 0) |
360 | return err; |
361 | |
362 | /* Disable DRDY, this might be still be enabled after reboot. */ |
363 | err = st_sensors_set_dataready_irq(indio_dev, enable: false); |
364 | if (err < 0) |
365 | return err; |
366 | |
367 | if (sdata->current_fullscale) { |
368 | err = st_sensors_set_fullscale(indio_dev, |
369 | fs: sdata->current_fullscale->num); |
370 | if (err < 0) |
371 | return err; |
372 | } else |
373 | dev_info(&indio_dev->dev, "Full-scale not possible\n" ); |
374 | |
375 | err = st_sensors_set_odr(indio_dev, sdata->odr); |
376 | if (err < 0) |
377 | return err; |
378 | |
379 | /* set BDU */ |
380 | if (sdata->sensor_settings->bdu.addr) { |
381 | err = st_sensors_write_data_with_mask(indio_dev, |
382 | reg_addr: sdata->sensor_settings->bdu.addr, |
383 | mask: sdata->sensor_settings->bdu.mask, data: true); |
384 | if (err < 0) |
385 | return err; |
386 | } |
387 | |
388 | /* set DAS */ |
389 | if (sdata->sensor_settings->das.addr) { |
390 | err = st_sensors_write_data_with_mask(indio_dev, |
391 | reg_addr: sdata->sensor_settings->das.addr, |
392 | mask: sdata->sensor_settings->das.mask, data: 1); |
393 | if (err < 0) |
394 | return err; |
395 | } |
396 | |
397 | if (sdata->int_pin_open_drain) { |
398 | u8 addr, mask; |
399 | |
400 | if (sdata->drdy_int_pin == 1) { |
401 | addr = sdata->sensor_settings->drdy_irq.int1.addr_od; |
402 | mask = sdata->sensor_settings->drdy_irq.int1.mask_od; |
403 | } else { |
404 | addr = sdata->sensor_settings->drdy_irq.int2.addr_od; |
405 | mask = sdata->sensor_settings->drdy_irq.int2.mask_od; |
406 | } |
407 | |
408 | dev_info(&indio_dev->dev, |
409 | "set interrupt line to open drain mode on pin %d\n" , |
410 | sdata->drdy_int_pin); |
411 | err = st_sensors_write_data_with_mask(indio_dev, reg_addr: addr, |
412 | mask, data: 1); |
413 | if (err < 0) |
414 | return err; |
415 | } |
416 | |
417 | err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); |
418 | |
419 | return err; |
420 | } |
421 | EXPORT_SYMBOL_NS(st_sensors_init_sensor, IIO_ST_SENSORS); |
422 | |
423 | int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) |
424 | { |
425 | int err; |
426 | u8 drdy_addr, drdy_mask; |
427 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
428 | |
429 | if (!sdata->sensor_settings->drdy_irq.int1.addr && |
430 | !sdata->sensor_settings->drdy_irq.int2.addr) { |
431 | /* |
432 | * there are some devices (e.g. LIS3MDL) where drdy line is |
433 | * routed to a given pin and it is not possible to select a |
434 | * different one. Take into account irq status register |
435 | * to understand if irq trigger can be properly supported |
436 | */ |
437 | if (sdata->sensor_settings->drdy_irq.stat_drdy.addr) |
438 | sdata->hw_irq_trigger = enable; |
439 | return 0; |
440 | } |
441 | |
442 | /* Enable/Disable the interrupt generator 1. */ |
443 | if (sdata->sensor_settings->drdy_irq.ig1.en_addr > 0) { |
444 | err = st_sensors_write_data_with_mask(indio_dev, |
445 | reg_addr: sdata->sensor_settings->drdy_irq.ig1.en_addr, |
446 | mask: sdata->sensor_settings->drdy_irq.ig1.en_mask, |
447 | data: (int)enable); |
448 | if (err < 0) |
449 | goto st_accel_set_dataready_irq_error; |
450 | } |
451 | |
452 | if (sdata->drdy_int_pin == 1) { |
453 | drdy_addr = sdata->sensor_settings->drdy_irq.int1.addr; |
454 | drdy_mask = sdata->sensor_settings->drdy_irq.int1.mask; |
455 | } else { |
456 | drdy_addr = sdata->sensor_settings->drdy_irq.int2.addr; |
457 | drdy_mask = sdata->sensor_settings->drdy_irq.int2.mask; |
458 | } |
459 | |
460 | /* Flag to the poll function that the hardware trigger is in use */ |
461 | sdata->hw_irq_trigger = enable; |
462 | |
463 | /* Enable/Disable the interrupt generator for data ready. */ |
464 | err = st_sensors_write_data_with_mask(indio_dev, reg_addr: drdy_addr, |
465 | mask: drdy_mask, data: (int)enable); |
466 | |
467 | st_accel_set_dataready_irq_error: |
468 | return err; |
469 | } |
470 | EXPORT_SYMBOL_NS(st_sensors_set_dataready_irq, IIO_ST_SENSORS); |
471 | |
472 | int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) |
473 | { |
474 | int err = -EINVAL, i; |
475 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
476 | |
477 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { |
478 | if ((sdata->sensor_settings->fs.fs_avl[i].gain == scale) && |
479 | (sdata->sensor_settings->fs.fs_avl[i].gain != 0)) { |
480 | err = 0; |
481 | break; |
482 | } |
483 | } |
484 | if (err < 0) |
485 | goto st_sensors_match_scale_error; |
486 | |
487 | err = st_sensors_set_fullscale(indio_dev, |
488 | fs: sdata->sensor_settings->fs.fs_avl[i].num); |
489 | |
490 | st_sensors_match_scale_error: |
491 | return err; |
492 | } |
493 | EXPORT_SYMBOL_NS(st_sensors_set_fullscale_by_gain, IIO_ST_SENSORS); |
494 | |
495 | static int st_sensors_read_axis_data(struct iio_dev *indio_dev, |
496 | struct iio_chan_spec const *ch, int *data) |
497 | { |
498 | int err; |
499 | u8 *outdata; |
500 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
501 | unsigned int byte_for_channel; |
502 | |
503 | byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits + |
504 | ch->scan_type.shift, 8); |
505 | outdata = kmalloc(size: byte_for_channel, GFP_DMA | GFP_KERNEL); |
506 | if (!outdata) |
507 | return -ENOMEM; |
508 | |
509 | err = regmap_bulk_read(map: sdata->regmap, reg: ch->address, |
510 | val: outdata, val_count: byte_for_channel); |
511 | if (err < 0) |
512 | goto st_sensors_free_memory; |
513 | |
514 | if (byte_for_channel == 1) |
515 | *data = (s8)*outdata; |
516 | else if (byte_for_channel == 2) |
517 | *data = (s16)get_unaligned_le16(p: outdata); |
518 | else if (byte_for_channel == 3) |
519 | *data = (s32)sign_extend32(value: get_unaligned_le24(p: outdata), index: 23); |
520 | |
521 | st_sensors_free_memory: |
522 | kfree(objp: outdata); |
523 | |
524 | return err; |
525 | } |
526 | |
527 | int st_sensors_read_info_raw(struct iio_dev *indio_dev, |
528 | struct iio_chan_spec const *ch, int *val) |
529 | { |
530 | int err; |
531 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
532 | |
533 | err = iio_device_claim_direct_mode(indio_dev); |
534 | if (err) |
535 | return err; |
536 | |
537 | mutex_lock(&sdata->odr_lock); |
538 | |
539 | err = st_sensors_set_enable(indio_dev, true); |
540 | if (err < 0) |
541 | goto out; |
542 | |
543 | msleep(msecs: (sdata->sensor_settings->bootime * 1000) / sdata->odr); |
544 | err = st_sensors_read_axis_data(indio_dev, ch, data: val); |
545 | if (err < 0) |
546 | goto out; |
547 | |
548 | *val = *val >> ch->scan_type.shift; |
549 | |
550 | err = st_sensors_set_enable(indio_dev, false); |
551 | |
552 | out: |
553 | mutex_unlock(lock: &sdata->odr_lock); |
554 | iio_device_release_direct_mode(indio_dev); |
555 | |
556 | return err; |
557 | } |
558 | EXPORT_SYMBOL_NS(st_sensors_read_info_raw, IIO_ST_SENSORS); |
559 | |
560 | /* |
561 | * st_sensors_get_settings_index() - get index of the sensor settings for a |
562 | * specific device from list of settings |
563 | * @name: device name buffer reference. |
564 | * @list: sensor settings list. |
565 | * @list_length: length of sensor settings list. |
566 | * |
567 | * Return: non negative number on success (valid index), |
568 | * negative error code otherwise. |
569 | */ |
570 | int st_sensors_get_settings_index(const char *name, |
571 | const struct st_sensor_settings *list, |
572 | const int list_length) |
573 | { |
574 | int i, n; |
575 | |
576 | for (i = 0; i < list_length; i++) { |
577 | for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { |
578 | if (strcmp(name, list[i].sensors_supported[n]) == 0) |
579 | return i; |
580 | } |
581 | } |
582 | |
583 | return -ENODEV; |
584 | } |
585 | EXPORT_SYMBOL_NS(st_sensors_get_settings_index, IIO_ST_SENSORS); |
586 | |
587 | /* |
588 | * st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the |
589 | * expected value |
590 | * @indio_dev: IIO device reference. |
591 | * |
592 | * Return: 0 on success (valid sensor ID), else a negative error code. |
593 | */ |
594 | int st_sensors_verify_id(struct iio_dev *indio_dev) |
595 | { |
596 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
597 | int wai, err; |
598 | |
599 | if (sdata->sensor_settings->wai_addr) { |
600 | err = regmap_read(map: sdata->regmap, |
601 | reg: sdata->sensor_settings->wai_addr, val: &wai); |
602 | if (err < 0) { |
603 | dev_err(&indio_dev->dev, |
604 | "failed to read Who-Am-I register.\n" ); |
605 | return err; |
606 | } |
607 | |
608 | if (sdata->sensor_settings->wai != wai) { |
609 | dev_err(&indio_dev->dev, |
610 | "%s: WhoAmI mismatch (0x%x).\n" , |
611 | indio_dev->name, wai); |
612 | return -EINVAL; |
613 | } |
614 | } |
615 | |
616 | return 0; |
617 | } |
618 | EXPORT_SYMBOL_NS(st_sensors_verify_id, IIO_ST_SENSORS); |
619 | |
620 | ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, |
621 | struct device_attribute *attr, char *buf) |
622 | { |
623 | int i, len = 0; |
624 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
625 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
626 | |
627 | for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) { |
628 | if (sdata->sensor_settings->odr.odr_avl[i].hz == 0) |
629 | break; |
630 | |
631 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%d " , |
632 | sdata->sensor_settings->odr.odr_avl[i].hz); |
633 | } |
634 | buf[len - 1] = '\n'; |
635 | |
636 | return len; |
637 | } |
638 | EXPORT_SYMBOL_NS(st_sensors_sysfs_sampling_frequency_avail, IIO_ST_SENSORS); |
639 | |
640 | ssize_t st_sensors_sysfs_scale_avail(struct device *dev, |
641 | struct device_attribute *attr, char *buf) |
642 | { |
643 | int i, len = 0, q, r; |
644 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
645 | struct st_sensor_data *sdata = iio_priv(indio_dev); |
646 | |
647 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { |
648 | if (sdata->sensor_settings->fs.fs_avl[i].num == 0) |
649 | break; |
650 | |
651 | q = sdata->sensor_settings->fs.fs_avl[i].gain / 1000000; |
652 | r = sdata->sensor_settings->fs.fs_avl[i].gain % 1000000; |
653 | |
654 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%u.%06u " , q, r); |
655 | } |
656 | buf[len - 1] = '\n'; |
657 | |
658 | return len; |
659 | } |
660 | EXPORT_SYMBOL_NS(st_sensors_sysfs_scale_avail, IIO_ST_SENSORS); |
661 | |
662 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>" ); |
663 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors core" ); |
664 | MODULE_LICENSE("GPL v2" ); |
665 | |