linux/drivers/iio/humidity/hdc100x.c
<<
>>
Prefs
   1/*
   2 * hdc100x.c - Support for the TI HDC100x temperature + humidity sensors
   3 *
   4 * Copyright (C) 2015 Matt Ranostay <mranostay@gmail.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 * GNU General Public License for more details.
  15 *
  16 */
  17
  18#include <linux/delay.h>
  19#include <linux/module.h>
  20#include <linux/init.h>
  21#include <linux/i2c.h>
  22
  23#include <linux/iio/iio.h>
  24#include <linux/iio/sysfs.h>
  25
  26#define HDC100X_REG_TEMP                        0x00
  27#define HDC100X_REG_HUMIDITY                    0x01
  28
  29#define HDC100X_REG_CONFIG                      0x02
  30#define HDC100X_REG_CONFIG_HEATER_EN            BIT(13)
  31
  32struct hdc100x_data {
  33        struct i2c_client *client;
  34        struct mutex lock;
  35        u16 config;
  36
  37        /* integration time of the sensor */
  38        int adc_int_us[2];
  39};
  40
  41/* integration time in us */
  42static const int hdc100x_int_time[][3] = {
  43        { 6350, 3650, 0 },      /* IIO_TEMP channel*/
  44        { 6500, 3850, 2500 },   /* IIO_HUMIDITYRELATIVE channel */
  45};
  46
  47/* HDC100X_REG_CONFIG shift and mask values */
  48static const struct {
  49        int shift;
  50        int mask;
  51} hdc100x_resolution_shift[2] = {
  52        { /* IIO_TEMP channel */
  53                .shift = 10,
  54                .mask = 1
  55        },
  56        { /* IIO_HUMIDITYRELATIVE channel */
  57                .shift = 8,
  58                .mask = 3,
  59        },
  60};
  61
  62static IIO_CONST_ATTR(temp_integration_time_available,
  63                "0.00365 0.00635");
  64
  65static IIO_CONST_ATTR(humidityrelative_integration_time_available,
  66                "0.0025 0.00385 0.0065");
  67
  68static IIO_CONST_ATTR(out_current_heater_raw_available,
  69                "0 1");
  70
  71static struct attribute *hdc100x_attributes[] = {
  72        &iio_const_attr_temp_integration_time_available.dev_attr.attr,
  73        &iio_const_attr_humidityrelative_integration_time_available.dev_attr.attr,
  74        &iio_const_attr_out_current_heater_raw_available.dev_attr.attr,
  75        NULL
  76};
  77
  78static struct attribute_group hdc100x_attribute_group = {
  79        .attrs = hdc100x_attributes,
  80};
  81
  82static const struct iio_chan_spec hdc100x_channels[] = {
  83        {
  84                .type = IIO_TEMP,
  85                .address = HDC100X_REG_TEMP,
  86                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  87                        BIT(IIO_CHAN_INFO_SCALE) |
  88                        BIT(IIO_CHAN_INFO_INT_TIME) |
  89                        BIT(IIO_CHAN_INFO_OFFSET),
  90        },
  91        {
  92                .type = IIO_HUMIDITYRELATIVE,
  93                .address = HDC100X_REG_HUMIDITY,
  94                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  95                        BIT(IIO_CHAN_INFO_SCALE) |
  96                        BIT(IIO_CHAN_INFO_INT_TIME)
  97        },
  98        {
  99                .type = IIO_CURRENT,
 100                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
 101                .extend_name = "heater",
 102                .output = 1,
 103        },
 104};
 105
 106static int hdc100x_update_config(struct hdc100x_data *data, int mask, int val)
 107{
 108        int tmp = (~mask & data->config) | val;
 109        int ret;
 110
 111        ret = i2c_smbus_write_word_swapped(data->client,
 112                                                HDC100X_REG_CONFIG, tmp);
 113        if (!ret)
 114                data->config = tmp;
 115
 116        return ret;
 117}
 118
 119static int hdc100x_set_it_time(struct hdc100x_data *data, int chan, int val2)
 120{
 121        int shift = hdc100x_resolution_shift[chan].shift;
 122        int ret = -EINVAL;
 123        int i;
 124
 125        for (i = 0; i < ARRAY_SIZE(hdc100x_int_time[chan]); i++) {
 126                if (val2 && val2 == hdc100x_int_time[chan][i]) {
 127                        ret = hdc100x_update_config(data,
 128                                hdc100x_resolution_shift[chan].mask << shift,
 129                                i << shift);
 130                        if (!ret)
 131                                data->adc_int_us[chan] = val2;
 132                        break;
 133                }
 134        }
 135
 136        return ret;
 137}
 138
 139static int hdc100x_get_measurement(struct hdc100x_data *data,
 140                                   struct iio_chan_spec const *chan)
 141{
 142        struct i2c_client *client = data->client;
 143        int delay = data->adc_int_us[chan->address];
 144        int ret;
 145        __be16 val;
 146
 147        /* start measurement */
 148        ret = i2c_smbus_write_byte(client, chan->address);
 149        if (ret < 0) {
 150                dev_err(&client->dev, "cannot start measurement");
 151                return ret;
 152        }
 153
 154        /* wait for integration time to pass */
 155        usleep_range(delay, delay + 1000);
 156
 157        /* read measurement */
 158        ret = i2c_master_recv(data->client, (char *)&val, sizeof(val));
 159        if (ret < 0) {
 160                dev_err(&client->dev, "cannot read sensor data\n");
 161                return ret;
 162        }
 163        return be16_to_cpu(val);
 164}
 165
 166static int hdc100x_get_heater_status(struct hdc100x_data *data)
 167{
 168        return !!(data->config & HDC100X_REG_CONFIG_HEATER_EN);
 169}
 170
 171static int hdc100x_read_raw(struct iio_dev *indio_dev,
 172                            struct iio_chan_spec const *chan, int *val,
 173                            int *val2, long mask)
 174{
 175        struct hdc100x_data *data = iio_priv(indio_dev);
 176
 177        switch (mask) {
 178        case IIO_CHAN_INFO_RAW: {
 179                int ret;
 180
 181                mutex_lock(&data->lock);
 182                if (chan->type == IIO_CURRENT) {
 183                        *val = hdc100x_get_heater_status(data);
 184                        ret = IIO_VAL_INT;
 185                } else {
 186                        ret = hdc100x_get_measurement(data, chan);
 187                        if (ret >= 0) {
 188                                *val = ret;
 189                                ret = IIO_VAL_INT;
 190                        }
 191                }
 192                mutex_unlock(&data->lock);
 193                return ret;
 194        }
 195        case IIO_CHAN_INFO_INT_TIME:
 196                *val = 0;
 197                *val2 = data->adc_int_us[chan->address];
 198                return IIO_VAL_INT_PLUS_MICRO;
 199        case IIO_CHAN_INFO_SCALE:
 200                if (chan->type == IIO_TEMP) {
 201                        *val = 165000;
 202                        *val2 = 65536;
 203                        return IIO_VAL_FRACTIONAL;
 204                } else {
 205                        *val = 100;
 206                        *val2 = 65536;
 207                        return IIO_VAL_FRACTIONAL;
 208                }
 209                break;
 210        case IIO_CHAN_INFO_OFFSET:
 211                *val = -15887;
 212                *val2 = 515151;
 213                return IIO_VAL_INT_PLUS_MICRO;
 214        default:
 215                return -EINVAL;
 216        }
 217}
 218
 219static int hdc100x_write_raw(struct iio_dev *indio_dev,
 220                             struct iio_chan_spec const *chan,
 221                             int val, int val2, long mask)
 222{
 223        struct hdc100x_data *data = iio_priv(indio_dev);
 224        int ret = -EINVAL;
 225
 226        switch (mask) {
 227        case IIO_CHAN_INFO_INT_TIME:
 228                if (val != 0)
 229                        return -EINVAL;
 230
 231                mutex_lock(&data->lock);
 232                ret = hdc100x_set_it_time(data, chan->address, val2);
 233                mutex_unlock(&data->lock);
 234                return ret;
 235        case IIO_CHAN_INFO_RAW:
 236                if (chan->type != IIO_CURRENT || val2 != 0)
 237                        return -EINVAL;
 238
 239                mutex_lock(&data->lock);
 240                ret = hdc100x_update_config(data, HDC100X_REG_CONFIG_HEATER_EN,
 241                                        val ? HDC100X_REG_CONFIG_HEATER_EN : 0);
 242                mutex_unlock(&data->lock);
 243                return ret;
 244        default:
 245                return -EINVAL;
 246        }
 247}
 248
 249static const struct iio_info hdc100x_info = {
 250        .read_raw = hdc100x_read_raw,
 251        .write_raw = hdc100x_write_raw,
 252        .attrs = &hdc100x_attribute_group,
 253        .driver_module = THIS_MODULE,
 254};
 255
 256static int hdc100x_probe(struct i2c_client *client,
 257                         const struct i2c_device_id *id)
 258{
 259        struct iio_dev *indio_dev;
 260        struct hdc100x_data *data;
 261
 262        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA |
 263                                     I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
 264                return -EOPNOTSUPP;
 265
 266        indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 267        if (!indio_dev)
 268                return -ENOMEM;
 269
 270        data = iio_priv(indio_dev);
 271        i2c_set_clientdata(client, indio_dev);
 272        data->client = client;
 273        mutex_init(&data->lock);
 274
 275        indio_dev->dev.parent = &client->dev;
 276        indio_dev->name = dev_name(&client->dev);
 277        indio_dev->modes = INDIO_DIRECT_MODE;
 278        indio_dev->info = &hdc100x_info;
 279
 280        indio_dev->channels = hdc100x_channels;
 281        indio_dev->num_channels = ARRAY_SIZE(hdc100x_channels);
 282
 283        /* be sure we are in a known state */
 284        hdc100x_set_it_time(data, 0, hdc100x_int_time[0][0]);
 285        hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]);
 286
 287        return devm_iio_device_register(&client->dev, indio_dev);
 288}
 289
 290static const struct i2c_device_id hdc100x_id[] = {
 291        { "hdc100x", 0 },
 292        { }
 293};
 294MODULE_DEVICE_TABLE(i2c, hdc100x_id);
 295
 296static struct i2c_driver hdc100x_driver = {
 297        .driver = {
 298                .name   = "hdc100x",
 299        },
 300        .probe = hdc100x_probe,
 301        .id_table = hdc100x_id,
 302};
 303module_i2c_driver(hdc100x_driver);
 304
 305MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
 306MODULE_DESCRIPTION("TI HDC100x humidity and temperature sensor driver");
 307MODULE_LICENSE("GPL");
 308