xref: /linux/drivers/iio/humidity/hdc3020.c (revision f058b2dd70b1a5503dff899010aeb53b436091e5)
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");
474