root/drivers/hwmon/hih6130.c

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

DEFINITIONS

This source file includes following definitions.
  1. hih6130_temp_ticks_to_millicelsius
  2. hih6130_rh_ticks_to_per_cent_mille
  3. hih6130_update_measurements
  4. hih6130_temperature_show
  5. hih6130_humidity_show
  6. hih6130_probe

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* Honeywell HIH-6130/HIH-6131 humidity and temperature sensor driver
   3  *
   4  * Copyright (C) 2012 Iain Paton <ipaton0@gmail.com>
   5  *
   6  * heavily based on the sht21 driver
   7  * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.com>
   8  *
   9  * Data sheets available (2012-06-22) at
  10  * http://sensing.honeywell.com/index.php?ci_id=3106&la_id=1&defId=44872
  11  */
  12 
  13 #include <linux/module.h>
  14 #include <linux/init.h>
  15 #include <linux/slab.h>
  16 #include <linux/i2c.h>
  17 #include <linux/hwmon.h>
  18 #include <linux/hwmon-sysfs.h>
  19 #include <linux/err.h>
  20 #include <linux/mutex.h>
  21 #include <linux/device.h>
  22 #include <linux/delay.h>
  23 #include <linux/jiffies.h>
  24 
  25 /**
  26  * struct hih6130 - HIH-6130 device specific data
  27  * @client: pointer to I2C client device
  28  * @lock: mutex to protect measurement values
  29  * @valid: only false before first measurement is taken
  30  * @last_update: time of last update (jiffies)
  31  * @temperature: cached temperature measurement value
  32  * @humidity: cached humidity measurement value
  33  * @write_length: length for I2C measurement request
  34  */
  35 struct hih6130 {
  36         struct i2c_client *client;
  37         struct mutex lock;
  38         bool valid;
  39         unsigned long last_update;
  40         int temperature;
  41         int humidity;
  42         size_t write_length;
  43 };
  44 
  45 /**
  46  * hih6130_temp_ticks_to_millicelsius() - convert raw temperature ticks to
  47  * milli celsius
  48  * @ticks: temperature ticks value received from sensor
  49  */
  50 static inline int hih6130_temp_ticks_to_millicelsius(int ticks)
  51 {
  52         ticks = ticks >> 2;
  53         /*
  54          * from data sheet section 5.0
  55          * Formula T = ( ticks / ( 2^14 - 2 ) ) * 165 -40
  56          */
  57         return (DIV_ROUND_CLOSEST(ticks * 1650, 16382) - 400) * 100;
  58 }
  59 
  60 /**
  61  * hih6130_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
  62  * one-thousandths of a percent relative humidity
  63  * @ticks: humidity ticks value received from sensor
  64  */
  65 static inline int hih6130_rh_ticks_to_per_cent_mille(int ticks)
  66 {
  67         ticks &= ~0xC000; /* clear status bits */
  68         /*
  69          * from data sheet section 4.0
  70          * Formula RH = ( ticks / ( 2^14 -2 ) ) * 100
  71          */
  72         return DIV_ROUND_CLOSEST(ticks * 1000, 16382) * 100;
  73 }
  74 
  75 /**
  76  * hih6130_update_measurements() - get updated measurements from device
  77  * @dev: device
  78  *
  79  * Returns 0 on success, else negative errno.
  80  */
  81 static int hih6130_update_measurements(struct device *dev)
  82 {
  83         struct hih6130 *hih6130 = dev_get_drvdata(dev);
  84         struct i2c_client *client = hih6130->client;
  85         int ret = 0;
  86         int t;
  87         unsigned char tmp[4];
  88         struct i2c_msg msgs[1] = {
  89                 {
  90                         .addr = client->addr,
  91                         .flags = I2C_M_RD,
  92                         .len = 4,
  93                         .buf = tmp,
  94                 }
  95         };
  96 
  97         mutex_lock(&hih6130->lock);
  98 
  99         /*
 100          * While the measurement can be completed in ~40ms the sensor takes
 101          * much longer to react to a change in external conditions. How quickly
 102          * it reacts depends on airflow and other factors outwith our control.
 103          * The datasheet specifies maximum 'Response time' for humidity at 8s
 104          * and temperature at 30s under specified conditions.
 105          * We therefore choose to only read the sensor at most once per second.
 106          * This trades off pointless activity polling the sensor much faster
 107          * than it can react against better response times in conditions more
 108          * favourable than specified in the datasheet.
 109          */
 110         if (time_after(jiffies, hih6130->last_update + HZ) || !hih6130->valid) {
 111 
 112                 /*
 113                  * Write to slave address to request a measurement.
 114                  * According with the datasheet it should be with no data, but
 115                  * for systems with I2C bus drivers that do not allow zero
 116                  * length packets we write one dummy byte to allow sensor
 117                  * measurements on them.
 118                  */
 119                 tmp[0] = 0;
 120                 ret = i2c_master_send(client, tmp, hih6130->write_length);
 121                 if (ret < 0)
 122                         goto out;
 123 
 124                 /* measurement cycle time is ~36.65msec */
 125                 msleep(40);
 126 
 127                 ret = i2c_transfer(client->adapter, msgs, 1);
 128                 if (ret < 0)
 129                         goto out;
 130 
 131                 if ((tmp[0] & 0xC0) != 0) {
 132                         dev_err(&client->dev, "Error while reading measurement result\n");
 133                         ret = -EIO;
 134                         goto out;
 135                 }
 136 
 137                 t = (tmp[0] << 8) + tmp[1];
 138                 hih6130->humidity = hih6130_rh_ticks_to_per_cent_mille(t);
 139 
 140                 t = (tmp[2] << 8) + tmp[3];
 141                 hih6130->temperature = hih6130_temp_ticks_to_millicelsius(t);
 142 
 143                 hih6130->last_update = jiffies;
 144                 hih6130->valid = true;
 145         }
 146 out:
 147         mutex_unlock(&hih6130->lock);
 148 
 149         return ret >= 0 ? 0 : ret;
 150 }
 151 
 152 /**
 153  * hih6130_show_temperature() - show temperature 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 temp1_input sysfs attribute.
 159  * Returns number of bytes written into buffer, negative errno on error.
 160  */
 161 static ssize_t hih6130_temperature_show(struct device *dev,
 162                                         struct device_attribute *attr,
 163                                         char *buf)
 164 {
 165         struct hih6130 *hih6130 = dev_get_drvdata(dev);
 166         int ret;
 167 
 168         ret = hih6130_update_measurements(dev);
 169         if (ret < 0)
 170                 return ret;
 171         return sprintf(buf, "%d\n", hih6130->temperature);
 172 }
 173 
 174 /**
 175  * hih6130_show_humidity() - show humidity measurement value in sysfs
 176  * @dev: device
 177  * @attr: device attribute
 178  * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
 179  *
 180  * Will be called on read access to humidity1_input sysfs attribute.
 181  * Returns number of bytes written into buffer, negative errno on error.
 182  */
 183 static ssize_t hih6130_humidity_show(struct device *dev,
 184                                      struct device_attribute *attr, char *buf)
 185 {
 186         struct hih6130 *hih6130 = dev_get_drvdata(dev);
 187         int ret;
 188 
 189         ret = hih6130_update_measurements(dev);
 190         if (ret < 0)
 191                 return ret;
 192         return sprintf(buf, "%d\n", hih6130->humidity);
 193 }
 194 
 195 /* sysfs attributes */
 196 static SENSOR_DEVICE_ATTR_RO(temp1_input, hih6130_temperature, 0);
 197 static SENSOR_DEVICE_ATTR_RO(humidity1_input, hih6130_humidity, 0);
 198 
 199 static struct attribute *hih6130_attrs[] = {
 200         &sensor_dev_attr_temp1_input.dev_attr.attr,
 201         &sensor_dev_attr_humidity1_input.dev_attr.attr,
 202         NULL
 203 };
 204 
 205 ATTRIBUTE_GROUPS(hih6130);
 206 
 207 static int hih6130_probe(struct i2c_client *client,
 208                                    const struct i2c_device_id *id)
 209 {
 210         struct device *dev = &client->dev;
 211         struct hih6130 *hih6130;
 212         struct device *hwmon_dev;
 213 
 214         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
 215                 dev_err(&client->dev, "adapter does not support true I2C\n");
 216                 return -ENODEV;
 217         }
 218 
 219         hih6130 = devm_kzalloc(dev, sizeof(*hih6130), GFP_KERNEL);
 220         if (!hih6130)
 221                 return -ENOMEM;
 222 
 223         hih6130->client = client;
 224         mutex_init(&hih6130->lock);
 225 
 226         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_QUICK))
 227                 hih6130->write_length = 1;
 228 
 229         hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 230                                                            hih6130,
 231                                                            hih6130_groups);
 232         return PTR_ERR_OR_ZERO(hwmon_dev);
 233 }
 234 
 235 /* Device ID table */
 236 static const struct i2c_device_id hih6130_id[] = {
 237         { "hih6130", 0 },
 238         { }
 239 };
 240 MODULE_DEVICE_TABLE(i2c, hih6130_id);
 241 
 242 static const struct of_device_id __maybe_unused hih6130_of_match[] = {
 243         { .compatible = "honeywell,hih6130", },
 244         { }
 245 };
 246 MODULE_DEVICE_TABLE(of, hih6130_of_match);
 247 
 248 static struct i2c_driver hih6130_driver = {
 249         .driver = {
 250                 .name = "hih6130",
 251                 .of_match_table = of_match_ptr(hih6130_of_match),
 252         },
 253         .probe       = hih6130_probe,
 254         .id_table    = hih6130_id,
 255 };
 256 
 257 module_i2c_driver(hih6130_driver);
 258 
 259 MODULE_AUTHOR("Iain Paton <ipaton0@gmail.com>");
 260 MODULE_DESCRIPTION("Honeywell HIH-6130 humidity and temperature sensor driver");
 261 MODULE_LICENSE("GPL");

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