summaryrefslogtreecommitdiff
path: root/drivers/iio/humidity
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/humidity')
-rw-r--r--drivers/iio/humidity/Kconfig6
-rw-r--r--drivers/iio/humidity/dht11.c77
-rw-r--r--drivers/iio/humidity/hdc100x.c2
-rw-r--r--drivers/iio/humidity/htu21.c2
-rw-r--r--drivers/iio/humidity/si7005.c3
-rw-r--r--drivers/iio/humidity/si7020.c3
6 files changed, 60 insertions, 33 deletions
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
index 6a23698d347c..866dda133336 100644
--- a/drivers/iio/humidity/Kconfig
+++ b/drivers/iio/humidity/Kconfig
@@ -43,14 +43,16 @@ config SI7005
humidity and temperature sensor.
To compile this driver as a module, choose M here: the module
- will be called si7005.
+ will be called si7005. This driver also
+ supports Hoperf TH02 Humidity and Temperature Sensor.
config SI7020
tristate "Si7013/20/21 Relative Humidity and Temperature Sensors"
depends on I2C
help
Say yes here to build support for the Silicon Labs Si7013/20/21
- Relative Humidity and Temperature Sensors.
+ Relative Humidity and Temperature Sensors. This driver also
+ supports Hoperf TH06 Humidity and Temperature Sensor.
To compile this driver as a module, choose M here: the module
will be called si7020.
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
index cfc5a051ab9f..20b500da94db 100644
--- a/drivers/iio/humidity/dht11.c
+++ b/drivers/iio/humidity/dht11.c
@@ -50,12 +50,32 @@
#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \
DHT11_EDGES_PREAMBLE + 1)
-/* Data transmission timing (nano seconds) */
+/*
+ * Data transmission timing:
+ * Data bits are encoded as pulse length (high time) on the data line.
+ * 0-bit: 22-30uS -- typically 26uS (AM2302)
+ * 1-bit: 68-75uS -- typically 70uS (AM2302)
+ * The acutal timings also depend on the properties of the cable, with
+ * longer cables typically making pulses shorter.
+ *
+ * Our decoding depends on the time resolution of the system:
+ * timeres > 34uS ... don't know what a 1-tick pulse is
+ * 34uS > timeres > 30uS ... no problem (30kHz and 32kHz clocks)
+ * 30uS > timeres > 23uS ... don't know what a 2-tick pulse is
+ * timeres < 23uS ... no problem
+ *
+ * Luckily clocks in the 33-44kHz range are quite uncommon, so we can
+ * support most systems if the threshold for decoding a pulse as 1-bit
+ * is chosen carefully. If somebody really wants to support clocks around
+ * 40kHz, where this driver is most unreliable, there are two options.
+ * a) select an implementation using busy loop polling on those systems
+ * b) use the checksum to do some probabilistic decoding
+ */
#define DHT11_START_TRANSMISSION 18 /* ms */
-#define DHT11_SENSOR_RESPONSE 80000
-#define DHT11_START_BIT 50000
-#define DHT11_DATA_BIT_LOW 27000
-#define DHT11_DATA_BIT_HIGH 70000
+#define DHT11_MIN_TIMERES 34000 /* ns */
+#define DHT11_THRESHOLD 49000 /* ns */
+#define DHT11_AMBIG_LOW 23000 /* ns */
+#define DHT11_AMBIG_HIGH 30000 /* ns */
struct dht11 {
struct device *dev;
@@ -76,43 +96,39 @@ struct dht11 {
struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ];
};
-static unsigned char dht11_decode_byte(int *timing, int threshold)
+static unsigned char dht11_decode_byte(char *bits)
{
unsigned char ret = 0;
int i;
for (i = 0; i < 8; ++i) {
ret <<= 1;
- if (timing[i] >= threshold)
+ if (bits[i])
++ret;
}
return ret;
}
-static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
+static int dht11_decode(struct dht11 *dht11, int offset)
{
- int i, t, timing[DHT11_BITS_PER_READ], threshold;
+ int i, t;
+ char bits[DHT11_BITS_PER_READ];
unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
- threshold = DHT11_DATA_BIT_HIGH / timeres;
- if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold)
- pr_err("dht11: WARNING: decoding ambiguous\n");
-
- /* scale down with timeres and check validity */
for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
t = dht11->edges[offset + 2 * i + 2].ts -
dht11->edges[offset + 2 * i + 1].ts;
if (!dht11->edges[offset + 2 * i + 1].value)
return -EIO; /* lost synchronisation */
- timing[i] = t / timeres;
+ bits[i] = t > DHT11_THRESHOLD;
}
- hum_int = dht11_decode_byte(timing, threshold);
- hum_dec = dht11_decode_byte(&timing[8], threshold);
- temp_int = dht11_decode_byte(&timing[16], threshold);
- temp_dec = dht11_decode_byte(&timing[24], threshold);
- checksum = dht11_decode_byte(&timing[32], threshold);
+ hum_int = dht11_decode_byte(bits);
+ hum_dec = dht11_decode_byte(&bits[8]);
+ temp_int = dht11_decode_byte(&bits[16]);
+ temp_dec = dht11_decode_byte(&bits[24]);
+ checksum = dht11_decode_byte(&bits[32]);
if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
return -EIO;
@@ -161,12 +177,12 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
int *val, int *val2, long m)
{
struct dht11 *dht11 = iio_priv(iio_dev);
- int ret, timeres;
+ int ret, timeres, offset;
mutex_lock(&dht11->lock);
if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_boot_ns()) {
timeres = ktime_get_resolution_ns();
- if (DHT11_DATA_BIT_HIGH < 2 * timeres) {
+ if (timeres > DHT11_MIN_TIMERES) {
dev_err(dht11->dev, "timeresolution %dns too low\n",
timeres);
/* In theory a better clock could become available
@@ -176,6 +192,10 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
ret = -EAGAIN;
goto err;
}
+ if (timeres > DHT11_AMBIG_LOW && timeres < DHT11_AMBIG_HIGH)
+ dev_warn(dht11->dev,
+ "timeresolution: %dns - decoding ambiguous\n",
+ timeres);
reinit_completion(&dht11->completion);
@@ -208,11 +228,14 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
if (ret < 0)
goto err;
- ret = dht11_decode(dht11,
- dht11->num_edges == DHT11_EDGES_PER_READ ?
- DHT11_EDGES_PREAMBLE :
- DHT11_EDGES_PREAMBLE - 2,
- timeres);
+ offset = DHT11_EDGES_PREAMBLE +
+ dht11->num_edges - DHT11_EDGES_PER_READ;
+ for (; offset >= 0; --offset) {
+ ret = dht11_decode(dht11, offset);
+ if (!ret)
+ break;
+ }
+
if (ret)
goto err;
}
diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c
index a7f61e881a49..fa4767613173 100644
--- a/drivers/iio/humidity/hdc100x.c
+++ b/drivers/iio/humidity/hdc100x.c
@@ -274,7 +274,7 @@ static int hdc100x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BYTE))
- return -ENODEV;
+ return -EOPNOTSUPP;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c
index d1636a74980e..11cbc38b450f 100644
--- a/drivers/iio/humidity/htu21.c
+++ b/drivers/iio/humidity/htu21.c
@@ -192,7 +192,7 @@ static int htu21_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
dev_err(&client->dev,
"Adapter does not support some i2c transaction\n");
- return -ENODEV;
+ return -EOPNOTSUPP;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data));
diff --git a/drivers/iio/humidity/si7005.c b/drivers/iio/humidity/si7005.c
index 91972ccd8aaf..6297766e93d0 100644
--- a/drivers/iio/humidity/si7005.c
+++ b/drivers/iio/humidity/si7005.c
@@ -135,7 +135,7 @@ static int si7005_probe(struct i2c_client *client,
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
- return -ENODEV;
+ return -EOPNOTSUPP;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@@ -170,6 +170,7 @@ static int si7005_probe(struct i2c_client *client,
static const struct i2c_device_id si7005_id[] = {
{ "si7005", 0 },
+ { "th02", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7005_id);
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
index 71991b5c0658..ffc2ccf6374e 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -121,7 +121,7 @@ static int si7020_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -ENODEV;
+ return -EOPNOTSUPP;
/* Reset device, loads default settings. */
ret = i2c_smbus_write_byte(client, SI7020CMD_RESET);
@@ -149,6 +149,7 @@ static int si7020_probe(struct i2c_client *client,
static const struct i2c_device_id si7020_id[] = {
{ "si7020", 0 },
+ { "th06", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si7020_id);