1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * STMicroelectronics hts221 sensor driver |
4 | * |
5 | * Copyright 2016 STMicroelectronics Inc. |
6 | * |
7 | * Lorenzo Bianconi <lorenzo.bianconi@st.com> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/device.h> |
13 | #include <linux/iio/sysfs.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/pm.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/regulator/consumer.h> |
18 | #include <linux/bitfield.h> |
19 | |
20 | #include "hts221.h" |
21 | |
22 | #define HTS221_REG_WHOAMI_ADDR 0x0f |
23 | #define HTS221_REG_WHOAMI_VAL 0xbc |
24 | |
25 | #define HTS221_REG_CNTRL1_ADDR 0x20 |
26 | #define HTS221_REG_CNTRL2_ADDR 0x21 |
27 | |
28 | #define HTS221_ODR_MASK 0x03 |
29 | #define HTS221_BDU_MASK BIT(2) |
30 | #define HTS221_ENABLE_MASK BIT(7) |
31 | |
32 | /* calibration registers */ |
33 | #define HTS221_REG_0RH_CAL_X_H 0x36 |
34 | #define HTS221_REG_1RH_CAL_X_H 0x3a |
35 | #define HTS221_REG_0RH_CAL_Y_H 0x30 |
36 | #define HTS221_REG_1RH_CAL_Y_H 0x31 |
37 | #define HTS221_REG_0T_CAL_X_L 0x3c |
38 | #define HTS221_REG_1T_CAL_X_L 0x3e |
39 | #define HTS221_REG_0T_CAL_Y_H 0x32 |
40 | #define HTS221_REG_1T_CAL_Y_H 0x33 |
41 | #define HTS221_REG_T1_T0_CAL_Y_H 0x35 |
42 | |
43 | struct hts221_odr { |
44 | u8 hz; |
45 | u8 val; |
46 | }; |
47 | |
48 | #define HTS221_AVG_DEPTH 8 |
49 | struct hts221_avg { |
50 | u8 addr; |
51 | u8 mask; |
52 | u16 avg_avl[HTS221_AVG_DEPTH]; |
53 | }; |
54 | |
55 | static const struct hts221_odr hts221_odr_table[] = { |
56 | { 1, 0x01 }, /* 1Hz */ |
57 | { 7, 0x02 }, /* 7Hz */ |
58 | { 13, 0x03 }, /* 12.5Hz */ |
59 | }; |
60 | |
61 | static const struct hts221_avg hts221_avg_list[] = { |
62 | { |
63 | .addr = 0x10, |
64 | .mask = 0x07, |
65 | .avg_avl = { |
66 | 4, /* 0.4 %RH */ |
67 | 8, /* 0.3 %RH */ |
68 | 16, /* 0.2 %RH */ |
69 | 32, /* 0.15 %RH */ |
70 | 64, /* 0.1 %RH */ |
71 | 128, /* 0.07 %RH */ |
72 | 256, /* 0.05 %RH */ |
73 | 512, /* 0.03 %RH */ |
74 | }, |
75 | }, |
76 | { |
77 | .addr = 0x10, |
78 | .mask = 0x38, |
79 | .avg_avl = { |
80 | 2, /* 0.08 degC */ |
81 | 4, /* 0.05 degC */ |
82 | 8, /* 0.04 degC */ |
83 | 16, /* 0.03 degC */ |
84 | 32, /* 0.02 degC */ |
85 | 64, /* 0.015 degC */ |
86 | 128, /* 0.01 degC */ |
87 | 256, /* 0.007 degC */ |
88 | }, |
89 | }, |
90 | }; |
91 | |
92 | static const struct iio_chan_spec hts221_channels[] = { |
93 | { |
94 | .type = IIO_HUMIDITYRELATIVE, |
95 | .address = 0x28, |
96 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
97 | BIT(IIO_CHAN_INFO_OFFSET) | |
98 | BIT(IIO_CHAN_INFO_SCALE) | |
99 | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), |
100 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
101 | .scan_index = 0, |
102 | .scan_type = { |
103 | .sign = 's', |
104 | .realbits = 16, |
105 | .storagebits = 16, |
106 | .endianness = IIO_LE, |
107 | }, |
108 | }, |
109 | { |
110 | .type = IIO_TEMP, |
111 | .address = 0x2a, |
112 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
113 | BIT(IIO_CHAN_INFO_OFFSET) | |
114 | BIT(IIO_CHAN_INFO_SCALE) | |
115 | BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), |
116 | .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), |
117 | .scan_index = 1, |
118 | .scan_type = { |
119 | .sign = 's', |
120 | .realbits = 16, |
121 | .storagebits = 16, |
122 | .endianness = IIO_LE, |
123 | }, |
124 | }, |
125 | IIO_CHAN_SOFT_TIMESTAMP(2), |
126 | }; |
127 | |
128 | static int hts221_check_whoami(struct hts221_hw *hw) |
129 | { |
130 | int err, data; |
131 | |
132 | err = regmap_read(map: hw->regmap, HTS221_REG_WHOAMI_ADDR, val: &data); |
133 | if (err < 0) { |
134 | dev_err(hw->dev, "failed to read whoami register\n" ); |
135 | return err; |
136 | } |
137 | |
138 | if (data != HTS221_REG_WHOAMI_VAL) { |
139 | dev_err(hw->dev, "wrong whoami {%02x vs %02x}\n" , |
140 | data, HTS221_REG_WHOAMI_VAL); |
141 | return -ENODEV; |
142 | } |
143 | |
144 | return 0; |
145 | } |
146 | |
147 | static int hts221_update_odr(struct hts221_hw *hw, u8 odr) |
148 | { |
149 | int i, err; |
150 | |
151 | for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++) |
152 | if (hts221_odr_table[i].hz == odr) |
153 | break; |
154 | |
155 | if (i == ARRAY_SIZE(hts221_odr_table)) |
156 | return -EINVAL; |
157 | |
158 | err = regmap_update_bits(map: hw->regmap, HTS221_REG_CNTRL1_ADDR, |
159 | HTS221_ODR_MASK, |
160 | FIELD_PREP(HTS221_ODR_MASK, |
161 | hts221_odr_table[i].val)); |
162 | if (err < 0) |
163 | return err; |
164 | |
165 | hw->odr = odr; |
166 | |
167 | return 0; |
168 | } |
169 | |
170 | static int hts221_update_avg(struct hts221_hw *hw, |
171 | enum hts221_sensor_type type, |
172 | u16 val) |
173 | { |
174 | const struct hts221_avg *avg = &hts221_avg_list[type]; |
175 | int i, err, data; |
176 | |
177 | for (i = 0; i < HTS221_AVG_DEPTH; i++) |
178 | if (avg->avg_avl[i] == val) |
179 | break; |
180 | |
181 | if (i == HTS221_AVG_DEPTH) |
182 | return -EINVAL; |
183 | |
184 | data = ((i << __ffs(avg->mask)) & avg->mask); |
185 | err = regmap_update_bits(map: hw->regmap, reg: avg->addr, |
186 | mask: avg->mask, val: data); |
187 | if (err < 0) |
188 | return err; |
189 | |
190 | hw->sensors[type].cur_avg_idx = i; |
191 | |
192 | return 0; |
193 | } |
194 | |
195 | static ssize_t hts221_sysfs_sampling_freq(struct device *dev, |
196 | struct device_attribute *attr, |
197 | char *buf) |
198 | { |
199 | int i; |
200 | ssize_t len = 0; |
201 | |
202 | for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++) |
203 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%d " , |
204 | hts221_odr_table[i].hz); |
205 | buf[len - 1] = '\n'; |
206 | |
207 | return len; |
208 | } |
209 | |
210 | static ssize_t |
211 | hts221_sysfs_rh_oversampling_avail(struct device *dev, |
212 | struct device_attribute *attr, |
213 | char *buf) |
214 | { |
215 | const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_H]; |
216 | ssize_t len = 0; |
217 | int i; |
218 | |
219 | for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++) |
220 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%d " , |
221 | avg->avg_avl[i]); |
222 | buf[len - 1] = '\n'; |
223 | |
224 | return len; |
225 | } |
226 | |
227 | static ssize_t |
228 | hts221_sysfs_temp_oversampling_avail(struct device *dev, |
229 | struct device_attribute *attr, |
230 | char *buf) |
231 | { |
232 | const struct hts221_avg *avg = &hts221_avg_list[HTS221_SENSOR_T]; |
233 | ssize_t len = 0; |
234 | int i; |
235 | |
236 | for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++) |
237 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, fmt: "%d " , |
238 | avg->avg_avl[i]); |
239 | buf[len - 1] = '\n'; |
240 | |
241 | return len; |
242 | } |
243 | |
244 | int hts221_set_enable(struct hts221_hw *hw, bool enable) |
245 | { |
246 | int err; |
247 | |
248 | err = regmap_update_bits(map: hw->regmap, HTS221_REG_CNTRL1_ADDR, |
249 | HTS221_ENABLE_MASK, |
250 | FIELD_PREP(HTS221_ENABLE_MASK, enable)); |
251 | if (err < 0) |
252 | return err; |
253 | |
254 | hw->enabled = enable; |
255 | |
256 | return 0; |
257 | } |
258 | |
259 | static int hts221_parse_temp_caldata(struct hts221_hw *hw) |
260 | { |
261 | int err, *slope, *b_gen, cal0, cal1; |
262 | s16 cal_x0, cal_x1, cal_y0, cal_y1; |
263 | __le16 val; |
264 | |
265 | err = regmap_read(map: hw->regmap, HTS221_REG_0T_CAL_Y_H, val: &cal0); |
266 | if (err < 0) |
267 | return err; |
268 | |
269 | err = regmap_read(map: hw->regmap, HTS221_REG_T1_T0_CAL_Y_H, val: &cal1); |
270 | if (err < 0) |
271 | return err; |
272 | cal_y0 = ((cal1 & 0x3) << 8) | cal0; |
273 | |
274 | err = regmap_read(map: hw->regmap, HTS221_REG_1T_CAL_Y_H, val: &cal0); |
275 | if (err < 0) |
276 | return err; |
277 | cal_y1 = (((cal1 & 0xc) >> 2) << 8) | cal0; |
278 | |
279 | err = regmap_bulk_read(map: hw->regmap, HTS221_REG_0T_CAL_X_L, |
280 | val: &val, val_count: sizeof(val)); |
281 | if (err < 0) |
282 | return err; |
283 | cal_x0 = le16_to_cpu(val); |
284 | |
285 | err = regmap_bulk_read(map: hw->regmap, HTS221_REG_1T_CAL_X_L, |
286 | val: &val, val_count: sizeof(val)); |
287 | if (err < 0) |
288 | return err; |
289 | cal_x1 = le16_to_cpu(val); |
290 | |
291 | slope = &hw->sensors[HTS221_SENSOR_T].slope; |
292 | b_gen = &hw->sensors[HTS221_SENSOR_T].b_gen; |
293 | |
294 | *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0); |
295 | *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) / |
296 | (cal_x1 - cal_x0); |
297 | *b_gen *= 8; |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | static int hts221_parse_rh_caldata(struct hts221_hw *hw) |
303 | { |
304 | int err, *slope, *b_gen, data; |
305 | s16 cal_x0, cal_x1, cal_y0, cal_y1; |
306 | __le16 val; |
307 | |
308 | err = regmap_read(map: hw->regmap, HTS221_REG_0RH_CAL_Y_H, val: &data); |
309 | if (err < 0) |
310 | return err; |
311 | cal_y0 = data; |
312 | |
313 | err = regmap_read(map: hw->regmap, HTS221_REG_1RH_CAL_Y_H, val: &data); |
314 | if (err < 0) |
315 | return err; |
316 | cal_y1 = data; |
317 | |
318 | err = regmap_bulk_read(map: hw->regmap, HTS221_REG_0RH_CAL_X_H, |
319 | val: &val, val_count: sizeof(val)); |
320 | if (err < 0) |
321 | return err; |
322 | cal_x0 = le16_to_cpu(val); |
323 | |
324 | err = regmap_bulk_read(map: hw->regmap, HTS221_REG_1RH_CAL_X_H, |
325 | val: &val, val_count: sizeof(val)); |
326 | if (err < 0) |
327 | return err; |
328 | cal_x1 = le16_to_cpu(val); |
329 | |
330 | slope = &hw->sensors[HTS221_SENSOR_H].slope; |
331 | b_gen = &hw->sensors[HTS221_SENSOR_H].b_gen; |
332 | |
333 | *slope = ((cal_y1 - cal_y0) * 8000) / (cal_x1 - cal_x0); |
334 | *b_gen = (((s32)cal_x1 * cal_y0 - (s32)cal_x0 * cal_y1) * 1000) / |
335 | (cal_x1 - cal_x0); |
336 | *b_gen *= 8; |
337 | |
338 | return 0; |
339 | } |
340 | |
341 | static int hts221_get_sensor_scale(struct hts221_hw *hw, |
342 | enum iio_chan_type ch_type, |
343 | int *val, int *val2) |
344 | { |
345 | s64 tmp; |
346 | s32 rem, div, data; |
347 | |
348 | switch (ch_type) { |
349 | case IIO_HUMIDITYRELATIVE: |
350 | data = hw->sensors[HTS221_SENSOR_H].slope; |
351 | div = (1 << 4) * 1000; |
352 | break; |
353 | case IIO_TEMP: |
354 | data = hw->sensors[HTS221_SENSOR_T].slope; |
355 | div = (1 << 6) * 1000; |
356 | break; |
357 | default: |
358 | return -EINVAL; |
359 | } |
360 | |
361 | tmp = div_s64(dividend: data * 1000000000LL, divisor: div); |
362 | tmp = div_s64_rem(dividend: tmp, divisor: 1000000000LL, remainder: &rem); |
363 | |
364 | *val = tmp; |
365 | *val2 = rem; |
366 | |
367 | return IIO_VAL_INT_PLUS_NANO; |
368 | } |
369 | |
370 | static int hts221_get_sensor_offset(struct hts221_hw *hw, |
371 | enum iio_chan_type ch_type, |
372 | int *val, int *val2) |
373 | { |
374 | s64 tmp; |
375 | s32 rem, div, data; |
376 | |
377 | switch (ch_type) { |
378 | case IIO_HUMIDITYRELATIVE: |
379 | data = hw->sensors[HTS221_SENSOR_H].b_gen; |
380 | div = hw->sensors[HTS221_SENSOR_H].slope; |
381 | break; |
382 | case IIO_TEMP: |
383 | data = hw->sensors[HTS221_SENSOR_T].b_gen; |
384 | div = hw->sensors[HTS221_SENSOR_T].slope; |
385 | break; |
386 | default: |
387 | return -EINVAL; |
388 | } |
389 | |
390 | tmp = div_s64(dividend: data * 1000000000LL, divisor: div); |
391 | tmp = div_s64_rem(dividend: tmp, divisor: 1000000000LL, remainder: &rem); |
392 | |
393 | *val = tmp; |
394 | *val2 = rem; |
395 | |
396 | return IIO_VAL_INT_PLUS_NANO; |
397 | } |
398 | |
399 | static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val) |
400 | { |
401 | __le16 data; |
402 | int err; |
403 | |
404 | err = hts221_set_enable(hw, enable: true); |
405 | if (err < 0) |
406 | return err; |
407 | |
408 | msleep(msecs: 50); |
409 | |
410 | err = regmap_bulk_read(map: hw->regmap, reg: addr, val: &data, val_count: sizeof(data)); |
411 | if (err < 0) |
412 | return err; |
413 | |
414 | hts221_set_enable(hw, enable: false); |
415 | |
416 | *val = (s16)le16_to_cpu(data); |
417 | |
418 | return IIO_VAL_INT; |
419 | } |
420 | |
421 | static int hts221_read_raw(struct iio_dev *iio_dev, |
422 | struct iio_chan_spec const *ch, |
423 | int *val, int *val2, long mask) |
424 | { |
425 | struct hts221_hw *hw = iio_priv(indio_dev: iio_dev); |
426 | int ret; |
427 | |
428 | ret = iio_device_claim_direct_mode(indio_dev: iio_dev); |
429 | if (ret) |
430 | return ret; |
431 | |
432 | switch (mask) { |
433 | case IIO_CHAN_INFO_RAW: |
434 | ret = hts221_read_oneshot(hw, addr: ch->address, val); |
435 | break; |
436 | case IIO_CHAN_INFO_SCALE: |
437 | ret = hts221_get_sensor_scale(hw, ch_type: ch->type, val, val2); |
438 | break; |
439 | case IIO_CHAN_INFO_OFFSET: |
440 | ret = hts221_get_sensor_offset(hw, ch_type: ch->type, val, val2); |
441 | break; |
442 | case IIO_CHAN_INFO_SAMP_FREQ: |
443 | *val = hw->odr; |
444 | ret = IIO_VAL_INT; |
445 | break; |
446 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { |
447 | u8 idx; |
448 | const struct hts221_avg *avg; |
449 | |
450 | switch (ch->type) { |
451 | case IIO_HUMIDITYRELATIVE: |
452 | avg = &hts221_avg_list[HTS221_SENSOR_H]; |
453 | idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx; |
454 | *val = avg->avg_avl[idx]; |
455 | ret = IIO_VAL_INT; |
456 | break; |
457 | case IIO_TEMP: |
458 | avg = &hts221_avg_list[HTS221_SENSOR_T]; |
459 | idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx; |
460 | *val = avg->avg_avl[idx]; |
461 | ret = IIO_VAL_INT; |
462 | break; |
463 | default: |
464 | ret = -EINVAL; |
465 | break; |
466 | } |
467 | break; |
468 | } |
469 | default: |
470 | ret = -EINVAL; |
471 | break; |
472 | } |
473 | |
474 | iio_device_release_direct_mode(indio_dev: iio_dev); |
475 | |
476 | return ret; |
477 | } |
478 | |
479 | static int hts221_write_raw(struct iio_dev *iio_dev, |
480 | struct iio_chan_spec const *chan, |
481 | int val, int val2, long mask) |
482 | { |
483 | struct hts221_hw *hw = iio_priv(indio_dev: iio_dev); |
484 | int ret; |
485 | |
486 | ret = iio_device_claim_direct_mode(indio_dev: iio_dev); |
487 | if (ret) |
488 | return ret; |
489 | |
490 | switch (mask) { |
491 | case IIO_CHAN_INFO_SAMP_FREQ: |
492 | ret = hts221_update_odr(hw, odr: val); |
493 | break; |
494 | case IIO_CHAN_INFO_OVERSAMPLING_RATIO: |
495 | switch (chan->type) { |
496 | case IIO_HUMIDITYRELATIVE: |
497 | ret = hts221_update_avg(hw, type: HTS221_SENSOR_H, val); |
498 | break; |
499 | case IIO_TEMP: |
500 | ret = hts221_update_avg(hw, type: HTS221_SENSOR_T, val); |
501 | break; |
502 | default: |
503 | ret = -EINVAL; |
504 | break; |
505 | } |
506 | break; |
507 | default: |
508 | ret = -EINVAL; |
509 | break; |
510 | } |
511 | |
512 | iio_device_release_direct_mode(indio_dev: iio_dev); |
513 | |
514 | return ret; |
515 | } |
516 | |
517 | static int hts221_validate_trigger(struct iio_dev *iio_dev, |
518 | struct iio_trigger *trig) |
519 | { |
520 | struct hts221_hw *hw = iio_priv(indio_dev: iio_dev); |
521 | |
522 | return hw->trig == trig ? 0 : -EINVAL; |
523 | } |
524 | |
525 | static IIO_DEVICE_ATTR(in_humidity_oversampling_ratio_available, S_IRUGO, |
526 | hts221_sysfs_rh_oversampling_avail, NULL, 0); |
527 | static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, S_IRUGO, |
528 | hts221_sysfs_temp_oversampling_avail, NULL, 0); |
529 | static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hts221_sysfs_sampling_freq); |
530 | |
531 | static struct attribute *hts221_attributes[] = { |
532 | &iio_dev_attr_sampling_frequency_available.dev_attr.attr, |
533 | &iio_dev_attr_in_humidity_oversampling_ratio_available.dev_attr.attr, |
534 | &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, |
535 | NULL, |
536 | }; |
537 | |
538 | static const struct attribute_group hts221_attribute_group = { |
539 | .attrs = hts221_attributes, |
540 | }; |
541 | |
542 | static const struct iio_info hts221_info = { |
543 | .attrs = &hts221_attribute_group, |
544 | .read_raw = hts221_read_raw, |
545 | .write_raw = hts221_write_raw, |
546 | .validate_trigger = hts221_validate_trigger, |
547 | }; |
548 | |
549 | static const unsigned long hts221_scan_masks[] = {0x3, 0x0}; |
550 | |
551 | static int hts221_init_regulators(struct device *dev) |
552 | { |
553 | int err; |
554 | |
555 | err = devm_regulator_get_enable(dev, id: "vdd" ); |
556 | if (err) |
557 | return dev_err_probe(dev, err, fmt: "failed to get vdd regulator\n" ); |
558 | |
559 | msleep(msecs: 50); |
560 | |
561 | return 0; |
562 | } |
563 | |
564 | int hts221_probe(struct device *dev, int irq, const char *name, |
565 | struct regmap *regmap) |
566 | { |
567 | struct iio_dev *iio_dev; |
568 | struct hts221_hw *hw; |
569 | int err; |
570 | u8 data; |
571 | |
572 | iio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*hw)); |
573 | if (!iio_dev) |
574 | return -ENOMEM; |
575 | |
576 | dev_set_drvdata(dev, data: (void *)iio_dev); |
577 | |
578 | hw = iio_priv(indio_dev: iio_dev); |
579 | hw->name = name; |
580 | hw->dev = dev; |
581 | hw->irq = irq; |
582 | hw->regmap = regmap; |
583 | |
584 | err = hts221_init_regulators(dev); |
585 | if (err) |
586 | return err; |
587 | |
588 | err = hts221_check_whoami(hw); |
589 | if (err < 0) |
590 | return err; |
591 | |
592 | iio_dev->modes = INDIO_DIRECT_MODE; |
593 | iio_dev->available_scan_masks = hts221_scan_masks; |
594 | iio_dev->channels = hts221_channels; |
595 | iio_dev->num_channels = ARRAY_SIZE(hts221_channels); |
596 | iio_dev->name = HTS221_DEV_NAME; |
597 | iio_dev->info = &hts221_info; |
598 | |
599 | /* enable Block Data Update */ |
600 | err = regmap_update_bits(map: hw->regmap, HTS221_REG_CNTRL1_ADDR, |
601 | HTS221_BDU_MASK, |
602 | FIELD_PREP(HTS221_BDU_MASK, 1)); |
603 | if (err < 0) |
604 | return err; |
605 | |
606 | err = hts221_update_odr(hw, odr: hts221_odr_table[0].hz); |
607 | if (err < 0) |
608 | return err; |
609 | |
610 | /* configure humidity sensor */ |
611 | err = hts221_parse_rh_caldata(hw); |
612 | if (err < 0) { |
613 | dev_err(hw->dev, "failed to get rh calibration data\n" ); |
614 | return err; |
615 | } |
616 | |
617 | data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3]; |
618 | err = hts221_update_avg(hw, type: HTS221_SENSOR_H, val: data); |
619 | if (err < 0) { |
620 | dev_err(hw->dev, "failed to set rh oversampling ratio\n" ); |
621 | return err; |
622 | } |
623 | |
624 | /* configure temperature sensor */ |
625 | err = hts221_parse_temp_caldata(hw); |
626 | if (err < 0) { |
627 | dev_err(hw->dev, |
628 | "failed to get temperature calibration data\n" ); |
629 | return err; |
630 | } |
631 | |
632 | data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3]; |
633 | err = hts221_update_avg(hw, type: HTS221_SENSOR_T, val: data); |
634 | if (err < 0) { |
635 | dev_err(hw->dev, |
636 | "failed to set temperature oversampling ratio\n" ); |
637 | return err; |
638 | } |
639 | |
640 | if (hw->irq > 0) { |
641 | err = hts221_allocate_buffers(iio_dev); |
642 | if (err < 0) |
643 | return err; |
644 | |
645 | err = hts221_allocate_trigger(iio_dev); |
646 | if (err) |
647 | return err; |
648 | } |
649 | |
650 | return devm_iio_device_register(hw->dev, iio_dev); |
651 | } |
652 | EXPORT_SYMBOL_NS(hts221_probe, IIO_HTS221); |
653 | |
654 | static int hts221_suspend(struct device *dev) |
655 | { |
656 | struct iio_dev *iio_dev = dev_get_drvdata(dev); |
657 | struct hts221_hw *hw = iio_priv(indio_dev: iio_dev); |
658 | |
659 | return regmap_update_bits(map: hw->regmap, HTS221_REG_CNTRL1_ADDR, |
660 | HTS221_ENABLE_MASK, |
661 | FIELD_PREP(HTS221_ENABLE_MASK, false)); |
662 | } |
663 | |
664 | static int hts221_resume(struct device *dev) |
665 | { |
666 | struct iio_dev *iio_dev = dev_get_drvdata(dev); |
667 | struct hts221_hw *hw = iio_priv(indio_dev: iio_dev); |
668 | int err = 0; |
669 | |
670 | if (hw->enabled) |
671 | err = regmap_update_bits(map: hw->regmap, HTS221_REG_CNTRL1_ADDR, |
672 | HTS221_ENABLE_MASK, |
673 | FIELD_PREP(HTS221_ENABLE_MASK, |
674 | true)); |
675 | return err; |
676 | } |
677 | |
678 | EXPORT_NS_SIMPLE_DEV_PM_OPS(hts221_pm_ops, hts221_suspend, hts221_resume, |
679 | IIO_HTS221); |
680 | |
681 | MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>" ); |
682 | MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver" ); |
683 | MODULE_LICENSE("GPL v2" ); |
684 | |