1049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald/* 2049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * si7005.c - Support for Silabs Si7005 humidity and temperature sensor 3049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * 4049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> 5049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * 6049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * This file is subject to the terms and conditions of version 2 of 7049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * the GNU General Public License. See the file COPYING in the main 8049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * directory of this archive for more details. 9049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * 10049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * (7-bit I2C slave address 0x40) 11049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * 12049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald * TODO: heater, fast mode, processed mode (temp. / linearity compensation) 13049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald */ 14049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 15049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/err.h> 16049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/i2c.h> 17049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/delay.h> 18049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/module.h> 19049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/pm.h> 20049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 21049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/iio/iio.h> 22049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#include <linux/iio/sysfs.h> 23049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 24049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_STATUS 0x00 25049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_DATA 0x01 /* 16-bit, MSB */ 26049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_CONFIG 0x03 27049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_ID 0x11 28049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 29049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_STATUS_NRDY BIT(0) 30049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_CONFIG_TEMP BIT(4) 31049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_CONFIG_START BIT(0) 32049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 33049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_ID_7005 0x50 34049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald#define SI7005_ID_7015 0xf0 35049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 36049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstruct si7005_data { 37049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald struct i2c_client *client; 38049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald struct mutex lock; 39049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald u8 config; 40049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald}; 41049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 42049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic int si7005_read_measurement(struct si7005_data *data, bool temp) 43049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald{ 44049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald int tries = 50; 45049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald int ret; 46049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 47049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald mutex_lock(&data->lock); 48049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 49049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = i2c_smbus_write_byte_data(data->client, SI7005_CONFIG, 50049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald data->config | SI7005_CONFIG_START | 51049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald (temp ? SI7005_CONFIG_TEMP : 0)); 52049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (ret < 0) 53049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald goto done; 54049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 55049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald while (tries-- > 0) { 56049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald msleep(20); 57049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = i2c_smbus_read_byte_data(data->client, SI7005_STATUS); 58049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (ret < 0) 59049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald goto done; 60049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (!(ret & SI7005_STATUS_NRDY)) 61049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald break; 62049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald } 63049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (tries < 0) { 64049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = -EIO; 65049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald goto done; 66049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald } 67049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 68049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = i2c_smbus_read_word_swapped(data->client, SI7005_DATA); 69049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 70049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwalddone: 71049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald mutex_unlock(&data->lock); 72049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 73049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return ret; 74049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald} 75049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 76049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic int si7005_read_raw(struct iio_dev *indio_dev, 77049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald struct iio_chan_spec const *chan, int *val, 78049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald int *val2, long mask) 79049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald{ 80049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald struct si7005_data *data = iio_priv(indio_dev); 81049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald int ret; 82049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 83049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald switch (mask) { 84049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald case IIO_CHAN_INFO_RAW: 85049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = si7005_read_measurement(data, chan->type == IIO_TEMP); 86049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (ret < 0) 87049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return ret; 88049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val = ret; 89049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return IIO_VAL_INT; 90049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald case IIO_CHAN_INFO_SCALE: 91049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (chan->type == IIO_TEMP) { 92049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val = 7; 93049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val2 = 812500; 94049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald } else { 95049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val = 3; 96049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val2 = 906250; 97049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald } 98049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return IIO_VAL_INT_PLUS_MICRO; 99049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald case IIO_CHAN_INFO_OFFSET: 100049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (chan->type == IIO_TEMP) 101049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val = -50 * 32 * 4; 102049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald else 103049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald *val = -24 * 16 * 16; 104049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return IIO_VAL_INT; 105049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald default: 106049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald break; 107049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald } 108049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 109049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return -EINVAL; 110049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald} 111049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 112049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic const struct iio_chan_spec si7005_channels[] = { 113049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald { 114049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .type = IIO_HUMIDITYRELATIVE, 115049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 116049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), 117049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald }, 118049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald { 119049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .type = IIO_TEMP, 120049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 121049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), 122049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald } 123049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald}; 124049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 125049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic const struct iio_info si7005_info = { 126049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .read_raw = si7005_read_raw, 127049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .driver_module = THIS_MODULE, 128049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald}; 129049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 130049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic int si7005_probe(struct i2c_client *client, 131049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald const struct i2c_device_id *id) 132049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald{ 133049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald struct iio_dev *indio_dev; 134049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald struct si7005_data *data; 135049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald int ret; 136049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 137049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) 138049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return -ENODEV; 139049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 140049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 141049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (!indio_dev) 142049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return -ENOMEM; 143049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 144049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald data = iio_priv(indio_dev); 145049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald i2c_set_clientdata(client, indio_dev); 146049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald data->client = client; 147049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald mutex_init(&data->lock); 148049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 149049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev->dev.parent = &client->dev; 150049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev->name = dev_name(&client->dev); 151049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev->modes = INDIO_DIRECT_MODE; 152049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev->info = &si7005_info; 153049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 154049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev->channels = si7005_channels; 155049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald indio_dev->num_channels = ARRAY_SIZE(si7005_channels); 156049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 157049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = i2c_smbus_read_byte_data(client, SI7005_ID); 158049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (ret < 0) 159049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return ret; 160049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (ret != SI7005_ID_7005 && ret != SI7005_ID_7015) 161049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return -ENODEV; 162049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 163049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald ret = i2c_smbus_read_byte_data(client, SI7005_CONFIG); 164049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald if (ret < 0) 165049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return ret; 166049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald data->config = ret; 167049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 168049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald return devm_iio_device_register(&client->dev, indio_dev); 169049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald} 170049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 171049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic const struct i2c_device_id si7005_id[] = { 172049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald { "si7005", 0 }, 173049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald { } 174049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald}; 175049973b23a6c77186dae45f708cdc0aa52b3a09ePeter MeerwaldMODULE_DEVICE_TABLE(i2c, si7005_id); 176049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 177049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldstatic struct i2c_driver si7005_driver = { 178049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .driver = { 179049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .name = "si7005", 180049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .owner = THIS_MODULE, 181049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald }, 182049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .probe = si7005_probe, 183049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald .id_table = si7005_id, 184049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald}; 185049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwaldmodule_i2c_driver(si7005_driver); 186049973b23a6c77186dae45f708cdc0aa52b3a09ePeter Meerwald 187049973b23a6c77186dae45f708cdc0aa52b3a09ePeter MeerwaldMODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 188049973b23a6c77186dae45f708cdc0aa52b3a09ePeter MeerwaldMODULE_DESCRIPTION("Silabs Si7005 humidity and temperature sensor driver"); 189049973b23a6c77186dae45f708cdc0aa52b3a09ePeter MeerwaldMODULE_LICENSE("GPL"); 190