root/drivers/iio/humidity/si7005.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. si7005_read_measurement
  2. si7005_read_raw
  3. si7005_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * si7005.c - Support for Silabs Si7005 humidity and temperature sensor
   4  *
   5  * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
   6  *
   7  * (7-bit I2C slave address 0x40)
   8  *
   9  * TODO: heater, fast mode, processed mode (temp. / linearity compensation)
  10  */
  11 
  12 #include <linux/err.h>
  13 #include <linux/i2c.h>
  14 #include <linux/delay.h>
  15 #include <linux/module.h>
  16 #include <linux/pm.h>
  17 
  18 #include <linux/iio/iio.h>
  19 #include <linux/iio/sysfs.h>
  20 
  21 #define SI7005_STATUS 0x00
  22 #define SI7005_DATA 0x01 /* 16-bit, MSB */
  23 #define SI7005_CONFIG 0x03
  24 #define SI7005_ID 0x11
  25 
  26 #define SI7005_STATUS_NRDY BIT(0)
  27 #define SI7005_CONFIG_TEMP BIT(4)
  28 #define SI7005_CONFIG_START BIT(0)
  29 
  30 #define SI7005_ID_7005 0x50
  31 #define SI7005_ID_7015 0xf0
  32 
  33 struct si7005_data {
  34         struct i2c_client *client;
  35         struct mutex lock;
  36         u8 config;
  37 };
  38 
  39 static int si7005_read_measurement(struct si7005_data *data, bool temp)
  40 {
  41         int tries = 50;
  42         int ret;
  43 
  44         mutex_lock(&data->lock);
  45 
  46         ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG,
  47                 data->config | SI7005_CONFIG_START |
  48                 (temp ? SI7005_CONFIG_TEMP : 0));
  49         if (ret < 0)
  50                 goto done;
  51 
  52         while (tries-- > 0) {
  53                 msleep(20);
  54                 ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS);
  55                 if (ret < 0)
  56                         goto done;
  57                 if (!(ret & SI7005_STATUS_NRDY))
  58                         break;
  59         }
  60         if (tries < 0) {
  61                 ret = -EIO;
  62                 goto done;
  63         }
  64 
  65         ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA);
  66 
  67 done:
  68         mutex_unlock(&data->lock);
  69 
  70         return ret;
  71 }
  72 
  73 static int si7005_read_raw(struct iio_dev *indio_dev,
  74                             struct iio_chan_spec const *chan, int *val,
  75                             int *val2, long mask)
  76 {
  77         struct si7005_data *data = iio_priv(indio_dev);
  78         int ret;
  79 
  80         switch (mask) {
  81         case IIO_CHAN_INFO_RAW:
  82                 ret = si7005_read_measurement(data, chan->type == IIO_TEMP);
  83                 if (ret < 0)
  84                         return ret;
  85                 *val = ret;
  86                 return IIO_VAL_INT;
  87         case IIO_CHAN_INFO_SCALE:
  88                 if (chan->type == IIO_TEMP) {
  89                         *val = 7;
  90                         *val2 = 812500;
  91                 } else {
  92                         *val = 3;
  93                         *val2 = 906250;
  94                 }
  95                 return IIO_VAL_INT_PLUS_MICRO;
  96         case IIO_CHAN_INFO_OFFSET:
  97                 if (chan->type == IIO_TEMP)
  98                         *val = -50 * 32 * 4;
  99                 else
 100                         *val = -24 * 16 * 16;
 101                 return IIO_VAL_INT;
 102         default:
 103                 break;
 104         }
 105 
 106         return -EINVAL;
 107 }
 108 
 109 static const struct iio_chan_spec si7005_channels[] = {
 110         {
 111                 .type = IIO_HUMIDITYRELATIVE,
 112                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 113                         BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
 114         },
 115         {
 116                 .type = IIO_TEMP,
 117                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 118                         BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET),
 119         }
 120 };
 121 
 122 static const struct iio_info si7005_info = {
 123         .read_raw = si7005_read_raw,
 124 };
 125 
 126 static int si7005_probe(struct i2c_client *client,
 127                          const struct i2c_device_id *id)
 128 {
 129         struct iio_dev *indio_dev;
 130         struct si7005_data *data;
 131         int ret;
 132 
 133         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
 134                 return -EOPNOTSUPP;
 135 
 136         indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
 137         if (!indio_dev)
 138                 return -ENOMEM;
 139 
 140         data = iio_priv(indio_dev);
 141         i2c_set_clientdata(client, indio_dev);
 142         data->client = client;
 143         mutex_init(&data->lock);
 144 
 145         indio_dev->dev.parent = &client->dev;
 146         indio_dev->name = dev_name(&client->dev);
 147         indio_dev->modes = INDIO_DIRECT_MODE;
 148         indio_dev->info = &si7005_info;
 149 
 150         indio_dev->channels = si7005_channels;
 151         indio_dev->num_channels = ARRAY_SIZE(si7005_channels);
 152 
 153         ret = i2c_smbus_read_byte_data(client, SI7005_ID);
 154         if (ret < 0)
 155                 return ret;
 156         if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015)
 157                 return -ENODEV;
 158 
 159         ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG);
 160         if (ret < 0)
 161                 return ret;
 162         data->config = ret;
 163 
 164         return devm_iio_device_register(&client->dev, indio_dev);
 165 }
 166 
 167 static const struct i2c_device_id si7005_id[] = {
 168         { "si7005", 0 },
 169         { "th02", 0 },
 170         { }
 171 };
 172 MODULE_DEVICE_TABLE(i2c, si7005_id);
 173 
 174 static struct i2c_driver si7005_driver = {
 175         .driver = {
 176                 .name   = "si7005",
 177         },
 178         .probe = si7005_probe,
 179         .id_table = si7005_id,
 180 };
 181 module_i2c_driver(si7005_driver);
 182 
 183 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
 184 MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver");
 185 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */