1 // SPDX-License-Identifier: GPL-2.0+
3 * hdc2010.c - Support for the TI HDC2010 and HDC2080
4 * temperature + relative humidity sensors
6 * Copyright (C) 2020 Norphonic AS
7 * Author: Eugene Zaikonnikov <ez@norphonic.com>
9 * Datasheet: https://www.ti.com/product/HDC2010/datasheet
10 * Datasheet: https://www.ti.com/product/HDC2080/datasheet
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/i2c.h>
16 #include <linux/bitops.h>
18 #include <linux/iio/iio.h>
19 #include <linux/iio/sysfs.h>
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
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)
44 struct i2c_client
*client
;
46 u8 measurement_config
;
51 enum hdc2010_addr_groups
{
52 HDC2010_GROUP_TEMP
= 0,
53 HDC2010_GROUP_HUMIDITY
,
56 struct hdc2010_reg_record
{
57 unsigned long primary
;
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
,
66 [HDC2010_GROUP_HUMIDITY
] = {
67 .primary
= HDC2010_REG_HUMIDITY_LOW
,
68 .peak
= HDC2010_REG_HUMIDITY_MAX
,
72 static IIO_CONST_ATTR(out_current_heater_raw_available
, "0 1");
74 static struct attribute
*hdc2010_attributes
[] = {
75 &iio_const_attr_out_current_heater_raw_available
.dev_attr
.attr
,
79 static const struct attribute_group hdc2010_attribute_group
= {
80 .attrs
= hdc2010_attributes
,
83 static const struct iio_chan_spec hdc2010_channels
[] = {
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
),
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
),
101 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
),
102 .extend_name
= "heater",
107 static int hdc2010_update_drdy_config(struct hdc2010_data
*data
,
110 u8 tmp
= (~mask
& data
->drdy_config
) | val
;
113 ret
= i2c_smbus_write_byte_data(data
->client
,
114 HDC2010_REG_RESET_DRDY_INT_CONF
, tmp
);
118 data
->drdy_config
= tmp
;
123 static int hdc2010_get_prim_measurement_word(struct hdc2010_data
*data
,
124 struct iio_chan_spec
const *chan
)
126 struct i2c_client
*client
= data
->client
;
129 ret
= i2c_smbus_read_word_data(client
,
130 hdc2010_reg_translation
[chan
->address
].primary
);
133 dev_err(&client
->dev
, "Could not read sensor measurement word\n");
138 static int hdc2010_get_peak_measurement_byte(struct hdc2010_data
*data
,
139 struct iio_chan_spec
const *chan
)
141 struct i2c_client
*client
= data
->client
;
144 ret
= i2c_smbus_read_byte_data(client
,
145 hdc2010_reg_translation
[chan
->address
].peak
);
148 dev_err(&client
->dev
, "Could not read sensor measurement byte\n");
153 static int hdc2010_get_heater_status(struct hdc2010_data
*data
)
155 return !!(data
->drdy_config
& HDC2010_HEATER_EN
);
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
)
162 struct hdc2010_data
*data
= iio_priv(indio_dev
);
165 case IIO_CHAN_INFO_RAW
: {
168 if (chan
->type
== IIO_CURRENT
) {
169 *val
= hdc2010_get_heater_status(data
);
172 ret
= iio_device_claim_direct_mode(indio_dev
);
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
);
184 case IIO_CHAN_INFO_PEAK
: {
187 ret
= iio_device_claim_direct_mode(indio_dev
);
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
);
196 /* Scaling up the value so we can use same offset as RAW */
200 case IIO_CHAN_INFO_SCALE
:
202 if (chan
->type
== IIO_TEMP
)
206 return IIO_VAL_FRACTIONAL
;
207 case IIO_CHAN_INFO_OFFSET
:
210 return IIO_VAL_INT_PLUS_MICRO
;
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
)
220 struct hdc2010_data
*data
= iio_priv(indio_dev
);
224 case IIO_CHAN_INFO_RAW
:
225 if (chan
->type
!= IIO_CURRENT
|| val2
!= 0)
230 new = HDC2010_HEATER_EN
;
239 mutex_lock(&data
->lock
);
240 ret
= hdc2010_update_drdy_config(data
, HDC2010_HEATER_EN
, new);
241 mutex_unlock(&data
->lock
);
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
,
254 static int hdc2010_probe(struct i2c_client
*client
)
256 struct iio_dev
*indio_dev
;
257 struct hdc2010_data
*data
;
261 if (!i2c_check_functionality(client
->adapter
,
262 I2C_FUNC_SMBUS_WORD_DATA
| I2C_FUNC_SMBUS_BYTE
| I2C_FUNC_I2C
))
265 indio_dev
= devm_iio_device_alloc(&client
->dev
, sizeof(*data
));
269 data
= iio_priv(indio_dev
);
270 i2c_set_clientdata(client
, indio_dev
);
271 data
->client
= client
;
272 mutex_init(&data
->lock
);
275 * As DEVICE ID register does not differentiate between
276 * HDC2010 and HDC2080, we have the name hardcoded
278 indio_dev
->name
= "hdc2010";
279 indio_dev
->modes
= INDIO_DIRECT_MODE
;
280 indio_dev
->info
= &hdc2010_info
;
282 indio_dev
->channels
= hdc2010_channels
;
283 indio_dev
->num_channels
= ARRAY_SIZE(hdc2010_channels
);
285 /* Enable Automatic Measurement Mode at 5Hz */
286 ret
= hdc2010_update_drdy_config(data
, HDC2010_AMM
, HDC2010_AMM
);
291 * We enable both temp and humidity measurement.
292 * However the measurement won't start even in AMM until triggered.
294 tmp
= (data
->measurement_config
& ~HDC2010_MEAS_CONF
) |
297 ret
= i2c_smbus_write_byte_data(client
, HDC2010_REG_MEASUREMENT_CONF
, tmp
);
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");
305 data
->measurement_config
= tmp
;
307 return iio_device_register(indio_dev
);
310 static void hdc2010_remove(struct i2c_client
*client
)
312 struct iio_dev
*indio_dev
= i2c_get_clientdata(client
);
313 struct hdc2010_data
*data
= iio_priv(indio_dev
);
315 iio_device_unregister(indio_dev
);
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");
322 static const struct i2c_device_id hdc2010_id
[] = {
327 MODULE_DEVICE_TABLE(i2c
, hdc2010_id
);
329 static const struct of_device_id hdc2010_dt_ids
[] = {
330 { .compatible
= "ti,hdc2010" },
331 { .compatible
= "ti,hdc2080" },
334 MODULE_DEVICE_TABLE(of
, hdc2010_dt_ids
);
336 static struct i2c_driver hdc2010_driver
= {
339 .of_match_table
= hdc2010_dt_ids
,
341 .probe
= hdc2010_probe
,
342 .remove
= hdc2010_remove
,
343 .id_table
= hdc2010_id
,
345 module_i2c_driver(hdc2010_driver
);
347 MODULE_AUTHOR("Eugene Zaikonnikov <ez@norphonic.com>");
348 MODULE_DESCRIPTION("TI HDC2010 humidity and temperature sensor driver");
349 MODULE_LICENSE("GPL");