xref: /linux/drivers/hwmon/htu31.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
1*bf1bb26fSAndrei Lalaev // SPDX-License-Identifier: GPL-2.0-or-later
2*bf1bb26fSAndrei Lalaev /*
3*bf1bb26fSAndrei Lalaev  * The driver for Measurement Specialties HTU31 Temperature and Humidity sensor.
4*bf1bb26fSAndrei Lalaev  *
5*bf1bb26fSAndrei Lalaev  * Copyright (C) 2025
6*bf1bb26fSAndrei Lalaev  * Author: Andrei Lalaev <andrey.lalaev@gmail.com>
7*bf1bb26fSAndrei Lalaev  */
8*bf1bb26fSAndrei Lalaev 
9*bf1bb26fSAndrei Lalaev #include <linux/array_size.h>
10*bf1bb26fSAndrei Lalaev #include <linux/cleanup.h>
11*bf1bb26fSAndrei Lalaev #include <linux/crc8.h>
12*bf1bb26fSAndrei Lalaev #include <linux/debugfs.h>
13*bf1bb26fSAndrei Lalaev #include <linux/delay.h>
14*bf1bb26fSAndrei Lalaev #include <linux/hwmon.h>
15*bf1bb26fSAndrei Lalaev #include <linux/hwmon-sysfs.h>
16*bf1bb26fSAndrei Lalaev #include <linux/i2c.h>
17*bf1bb26fSAndrei Lalaev #include <linux/init.h>
18*bf1bb26fSAndrei Lalaev #include <linux/module.h>
19*bf1bb26fSAndrei Lalaev 
20*bf1bb26fSAndrei Lalaev #define HTU31_READ_TEMP_HUM_CMD	0x00
21*bf1bb26fSAndrei Lalaev #define HTU31_READ_SERIAL_CMD		0x0a
22*bf1bb26fSAndrei Lalaev #define HTU31_CONVERSION_CMD		0x5e
23*bf1bb26fSAndrei Lalaev #define HTU31_HEATER_OFF_CMD		0x02
24*bf1bb26fSAndrei Lalaev #define HTU31_HEATER_ON_CMD		0x04
25*bf1bb26fSAndrei Lalaev 
26*bf1bb26fSAndrei Lalaev #define HTU31_TEMP_HUM_LEN		6
27*bf1bb26fSAndrei Lalaev 
28*bf1bb26fSAndrei Lalaev /* Conversion time for the highest resolution */
29*bf1bb26fSAndrei Lalaev #define HTU31_HUMIDITY_CONV_TIME	10000 /* us */
30*bf1bb26fSAndrei Lalaev #define HTU31_TEMPERATURE_CONV_TIME	15000 /* us */
31*bf1bb26fSAndrei Lalaev 
32*bf1bb26fSAndrei Lalaev #define HTU31_SERIAL_NUMBER_LEN	3
33*bf1bb26fSAndrei Lalaev #define HTU31_SERIAL_NUMBER_CRC_LEN	1
34*bf1bb26fSAndrei Lalaev #define HTU31_SERIAL_NUMBER_CRC_OFFSET	3
35*bf1bb26fSAndrei Lalaev 
36*bf1bb26fSAndrei Lalaev #define HTU31_CRC8_INIT_VAL		0
37*bf1bb26fSAndrei Lalaev #define HTU31_CRC8_POLYNOMIAL		0x31
38*bf1bb26fSAndrei Lalaev DECLARE_CRC8_TABLE(htu31_crc8_table);
39*bf1bb26fSAndrei Lalaev 
40*bf1bb26fSAndrei Lalaev /**
41*bf1bb26fSAndrei Lalaev  * struct htu31_data - all the data required to operate a HTU31 chip
42*bf1bb26fSAndrei Lalaev  * @client: the i2c client associated with the HTU31
43*bf1bb26fSAndrei Lalaev  * @lock: a mutex to prevent parallel access to the data
44*bf1bb26fSAndrei Lalaev  * @wait_time: the time needed by sensor to convert values
45*bf1bb26fSAndrei Lalaev  * @temperature: the latest temperature value in millidegrees
46*bf1bb26fSAndrei Lalaev  * @humidity: the latest relative humidity value in millipercent
47*bf1bb26fSAndrei Lalaev  * @serial_number: the serial number of the sensor
48*bf1bb26fSAndrei Lalaev  * @heater_enable: the internal state of the heater
49*bf1bb26fSAndrei Lalaev  */
50*bf1bb26fSAndrei Lalaev struct htu31_data {
51*bf1bb26fSAndrei Lalaev 	struct i2c_client *client;
52*bf1bb26fSAndrei Lalaev 	struct mutex lock; /* Used to protect against parallel data updates */
53*bf1bb26fSAndrei Lalaev 	long wait_time;
54*bf1bb26fSAndrei Lalaev 	long temperature;
55*bf1bb26fSAndrei Lalaev 	long humidity;
56*bf1bb26fSAndrei Lalaev 	u8 serial_number[HTU31_SERIAL_NUMBER_LEN];
57*bf1bb26fSAndrei Lalaev 	bool heater_enable;
58*bf1bb26fSAndrei Lalaev };
59*bf1bb26fSAndrei Lalaev 
60*bf1bb26fSAndrei Lalaev static long htu31_temp_to_millicelsius(u16 val)
61*bf1bb26fSAndrei Lalaev {
62*bf1bb26fSAndrei Lalaev 	return -40000 + DIV_ROUND_CLOSEST_ULL(165000ULL * val, 65535);
63*bf1bb26fSAndrei Lalaev }
64*bf1bb26fSAndrei Lalaev 
65*bf1bb26fSAndrei Lalaev static long htu31_relative_humidity(u16 val)
66*bf1bb26fSAndrei Lalaev {
67*bf1bb26fSAndrei Lalaev 	return DIV_ROUND_CLOSEST_ULL(100000ULL * val, 65535);
68*bf1bb26fSAndrei Lalaev }
69*bf1bb26fSAndrei Lalaev 
70*bf1bb26fSAndrei Lalaev static int htu31_data_fetch_command(struct htu31_data *data)
71*bf1bb26fSAndrei Lalaev {
72*bf1bb26fSAndrei Lalaev 	struct i2c_client *client = data->client;
73*bf1bb26fSAndrei Lalaev 	u8 conversion_on = HTU31_CONVERSION_CMD;
74*bf1bb26fSAndrei Lalaev 	u8 read_data_cmd = HTU31_READ_TEMP_HUM_CMD;
75*bf1bb26fSAndrei Lalaev 	u8 t_h_buf[HTU31_TEMP_HUM_LEN] = {};
76*bf1bb26fSAndrei Lalaev 	struct i2c_msg msgs[] = {
77*bf1bb26fSAndrei Lalaev 		{
78*bf1bb26fSAndrei Lalaev 			.addr = client->addr,
79*bf1bb26fSAndrei Lalaev 			.flags = 0,
80*bf1bb26fSAndrei Lalaev 			.len = 1,
81*bf1bb26fSAndrei Lalaev 			.buf = &read_data_cmd,
82*bf1bb26fSAndrei Lalaev 		},
83*bf1bb26fSAndrei Lalaev 		{
84*bf1bb26fSAndrei Lalaev 			.addr = client->addr,
85*bf1bb26fSAndrei Lalaev 			.flags = I2C_M_RD,
86*bf1bb26fSAndrei Lalaev 			.len = sizeof(t_h_buf),
87*bf1bb26fSAndrei Lalaev 			.buf = t_h_buf,
88*bf1bb26fSAndrei Lalaev 		},
89*bf1bb26fSAndrei Lalaev 	};
90*bf1bb26fSAndrei Lalaev 	int ret;
91*bf1bb26fSAndrei Lalaev 	u8 crc;
92*bf1bb26fSAndrei Lalaev 
93*bf1bb26fSAndrei Lalaev 	guard(mutex)(&data->lock);
94*bf1bb26fSAndrei Lalaev 
95*bf1bb26fSAndrei Lalaev 	ret = i2c_master_send(client, &conversion_on, 1);
96*bf1bb26fSAndrei Lalaev 	if (ret != 1) {
97*bf1bb26fSAndrei Lalaev 		ret = ret < 0 ? ret : -EIO;
98*bf1bb26fSAndrei Lalaev 		dev_err(&client->dev,
99*bf1bb26fSAndrei Lalaev 			"Conversion command is failed. Error code: %d\n", ret);
100*bf1bb26fSAndrei Lalaev 		return ret;
101*bf1bb26fSAndrei Lalaev 	}
102*bf1bb26fSAndrei Lalaev 
103*bf1bb26fSAndrei Lalaev 	fsleep(data->wait_time);
104*bf1bb26fSAndrei Lalaev 
105*bf1bb26fSAndrei Lalaev 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
106*bf1bb26fSAndrei Lalaev 	if (ret != ARRAY_SIZE(msgs)) {
107*bf1bb26fSAndrei Lalaev 		ret = ret < 0 ? ret : -EIO;
108*bf1bb26fSAndrei Lalaev 		dev_err(&client->dev,
109*bf1bb26fSAndrei Lalaev 			"T&H command is failed. Error code: %d\n", ret);
110*bf1bb26fSAndrei Lalaev 		return ret;
111*bf1bb26fSAndrei Lalaev 	}
112*bf1bb26fSAndrei Lalaev 
113*bf1bb26fSAndrei Lalaev 	crc = crc8(htu31_crc8_table, &t_h_buf[0], 2, HTU31_CRC8_INIT_VAL);
114*bf1bb26fSAndrei Lalaev 	if (crc != t_h_buf[2]) {
115*bf1bb26fSAndrei Lalaev 		dev_err(&client->dev, "Temperature CRC mismatch\n");
116*bf1bb26fSAndrei Lalaev 		return -EIO;
117*bf1bb26fSAndrei Lalaev 	}
118*bf1bb26fSAndrei Lalaev 
119*bf1bb26fSAndrei Lalaev 	crc = crc8(htu31_crc8_table, &t_h_buf[3], 2, HTU31_CRC8_INIT_VAL);
120*bf1bb26fSAndrei Lalaev 	if (crc != t_h_buf[5]) {
121*bf1bb26fSAndrei Lalaev 		dev_err(&client->dev, "Humidity CRC mismatch\n");
122*bf1bb26fSAndrei Lalaev 		return -EIO;
123*bf1bb26fSAndrei Lalaev 	}
124*bf1bb26fSAndrei Lalaev 
125*bf1bb26fSAndrei Lalaev 	data->temperature = htu31_temp_to_millicelsius(be16_to_cpup((__be16 *)&t_h_buf[0]));
126*bf1bb26fSAndrei Lalaev 	data->humidity = htu31_relative_humidity(be16_to_cpup((__be16 *)&t_h_buf[3]));
127*bf1bb26fSAndrei Lalaev 
128*bf1bb26fSAndrei Lalaev 	return 0;
129*bf1bb26fSAndrei Lalaev }
130*bf1bb26fSAndrei Lalaev 
131*bf1bb26fSAndrei Lalaev static umode_t htu31_is_visible(const void *data, enum hwmon_sensor_types type,
132*bf1bb26fSAndrei Lalaev 				u32 attr, int channel)
133*bf1bb26fSAndrei Lalaev {
134*bf1bb26fSAndrei Lalaev 	switch (type) {
135*bf1bb26fSAndrei Lalaev 	case hwmon_temp:
136*bf1bb26fSAndrei Lalaev 	case hwmon_humidity:
137*bf1bb26fSAndrei Lalaev 		return 0444;
138*bf1bb26fSAndrei Lalaev 	default:
139*bf1bb26fSAndrei Lalaev 		return 0;
140*bf1bb26fSAndrei Lalaev 	}
141*bf1bb26fSAndrei Lalaev }
142*bf1bb26fSAndrei Lalaev 
143*bf1bb26fSAndrei Lalaev static int htu31_read(struct device *dev, enum hwmon_sensor_types type,
144*bf1bb26fSAndrei Lalaev 		      u32 attr, int channel, long *val)
145*bf1bb26fSAndrei Lalaev {
146*bf1bb26fSAndrei Lalaev 	struct htu31_data *data = dev_get_drvdata(dev);
147*bf1bb26fSAndrei Lalaev 	int ret;
148*bf1bb26fSAndrei Lalaev 
149*bf1bb26fSAndrei Lalaev 	ret = htu31_data_fetch_command(data);
150*bf1bb26fSAndrei Lalaev 	if (ret < 0)
151*bf1bb26fSAndrei Lalaev 		return ret;
152*bf1bb26fSAndrei Lalaev 
153*bf1bb26fSAndrei Lalaev 	switch (type) {
154*bf1bb26fSAndrei Lalaev 	case hwmon_temp:
155*bf1bb26fSAndrei Lalaev 		if (attr != hwmon_temp_input)
156*bf1bb26fSAndrei Lalaev 			return -EINVAL;
157*bf1bb26fSAndrei Lalaev 
158*bf1bb26fSAndrei Lalaev 		*val = data->temperature;
159*bf1bb26fSAndrei Lalaev 		break;
160*bf1bb26fSAndrei Lalaev 	case hwmon_humidity:
161*bf1bb26fSAndrei Lalaev 		if (attr != hwmon_humidity_input)
162*bf1bb26fSAndrei Lalaev 			return -EINVAL;
163*bf1bb26fSAndrei Lalaev 
164*bf1bb26fSAndrei Lalaev 		*val = data->humidity;
165*bf1bb26fSAndrei Lalaev 		break;
166*bf1bb26fSAndrei Lalaev 	default:
167*bf1bb26fSAndrei Lalaev 		return -EOPNOTSUPP;
168*bf1bb26fSAndrei Lalaev 	}
169*bf1bb26fSAndrei Lalaev 
170*bf1bb26fSAndrei Lalaev 	return 0;
171*bf1bb26fSAndrei Lalaev }
172*bf1bb26fSAndrei Lalaev 
173*bf1bb26fSAndrei Lalaev static int htu31_read_serial_number(struct htu31_data *data)
174*bf1bb26fSAndrei Lalaev {
175*bf1bb26fSAndrei Lalaev 	struct i2c_client *client = data->client;
176*bf1bb26fSAndrei Lalaev 	u8 read_sn_cmd = HTU31_READ_SERIAL_CMD;
177*bf1bb26fSAndrei Lalaev 	u8 sn_buf[HTU31_SERIAL_NUMBER_LEN + HTU31_SERIAL_NUMBER_CRC_LEN];
178*bf1bb26fSAndrei Lalaev 	struct i2c_msg msgs[] = {
179*bf1bb26fSAndrei Lalaev 		{
180*bf1bb26fSAndrei Lalaev 			.addr = client->addr,
181*bf1bb26fSAndrei Lalaev 			.flags = 0,
182*bf1bb26fSAndrei Lalaev 			.len = 1,
183*bf1bb26fSAndrei Lalaev 			.buf = &read_sn_cmd,
184*bf1bb26fSAndrei Lalaev 		},
185*bf1bb26fSAndrei Lalaev 		{
186*bf1bb26fSAndrei Lalaev 			.addr = client->addr,
187*bf1bb26fSAndrei Lalaev 			.flags = I2C_M_RD,
188*bf1bb26fSAndrei Lalaev 			.len = sizeof(sn_buf),
189*bf1bb26fSAndrei Lalaev 			.buf = sn_buf,
190*bf1bb26fSAndrei Lalaev 		},
191*bf1bb26fSAndrei Lalaev 	};
192*bf1bb26fSAndrei Lalaev 	int ret;
193*bf1bb26fSAndrei Lalaev 	u8 crc;
194*bf1bb26fSAndrei Lalaev 
195*bf1bb26fSAndrei Lalaev 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
196*bf1bb26fSAndrei Lalaev 	if (ret < 0)
197*bf1bb26fSAndrei Lalaev 		return ret;
198*bf1bb26fSAndrei Lalaev 
199*bf1bb26fSAndrei Lalaev 	crc = crc8(htu31_crc8_table, sn_buf, HTU31_SERIAL_NUMBER_LEN, HTU31_CRC8_INIT_VAL);
200*bf1bb26fSAndrei Lalaev 	if (crc != sn_buf[HTU31_SERIAL_NUMBER_CRC_OFFSET]) {
201*bf1bb26fSAndrei Lalaev 		dev_err(&client->dev, "Serial number CRC mismatch\n");
202*bf1bb26fSAndrei Lalaev 		return -EIO;
203*bf1bb26fSAndrei Lalaev 	}
204*bf1bb26fSAndrei Lalaev 
205*bf1bb26fSAndrei Lalaev 	memcpy(data->serial_number, sn_buf, HTU31_SERIAL_NUMBER_LEN);
206*bf1bb26fSAndrei Lalaev 
207*bf1bb26fSAndrei Lalaev 	return 0;
208*bf1bb26fSAndrei Lalaev }
209*bf1bb26fSAndrei Lalaev 
210*bf1bb26fSAndrei Lalaev static ssize_t heater_enable_show(struct device *dev,
211*bf1bb26fSAndrei Lalaev 				  struct device_attribute *attr,
212*bf1bb26fSAndrei Lalaev 				  char *buf)
213*bf1bb26fSAndrei Lalaev {
214*bf1bb26fSAndrei Lalaev 	struct htu31_data *data = dev_get_drvdata(dev);
215*bf1bb26fSAndrei Lalaev 
216*bf1bb26fSAndrei Lalaev 	return sysfs_emit(buf, "%d\n", data->heater_enable);
217*bf1bb26fSAndrei Lalaev }
218*bf1bb26fSAndrei Lalaev 
219*bf1bb26fSAndrei Lalaev static ssize_t heater_enable_store(struct device *dev,
220*bf1bb26fSAndrei Lalaev 				   struct device_attribute *attr,
221*bf1bb26fSAndrei Lalaev 				   const char *buf,
222*bf1bb26fSAndrei Lalaev 				   size_t count)
223*bf1bb26fSAndrei Lalaev {
224*bf1bb26fSAndrei Lalaev 	struct htu31_data *data = dev_get_drvdata(dev);
225*bf1bb26fSAndrei Lalaev 	u8 heater_cmd;
226*bf1bb26fSAndrei Lalaev 	bool status;
227*bf1bb26fSAndrei Lalaev 	int ret;
228*bf1bb26fSAndrei Lalaev 
229*bf1bb26fSAndrei Lalaev 	ret = kstrtobool(buf, &status);
230*bf1bb26fSAndrei Lalaev 	if (ret)
231*bf1bb26fSAndrei Lalaev 		return ret;
232*bf1bb26fSAndrei Lalaev 
233*bf1bb26fSAndrei Lalaev 	heater_cmd = status ? HTU31_HEATER_ON_CMD : HTU31_HEATER_OFF_CMD;
234*bf1bb26fSAndrei Lalaev 
235*bf1bb26fSAndrei Lalaev 	guard(mutex)(&data->lock);
236*bf1bb26fSAndrei Lalaev 
237*bf1bb26fSAndrei Lalaev 	ret = i2c_master_send(data->client, &heater_cmd, 1);
238*bf1bb26fSAndrei Lalaev 	if (ret < 0)
239*bf1bb26fSAndrei Lalaev 		return ret;
240*bf1bb26fSAndrei Lalaev 
241*bf1bb26fSAndrei Lalaev 	data->heater_enable = status;
242*bf1bb26fSAndrei Lalaev 
243*bf1bb26fSAndrei Lalaev 	return count;
244*bf1bb26fSAndrei Lalaev }
245*bf1bb26fSAndrei Lalaev 
246*bf1bb26fSAndrei Lalaev static DEVICE_ATTR_RW(heater_enable);
247*bf1bb26fSAndrei Lalaev 
248*bf1bb26fSAndrei Lalaev static int serial_number_show(struct seq_file *seq_file,
249*bf1bb26fSAndrei Lalaev 			      void *unused)
250*bf1bb26fSAndrei Lalaev {
251*bf1bb26fSAndrei Lalaev 	struct htu31_data *data = seq_file->private;
252*bf1bb26fSAndrei Lalaev 
253*bf1bb26fSAndrei Lalaev 	seq_printf(seq_file, "%X%X%X\n", data->serial_number[0],
254*bf1bb26fSAndrei Lalaev 		   data->serial_number[1], data->serial_number[2]);
255*bf1bb26fSAndrei Lalaev 	return 0;
256*bf1bb26fSAndrei Lalaev }
257*bf1bb26fSAndrei Lalaev 
258*bf1bb26fSAndrei Lalaev DEFINE_SHOW_ATTRIBUTE(serial_number);
259*bf1bb26fSAndrei Lalaev 
260*bf1bb26fSAndrei Lalaev static struct attribute *htu31_attrs[] = {
261*bf1bb26fSAndrei Lalaev 	&dev_attr_heater_enable.attr,
262*bf1bb26fSAndrei Lalaev 	NULL
263*bf1bb26fSAndrei Lalaev };
264*bf1bb26fSAndrei Lalaev 
265*bf1bb26fSAndrei Lalaev ATTRIBUTE_GROUPS(htu31);
266*bf1bb26fSAndrei Lalaev 
267*bf1bb26fSAndrei Lalaev static const struct hwmon_channel_info * const htu31_info[] = {
268*bf1bb26fSAndrei Lalaev 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
269*bf1bb26fSAndrei Lalaev 	HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT),
270*bf1bb26fSAndrei Lalaev 	NULL
271*bf1bb26fSAndrei Lalaev };
272*bf1bb26fSAndrei Lalaev 
273*bf1bb26fSAndrei Lalaev static const struct hwmon_ops htu31_hwmon_ops = {
274*bf1bb26fSAndrei Lalaev 	.is_visible = htu31_is_visible,
275*bf1bb26fSAndrei Lalaev 	.read = htu31_read,
276*bf1bb26fSAndrei Lalaev };
277*bf1bb26fSAndrei Lalaev 
278*bf1bb26fSAndrei Lalaev static const struct hwmon_chip_info htu31_chip_info = {
279*bf1bb26fSAndrei Lalaev 	.info = htu31_info,
280*bf1bb26fSAndrei Lalaev 	.ops = &htu31_hwmon_ops,
281*bf1bb26fSAndrei Lalaev };
282*bf1bb26fSAndrei Lalaev 
283*bf1bb26fSAndrei Lalaev static int htu31_probe(struct i2c_client *client)
284*bf1bb26fSAndrei Lalaev {
285*bf1bb26fSAndrei Lalaev 	struct device *dev = &client->dev;
286*bf1bb26fSAndrei Lalaev 	struct device *hwmon_dev;
287*bf1bb26fSAndrei Lalaev 	struct htu31_data *data;
288*bf1bb26fSAndrei Lalaev 	int ret;
289*bf1bb26fSAndrei Lalaev 
290*bf1bb26fSAndrei Lalaev 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
291*bf1bb26fSAndrei Lalaev 	if (!data)
292*bf1bb26fSAndrei Lalaev 		return -ENOMEM;
293*bf1bb26fSAndrei Lalaev 
294*bf1bb26fSAndrei Lalaev 	data->client = client;
295*bf1bb26fSAndrei Lalaev 	data->wait_time = HTU31_TEMPERATURE_CONV_TIME + HTU31_HUMIDITY_CONV_TIME;
296*bf1bb26fSAndrei Lalaev 
297*bf1bb26fSAndrei Lalaev 	ret = devm_mutex_init(dev, &data->lock);
298*bf1bb26fSAndrei Lalaev 	if (ret)
299*bf1bb26fSAndrei Lalaev 		return ret;
300*bf1bb26fSAndrei Lalaev 
301*bf1bb26fSAndrei Lalaev 	crc8_populate_msb(htu31_crc8_table, HTU31_CRC8_POLYNOMIAL);
302*bf1bb26fSAndrei Lalaev 
303*bf1bb26fSAndrei Lalaev 	ret = htu31_read_serial_number(data);
304*bf1bb26fSAndrei Lalaev 	if (ret) {
305*bf1bb26fSAndrei Lalaev 		dev_err(dev, "Failed to read serial number\n");
306*bf1bb26fSAndrei Lalaev 		return ret;
307*bf1bb26fSAndrei Lalaev 	}
308*bf1bb26fSAndrei Lalaev 
309*bf1bb26fSAndrei Lalaev 	debugfs_create_file("serial_number",
310*bf1bb26fSAndrei Lalaev 			    0444,
311*bf1bb26fSAndrei Lalaev 			    client->debugfs,
312*bf1bb26fSAndrei Lalaev 			    data,
313*bf1bb26fSAndrei Lalaev 			    &serial_number_fops);
314*bf1bb26fSAndrei Lalaev 
315*bf1bb26fSAndrei Lalaev 	hwmon_dev = devm_hwmon_device_register_with_info(dev,
316*bf1bb26fSAndrei Lalaev 							 client->name,
317*bf1bb26fSAndrei Lalaev 							 data,
318*bf1bb26fSAndrei Lalaev 							 &htu31_chip_info,
319*bf1bb26fSAndrei Lalaev 							 htu31_groups);
320*bf1bb26fSAndrei Lalaev 
321*bf1bb26fSAndrei Lalaev 	return PTR_ERR_OR_ZERO(hwmon_dev);
322*bf1bb26fSAndrei Lalaev }
323*bf1bb26fSAndrei Lalaev 
324*bf1bb26fSAndrei Lalaev static const struct i2c_device_id htu31_id[] = {
325*bf1bb26fSAndrei Lalaev 	{ "htu31" },
326*bf1bb26fSAndrei Lalaev 	{ }
327*bf1bb26fSAndrei Lalaev };
328*bf1bb26fSAndrei Lalaev MODULE_DEVICE_TABLE(i2c, htu31_id);
329*bf1bb26fSAndrei Lalaev 
330*bf1bb26fSAndrei Lalaev #if IS_ENABLED(CONFIG_OF)
331*bf1bb26fSAndrei Lalaev static const struct of_device_id htu31_of_match[] = {
332*bf1bb26fSAndrei Lalaev 	{ .compatible = "meas,htu31" },
333*bf1bb26fSAndrei Lalaev 	{ }
334*bf1bb26fSAndrei Lalaev };
335*bf1bb26fSAndrei Lalaev MODULE_DEVICE_TABLE(of, htu31_of_match);
336*bf1bb26fSAndrei Lalaev #endif
337*bf1bb26fSAndrei Lalaev 
338*bf1bb26fSAndrei Lalaev static struct i2c_driver htu31_driver = {
339*bf1bb26fSAndrei Lalaev 	.driver = {
340*bf1bb26fSAndrei Lalaev 		.name = "htu31",
341*bf1bb26fSAndrei Lalaev 		.of_match_table = of_match_ptr(htu31_of_match),
342*bf1bb26fSAndrei Lalaev 	},
343*bf1bb26fSAndrei Lalaev 	.probe = htu31_probe,
344*bf1bb26fSAndrei Lalaev 	.id_table = htu31_id,
345*bf1bb26fSAndrei Lalaev };
346*bf1bb26fSAndrei Lalaev module_i2c_driver(htu31_driver);
347*bf1bb26fSAndrei Lalaev 
348*bf1bb26fSAndrei Lalaev MODULE_AUTHOR("Andrei Lalaev <andrey.lalaev@gmail.com>");
349*bf1bb26fSAndrei Lalaev MODULE_DESCRIPTION("HTU31 Temperature and Humidity sensor driver");
350*bf1bb26fSAndrei Lalaev MODULE_LICENSE("GPL");
351