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