From: Peter Meerwald Date: Wed, 1 Oct 2014 11:03:00 +0000 (+0100) Subject: iio: Add si7005 relative humidity and temperature sensor driver X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=049973b23a6c77186dae45f708cdc0aa52b3a09e;p=openwrt%2Fstaging%2Fblogic.git 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 Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig index 463c4d9da79e..e116bd8dd0e4 100644 --- a/drivers/iio/humidity/Kconfig +++ b/drivers/iio/humidity/Kconfig @@ -12,4 +12,14 @@ config DHT11 Other sensors should work as well as long as they speak the same protocol. +config SI7005 + tristate "SI7005 relative humidity and temperature sensor" + depends on I2C + help + Say yes here to build support for the Silabs Si7005 relative + humidity and temperature sensor. + + To compile this driver as a module, choose M here: the module + will be called si7005. + endmenu diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile index d5d36c0c95f9..e3f3d942e646 100644 --- a/drivers/iio/humidity/Makefile +++ b/drivers/iio/humidity/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_DHT11) += dht11.o +obj-$(CONFIG_SI7005) += si7005.o diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c new file mode 100644 index 000000000000..bdd586e6d955 --- /dev/null +++ b/drivers/iio/humidity/si7005.c @@ -0,0 +1,189 @@ +/* + * si7005.c - Support for Silabs Si7005 humidity and temperature sensor + * + * Copyright (c) 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * (7-bit I2C slave address 0x40) + * + * TODO: heater, fast mode, processed mode (temp. / linearity compensation) + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define SI7005_STATUS 0x00 +#define SI7005_DATA 0x01 /* 16-bit, MSB */ +#define SI7005_CONFIG 0x03 +#define SI7005_ID 0x11 + +#define SI7005_STATUS_NRDY BIT(0) +#define SI7005_CONFIG_TEMP BIT(4) +#define SI7005_CONFIG_START BIT(0) + +#define SI7005_ID_7005 0x50 +#define SI7005_ID_7015 0xf0 + +struct si7005_data { + struct i2c_client *client; + struct mutex lock; + u8 config; +}; + +static int si7005_read_measurement(struct si7005_data *data, bool temp) +{ + int tries = 50; + int ret; + + mutex_lock(&data->lock); + + ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG, + data->config | SI7005_CONFIG_START | + (temp ? SI7005_CONFIG_TEMP : 0)); + if (ret < 0) + goto done; + + while (tries-- > 0) { + msleep(20); + ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS); + if (ret < 0) + goto done; + if (!(ret & SI7005_STATUS_NRDY)) + break; + } + if (tries < 0) { + ret = -EIO; + goto done; + } + + ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA); + +done: + mutex_unlock(&data->lock); + + return ret; +} + +static int si7005_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct si7005_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = si7005_read_measurement(data, chan->type == IIO_TEMP); + if (ret < 0) + return ret; + *val = ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + if (chan->type == IIO_TEMP) { + *val = 7; + *val2 = 812500; + } else { + *val = 3; + *val2 = 906250; + } + return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) + *val = -50 * 32 * 4; + else + *val = -24 * 16 * 16; + return IIO_VAL_INT; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_chan_spec si7005_channels[] = { + { + .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), + } +}; + +static const struct iio_info si7005_info = { + .read_raw = si7005_read_raw, + .driver_module = THIS_MODULE, +}; + +static int si7005_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct si7005_data *data; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->name = dev_name(&client->dev); + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &si7005_info; + + indio_dev->channels = si7005_channels; + indio_dev->num_channels = ARRAY_SIZE(si7005_channels); + + ret = i2c_smbus_read_byte_data(client, SI7005_ID); + if (ret < 0) + return ret; + if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015) + return -ENODEV; + + ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG); + if (ret < 0) + return ret; + data->config = ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id si7005_id[] = { + { "si7005", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, si7005_id); + +static struct i2c_driver si7005_driver = { + .driver = { + .name = "si7005", + .owner = THIS_MODULE, + }, + .probe = si7005_probe, + .id_table = si7005_id, +}; +module_i2c_driver(si7005_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver"); +MODULE_LICENSE("GPL");