[lm-sensors] [PATCH v2] adt7470: Update sensors periodically via timer to avoid blocking
Darrick J. Wong
djwong at us.ibm.com
Thu Jul 26 18:58:43 CEST 2007
To avoid blocking for 1s in the sysfs read functions, make it so
that adt7470 updates are done periodically with a delayed workqueue
instead of being called from the read functions directly. This
causes near-instant reading of sensors at the cost of reading them
even if nobody's watching them.
Signed-off-by: Darrick J. Wong <djwong at us.ibm.com>
---
drivers/hwmon/adt7470.c | 103 +++++++++++++++++++++++++++++++++++------------
1 files changed, 76 insertions(+), 27 deletions(-)
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 75aee3b..78d858e 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -28,6 +28,7 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/log2.h>
+#include <linux/workqueue.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
@@ -105,7 +106,8 @@ I2C_CLIENT_INSMOD_1(adt7470);
/* "all temps" according to hwmon sysfs interface spec */
#define ADT7470_PWM_ALL_TEMPS 0x3FF
-#define REFRESH_INTERVAL (5 * HZ)
+/* update sensors every 5 seconds */
+#define DEFAULT_REFRESH_INTERVAL 5000
/* sleep 1s while gathering temperature data */
#define TEMP_COLLECTION_TIME 1000
@@ -118,12 +120,19 @@ I2C_CLIENT_INSMOD_1(adt7470);
#define FAN_PERIOD_INVALID 65535
#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID)
+static int refresh_interval = DEFAULT_REFRESH_INTERVAL;
+module_param_named(refresh_interval, refresh_interval, int, S_IRUGO);
+MODULE_PARM_DESC(refresh_interval, "\n"
+ "\tHow often (in ms) to update the sensor readings.\n"
+ "\tDefault: 5000 (5s)");
+
struct adt7470_data {
struct i2c_client client;
struct class_device *class_dev;
struct mutex lock;
char valid;
- unsigned long last_updated; /* In jiffies */
+ struct delayed_work ref_start;
+ struct delayed_work ref_finish;
s8 temp[ADT7470_TEMP_COUNT];
s8 temp_min[ADT7470_TEMP_COUNT];
@@ -184,17 +193,12 @@ static void adt7470_init_client(struct i2c_client *client)
}
}
-static struct adt7470_data *adt7470_update_device(struct device *dev)
+static void adt7470_begin_update(struct adt7470_data *data)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct adt7470_data *data = i2c_get_clientdata(client);
+ struct i2c_client *client = &data->client;
u8 cfg;
- int i;
mutex_lock(&data->lock);
- if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL)
- && data->valid)
- goto out;
/* start reading temperature sensors */
cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
@@ -205,9 +209,19 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
* Delay is 200ms * number of tmp05 sensors. Too bad
* there's no way to figure out how many are connected.
* For now, assume 1s will work.
+ *
+ * (Sleep now handled by delayed workqueue)
*/
- msleep(TEMP_COLLECTION_TIME);
+ mutex_unlock(&data->lock);
+}
+
+static void adt7470_end_update(struct adt7470_data *data)
+{
+ struct i2c_client *client = &data->client;
+ u8 cfg;
+ int i;
+ mutex_lock(&data->lock);
/* done reading temperature sensors */
cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG);
cfg &= ~0x80;
@@ -272,11 +286,36 @@ static struct adt7470_data *adt7470_update_device(struct device *dev)
data->alarms_mask = adt7470_read_word_data(client,
ADT7470_REG_ALARM1_MASK);
- data->last_updated = jiffies;
data->valid = 1;
-out:
mutex_unlock(&data->lock);
+}
+
+static void adt7470_start_reading(struct work_struct *work)
+{
+ struct adt7470_data *data =
+ container_of(work, struct adt7470_data, ref_start.work);
+
+ adt7470_begin_update(data);
+ schedule_delayed_work(&data->ref_finish,
+ msecs_to_jiffies(TEMP_COLLECTION_TIME));
+}
+
+static void adt7470_finish_reading(struct work_struct *work)
+{
+ struct adt7470_data *data =
+ container_of(work, struct adt7470_data, ref_finish.work);
+
+ adt7470_end_update(data);
+ schedule_delayed_work(&data->ref_start,
+ msecs_to_jiffies(refresh_interval));
+}
+
+static struct adt7470_data *dev_to_adt7470_data(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct adt7470_data *data = i2c_get_clientdata(client);
+
return data;
}
@@ -285,7 +324,7 @@ static ssize_t show_temp_min(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]);
}
@@ -313,7 +352,7 @@ static ssize_t show_temp_max(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]);
}
@@ -340,7 +379,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]);
}
@@ -349,7 +388,7 @@ static ssize_t show_alarms(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
if (attr->index)
return sprintf(buf, "%x\n", data->alarms);
@@ -362,7 +401,7 @@ static ssize_t show_fan_max(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
if (FAN_DATA_VALID(data->fan_max[attr->index]))
return sprintf(buf, "%d\n",
@@ -397,7 +436,7 @@ static ssize_t show_fan_min(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
if (FAN_DATA_VALID(data->fan_min[attr->index]))
return sprintf(buf, "%d\n",
@@ -431,7 +470,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
if (FAN_DATA_VALID(data->fan[attr->index]))
return sprintf(buf, "%d\n",
@@ -444,7 +483,7 @@ static ssize_t show_force_pwm_max(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", data->force_pwm_max);
}
@@ -475,7 +514,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", data->pwm[attr->index]);
}
@@ -500,7 +539,7 @@ static ssize_t show_pwm_max(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", data->pwm_max[attr->index]);
}
@@ -528,7 +567,7 @@ static ssize_t show_pwm_min(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", data->pwm_min[attr->index]);
}
@@ -556,7 +595,7 @@ static ssize_t show_pwm_tmax(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
/* the datasheet says that tmax = tmin + 20C */
return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index]));
}
@@ -566,7 +605,7 @@ static ssize_t show_pwm_tmin(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]);
}
@@ -594,7 +633,7 @@ static ssize_t show_pwm_auto(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]);
}
@@ -638,7 +677,7 @@ static ssize_t show_pwm_auto_temp(struct device *dev,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adt7470_data *data = adt7470_update_device(dev);
+ struct adt7470_data *data = dev_to_adt7470_data(dev);
u8 ctrl = data->pwm_auto_temp[attr->index];
if (ctrl)
@@ -913,6 +952,13 @@ static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_remove;
}
+ /* Initialize automatic sensor refresh mechanism */
+ INIT_DELAYED_WORK(&data->ref_start, adt7470_start_reading);
+ INIT_DELAYED_WORK(&data->ref_finish, adt7470_finish_reading);
+
+ /* Start reading sensors immediately */
+ schedule_delayed_work(&data->ref_start, 0);
+
return 0;
exit_remove:
@@ -930,6 +976,9 @@ static int adt7470_detach_client(struct i2c_client *client)
struct adt7470_data *data = i2c_get_clientdata(client);
int i;
+ flush_scheduled_work();
+ cancel_delayed_work_sync(&data->ref_start);
+ cancel_delayed_work_sync(&data->ref_finish);
hwmon_device_unregister(data->class_dev);
for (i = 0; i < ARRAY_SIZE(adt7470_attr); i++)
device_remove_file(&client->dev, &adt7470_attr[i].dev_attr);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://lists.lm-sensors.org/pipermail/lm-sensors/attachments/20070726/0db64d8f/attachment-0001.bin
More information about the lm-sensors
mailing list