Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: Add si7005 relative humidity and temperature sensor driver

sensor provides 12-bit relative humidity and 14-bit temperature
via I2C interface; temperature and linearity compensation is not
implemented (yet)

driver also supports the Si7015, but not the 2nd generation
sensors Si7013/Si7020/Si7021

datasheet is here
http://www.silabs.com/Support%20Documents/TechnicalDocs/Si7005.pdf

v2: (thanks to Lars-Peter Clausen)
* fix coding style
* use devm_iio_device_register()
* change copyright year to 2014

Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>

authored by

Peter Meerwald and committed by
Jonathan Cameron
049973b2 4c45b1a8

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