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 * Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
9 *
10 * Datasheet: https://www.ti.com/lit/ds/symlink/hdc3020.pdf
11 */
12
13#include <linux/bitfield.h>
14#include <linux/bitops.h>
15#include <linux/cleanup.h>
16#include <linux/crc8.h>
17#include <linux/delay.h>
18#include <linux/i2c.h>
19#include <linux/init.h>
20#include <linux/interrupt.h>
21#include <linux/module.h>
22#include <linux/mutex.h>
23#include <linux/units.h>
24
25#include <asm/unaligned.h>
26
27#include <linux/iio/events.h>
28#include <linux/iio/iio.h>
29
30#define HDC3020_S_AUTO_10HZ_MOD0 0x2737
31#define HDC3020_S_STATUS 0x3041
32#define HDC3020_HEATER_DISABLE 0x3066
33#define HDC3020_HEATER_ENABLE 0x306D
34#define HDC3020_HEATER_CONFIG 0x306E
35#define HDC3020_EXIT_AUTO 0x3093
36#define HDC3020_S_T_RH_THRESH_LOW 0x6100
37#define HDC3020_S_T_RH_THRESH_LOW_CLR 0x610B
38#define HDC3020_S_T_RH_THRESH_HIGH_CLR 0x6116
39#define HDC3020_S_T_RH_THRESH_HIGH 0x611D
40#define HDC3020_R_T_RH_AUTO 0xE000
41#define HDC3020_R_T_LOW_AUTO 0xE002
42#define HDC3020_R_T_HIGH_AUTO 0xE003
43#define HDC3020_R_RH_LOW_AUTO 0xE004
44#define HDC3020_R_RH_HIGH_AUTO 0xE005
45#define HDC3020_R_T_RH_THRESH_LOW 0xE102
46#define HDC3020_R_T_RH_THRESH_LOW_CLR 0xE109
47#define HDC3020_R_T_RH_THRESH_HIGH_CLR 0xE114
48#define HDC3020_R_T_RH_THRESH_HIGH 0xE11F
49#define HDC3020_R_STATUS 0xF32D
50
51#define HDC3020_THRESH_TEMP_MASK GENMASK(8, 0)
52#define HDC3020_THRESH_TEMP_TRUNC_SHIFT 7
53#define HDC3020_THRESH_HUM_MASK GENMASK(15, 9)
54#define HDC3020_THRESH_HUM_TRUNC_SHIFT 9
55
56#define HDC3020_STATUS_T_LOW_ALERT BIT(6)
57#define HDC3020_STATUS_T_HIGH_ALERT BIT(7)
58#define HDC3020_STATUS_RH_LOW_ALERT BIT(8)
59#define HDC3020_STATUS_RH_HIGH_ALERT BIT(9)
60
61#define HDC3020_READ_RETRY_TIMES 10
62#define HDC3020_BUSY_DELAY_MS 10
63
64#define HDC3020_CRC8_POLYNOMIAL 0x31
65
66#define HDC3020_MIN_TEMP -40
67#define HDC3020_MAX_TEMP 125
68
69struct hdc3020_data {
70 struct i2c_client *client;
71 /*
72 * Ensure that the sensor configuration (currently only heater is
73 * supported) will not be changed during the process of reading
74 * sensor data (this driver will try HDC3020_READ_RETRY_TIMES times
75 * if the device does not respond).
76 */
77 struct mutex lock;
78};
79
80static const int hdc3020_heater_vals[] = {0, 1, 0x3FFF};
81
82static const struct iio_event_spec hdc3020_t_rh_event[] = {
83 {
84 .type = IIO_EV_TYPE_THRESH,
85 .dir = IIO_EV_DIR_RISING,
86 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
87 BIT(IIO_EV_INFO_HYSTERESIS),
88 },
89 {
90 .type = IIO_EV_TYPE_THRESH,
91 .dir = IIO_EV_DIR_FALLING,
92 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
93 BIT(IIO_EV_INFO_HYSTERESIS),
94 },
95};
96
97static const struct iio_chan_spec hdc3020_channels[] = {
98 {
99 .type = IIO_TEMP,
100 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
101 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
102 BIT(IIO_CHAN_INFO_TROUGH) | BIT(IIO_CHAN_INFO_OFFSET),
103 .event_spec = hdc3020_t_rh_event,
104 .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event),
105 },
106 {
107 .type = IIO_HUMIDITYRELATIVE,
108 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
109 BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_PEAK) |
110 BIT(IIO_CHAN_INFO_TROUGH),
111 .event_spec = hdc3020_t_rh_event,
112 .num_event_specs = ARRAY_SIZE(hdc3020_t_rh_event),
113 },
114 {
115 /*
116 * For setting the internal heater, which can be switched on to
117 * prevent or remove any condensation that may develop when the
118 * ambient environment approaches its dew point temperature.
119 */
120 .type = IIO_CURRENT,
121 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
122 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
123 .output = 1,
124 },
125};
126
127DECLARE_CRC8_TABLE(hdc3020_crc8_table);
128
129static int hdc3020_write_bytes(struct hdc3020_data *data, u8 *buf, u8 len)
130{
131 struct i2c_client *client = data->client;
132 struct i2c_msg msg;
133 int ret, cnt;
134
135 msg.addr = client->addr;
136 msg.flags = 0;
137 msg.buf = buf;
138 msg.len = len;
139
140 /*
141 * During the measurement process, HDC3020 will not return data.
142 * So wait for a while and try again
143 */
144 for (cnt = 0; cnt < HDC3020_READ_RETRY_TIMES; cnt++) {
145 ret = i2c_transfer(adap: client->adapter, msgs: &msg, num: 1);
146 if (ret == 1)
147 return 0;
148
149 mdelay(HDC3020_BUSY_DELAY_MS);
150 }
151 dev_err(&client->dev, "Could not write sensor command\n");
152
153 return -ETIMEDOUT;
154}
155
156static
157int hdc3020_read_bytes(struct hdc3020_data *data, u16 reg, u8 *buf, int len)
158{
159 u8 reg_buf[2];
160 int ret, cnt;
161 struct i2c_client *client = data->client;
162 struct i2c_msg msg[2] = {
163 [0] = {
164 .addr = client->addr,
165 .flags = 0,
166 .buf = reg_buf,
167 .len = 2,
168 },
169 [1] = {
170 .addr = client->addr,
171 .flags = I2C_M_RD,
172 .buf = buf,
173 .len = len,
174 },
175 };
176
177 put_unaligned_be16(val: reg, p: reg_buf);
178 /*
179 * During the measurement process, HDC3020 will not return data.
180 * So wait for a while and try again
181 */
182 for (cnt = 0; cnt < HDC3020_READ_RETRY_TIMES; cnt++) {
183 ret = i2c_transfer(adap: client->adapter, msgs: msg, num: 2);
184 if (ret == 2)
185 return 0;
186
187 mdelay(HDC3020_BUSY_DELAY_MS);
188 }
189 dev_err(&client->dev, "Could not read sensor data\n");
190
191 return -ETIMEDOUT;
192}
193
194static int hdc3020_read_be16(struct hdc3020_data *data, u16 reg)
195{
196 u8 crc, buf[3];
197 int ret;
198
199 ret = hdc3020_read_bytes(data, reg, buf, len: 3);
200 if (ret < 0)
201 return ret;
202
203 crc = crc8(table: hdc3020_crc8_table, pdata: buf, nbytes: 2, CRC8_INIT_VALUE);
204 if (crc != buf[2])
205 return -EINVAL;
206
207 return get_unaligned_be16(p: buf);
208}
209
210static int hdc3020_exec_cmd(struct hdc3020_data *data, u16 reg)
211{
212 u8 reg_buf[2];
213
214 put_unaligned_be16(val: reg, p: reg_buf);
215 return hdc3020_write_bytes(data, buf: reg_buf, len: 2);
216}
217
218static int hdc3020_read_measurement(struct hdc3020_data *data,
219 enum iio_chan_type type, int *val)
220{
221 u8 crc, buf[6];
222 int ret;
223
224 ret = hdc3020_read_bytes(data, HDC3020_R_T_RH_AUTO, buf, len: 6);
225 if (ret < 0)
226 return ret;
227
228 /* CRC check of the temperature measurement */
229 crc = crc8(table: hdc3020_crc8_table, pdata: buf, nbytes: 2, CRC8_INIT_VALUE);
230 if (crc != buf[2])
231 return -EINVAL;
232
233 /* CRC check of the relative humidity measurement */
234 crc = crc8(table: hdc3020_crc8_table, pdata: buf + 3, nbytes: 2, CRC8_INIT_VALUE);
235 if (crc != buf[5])
236 return -EINVAL;
237
238 if (type == IIO_TEMP)
239 *val = get_unaligned_be16(p: buf);
240 else if (type == IIO_HUMIDITYRELATIVE)
241 *val = get_unaligned_be16(p: &buf[3]);
242 else
243 return -EINVAL;
244
245 return 0;
246}
247
248static int hdc3020_read_raw(struct iio_dev *indio_dev,
249 struct iio_chan_spec const *chan, int *val,
250 int *val2, long mask)
251{
252 struct hdc3020_data *data = iio_priv(indio_dev);
253 int ret;
254
255 if (chan->type != IIO_TEMP && chan->type != IIO_HUMIDITYRELATIVE)
256 return -EINVAL;
257
258 switch (mask) {
259 case IIO_CHAN_INFO_RAW: {
260 guard(mutex)(T: &data->lock);
261 ret = hdc3020_read_measurement(data, type: chan->type, val);
262 if (ret < 0)
263 return ret;
264
265 return IIO_VAL_INT;
266 }
267 case IIO_CHAN_INFO_PEAK: {
268 guard(mutex)(T: &data->lock);
269 if (chan->type == IIO_TEMP)
270 ret = hdc3020_read_be16(data, HDC3020_R_T_HIGH_AUTO);
271 else
272 ret = hdc3020_read_be16(data, HDC3020_R_RH_HIGH_AUTO);
273
274 if (ret < 0)
275 return ret;
276
277 *val = ret;
278 return IIO_VAL_INT;
279 }
280 case IIO_CHAN_INFO_TROUGH: {
281 guard(mutex)(T: &data->lock);
282 if (chan->type == IIO_TEMP)
283 ret = hdc3020_read_be16(data, HDC3020_R_T_LOW_AUTO);
284 else
285 ret = hdc3020_read_be16(data, HDC3020_R_RH_LOW_AUTO);
286
287 if (ret < 0)
288 return ret;
289
290 *val = ret;
291 return IIO_VAL_INT;
292 }
293 case IIO_CHAN_INFO_SCALE:
294 *val2 = 65536;
295 if (chan->type == IIO_TEMP)
296 *val = 175;
297 else
298 *val = 100;
299 return IIO_VAL_FRACTIONAL;
300
301 case IIO_CHAN_INFO_OFFSET:
302 if (chan->type != IIO_TEMP)
303 return -EINVAL;
304
305 *val = -16852;
306 return IIO_VAL_INT;
307
308 default:
309 return -EINVAL;
310 }
311}
312
313static int hdc3020_read_available(struct iio_dev *indio_dev,
314 struct iio_chan_spec const *chan,
315 const int **vals,
316 int *type, int *length, long mask)
317{
318 if (mask != IIO_CHAN_INFO_RAW || chan->type != IIO_CURRENT)
319 return -EINVAL;
320
321 *vals = hdc3020_heater_vals;
322 *type = IIO_VAL_INT;
323
324 return IIO_AVAIL_RANGE;
325}
326
327static int hdc3020_update_heater(struct hdc3020_data *data, int val)
328{
329 u8 buf[5];
330 int ret;
331
332 if (val < hdc3020_heater_vals[0] || val > hdc3020_heater_vals[2])
333 return -EINVAL;
334
335 if (!val)
336 hdc3020_exec_cmd(data, HDC3020_HEATER_DISABLE);
337
338 put_unaligned_be16(HDC3020_HEATER_CONFIG, p: buf);
339 put_unaligned_be16(val: val & GENMASK(13, 0), p: &buf[2]);
340 buf[4] = crc8(table: hdc3020_crc8_table, pdata: buf + 2, nbytes: 2, CRC8_INIT_VALUE);
341 ret = hdc3020_write_bytes(data, buf, len: 5);
342 if (ret < 0)
343 return ret;
344
345 return hdc3020_exec_cmd(data, HDC3020_HEATER_ENABLE);
346}
347
348static int hdc3020_write_raw(struct iio_dev *indio_dev,
349 struct iio_chan_spec const *chan,
350 int val, int val2, long mask)
351{
352 struct hdc3020_data *data = iio_priv(indio_dev);
353
354 switch (mask) {
355 case IIO_CHAN_INFO_RAW:
356 if (chan->type != IIO_CURRENT)
357 return -EINVAL;
358
359 guard(mutex)(T: &data->lock);
360 return hdc3020_update_heater(data, val);
361 }
362
363 return -EINVAL;
364}
365
366static int hdc3020_write_thresh(struct iio_dev *indio_dev,
367 const struct iio_chan_spec *chan,
368 enum iio_event_type type,
369 enum iio_event_direction dir,
370 enum iio_event_info info,
371 int val, int val2)
372{
373 struct hdc3020_data *data = iio_priv(indio_dev);
374 u8 buf[5];
375 u64 tmp;
376 u16 reg;
377 int ret;
378
379 /* Supported temperature range is from –40 to 125 degree celsius */
380 if (val < HDC3020_MIN_TEMP || val > HDC3020_MAX_TEMP)
381 return -EINVAL;
382
383 /* Select threshold register */
384 if (info == IIO_EV_INFO_VALUE) {
385 if (dir == IIO_EV_DIR_RISING)
386 reg = HDC3020_S_T_RH_THRESH_HIGH;
387 else
388 reg = HDC3020_S_T_RH_THRESH_LOW;
389 } else {
390 if (dir == IIO_EV_DIR_RISING)
391 reg = HDC3020_S_T_RH_THRESH_HIGH_CLR;
392 else
393 reg = HDC3020_S_T_RH_THRESH_LOW_CLR;
394 }
395
396 guard(mutex)(T: &data->lock);
397 ret = hdc3020_read_be16(data, reg);
398 if (ret < 0)
399 return ret;
400
401 switch (chan->type) {
402 case IIO_TEMP:
403 /*
404 * Calculate temperature threshold, shift it down to get the
405 * truncated threshold representation in the 9LSBs while keeping
406 * the current humidity threshold in the 7 MSBs.
407 */
408 tmp = ((u64)(((val + 45) * MICRO) + val2)) * 65535ULL;
409 tmp = div_u64(dividend: tmp, MICRO * 175);
410 val = tmp >> HDC3020_THRESH_TEMP_TRUNC_SHIFT;
411 val = FIELD_PREP(HDC3020_THRESH_TEMP_MASK, val);
412 val |= (FIELD_GET(HDC3020_THRESH_HUM_MASK, ret) <<
413 HDC3020_THRESH_HUM_TRUNC_SHIFT);
414 break;
415 case IIO_HUMIDITYRELATIVE:
416 /*
417 * Calculate humidity threshold, shift it down and up to get the
418 * truncated threshold representation in the 7MSBs while keeping
419 * the current temperature threshold in the 9 LSBs.
420 */
421 tmp = ((u64)((val * MICRO) + val2)) * 65535ULL;
422 tmp = div_u64(dividend: tmp, MICRO * 100);
423 val = tmp >> HDC3020_THRESH_HUM_TRUNC_SHIFT;
424 val = FIELD_PREP(HDC3020_THRESH_HUM_MASK, val);
425 val |= FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret);
426 break;
427 default:
428 return -EOPNOTSUPP;
429 }
430
431 put_unaligned_be16(val: reg, p: buf);
432 put_unaligned_be16(val, p: buf + 2);
433 buf[4] = crc8(table: hdc3020_crc8_table, pdata: buf + 2, nbytes: 2, CRC8_INIT_VALUE);
434 return hdc3020_write_bytes(data, buf, len: 5);
435}
436
437static int hdc3020_read_thresh(struct iio_dev *indio_dev,
438 const struct iio_chan_spec *chan,
439 enum iio_event_type type,
440 enum iio_event_direction dir,
441 enum iio_event_info info,
442 int *val, int *val2)
443{
444 struct hdc3020_data *data = iio_priv(indio_dev);
445 u16 reg;
446 int ret;
447
448 /* Select threshold register */
449 if (info == IIO_EV_INFO_VALUE) {
450 if (dir == IIO_EV_DIR_RISING)
451 reg = HDC3020_R_T_RH_THRESH_HIGH;
452 else
453 reg = HDC3020_R_T_RH_THRESH_LOW;
454 } else {
455 if (dir == IIO_EV_DIR_RISING)
456 reg = HDC3020_R_T_RH_THRESH_HIGH_CLR;
457 else
458 reg = HDC3020_R_T_RH_THRESH_LOW_CLR;
459 }
460
461 guard(mutex)(T: &data->lock);
462 ret = hdc3020_read_be16(data, reg);
463 if (ret < 0)
464 return ret;
465
466 switch (chan->type) {
467 case IIO_TEMP:
468 /*
469 * Get the temperature threshold from 9 LSBs, shift them to get
470 * the truncated temperature threshold representation and
471 * calculate the threshold according to the formula in the
472 * datasheet.
473 */
474 *val = FIELD_GET(HDC3020_THRESH_TEMP_MASK, ret);
475 *val = *val << HDC3020_THRESH_TEMP_TRUNC_SHIFT;
476 *val = -2949075 + (175 * (*val));
477 *val2 = 65535;
478 return IIO_VAL_FRACTIONAL;
479 case IIO_HUMIDITYRELATIVE:
480 /*
481 * Get the humidity threshold from 7 MSBs, shift them to get the
482 * truncated humidity threshold representation and calculate the
483 * threshold according to the formula in the datasheet.
484 */
485 *val = FIELD_GET(HDC3020_THRESH_HUM_MASK, ret);
486 *val = (*val << HDC3020_THRESH_HUM_TRUNC_SHIFT) * 100;
487 *val2 = 65535;
488 return IIO_VAL_FRACTIONAL;
489 default:
490 return -EOPNOTSUPP;
491 }
492}
493
494static irqreturn_t hdc3020_interrupt_handler(int irq, void *private)
495{
496 struct iio_dev *indio_dev = private;
497 struct hdc3020_data *data;
498 s64 time;
499 int ret;
500
501 data = iio_priv(indio_dev);
502 ret = hdc3020_read_be16(data, HDC3020_R_STATUS);
503 if (ret < 0)
504 return IRQ_HANDLED;
505
506 if (!(ret & (HDC3020_STATUS_T_HIGH_ALERT | HDC3020_STATUS_T_LOW_ALERT |
507 HDC3020_STATUS_RH_HIGH_ALERT | HDC3020_STATUS_RH_LOW_ALERT)))
508 return IRQ_NONE;
509
510 time = iio_get_time_ns(indio_dev);
511 if (ret & HDC3020_STATUS_T_HIGH_ALERT)
512 iio_push_event(indio_dev,
513 IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
514 IIO_NO_MOD,
515 IIO_EV_TYPE_THRESH,
516 IIO_EV_DIR_RISING),
517 timestamp: time);
518
519 if (ret & HDC3020_STATUS_T_LOW_ALERT)
520 iio_push_event(indio_dev,
521 IIO_MOD_EVENT_CODE(IIO_TEMP, 0,
522 IIO_NO_MOD,
523 IIO_EV_TYPE_THRESH,
524 IIO_EV_DIR_FALLING),
525 timestamp: time);
526
527 if (ret & HDC3020_STATUS_RH_HIGH_ALERT)
528 iio_push_event(indio_dev,
529 IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0,
530 IIO_NO_MOD,
531 IIO_EV_TYPE_THRESH,
532 IIO_EV_DIR_RISING),
533 timestamp: time);
534
535 if (ret & HDC3020_STATUS_RH_LOW_ALERT)
536 iio_push_event(indio_dev,
537 IIO_MOD_EVENT_CODE(IIO_HUMIDITYRELATIVE, 0,
538 IIO_NO_MOD,
539 IIO_EV_TYPE_THRESH,
540 IIO_EV_DIR_FALLING),
541 timestamp: time);
542
543 return IRQ_HANDLED;
544}
545
546static const struct iio_info hdc3020_info = {
547 .read_raw = hdc3020_read_raw,
548 .write_raw = hdc3020_write_raw,
549 .read_avail = hdc3020_read_available,
550 .read_event_value = hdc3020_read_thresh,
551 .write_event_value = hdc3020_write_thresh,
552};
553
554static void hdc3020_stop(void *data)
555{
556 hdc3020_exec_cmd(data: (struct hdc3020_data *)data, HDC3020_EXIT_AUTO);
557}
558
559static int hdc3020_probe(struct i2c_client *client)
560{
561 struct iio_dev *indio_dev;
562 struct hdc3020_data *data;
563 int ret;
564
565 if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_I2C))
566 return -EOPNOTSUPP;
567
568 indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data));
569 if (!indio_dev)
570 return -ENOMEM;
571
572 data = iio_priv(indio_dev);
573 data->client = client;
574 mutex_init(&data->lock);
575
576 crc8_populate_msb(table: hdc3020_crc8_table, HDC3020_CRC8_POLYNOMIAL);
577
578 indio_dev->name = "hdc3020";
579 indio_dev->modes = INDIO_DIRECT_MODE;
580 indio_dev->info = &hdc3020_info;
581 indio_dev->channels = hdc3020_channels;
582 indio_dev->num_channels = ARRAY_SIZE(hdc3020_channels);
583 if (client->irq) {
584 ret = devm_request_threaded_irq(dev: &client->dev, irq: client->irq,
585 NULL, thread_fn: hdc3020_interrupt_handler,
586 IRQF_ONESHOT, devname: "hdc3020",
587 dev_id: indio_dev);
588 if (ret)
589 return dev_err_probe(dev: &client->dev, err: ret,
590 fmt: "Failed to request IRQ\n");
591
592 /*
593 * The alert output is activated by default upon power up,
594 * hardware reset, and soft reset. Clear the status register.
595 */
596 ret = hdc3020_exec_cmd(data, HDC3020_S_STATUS);
597 if (ret)
598 return ret;
599 }
600
601 ret = hdc3020_exec_cmd(data, HDC3020_S_AUTO_10HZ_MOD0);
602 if (ret)
603 return dev_err_probe(dev: &client->dev, err: ret,
604 fmt: "Unable to set up measurement\n");
605
606 ret = devm_add_action_or_reset(&data->client->dev, hdc3020_stop, data);
607 if (ret)
608 return ret;
609
610 ret = devm_iio_device_register(&data->client->dev, indio_dev);
611 if (ret)
612 return dev_err_probe(dev: &client->dev, err: ret, fmt: "Failed to add device");
613
614 return 0;
615}
616
617static const struct i2c_device_id hdc3020_id[] = {
618 { "hdc3020" },
619 { "hdc3021" },
620 { "hdc3022" },
621 { }
622};
623MODULE_DEVICE_TABLE(i2c, hdc3020_id);
624
625static const struct of_device_id hdc3020_dt_ids[] = {
626 { .compatible = "ti,hdc3020" },
627 { .compatible = "ti,hdc3021" },
628 { .compatible = "ti,hdc3022" },
629 { }
630};
631MODULE_DEVICE_TABLE(of, hdc3020_dt_ids);
632
633static struct i2c_driver hdc3020_driver = {
634 .driver = {
635 .name = "hdc3020",
636 .of_match_table = hdc3020_dt_ids,
637 },
638 .probe = hdc3020_probe,
639 .id_table = hdc3020_id,
640};
641module_i2c_driver(hdc3020_driver);
642
643MODULE_AUTHOR("Javier Carrasco <javier.carrasco.cruz@gmail.com>");
644MODULE_AUTHOR("Li peiyu <579lpy@gmail.com>");
645MODULE_DESCRIPTION("TI HDC3020 humidity and temperature sensor driver");
646MODULE_LICENSE("GPL");
647

source code of linux/drivers/iio/humidity/hdc3020.c