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