1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * hdc2010.c - Support for the TI HDC2010 and HDC2080 4 * temperature + relative humidity sensors 5 * 6 * Copyright (C) 2020 Norphonic AS 7 * Author: Eugene Zaikonnikov <ez@norphonic.com> 8 * 9 * Datasheet: https://www.ti.com/product/HDC2010/datasheet 10 * Datasheet: https://www.ti.com/product/HDC2080/datasheet 11 */ 12 13 #include <linux/module.h> 14 #include <linux/init.h> 15 #include <linux/i2c.h> 16 #include <linux/bitops.h> 17 18 #include <linux/iio/iio.h> 19 #include <linux/iio/sysfs.h> 20 21 #define HDC2010_REG_TEMP_LOW 0x00 22 #define HDC2010_REG_TEMP_HIGH 0x01 23 #define HDC2010_REG_HUMIDITY_LOW 0x02 24 #define HDC2010_REG_HUMIDITY_HIGH 0x03 25 #define HDC2010_REG_INTERRUPT_DRDY 0x04 26 #define HDC2010_REG_TEMP_MAX 0x05 27 #define HDC2010_REG_HUMIDITY_MAX 0x06 28 #define HDC2010_REG_INTERRUPT_EN 0x07 29 #define HDC2010_REG_TEMP_OFFSET_ADJ 0x08 30 #define HDC2010_REG_HUMIDITY_OFFSET_ADJ 0x09 31 #define HDC2010_REG_TEMP_THR_L 0x0a 32 #define HDC2010_REG_TEMP_THR_H 0x0b 33 #define HDC2010_REG_RH_THR_L 0x0c 34 #define HDC2010_REG_RH_THR_H 0x0d 35 #define HDC2010_REG_RESET_DRDY_INT_CONF 0x0e 36 #define HDC2010_REG_MEASUREMENT_CONF 0x0f 37 38 #define HDC2010_MEAS_CONF GENMASK(2, 1) 39 #define HDC2010_MEAS_TRIG BIT(0) 40 #define HDC2010_HEATER_EN BIT(3) 41 #define HDC2010_AMM GENMASK(6, 4) 42 43 struct hdc2010_data { 44 struct i2c_client *client; 45 struct mutex lock; 46 u8 measurement_config; 47 u8 interrupt_config; 48 u8 drdy_config; 49 }; 50 51 enum hdc2010_addr_groups { 52 HDC2010_GROUP_TEMP = 0, 53 HDC2010_GROUP_HUMIDITY, 54 }; 55 56 struct hdc2010_reg_record { 57 unsigned long primary; 58 unsigned long peak; 59 }; 60 61 static const struct hdc2010_reg_record hdc2010_reg_translation[] = { 62 [HDC2010_GROUP_TEMP] = { 63 .primary = HDC2010_REG_TEMP_LOW, 64 .peak = HDC2010_REG_TEMP_MAX, 65 }, 66 [HDC2010_GROUP_HUMIDITY] = { 67 .primary = HDC2010_REG_HUMIDITY_LOW, 68 .peak = HDC2010_REG_HUMIDITY_MAX, 69 }, 70 }; 71 72 static IIO_CONST_ATTR(out_current_heater_raw_available, "0 1"); 73 74 static struct attribute *hdc2010_attributes[] = { 75 &iio_const_attr_out_current_heater_raw_available.dev_attr.attr, 76 NULL 77 }; 78 79 static const struct attribute_group hdc2010_attribute_group = { 80 .attrs = hdc2010_attributes, 81 }; 82 83 static const struct iio_chan_spec hdc2010_channels[] = { 84 { 85 .type = IIO_TEMP, 86 .address = HDC2010_GROUP_TEMP, 87 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 88 BIT(IIO_CHAN_INFO_PEAK) | 89 BIT(IIO_CHAN_INFO_OFFSET) | 90 BIT(IIO_CHAN_INFO_SCALE), 91 }, 92 { 93 .type = IIO_HUMIDITYRELATIVE, 94 .address = HDC2010_GROUP_HUMIDITY, 95 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 96 BIT(IIO_CHAN_INFO_PEAK) | 97 BIT(IIO_CHAN_INFO_SCALE), 98 }, 99 { 100 .type = IIO_CURRENT, 101 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 102 .extend_name = "heater", 103 .output = 1, 104 }, 105 }; 106 107 static int hdc2010_update_drdy_config(struct hdc2010_data *data, 108 char mask, char val) 109 { 110 u8 tmp = (~mask & data->drdy_config) | val; 111 int ret; 112 113 ret = i2c_smbus_write_byte_data(data->client, 114 HDC2010_REG_RESET_DRDY_INT_CONF, tmp); 115 if (ret) 116 return ret; 117 118 data->drdy_config = tmp; 119 120 return 0; 121 } 122 123 static int hdc2010_get_prim_measurement_word(struct hdc2010_data *data, 124 struct iio_chan_spec const *chan) 125 { 126 struct i2c_client *client = data->client; 127 s32 ret; 128 129 ret = i2c_smbus_read_word_data(client, 130 hdc2010_reg_translation[chan->address].primary); 131 132 if (ret < 0) 133 dev_err(&client->dev, "Could not read sensor measurement word\n"); 134 135 return ret; 136 } 137 138 static int hdc2010_get_peak_measurement_byte(struct hdc2010_data *data, 139 struct iio_chan_spec const *chan) 140 { 141 struct i2c_client *client = data->client; 142 s32 ret; 143 144 ret = i2c_smbus_read_byte_data(client, 145 hdc2010_reg_translation[chan->address].peak); 146 147 if (ret < 0) 148 dev_err(&client->dev, "Could not read sensor measurement byte\n"); 149 150 return ret; 151 } 152 153 static int hdc2010_get_heater_status(struct hdc2010_data *data) 154 { 155 return !!(data->drdy_config & HDC2010_HEATER_EN); 156 } 157 158 static int hdc2010_read_raw(struct iio_dev *indio_dev, 159 struct iio_chan_spec const *chan, int *val, 160 int *val2, long mask) 161 { 162 struct hdc2010_data *data = iio_priv(indio_dev); 163 164 switch (mask) { 165 case IIO_CHAN_INFO_RAW: { 166 int ret; 167 168 if (chan->type == IIO_CURRENT) { 169 *val = hdc2010_get_heater_status(data); 170 return IIO_VAL_INT; 171 } 172 ret = iio_device_claim_direct_mode(indio_dev); 173 if (ret) 174 return ret; 175 mutex_lock(&data->lock); 176 ret = hdc2010_get_prim_measurement_word(data, chan); 177 mutex_unlock(&data->lock); 178 iio_device_release_direct_mode(indio_dev); 179 if (ret < 0) 180 return ret; 181 *val = ret; 182 return IIO_VAL_INT; 183 } 184 case IIO_CHAN_INFO_PEAK: { 185 int ret; 186 187 ret = iio_device_claim_direct_mode(indio_dev); 188 if (ret) 189 return ret; 190 mutex_lock(&data->lock); 191 ret = hdc2010_get_peak_measurement_byte(data, chan); 192 mutex_unlock(&data->lock); 193 iio_device_release_direct_mode(indio_dev); 194 if (ret < 0) 195 return ret; 196 /* Scaling up the value so we can use same offset as RAW */ 197 *val = ret * 256; 198 return IIO_VAL_INT; 199 } 200 case IIO_CHAN_INFO_SCALE: 201 *val2 = 65536; 202 if (chan->type == IIO_TEMP) 203 *val = 165000; 204 else 205 *val = 100000; 206 return IIO_VAL_FRACTIONAL; 207 case IIO_CHAN_INFO_OFFSET: 208 *val = -15887; 209 *val2 = 515151; 210 return IIO_VAL_INT_PLUS_MICRO; 211 default: 212 return -EINVAL; 213 } 214 } 215 216 static int hdc2010_write_raw(struct iio_dev *indio_dev, 217 struct iio_chan_spec const *chan, 218 int val, int val2, long mask) 219 { 220 struct hdc2010_data *data = iio_priv(indio_dev); 221 int new, ret; 222 223 switch (mask) { 224 case IIO_CHAN_INFO_RAW: 225 if (chan->type != IIO_CURRENT || val2 != 0) 226 return -EINVAL; 227 228 switch (val) { 229 case 1: 230 new = HDC2010_HEATER_EN; 231 break; 232 case 0: 233 new = 0; 234 break; 235 default: 236 return -EINVAL; 237 } 238 239 mutex_lock(&data->lock); 240 ret = hdc2010_update_drdy_config(data, HDC2010_HEATER_EN, new); 241 mutex_unlock(&data->lock); 242 return ret; 243 default: 244 return -EINVAL; 245 } 246 } 247 248 static const struct iio_info hdc2010_info = { 249 .read_raw = hdc2010_read_raw, 250 .write_raw = hdc2010_write_raw, 251 .attrs = &hdc2010_attribute_group, 252 }; 253 254 static int hdc2010_probe(struct i2c_client *client) 255 { 256 struct iio_dev *indio_dev; 257 struct hdc2010_data *data; 258 u8 tmp; 259 int ret; 260 261 if (!i2c_check_functionality(client->adapter, 262 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C)) 263 return -EOPNOTSUPP; 264 265 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 266 if (!indio_dev) 267 return -ENOMEM; 268 269 data = iio_priv(indio_dev); 270 i2c_set_clientdata(client, indio_dev); 271 data->client = client; 272 mutex_init(&data->lock); 273 274 /* 275 * As DEVICE ID register does not differentiate between 276 * HDC2010 and HDC2080, we have the name hardcoded 277 */ 278 indio_dev->name = "hdc2010"; 279 indio_dev->modes = INDIO_DIRECT_MODE; 280 indio_dev->info = &hdc2010_info; 281 282 indio_dev->channels = hdc2010_channels; 283 indio_dev->num_channels = ARRAY_SIZE(hdc2010_channels); 284 285 /* Enable Automatic Measurement Mode at 5Hz */ 286 ret = hdc2010_update_drdy_config(data, HDC2010_AMM, HDC2010_AMM); 287 if (ret) 288 return ret; 289 290 /* 291 * We enable both temp and humidity measurement. 292 * However the measurement won't start even in AMM until triggered. 293 */ 294 tmp = (data->measurement_config & ~HDC2010_MEAS_CONF) | 295 HDC2010_MEAS_TRIG; 296 297 ret = i2c_smbus_write_byte_data(client, HDC2010_REG_MEASUREMENT_CONF, tmp); 298 if (ret) { 299 dev_warn(&client->dev, "Unable to set up measurement\n"); 300 if (hdc2010_update_drdy_config(data, HDC2010_AMM, 0)) 301 dev_warn(&client->dev, "Unable to restore default AMM\n"); 302 return ret; 303 } 304 305 data->measurement_config = tmp; 306 307 return iio_device_register(indio_dev); 308 } 309 310 static void hdc2010_remove(struct i2c_client *client) 311 { 312 struct iio_dev *indio_dev = i2c_get_clientdata(client); 313 struct hdc2010_data *data = iio_priv(indio_dev); 314 315 iio_device_unregister(indio_dev); 316 317 /* Disable Automatic Measurement Mode */ 318 if (hdc2010_update_drdy_config(data, HDC2010_AMM, 0)) 319 dev_warn(&client->dev, "Unable to restore default AMM\n"); 320 } 321 322 static const struct i2c_device_id hdc2010_id[] = { 323 { "hdc2010" }, 324 { "hdc2080" }, 325 { } 326 }; 327 MODULE_DEVICE_TABLE(i2c, hdc2010_id); 328 329 static const struct of_device_id hdc2010_dt_ids[] = { 330 { .compatible = "ti,hdc2010" }, 331 { .compatible = "ti,hdc2080" }, 332 { } 333 }; 334 MODULE_DEVICE_TABLE(of, hdc2010_dt_ids); 335 336 static struct i2c_driver hdc2010_driver = { 337 .driver = { 338 .name = "hdc2010", 339 .of_match_table = hdc2010_dt_ids, 340 }, 341 .probe_new = hdc2010_probe, 342 .remove = hdc2010_remove, 343 .id_table = hdc2010_id, 344 }; 345 module_i2c_driver(hdc2010_driver); 346 347 MODULE_AUTHOR("Eugene Zaikonnikov <ez@norphonic.com>"); 348 MODULE_DESCRIPTION("TI HDC2010 humidity and temperature sensor driver"); 349 MODULE_LICENSE("GPL"); 350