RE: [PATCH] hwmon: (htu21) Use the nohold mode to read out values

From: Markezana, William
Date: Tue Sep 09 2014 - 05:17:35 EST


Hi Bernhard,

This is a well-known issue on the Raspberry Pi whose i2c stretching timeout is too short to allow proper HTU21 conversion.
See this discussion over here which provides a patch to allow hold master mode on the Raspberry Pi: https://github.com/raspberrypi/linux/issues/211

We will soon publish a new version of the HTU21 driver which provides a lot of new features including both hold master and no hold measurement modes support.

Best regards,

William MARKEZANA
Advanced Development
MEAS France
Impasse Jeanne Benozzi
CS 83163
31027 Toulouse Cedex 3
DirectÂ: + 33 (0) 582 082 286
Fax : + 33 (0) 582 082 151
william.markezana@xxxxxxxxxxxxx
http://www.meas-spec.com

-----Message d'origine-----
DeÂ: Bernhard Walle [mailto:bernhard@xxxxxxxxx]
EnvoyÃÂ: mardi 9 septembre 2014 10:57
ÃÂ: Markezana, William; linux@xxxxxxxxxxxx
CcÂ: jdelvare@xxxxxxx; lm-sensors@xxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; Bernhard Walle
ObjetÂ: [PATCH] hwmon: (htu21) Use the nohold mode to read out values

On my Raspberry Pi, the driver doesn't work. Every read fails with -EIO.
Reading the data sheet and experimenting a bit made me finding out that using the nohold mode works. The Raspberry Pi IÂC chip seems to have problems with slaves blocking the SCK line.

In any case, freeing the bus while performing the measurement seems to be the better way, I think.

Signed-off-by: Bernhard Walle <bernhard@xxxxxxxxx>
---
drivers/hwmon/htu21.c | 52 +++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 46 insertions(+), 6 deletions(-)

diff --git a/drivers/hwmon/htu21.c b/drivers/hwmon/htu21.c index 839086e..7defae2 100644
--- a/drivers/hwmon/htu21.c
+++ b/drivers/hwmon/htu21.c
@@ -25,10 +25,11 @@
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/jiffies.h>
+#include <linux/delay.h>

/* HTU21 Commands */
-#define HTU21_T_MEASUREMENT_HM 0xE3
-#define HTU21_RH_MEASUREMENT_HM 0xE5
+#define HTU21_T_MEASUREMENT_HM_NOHOLD 0xF3
+#define HTU21_RH_MEASUREMENT_HM_NOHOLD 0xF5

struct htu21 {
struct device *hwmon_dev;
@@ -59,6 +60,47 @@ static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
return ((15625 * ticks) >> 13) - 6000; }

+/* retry for one second, then give up */ #define MAX_RETRIES 20
+
+static int htu21_read_word(struct i2c_client *client, u8 command) {
+ char data[2];
+ int ret, i;
+
+ /* start the measurement */
+ ret = i2c_master_send(client, &command, sizeof(command));
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to send command 0x%hhx: %d\n",
+ command, ret);
+ return ret;
+ }
+
+ /*
+ * Now poll until we get the data. On I2C level the device sends a NAK
+ * until it is ready
+ */
+
+ msleep(50);
+
+ for (i = 0; i < MAX_RETRIES; i++) {
+ ret = i2c_master_recv(client, data, sizeof(data));
+ if (ret == sizeof(data))
+ break;
+
+ msleep(50);
+ }
+
+ if (ret < 0) {
+ dev_err(&client->dev, "Unable to receive result from command 0x%hhx: %d\n",
+ command, ret);
+ return ret;
+ }
+
+ return (data[0] << 8) | data[1];
+}
+
+
static int htu21_update_measurements(struct i2c_client *client) {
int ret = 0;
@@ -68,13 +110,11 @@ static int htu21_update_measurements(struct i2c_client *client)

if (time_after(jiffies, htu21->last_update + HZ / 2) ||
!htu21->valid) {
- ret = i2c_smbus_read_word_swapped(client,
- HTU21_T_MEASUREMENT_HM);
+ ret = htu21_read_word(client, HTU21_T_MEASUREMENT_HM_NOHOLD);
if (ret < 0)
goto out;
htu21->temperature = htu21_temp_ticks_to_millicelsius(ret);
- ret = i2c_smbus_read_word_swapped(client,
- HTU21_RH_MEASUREMENT_HM);
+ ret = htu21_read_word(client, HTU21_RH_MEASUREMENT_HM_NOHOLD);
if (ret < 0)
goto out;
htu21->humidity = htu21_rh_ticks_to_per_cent_mille(ret);
--
2.1.0