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