rust: upgrade to Rust 1.76.0
[sfrench/cifs-2.6.git] / drivers / iio / humidity / hdc3020.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * hdc3020.c - Support for the TI HDC3020,HDC3021 and HDC3022
4  * temperature + relative humidity sensors
5  *
6  * Copyright (C) 2023
7  *
8  * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf
9  */
10
11 #include <linux/bitops.h>
12 #include <linux/cleanup.h>
13 #include <linux/crc8.h>
14 #include <linux/delay.h>
15 #include <linux/i2c.h>
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19
20 #include <asm/unaligned.h>
21
22 #include <linux/iio/iio.h>
23
24 #define HDC3020_HEATER_CMD_MSB          0x30 /* shared by all heater commands */
25 #define HDC3020_HEATER_ENABLE           0x6D
26 #define HDC3020_HEATER_DISABLE          0x66
27 #define HDC3020_HEATER_CONFIG           0x6E
28
29 #define HDC3020_READ_RETRY_TIMES        10
30 #define HDC3020_BUSY_DELAY_MS           10
31
32 #define HDC3020_CRC8_POLYNOMIAL         0x31
33
34 static const u8 HDC3020_S_AUTO_10HZ_MOD0[2] = { 0x27, 0x37 };
35
36 static const u8 HDC3020_EXIT_AUTO[2] = { 0x30, 0x93 };
37
38 static const u8 HDC3020_R_T_RH_AUTO[2] = { 0xE0, 0x00 };
39 static const u8 HDC3020_R_T_LOW_AUTO[2] = { 0xE0, 0x02 };
40 static const u8 HDC3020_R_T_HIGH_AUTO[2] = { 0xE0, 0x03 };
41 static const u8 HDC3020_R_RH_LOW_AUTO[2] = { 0xE0, 0x04 };
42 static const u8 HDC3020_R_RH_HIGH_AUTO[2] = { 0xE0, 0x05 };
43
44 struct hdc3020_data {
45         struct i2c_client *client;
46         /*
47          * Ensure that the sensor configuration (currently only heater is
48          * supported) will not be changed during the process of reading
49          * sensor data (this driver will try HDC3020_READ_RETRY_TIMES times
50          * if the device does not respond).
51          */
52         struct mutex lock;
53 };
54
55 static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF};
56
57 static const struct iio_chan_spec hdc3020_channels[] = {
58         {
59                 .type = IIO_TEMP,
60                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
61                 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
62                 BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET),
63         },
64         {
65                 .type = IIO_HUMIDITYRELATIVE,
66                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
67                 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
68                 BIT(IIO_CHAN_INFO_TROUGH),
69         },
70         {
71                 /*
72                  * For setting the internal heater, which can be switched on to
73                  * prevent or remove any condensation that may develop when the
74                  * ambient environment approaches its dew point temperature.
75                  */
76                 .type = IIO_CURRENT,
77                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
78                 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
79                 .output = 1,
80         },
81 };
82
83 DECLARE_CRC8_TABLE(hdc3020_crc8_table);
84
85 static int hdc3020_write_bytes(struct hdc3020_data *data, const u8 *buf, u8 len)
86 {
87         struct i2c_client *client = data->client;
88         struct i2c_msg msg;
89         int ret, cnt;
90
91         msg.addr = client->addr;
92         msg.flags = 0;
93         msg.buf = (char *)buf;
94         msg.len = len;
95
96         /*
97          * During the measurement process, HDC3020 will not return data.
98          * So wait for a while and try again
99          */
100         for (cnt = 0; cnt < HDC3020_READ_RETRY_TIMES; cnt++) {
101                 ret = i2c_transfer(client->adapter, &msg, 1);
102                 if (ret == 1)
103                         return 0;
104
105                 mdelay(HDC3020_BUSY_DELAY_MS);
106         }
107         dev_err(&client->dev, "Could not write sensor command\n");
108
109         return -ETIMEDOUT;
110 }
111
112 static int hdc3020_read_bytes(struct hdc3020_data *data, const u8 *buf,
113                               void *val, int len)
114 {
115         int ret, cnt;
116         struct i2c_client *client = data->client;
117         struct i2c_msg msg[2] = {
118                 [0] = {
119                         .addr = client->addr,
120                         .flags = 0,
121                         .buf = (char *)buf,
122                         .len = 2,
123                 },
124                 [1] = {
125                         .addr = client->addr,
126                         .flags = I2C_M_RD,
127                         .buf = val,
128                         .len = len,
129                 },
130         };
131
132         /*
133          * During the measurement process, HDC3020 will not return data.
134          * So wait for a while and try again
135          */
136         for (cnt = 0; cnt < HDC3020_READ_RETRY_TIMES; cnt++) {
137                 ret = i2c_transfer(client->adapter, msg, 2);
138                 if (ret == 2)
139                         return 0;
140
141                 mdelay(HDC3020_BUSY_DELAY_MS);
142         }
143         dev_err(&client->dev, "Could not read sensor data\n");
144
145         return -ETIMEDOUT;
146 }
147
148 static int hdc3020_read_measurement(struct hdc3020_data *data,
149                                     enum iio_chan_type type, int *val)
150 {
151         u8 crc, buf[6];
152         int ret;
153
154         ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, 6);
155         if (ret < 0)
156                 return ret;
157
158         /* CRC check of the temperature measurement */
159         crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
160         if (crc != buf[2])
161                 return -EINVAL;
162
163         /* CRC check of the relative humidity measurement */
164         crc = crc8(hdc3020_crc8_table, buf + 3, 2, CRC8_INIT_VALUE);
165         if (crc != buf[5])
166                 return -EINVAL;
167
168         if (type == IIO_TEMP)
169                 *val = get_unaligned_be16(buf);
170         else if (type == IIO_HUMIDITYRELATIVE)
171                 *val = get_unaligned_be16(&buf[3]);
172         else
173                 return -EINVAL;
174
175         return 0;
176 }
177
178 /*
179  * After exiting the automatic measurement mode or resetting, the peak
180  * value will be reset to the default value
181  * This method is used to get the highest temp measured during automatic
182  * measurement
183  */
184 static int hdc3020_read_high_peak_t(struct hdc3020_data *data, int *val)
185 {
186         u8 crc, buf[3];
187         int ret;
188
189         ret = hdc3020_read_bytes(data, HDC3020_R_T_HIGH_AUTO, buf, 3);
190         if (ret < 0)
191                 return ret;
192
193         crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
194         if (crc != buf[2])
195                 return -EINVAL;
196
197         *val = get_unaligned_be16(buf);
198
199         return 0;
200 }
201
202 /*
203  * This method is used to get the lowest temp measured during automatic
204  * measurement
205  */
206 static int hdc3020_read_low_peak_t(struct hdc3020_data *data, int *val)
207 {
208         u8 crc, buf[3];
209         int ret;
210
211         ret = hdc3020_read_bytes(data, HDC3020_R_T_LOW_AUTO, buf, 3);
212         if (ret < 0)
213                 return ret;
214
215         crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
216         if (crc != buf[2])
217                 return -EINVAL;
218
219         *val = get_unaligned_be16(buf);
220
221         return 0;
222 }
223
224 /*
225  * This method is used to get the highest humidity measured during automatic
226  * measurement
227  */
228 static int hdc3020_read_high_peak_rh(struct hdc3020_data *data, int *val)
229 {
230         u8 crc, buf[3];
231         int ret;
232
233         ret = hdc3020_read_bytes(data, HDC3020_R_RH_HIGH_AUTO, buf, 3);
234         if (ret < 0)
235                 return ret;
236
237         crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
238         if (crc != buf[2])
239                 return -EINVAL;
240
241         *val = get_unaligned_be16(buf);
242
243         return 0;
244 }
245
246 /*
247  * This method is used to get the lowest humidity measured during automatic
248  * measurement
249  */
250 static int hdc3020_read_low_peak_rh(struct hdc3020_data *data, int *val)
251 {
252         u8 crc, buf[3];
253         int ret;
254
255         ret = hdc3020_read_bytes(data, HDC3020_R_RH_LOW_AUTO, buf, 3);
256         if (ret < 0)
257                 return ret;
258
259         crc = crc8(hdc3020_crc8_table, buf, 2, CRC8_INIT_VALUE);
260         if (crc != buf[2])
261                 return -EINVAL;
262
263         *val = get_unaligned_be16(buf);
264
265         return 0;
266 }
267
268 static int hdc3020_read_raw(struct iio_dev *indio_dev,
269                             struct iio_chan_spec const *chan, int *val,
270                             int *val2, long mask)
271 {
272         struct hdc3020_data *data = iio_priv(indio_dev);
273         int ret;
274
275         if (chan->type != IIO_TEMP && chan->type != IIO_HUMIDITYRELATIVE)
276                 return -EINVAL;
277
278         switch (mask) {
279         case IIO_CHAN_INFO_RAW: {
280                 guard(mutex)(&data->lock);
281                 ret = hdc3020_read_measurement(data, chan->type, val);
282                 if (ret < 0)
283                         return ret;
284
285                 return IIO_VAL_INT;
286         }
287         case IIO_CHAN_INFO_PEAK: {
288                 guard(mutex)(&data->lock);
289                 if (chan->type == IIO_TEMP) {
290                         ret = hdc3020_read_high_peak_t(data, val);
291                         if (ret < 0)
292                                 return ret;
293                 } else {
294                         ret = hdc3020_read_high_peak_rh(data, val);
295                         if (ret < 0)
296                                 return ret;
297                 }
298                 return IIO_VAL_INT;
299         }
300         case IIO_CHAN_INFO_TROUGH: {
301                 guard(mutex)(&data->lock);
302                 if (chan->type == IIO_TEMP) {
303                         ret = hdc3020_read_low_peak_t(data, val);
304                         if (ret < 0)
305                                 return ret;
306                 } else {
307                         ret = hdc3020_read_low_peak_rh(data, val);
308                         if (ret < 0)
309                                 return ret;
310                 }
311                 return IIO_VAL_INT;
312         }
313         case IIO_CHAN_INFO_SCALE:
314                 *val2 = 65536;
315                 if (chan->type == IIO_TEMP)
316                         *val = 175;
317                 else
318                         *val = 100;
319                 return IIO_VAL_FRACTIONAL;
320
321         case IIO_CHAN_INFO_OFFSET:
322                 if (chan->type != IIO_TEMP)
323                         return -EINVAL;
324
325                 *val = 16852;
326                 return IIO_VAL_INT;
327
328         default:
329                 return -EINVAL;
330         }
331 }
332
333 static int hdc3020_read_available(struct iio_dev *indio_dev,
334                                   struct iio_chan_spec const *chan,
335                                   const int **vals,
336                                   int *type, int *length, long mask)
337 {
338         if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT)
339                 return -EINVAL;
340
341         *vals = hdc3020_heater_vals;
342         *type = IIO_VAL_INT;
343
344         return IIO_AVAIL_RANGE;
345 }
346
347 static int hdc3020_update_heater(struct hdc3020_data *data, int val)
348 {
349         u8 buf[5];
350         int ret;
351
352         if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2])
353                 return -EINVAL;
354
355         buf[0] = HDC3020_HEATER_CMD_MSB;
356
357         if (!val) {
358                 buf[1] = HDC3020_HEATER_DISABLE;
359                 return hdc3020_write_bytes(data, buf, 2);
360         }
361
362         buf[1] = HDC3020_HEATER_CONFIG;
363         put_unaligned_be16(val & GENMASK(13, 0), &buf[2]);
364         buf[4] = crc8(hdc3020_crc8_table, buf + 2, 2, CRC8_INIT_VALUE);
365         ret = hdc3020_write_bytes(data, buf, 5);
366         if (ret < 0)
367                 return ret;
368
369         buf[1] = HDC3020_HEATER_ENABLE;
370
371         return hdc3020_write_bytes(data, buf, 2);
372 }
373
374 static int hdc3020_write_raw(struct iio_dev *indio_dev,
375                              struct iio_chan_spec const *chan,
376                              int val, int val2, long mask)
377 {
378         struct hdc3020_data *data = iio_priv(indio_dev);
379
380         switch (mask) {
381         case IIO_CHAN_INFO_RAW:
382                 if (chan->type != IIO_CURRENT)
383                         return -EINVAL;
384
385                 guard(mutex)(&data->lock);
386                 return hdc3020_update_heater(data, val);
387         }
388
389         return -EINVAL;
390 }
391
392 static const struct iio_info hdc3020_info = {
393         .read_raw = hdc3020_read_raw,
394         .write_raw = hdc3020_write_raw,
395         .read_avail = hdc3020_read_available,
396 };
397
398 static void hdc3020_stop(void *data)
399 {
400         hdc3020_write_bytes((struct hdc3020_data *)data, HDC3020_EXIT_AUTO, 2);
401 }
402
403 static int hdc3020_probe(struct i2c_client *client)
404 {
405         struct iio_dev *indio_dev;
406         struct hdc3020_data *data;
407         int ret;
408
409         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
410                 return -EOPNOTSUPP;
411
412         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
413         if (!indio_dev)
414                 return -ENOMEM;
415
416         data = iio_priv(indio_dev);
417         data->client = client;
418         mutex_init(&data->lock);
419
420         crc8_populate_msb(hdc3020_crc8_table, HDC3020_CRC8_POLYNOMIAL);
421
422         indio_dev->name = "hdc3020";
423         indio_dev->modes = INDIO_DIRECT_MODE;
424         indio_dev->info = &hdc3020_info;
425         indio_dev->channels = hdc3020_channels;
426         indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels);
427
428         ret = hdc3020_write_bytes(data, HDC3020_S_AUTO_10HZ_MOD0, 2);
429         if (ret)
430                 return dev_err_probe(&client->dev, ret,
431                                      "Unable to set up measurement\n");
432
433         ret = devm_add_action_or_reset(&data->client->dev, hdc3020_stop, data);
434         if (ret)
435                 return ret;
436
437         ret = devm_iio_device_register(&data->client->dev, indio_dev);
438         if (ret)
439                 return dev_err_probe(&client->dev, ret, "Failed to add device");
440
441         return 0;
442 }
443
444 static const struct i2c_device_id hdc3020_id[] = {
445         { "hdc3020" },
446         { "hdc3021" },
447         { "hdc3022" },
448         { }
449 };
450 MODULE_DEVICE_TABLE(i2c, hdc3020_id);
451
452 static const struct of_device_id hdc3020_dt_ids[] = {
453         { .compatible = "ti,hdc3020" },
454         { .compatible = "ti,hdc3021" },
455         { .compatible = "ti,hdc3022" },
456         { }
457 };
458 MODULE_DEVICE_TABLE(of, hdc3020_dt_ids);
459
460 static struct i2c_driver hdc3020_driver = {
461         .driver = {
462                 .name = "hdc3020",
463                 .of_match_table = hdc3020_dt_ids,
464         },
465         .probe = hdc3020_probe,
466         .id_table = hdc3020_id,
467 };
468 module_i2c_driver(hdc3020_driver);
469
470 MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>");
471 MODULE_AUTHOR("Li peiyu <579lpy@gmail.com>");
472 MODULE_DESCRIPTION("TI HDC3020 humidity and temperature sensor driver");
473 MODULE_LICENSE("GPL");