* [lm-sensors] [PATCH v2 3/4] hwmon: (sht15) add support for the
@ 2011-04-12 19:34 Vivien Didelot
2011-04-13 11:39 ` Jonathan Cameron
2011-04-14 21:38 ` Guenter Roeck
0 siblings, 2 replies; 3+ messages in thread
From: Vivien Didelot @ 2011-04-12 19:34 UTC (permalink / raw)
To: lm-sensors
* Add support for:
- Heater.
- End of battery notice.
- Ability not to reload from OTP.
- Low resolution (12bit temp, 8bit humidity).
* Add an utility function to read individual bytes from the device.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
Documentation/hwmon/sht15 | 29 +++++-
drivers/hwmon/sht15.c | 247 +++++++++++++++++++++++++++++++++++++++------
include/linux/sht15.h | 4 +
3 files changed, 245 insertions(+), 35 deletions(-)
diff --git a/Documentation/hwmon/sht15 b/Documentation/hwmon/sht15
index 50c07f5..a9e36e3 100644
--- a/Documentation/hwmon/sht15
+++ b/Documentation/hwmon/sht15
@@ -4,6 +4,7 @@ Kernel driver sht15
Authors:
* Wouter Horre
* Jonathan Cameron
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Supported chips:
* Sensirion SHT10
@@ -30,14 +31,38 @@ Description
The SHT10, SHT11, SHT15, SHT71, and SHT75 are humidity and temperature
sensors.
-The devices communicate using two GPIO lines and use the default
-resolution settings of 14 bits for temperature and 12 bits for humidity.
+The devices communicate using two GPIO lines.
+
+Supported resolutions for the measurements are 14 bits for temperature and 12
+bits for humidity, or 12 bits for temperature and 8 bits for humidity.
+
+The humidity calibration coefficients are programmed into an OTP memory on the
+chip. These coefficients are used to internally calibrate the signals from the
+sensors. Disabling the reload of those coefficients allows saving 10ms for each
+measurement and decrease power consumption, while loosing on precision.
+
+Some options may be set directly in the sht15_platform_data structure
+or via sysfs attributes.
Note: The regulator supply name is set to "vcc".
+Platform data
+-------------
+
+* no_otp_reload:
+ flag to indicate not to reload from OTP (default to false).
+* low_resolution:
+ flag to indicate the temp/humidity resolution to use (default to false).
+
Sysfs interface
---------------
* temp1_input: temperature input
* humidity1_input: humidity input
+* heater_enable: write 1 in this attribute to enable the on-chip heater,
+ 0 to disable it. Be careful not to enable the heater
+ for too long.
+* temp1_fault: if 1, this means that the voltage is low (below 2.47V) and
+ measurement may be invalid.
+* humidity1_fault: same as temp1_fault.
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index 42992fe..77d25d3 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -1,6 +1,9 @@
/*
* sht15.c - support for the SHT15 Temperature and Humidity Sensor
*
+ * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
* Copyright (c) 2009 Jonathan Cameron
*
* Copyright (c) 2007 Wouter Horre
@@ -33,6 +36,8 @@
/* Commands */
#define SHT15_MEASURE_TEMP 0x03
#define SHT15_MEASURE_RH 0x05
+#define SHT15_WRITE_STATUS 0x06
+#define SHT15_READ_STATUS 0x07
#define SHT15_SOFT_RESET 0x1E
/* Min timings */
@@ -41,6 +46,12 @@
#define SHT15_TSU 150 /* (nsecs) data setup time */
#define SHT15_TSRST 11 /* (msecs) soft reset time */
+/* Status Register Bits */
+#define SHT15_STATUS_LOW_RESOLUTION 0x01
+#define SHT15_STATUS_NO_OTP_RELOAD 0x02
+#define SHT15_STATUS_HEATER 0x04
+#define SHT15_STATUS_LOW_BATTERY 0x40
+
/* Actions the driver may be doing */
enum sht15_state {
SHT15_READING_NOTHING,
@@ -74,9 +85,12 @@ static const struct sht15_temppair temppoints[] = {
* @wait_queue: wait queue for getting values from device.
* @val_temp: last temperature value read from device.
* @val_humid: last humidity value read from device.
+ * @val_status: last status register value read from device.
* @state: state identifying the action the driver is doing.
* @measurements_valid: are the current stored measures valid (start condition).
+ * @status_valid: is the current stored status valid (start condition).
* @last_measurement: time of last measure.
+ * @last_status: time of last status reading.
* @read_lock: mutex to ensure only one read in progress at a time.
* @dev: associate device structure.
* @hwmon_dev: device associated with hwmon subsystem.
@@ -97,9 +111,12 @@ struct sht15_data {
wait_queue_head_t wait_queue;
uint16_t val_temp;
uint16_t val_humid;
+ u8 val_status;
enum sht15_state state;
bool measurements_valid;
+ bool status_valid;
unsigned long last_measurement;
+ unsigned long last_status;
struct mutex read_lock;
struct device *dev;
struct device *hwmon_dev;
@@ -244,11 +261,106 @@ static int sht15_soft_reset(struct sht15_data *data)
if (ret)
return ret;
msleep(SHT15_TSRST);
+ /* device resets default hardware status register value */
+ data->val_status = 0;
+
+ return ret;
+}
+
+/**
+ * sht15_end_transmission() - notify device of end of transmission
+ * @data: device state.
+ *
+ * This is basically a NAK (single clock pulse, data high).
+ */
+static void sht15_end_transmission(struct sht15_data *data)
+{
+ gpio_direction_output(data->pdata->gpio_data, 1);
+ ndelay(SHT15_TSU);
+ gpio_set_value(data->pdata->gpio_sck, 1);
+ ndelay(SHT15_TSCKH);
+ gpio_set_value(data->pdata->gpio_sck, 0);
+ ndelay(SHT15_TSCKL);
+}
+
+/**
+ * sht15_read_byte() - Read a byte back from the device
+ * @data: device state.
+ */
+static u8 sht15_read_byte(struct sht15_data *data)
+{
+ int i;
+ u8 byte = 0;
+
+ for (i = 0; i < 8; ++i) {
+ byte <<= 1;
+ gpio_set_value(data->pdata->gpio_sck, 1);
+ ndelay(SHT15_TSCKH);
+ byte |= !!gpio_get_value(data->pdata->gpio_data);
+ gpio_set_value(data->pdata->gpio_sck, 0);
+ ndelay(SHT15_TSCKL);
+ }
+ return byte;
+}
+
+/**
+ * sht15_send_status() - write the status register byte
+ * @data: sht15 specific data.
+ * @status: the byte to set the status register with.
+ *
+ * As described in figure 14 and table 5 of the datasheet.
+ */
+static int sht15_send_status(struct sht15_data *data, u8 status)
+{
+ int ret;
+
+ ret = sht15_send_cmd(data, SHT15_WRITE_STATUS);
+ if (ret)
+ return ret;
+ gpio_direction_output(data->pdata->gpio_data, 1);
+ ndelay(SHT15_TSU);
+ sht15_send_byte(data, status);
+ ret = sht15_wait_for_response(data);
+ if (ret)
+ return ret;
+ data->val_status = status;
return 0;
}
/**
+ * sht15_update_status() - get updated status register from device if too old
+ * @data: device instance specific data.
+ *
+ * As described in figure 15 and table 5 of the datasheet.
+ */
+static int sht15_update_status(struct sht15_data *data)
+{
+ int ret = 0;
+ u8 status;
+ int timeout = HZ;
+
+ mutex_lock(&data->read_lock);
+ if (time_after(jiffies, data->last_status + timeout)
+ || !data->status_valid) {
+ ret = sht15_send_cmd(data, SHT15_READ_STATUS);
+ if (ret)
+ goto error_ret;
+ status = sht15_read_byte(data);
+
+ sht15_end_transmission(data);
+
+ data->val_status = status;
+ data->status_valid = true;
+ data->last_status = jiffies;
+ }
+error_ret:
+ mutex_unlock(&data->read_lock);
+
+ return ret;
+}
+
+/**
* sht15_measurement() - get a new value from device
* @data: device instance specific data
* @command: command sent to request value
@@ -324,6 +436,7 @@ error_ret:
static inline int sht15_calc_temp(struct sht15_data *data)
{
int d1 = temppoints[0].d1;
+ int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10;
int i;
for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
@@ -336,7 +449,7 @@ static inline int sht15_calc_temp(struct sht15_data *data)
break;
}
- return data->val_temp * 10 + d1;
+ return data->val_temp * d2 + d1;
}
/**
@@ -353,19 +466,86 @@ static inline int sht15_calc_humid(struct sht15_data *data)
{
int rh_linear; /* milli percent */
int temp = sht15_calc_temp(data);
-
+ int c2, c3;
+ int t2;
const int c1 = -4;
- const int c2 = 40500; /* x 10 ^ -6 */
- const int c3 = -28; /* x 10 ^ -7 */
+
+ if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) {
+ c2 = 648000; /* x 10 ^ -6 */
+ c3 = -7200; /* x 10 ^ -7 */
+ t2 = 1280;
+ } else {
+ c2 = 40500; /* x 10 ^ -6 */
+ c3 = -28; /* x 10 ^ -7 */
+ t2 = 80;
+ }
rh_linear = c1 * 1000
+ c2 * data->val_humid / 1000
+ (data->val_humid * data->val_humid * c3) / 10000;
- return (temp - 25000) * (10000 + 80 * data->val_humid)
+ return (temp - 25000) * (10000 + t2 * data->val_humid)
/ 1000000 + rh_linear;
}
/**
+ * sht15_show_status() - show status information in sysfs
+ * @dev: device.
+ * @attr: device attribute.
+ * @buf: sysfs buffer where information is written to.
+ *
+ * Will be called on read access to temp1_fault, humidity1_fault
+ * and heater_enable sysfs attributes.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht15_show_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ struct sht15_data *data = dev_get_drvdata(dev);
+ u8 bit = to_sensor_dev_attr(attr)->index;
+
+ ret = sht15_update_status(data);
+
+ return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit));
+}
+
+/**
+ * sht15_store_heater() - change heater state via sysfs
+ * @dev: device.
+ * @attr: device attribute.
+ * @buf: sysfs buffer to read the new heater state from.
+ * @count: length of the data.
+ *
+ * Will be called on read access to heater_enable sysfs attribute.
+ * Returns number of bytes actually decoded, negative errno on error.
+ */
+static ssize_t sht15_store_heater(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct sht15_data *data = dev_get_drvdata(dev);
+ long value;
+ u8 status;
+
+ if (strict_strtol(buf, 10, &value))
+ return -EINVAL;
+
+ mutex_lock(&data->read_lock);
+ status = data->val_status & 0x07;
+ if (!!value)
+ status |= SHT15_STATUS_HEATER;
+ else
+ status &= ~SHT15_STATUS_HEATER;
+
+ ret = sht15_send_status(data, status);
+ mutex_unlock(&data->read_lock);
+
+ return ret ? ret : count;
+}
+
+/**
* sht15_show_temp() - show temperature measurement value in sysfs
* @dev: device.
* @attr: device attribute.
@@ -407,7 +587,6 @@ static ssize_t sht15_show_humidity(struct device *dev,
ret = sht15_update_measurements(data);
return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data));
-
}
static ssize_t show_name(struct device *dev,
@@ -422,10 +601,19 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
sht15_show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
sht15_show_humidity, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, sht15_show_status, NULL,
+ SHT15_STATUS_LOW_BATTERY);
+static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL,
+ SHT15_STATUS_LOW_BATTERY);
+static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status,
+ sht15_store_heater, SHT15_STATUS_HEATER);
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct attribute *sht15_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_humidity1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_humidity1_fault.dev_attr.attr,
+ &sensor_dev_attr_heater_enable.dev_attr.attr,
&dev_attr_name.attr,
NULL,
};
@@ -466,25 +654,8 @@ static void sht15_ack(struct sht15_data *data)
gpio_direction_input(data->pdata->gpio_data);
}
-/**
- * sht15_end_transmission() - notify device of end of transmission
- * @data: device state
- *
- * This is basically a NAK. (single clock pulse, data high)
- */
-static void sht15_end_transmission(struct sht15_data *data)
-{
- gpio_direction_output(data->pdata->gpio_data, 1);
- ndelay(SHT15_TSU);
- gpio_set_value(data->pdata->gpio_sck, 1);
- ndelay(SHT15_TSCKH);
- gpio_set_value(data->pdata->gpio_sck, 0);
- ndelay(SHT15_TSCKL);
-}
-
static void sht15_bh_read_data(struct work_struct *work_s)
{
- int i;
uint16_t val = 0;
struct sht15_data *data
= container_of(work_s, struct sht15_data,
@@ -505,16 +676,10 @@ static void sht15_bh_read_data(struct work_struct *work_s)
}
/* Read the data back from the device */
- for (i = 0; i < 16; ++i) {
- val <<= 1;
- gpio_set_value(data->pdata->gpio_sck, 1);
- ndelay(SHT15_TSCKH);
- val |= !!gpio_get_value(data->pdata->gpio_data);
- gpio_set_value(data->pdata->gpio_sck, 0);
- ndelay(SHT15_TSCKL);
- if (i = 7)
- sht15_ack(data);
- }
+ val = sht15_read_byte(data);
+ val <<= 8;
+ sht15_ack(data);
+ val |= sht15_read_byte(data);
/* Tell the device we are done */
sht15_end_transmission(data);
@@ -568,6 +733,7 @@ static int __devinit sht15_probe(struct platform_device *pdev)
{
int ret = 0;
struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+ u8 status = 0;
if (!data) {
ret = -ENOMEM;
@@ -588,6 +754,10 @@ static int __devinit sht15_probe(struct platform_device *pdev)
}
data->pdata = pdev->dev.platform_data;
data->supply_uV = data->pdata->supply_mv * 1000;
+ if (data->pdata->no_otp_reload)
+ status |= SHT15_STATUS_NO_OTP_RELOAD;
+ if (data->pdata->low_resolution)
+ status |= SHT15_STATUS_LOW_RESOLUTION;
/*
* If a regulator is available,
@@ -646,6 +816,13 @@ static int __devinit sht15_probe(struct platform_device *pdev)
if (ret)
goto err_release_irq;
+ /* write status with platform data options */
+ if (status) {
+ ret = sht15_send_status(data, status);
+ if (ret)
+ goto err_release_irq;
+ }
+
ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
if (ret) {
dev_err(&pdev->dev, "sysfs create failed\n");
@@ -689,6 +866,10 @@ static int __devexit sht15_remove(struct platform_device *pdev)
* prevent new ones beginning
*/
mutex_lock(&data->read_lock);
+ if (sht15_soft_reset(data)) {
+ mutex_unlock(&data->read_lock);
+ return -EFAULT;
+ }
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
if (!IS_ERR(data->reg)) {
diff --git a/include/linux/sht15.h b/include/linux/sht15.h
index 1e30214..d836ca6 100644
--- a/include/linux/sht15.h
+++ b/include/linux/sht15.h
@@ -19,10 +19,14 @@
* @gpio_sck: no. of gpio to which the data clock is connected.
* @supply_mv: supply voltage in mv. Overridden by regulator if
* available.
+ * @no_otp_reload: flag to indicate no reload from OTP.
+ * @low_resolution: flag to indicate the temp/humidity resolution to use.
*/
struct sht15_platform_data {
int gpio_data;
int gpio_sck;
int supply_mv;
+ bool no_otp_reload;
+ bool low_resolution;
};
--
1.7.1
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [lm-sensors] [PATCH v2 3/4] hwmon: (sht15) add support for the
2011-04-12 19:34 [lm-sensors] [PATCH v2 3/4] hwmon: (sht15) add support for the Vivien Didelot
@ 2011-04-13 11:39 ` Jonathan Cameron
2011-04-14 21:38 ` Guenter Roeck
1 sibling, 0 replies; 3+ messages in thread
From: Jonathan Cameron @ 2011-04-13 11:39 UTC (permalink / raw)
To: lm-sensors
On 04/12/11 20:34, Vivien Didelot wrote:
> * Add support for:
> - Heater.
> - End of battery notice.
> - Ability not to reload from OTP.
> - Low resolution (12bit temp, 8bit humidity).
> * Add an utility function to read individual bytes from the device.
>
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
> ---
> Documentation/hwmon/sht15 | 29 +++++-
> drivers/hwmon/sht15.c | 247 +++++++++++++++++++++++++++++++++++++++------
> include/linux/sht15.h | 4 +
> 3 files changed, 245 insertions(+), 35 deletions(-)
>
> diff --git a/Documentation/hwmon/sht15 b/Documentation/hwmon/sht15
> index 50c07f5..a9e36e3 100644
> --- a/Documentation/hwmon/sht15
> +++ b/Documentation/hwmon/sht15
> @@ -4,6 +4,7 @@ Kernel driver sht15
> Authors:
> * Wouter Horre
> * Jonathan Cameron
> + * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
>
> Supported chips:
> * Sensirion SHT10
> @@ -30,14 +31,38 @@ Description
> The SHT10, SHT11, SHT15, SHT71, and SHT75 are humidity and temperature
> sensors.
>
> -The devices communicate using two GPIO lines and use the default
> -resolution settings of 14 bits for temperature and 12 bits for humidity.
> +The devices communicate using two GPIO lines.
> +
> +Supported resolutions for the measurements are 14 bits for temperature and 12
> +bits for humidity, or 12 bits for temperature and 8 bits for humidity.
> +
> +The humidity calibration coefficients are programmed into an OTP memory on the
> +chip. These coefficients are used to internally calibrate the signals from the
> +sensors. Disabling the reload of those coefficients allows saving 10ms for each
> +measurement and decrease power consumption, while loosing on precision.
> +
> +Some options may be set directly in the sht15_platform_data structure
> +or via sysfs attributes.
>
> Note: The regulator supply name is set to "vcc".
>
> +Platform data
> +-------------
> +
> +* no_otp_reload:
> + flag to indicate not to reload from OTP (default to false).
> +* low_resolution:
> + flag to indicate the temp/humidity resolution to use (default to false).
> +
> Sysfs interface
> ---------------
>
> * temp1_input: temperature input
> * humidity1_input: humidity input
> +* heater_enable: write 1 in this attribute to enable the on-chip heater,
> + 0 to disable it. Be careful not to enable the heater
> + for too long.
> +* temp1_fault: if 1, this means that the voltage is low (below 2.47V) and
> + measurement may be invalid.
> +* humidity1_fault: same as temp1_fault.
>
> diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
> index 42992fe..77d25d3 100644
> --- a/drivers/hwmon/sht15.c
> +++ b/drivers/hwmon/sht15.c
> @@ -1,6 +1,9 @@
> /*
> * sht15.c - support for the SHT15 Temperature and Humidity Sensor
> *
> + * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc.
> + * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
> + *
> * Copyright (c) 2009 Jonathan Cameron
> *
> * Copyright (c) 2007 Wouter Horre
> @@ -33,6 +36,8 @@
> /* Commands */
> #define SHT15_MEASURE_TEMP 0x03
> #define SHT15_MEASURE_RH 0x05
> +#define SHT15_WRITE_STATUS 0x06
> +#define SHT15_READ_STATUS 0x07
> #define SHT15_SOFT_RESET 0x1E
>
> /* Min timings */
> @@ -41,6 +46,12 @@
> #define SHT15_TSU 150 /* (nsecs) data setup time */
> #define SHT15_TSRST 11 /* (msecs) soft reset time */
>
> +/* Status Register Bits */
> +#define SHT15_STATUS_LOW_RESOLUTION 0x01
> +#define SHT15_STATUS_NO_OTP_RELOAD 0x02
> +#define SHT15_STATUS_HEATER 0x04
> +#define SHT15_STATUS_LOW_BATTERY 0x40
> +
> /* Actions the driver may be doing */
> enum sht15_state {
> SHT15_READING_NOTHING,
> @@ -74,9 +85,12 @@ static const struct sht15_temppair temppoints[] = {
> * @wait_queue: wait queue for getting values from device.
> * @val_temp: last temperature value read from device.
> * @val_humid: last humidity value read from device.
> + * @val_status: last status register value read from device.
> * @state: state identifying the action the driver is doing.
> * @measurements_valid: are the current stored measures valid (start condition).
> + * @status_valid: is the current stored status valid (start condition).
> * @last_measurement: time of last measure.
> + * @last_status: time of last status reading.
> * @read_lock: mutex to ensure only one read in progress at a time.
> * @dev: associate device structure.
> * @hwmon_dev: device associated with hwmon subsystem.
> @@ -97,9 +111,12 @@ struct sht15_data {
> wait_queue_head_t wait_queue;
> uint16_t val_temp;
> uint16_t val_humid;
> + u8 val_status;
> enum sht15_state state;
> bool measurements_valid;
> + bool status_valid;
> unsigned long last_measurement;
> + unsigned long last_status;
> struct mutex read_lock;
> struct device *dev;
> struct device *hwmon_dev;
> @@ -244,11 +261,106 @@ static int sht15_soft_reset(struct sht15_data *data)
> if (ret)
> return ret;
> msleep(SHT15_TSRST);
> + /* device resets default hardware status register value */
> + data->val_status = 0;
> +
> + return ret;
> +}
> +
> +/**
> + * sht15_end_transmission() - notify device of end of transmission
> + * @data: device state.
> + *
> + * This is basically a NAK (single clock pulse, data high).
> + */
> +static void sht15_end_transmission(struct sht15_data *data)
> +{
> + gpio_direction_output(data->pdata->gpio_data, 1);
> + ndelay(SHT15_TSU);
> + gpio_set_value(data->pdata->gpio_sck, 1);
> + ndelay(SHT15_TSCKH);
> + gpio_set_value(data->pdata->gpio_sck, 0);
> + ndelay(SHT15_TSCKL);
> +}
> +
> +/**
> + * sht15_read_byte() - Read a byte back from the device
> + * @data: device state.
> + */
> +static u8 sht15_read_byte(struct sht15_data *data)
> +{
> + int i;
> + u8 byte = 0;
> +
> + for (i = 0; i < 8; ++i) {
> + byte <<= 1;
> + gpio_set_value(data->pdata->gpio_sck, 1);
> + ndelay(SHT15_TSCKH);
> + byte |= !!gpio_get_value(data->pdata->gpio_data);
> + gpio_set_value(data->pdata->gpio_sck, 0);
> + ndelay(SHT15_TSCKL);
> + }
> + return byte;
> +}
> +
> +/**
> + * sht15_send_status() - write the status register byte
> + * @data: sht15 specific data.
> + * @status: the byte to set the status register with.
> + *
> + * As described in figure 14 and table 5 of the datasheet.
> + */
> +static int sht15_send_status(struct sht15_data *data, u8 status)
> +{
> + int ret;
> +
> + ret = sht15_send_cmd(data, SHT15_WRITE_STATUS);
> + if (ret)
> + return ret;
> + gpio_direction_output(data->pdata->gpio_data, 1);
> + ndelay(SHT15_TSU);
> + sht15_send_byte(data, status);
> + ret = sht15_wait_for_response(data);
> + if (ret)
> + return ret;
>
> + data->val_status = status;
> return 0;
> }
>
> /**
> + * sht15_update_status() - get updated status register from device if too old
> + * @data: device instance specific data.
> + *
> + * As described in figure 15 and table 5 of the datasheet.
> + */
> +static int sht15_update_status(struct sht15_data *data)
> +{
> + int ret = 0;
> + u8 status;
> + int timeout = HZ;
> +
> + mutex_lock(&data->read_lock);
> + if (time_after(jiffies, data->last_status + timeout)
> + || !data->status_valid) {
> + ret = sht15_send_cmd(data, SHT15_READ_STATUS);
> + if (ret)
> + goto error_ret;
> + status = sht15_read_byte(data);
> +
> + sht15_end_transmission(data);
> +
> + data->val_status = status;
> + data->status_valid = true;
> + data->last_status = jiffies;
> + }
> +error_ret:
> + mutex_unlock(&data->read_lock);
> +
> + return ret;
> +}
> +
> +/**
> * sht15_measurement() - get a new value from device
> * @data: device instance specific data
> * @command: command sent to request value
> @@ -324,6 +436,7 @@ error_ret:
> static inline int sht15_calc_temp(struct sht15_data *data)
> {
> int d1 = temppoints[0].d1;
> + int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10;
> int i;
>
> for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
> @@ -336,7 +449,7 @@ static inline int sht15_calc_temp(struct sht15_data *data)
> break;
> }
>
> - return data->val_temp * 10 + d1;
> + return data->val_temp * d2 + d1;
> }
>
> /**
> @@ -353,19 +466,86 @@ static inline int sht15_calc_humid(struct sht15_data *data)
> {
> int rh_linear; /* milli percent */
> int temp = sht15_calc_temp(data);
> -
> + int c2, c3;
> + int t2;
> const int c1 = -4;
> - const int c2 = 40500; /* x 10 ^ -6 */
> - const int c3 = -28; /* x 10 ^ -7 */
> +
> + if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) {
> + c2 = 648000; /* x 10 ^ -6 */
> + c3 = -7200; /* x 10 ^ -7 */
> + t2 = 1280;
> + } else {
> + c2 = 40500; /* x 10 ^ -6 */
> + c3 = -28; /* x 10 ^ -7 */
> + t2 = 80;
> + }
>
> rh_linear = c1 * 1000
> + c2 * data->val_humid / 1000
> + (data->val_humid * data->val_humid * c3) / 10000;
> - return (temp - 25000) * (10000 + 80 * data->val_humid)
> + return (temp - 25000) * (10000 + t2 * data->val_humid)
> / 1000000 + rh_linear;
> }
>
> /**
> + * sht15_show_status() - show status information in sysfs
> + * @dev: device.
> + * @attr: device attribute.
> + * @buf: sysfs buffer where information is written to.
> + *
> + * Will be called on read access to temp1_fault, humidity1_fault
> + * and heater_enable sysfs attributes.
> + * Returns number of bytes written into buffer, negative errno on error.
> + */
> +static ssize_t sht15_show_status(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + int ret;
> + struct sht15_data *data = dev_get_drvdata(dev);
> + u8 bit = to_sensor_dev_attr(attr)->index;
> +
> + ret = sht15_update_status(data);
> +
> + return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit));
> +}
> +
> +/**
> + * sht15_store_heater() - change heater state via sysfs
> + * @dev: device.
> + * @attr: device attribute.
> + * @buf: sysfs buffer to read the new heater state from.
> + * @count: length of the data.
> + *
> + * Will be called on read access to heater_enable sysfs attribute.
> + * Returns number of bytes actually decoded, negative errno on error.
> + */
> +static ssize_t sht15_store_heater(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int ret;
> + struct sht15_data *data = dev_get_drvdata(dev);
> + long value;
> + u8 status;
> +
> + if (strict_strtol(buf, 10, &value))
> + return -EINVAL;
> +
> + mutex_lock(&data->read_lock);
> + status = data->val_status & 0x07;
> + if (!!value)
> + status |= SHT15_STATUS_HEATER;
> + else
> + status &= ~SHT15_STATUS_HEATER;
> +
> + ret = sht15_send_status(data, status);
> + mutex_unlock(&data->read_lock);
> +
> + return ret ? ret : count;
> +}
> +
> +/**
> * sht15_show_temp() - show temperature measurement value in sysfs
> * @dev: device.
> * @attr: device attribute.
> @@ -407,7 +587,6 @@ static ssize_t sht15_show_humidity(struct device *dev,
> ret = sht15_update_measurements(data);
>
> return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data));
> -
> }
>
> static ssize_t show_name(struct device *dev,
> @@ -422,10 +601,19 @@ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
> sht15_show_temp, NULL, 0);
> static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
> sht15_show_humidity, NULL, 0);
> +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, sht15_show_status, NULL,
> + SHT15_STATUS_LOW_BATTERY);
> +static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL,
> + SHT15_STATUS_LOW_BATTERY);
> +static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status,
> + sht15_store_heater, SHT15_STATUS_HEATER);
> static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
> static struct attribute *sht15_attrs[] = {
> &sensor_dev_attr_temp1_input.dev_attr.attr,
> &sensor_dev_attr_humidity1_input.dev_attr.attr,
> + &sensor_dev_attr_temp1_fault.dev_attr.attr,
> + &sensor_dev_attr_humidity1_fault.dev_attr.attr,
> + &sensor_dev_attr_heater_enable.dev_attr.attr,
> &dev_attr_name.attr,
> NULL,
> };
> @@ -466,25 +654,8 @@ static void sht15_ack(struct sht15_data *data)
> gpio_direction_input(data->pdata->gpio_data);
> }
>
> -/**
> - * sht15_end_transmission() - notify device of end of transmission
> - * @data: device state
> - *
> - * This is basically a NAK. (single clock pulse, data high)
> - */
> -static void sht15_end_transmission(struct sht15_data *data)
> -{
> - gpio_direction_output(data->pdata->gpio_data, 1);
> - ndelay(SHT15_TSU);
> - gpio_set_value(data->pdata->gpio_sck, 1);
> - ndelay(SHT15_TSCKH);
> - gpio_set_value(data->pdata->gpio_sck, 0);
> - ndelay(SHT15_TSCKL);
> -}
> -
> static void sht15_bh_read_data(struct work_struct *work_s)
> {
> - int i;
> uint16_t val = 0;
> struct sht15_data *data
> = container_of(work_s, struct sht15_data,
> @@ -505,16 +676,10 @@ static void sht15_bh_read_data(struct work_struct *work_s)
> }
>
> /* Read the data back from the device */
> - for (i = 0; i < 16; ++i) {
> - val <<= 1;
> - gpio_set_value(data->pdata->gpio_sck, 1);
> - ndelay(SHT15_TSCKH);
> - val |= !!gpio_get_value(data->pdata->gpio_data);
> - gpio_set_value(data->pdata->gpio_sck, 0);
> - ndelay(SHT15_TSCKL);
> - if (i = 7)
> - sht15_ack(data);
> - }
> + val = sht15_read_byte(data);
> + val <<= 8;
> + sht15_ack(data);
> + val |= sht15_read_byte(data);
>
> /* Tell the device we are done */
> sht15_end_transmission(data);
> @@ -568,6 +733,7 @@ static int __devinit sht15_probe(struct platform_device *pdev)
> {
> int ret = 0;
> struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
> + u8 status = 0;
>
> if (!data) {
> ret = -ENOMEM;
> @@ -588,6 +754,10 @@ static int __devinit sht15_probe(struct platform_device *pdev)
> }
> data->pdata = pdev->dev.platform_data;
> data->supply_uV = data->pdata->supply_mv * 1000;
> + if (data->pdata->no_otp_reload)
> + status |= SHT15_STATUS_NO_OTP_RELOAD;
> + if (data->pdata->low_resolution)
> + status |= SHT15_STATUS_LOW_RESOLUTION;
>
> /*
> * If a regulator is available,
> @@ -646,6 +816,13 @@ static int __devinit sht15_probe(struct platform_device *pdev)
> if (ret)
> goto err_release_irq;
>
> + /* write status with platform data options */
> + if (status) {
> + ret = sht15_send_status(data, status);
> + if (ret)
> + goto err_release_irq;
> + }
> +
> ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
> if (ret) {
> dev_err(&pdev->dev, "sysfs create failed\n");
> @@ -689,6 +866,10 @@ static int __devexit sht15_remove(struct platform_device *pdev)
> * prevent new ones beginning
> */
> mutex_lock(&data->read_lock);
> + if (sht15_soft_reset(data)) {
> + mutex_unlock(&data->read_lock);
> + return -EFAULT;
> + }
> hwmon_device_unregister(data->hwmon_dev);
> sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
> if (!IS_ERR(data->reg)) {
> diff --git a/include/linux/sht15.h b/include/linux/sht15.h
> index 1e30214..d836ca6 100644
> --- a/include/linux/sht15.h
> +++ b/include/linux/sht15.h
> @@ -19,10 +19,14 @@
> * @gpio_sck: no. of gpio to which the data clock is connected.
> * @supply_mv: supply voltage in mv. Overridden by regulator if
> * available.
> + * @no_otp_reload: flag to indicate no reload from OTP.
> + * @low_resolution: flag to indicate the temp/humidity resolution to use.
> */
> struct sht15_platform_data {
> int gpio_data;
> int gpio_sck;
> int supply_mv;
> + bool no_otp_reload;
> + bool low_resolution;
> };
>
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [lm-sensors] [PATCH v2 3/4] hwmon: (sht15) add support for the
2011-04-12 19:34 [lm-sensors] [PATCH v2 3/4] hwmon: (sht15) add support for the Vivien Didelot
2011-04-13 11:39 ` Jonathan Cameron
@ 2011-04-14 21:38 ` Guenter Roeck
1 sibling, 0 replies; 3+ messages in thread
From: Guenter Roeck @ 2011-04-14 21:38 UTC (permalink / raw)
To: lm-sensors
On Tue, 2011-04-12 at 15:34 -0400, Vivien Didelot wrote:
> * Add support for:
> - Heater.
> - End of battery notice.
> - Ability not to reload from OTP.
> - Low resolution (12bit temp, 8bit humidity).
> * Add an utility function to read individual bytes from the device.
>
> Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Applied to -next.
Thanks,
Guenter
_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-04-14 21:38 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-12 19:34 [lm-sensors] [PATCH v2 3/4] hwmon: (sht15) add support for the Vivien Didelot
2011-04-13 11:39 ` Jonathan Cameron
2011-04-14 21:38 ` Guenter Roeck
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.