linux/drivers/hwmon/sht21.c
<<
>>
Prefs
   1/* Sensirion SHT21 humidity and temperature sensor driver
   2 *
   3 * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
  18 *
  19 * Data sheet available (5/2010) at
  20 * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
  21 */
  22
  23#include <linux/module.h>
  24#include <linux/init.h>
  25#include <linux/slab.h>
  26#include <linux/i2c.h>
  27#include <linux/hwmon.h>
  28#include <linux/hwmon-sysfs.h>
  29#include <linux/err.h>
  30#include <linux/mutex.h>
  31#include <linux/device.h>
  32#include <linux/jiffies.h>
  33
  34/* I2C command bytes */
  35#define SHT21_TRIG_T_MEASUREMENT_HM  0xe3
  36#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
  37#define SHT21_READ_SNB_CMD1 0xFA
  38#define SHT21_READ_SNB_CMD2 0x0F
  39#define SHT21_READ_SNAC_CMD1 0xFC
  40#define SHT21_READ_SNAC_CMD2 0xC9
  41
  42/**
  43 * struct sht21 - SHT21 device specific data
  44 * @hwmon_dev: device registered with hwmon
  45 * @lock: mutex to protect measurement values
  46 * @last_update: time of last update (jiffies)
  47 * @temperature: cached temperature measurement value
  48 * @humidity: cached humidity measurement value
  49 * @valid: only 0 before first measurement is taken
  50 * @eic: cached electronic identification code text
  51 */
  52struct sht21 {
  53        struct i2c_client *client;
  54        struct mutex lock;
  55        unsigned long last_update;
  56        int temperature;
  57        int humidity;
  58        char valid;
  59        char eic[18];
  60};
  61
  62/**
  63 * sht21_temp_ticks_to_millicelsius() - convert raw temperature ticks to
  64 * milli celsius
  65 * @ticks: temperature ticks value received from sensor
  66 */
  67static inline int sht21_temp_ticks_to_millicelsius(int ticks)
  68{
  69        ticks &= ~0x0003; /* clear status bits */
  70        /*
  71         * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,
  72         * optimized for integer fixed point (3 digits) arithmetic
  73         */
  74        return ((21965 * ticks) >> 13) - 46850;
  75}
  76
  77/**
  78 * sht21_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
  79 * one-thousandths of a percent relative humidity
  80 * @ticks: humidity ticks value received from sensor
  81 */
  82static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
  83{
  84        ticks &= ~0x0003; /* clear status bits */
  85        /*
  86         * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,
  87         * optimized for integer fixed point (3 digits) arithmetic
  88         */
  89        return ((15625 * ticks) >> 13) - 6000;
  90}
  91
  92/**
  93 * sht21_update_measurements() - get updated measurements from device
  94 * @dev: device
  95 *
  96 * Returns 0 on success, else negative errno.
  97 */
  98static int sht21_update_measurements(struct device *dev)
  99{
 100        int ret = 0;
 101        struct sht21 *sht21 = dev_get_drvdata(dev);
 102        struct i2c_client *client = sht21->client;
 103
 104        mutex_lock(&sht21->lock);
 105        /*
 106         * Data sheet 2.4:
 107         * SHT2x should not be active for more than 10% of the time - e.g.
 108         * maximum two measurements per second at 12bit accuracy shall be made.
 109         */
 110        if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) {
 111                ret = i2c_smbus_read_word_swapped(client,
 112                                                  SHT21_TRIG_T_MEASUREMENT_HM);
 113                if (ret < 0)
 114                        goto out;
 115                sht21->temperature = sht21_temp_ticks_to_millicelsius(ret);
 116                ret = i2c_smbus_read_word_swapped(client,
 117                                                  SHT21_TRIG_RH_MEASUREMENT_HM);
 118                if (ret < 0)
 119                        goto out;
 120                sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret);
 121                sht21->last_update = jiffies;
 122                sht21->valid = 1;
 123        }
 124out:
 125        mutex_unlock(&sht21->lock);
 126
 127        return ret >= 0 ? 0 : ret;
 128}
 129
 130/**
 131 * sht21_show_temperature() - show temperature measurement value in sysfs
 132 * @dev: device
 133 * @attr: device attribute
 134 * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
 135 *
 136 * Will be called on read access to temp1_input sysfs attribute.
 137 * Returns number of bytes written into buffer, negative errno on error.
 138 */
 139static ssize_t sht21_show_temperature(struct device *dev,
 140        struct device_attribute *attr,
 141        char *buf)
 142{
 143        struct sht21 *sht21 = dev_get_drvdata(dev);
 144        int ret;
 145
 146        ret = sht21_update_measurements(dev);
 147        if (ret < 0)
 148                return ret;
 149        return sprintf(buf, "%d\n", sht21->temperature);
 150}
 151
 152/**
 153 * sht21_show_humidity() - show humidity measurement value in sysfs
 154 * @dev: device
 155 * @attr: device attribute
 156 * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
 157 *
 158 * Will be called on read access to humidity1_input sysfs attribute.
 159 * Returns number of bytes written into buffer, negative errno on error.
 160 */
 161static ssize_t sht21_show_humidity(struct device *dev,
 162        struct device_attribute *attr,
 163        char *buf)
 164{
 165        struct sht21 *sht21 = dev_get_drvdata(dev);
 166        int ret;
 167
 168        ret = sht21_update_measurements(dev);
 169        if (ret < 0)
 170                return ret;
 171        return sprintf(buf, "%d\n", sht21->humidity);
 172}
 173
 174static ssize_t eic_read(struct sht21 *sht21)
 175{
 176        struct i2c_client *client = sht21->client;
 177        u8 tx[2];
 178        u8 rx[8];
 179        u8 eic[8];
 180        struct i2c_msg msgs[2] = {
 181                {
 182                        .addr = client->addr,
 183                        .flags = 0,
 184                        .len = 2,
 185                        .buf = tx,
 186                },
 187                {
 188                        .addr = client->addr,
 189                        .flags = I2C_M_RD,
 190                        .len = 8,
 191                        .buf = rx,
 192                },
 193        };
 194        int ret;
 195
 196        tx[0] = SHT21_READ_SNB_CMD1;
 197        tx[1] = SHT21_READ_SNB_CMD2;
 198        ret = i2c_transfer(client->adapter, msgs, 2);
 199        if (ret < 0)
 200                goto out;
 201        eic[2] = rx[0];
 202        eic[3] = rx[2];
 203        eic[4] = rx[4];
 204        eic[5] = rx[6];
 205
 206        tx[0] = SHT21_READ_SNAC_CMD1;
 207        tx[1] = SHT21_READ_SNAC_CMD2;
 208        msgs[1].len = 6;
 209        ret = i2c_transfer(client->adapter, msgs, 2);
 210        if (ret < 0)
 211                goto out;
 212        eic[0] = rx[3];
 213        eic[1] = rx[4];
 214        eic[6] = rx[0];
 215        eic[7] = rx[1];
 216
 217        ret = snprintf(sht21->eic, sizeof(sht21->eic),
 218                       "%02x%02x%02x%02x%02x%02x%02x%02x\n",
 219                       eic[0], eic[1], eic[2], eic[3],
 220                       eic[4], eic[5], eic[6], eic[7]);
 221out:
 222        if (ret < 0)
 223                sht21->eic[0] = 0;
 224
 225        return ret;
 226}
 227
 228/**
 229 * eic_show() - show Electronic Identification Code in sysfs
 230 * @dev: device
 231 * @attr: device attribute
 232 * @buf: sysfs buffer (PAGE_SIZE) where EIC is written
 233 *
 234 * Will be called on read access to eic sysfs attribute.
 235 * Returns number of bytes written into buffer, negative errno on error.
 236 */
 237static ssize_t eic_show(struct device *dev,
 238        struct device_attribute *attr,
 239        char *buf)
 240{
 241        struct sht21 *sht21 = dev_get_drvdata(dev);
 242        int ret;
 243
 244        ret = sizeof(sht21->eic) - 1;
 245        mutex_lock(&sht21->lock);
 246        if (!sht21->eic[0])
 247                ret = eic_read(sht21);
 248        if (ret > 0)
 249                memcpy(buf, sht21->eic, ret);
 250        mutex_unlock(&sht21->lock);
 251        return ret;
 252}
 253
 254/* sysfs attributes */
 255static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
 256        NULL, 0);
 257static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
 258        NULL, 0);
 259static DEVICE_ATTR_RO(eic);
 260
 261static struct attribute *sht21_attrs[] = {
 262        &sensor_dev_attr_temp1_input.dev_attr.attr,
 263        &sensor_dev_attr_humidity1_input.dev_attr.attr,
 264        &dev_attr_eic.attr,
 265        NULL
 266};
 267
 268ATTRIBUTE_GROUPS(sht21);
 269
 270static int sht21_probe(struct i2c_client *client,
 271        const struct i2c_device_id *id)
 272{
 273        struct device *dev = &client->dev;
 274        struct device *hwmon_dev;
 275        struct sht21 *sht21;
 276
 277        if (!i2c_check_functionality(client->adapter,
 278                                     I2C_FUNC_SMBUS_WORD_DATA)) {
 279                dev_err(&client->dev,
 280                        "adapter does not support SMBus word transactions\n");
 281                return -ENODEV;
 282        }
 283
 284        sht21 = devm_kzalloc(dev, sizeof(*sht21), GFP_KERNEL);
 285        if (!sht21)
 286                return -ENOMEM;
 287
 288        sht21->client = client;
 289
 290        mutex_init(&sht21->lock);
 291
 292        hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 293                                                           sht21, sht21_groups);
 294        return PTR_ERR_OR_ZERO(hwmon_dev);
 295}
 296
 297/* Device ID table */
 298static const struct i2c_device_id sht21_id[] = {
 299        { "sht21", 0 },
 300        { }
 301};
 302MODULE_DEVICE_TABLE(i2c, sht21_id);
 303
 304static struct i2c_driver sht21_driver = {
 305        .driver.name = "sht21",
 306        .probe       = sht21_probe,
 307        .id_table    = sht21_id,
 308};
 309
 310module_i2c_driver(sht21_driver);
 311
 312MODULE_AUTHOR("Urs Fleisch <urs.fleisch@sensirion.com>");
 313MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver");
 314MODULE_LICENSE("GPL");
 315