diff options
author | Guenter Roeck <guenter.roeck@ericsson.com> | 2010-10-28 14:31:44 -0400 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2010-10-28 14:31:44 -0400 |
commit | 0c01b644f77a3df892a48a59901997469aeab0a7 (patch) | |
tree | b202fe917771ed4816e4f71730571f364441d468 /drivers/hwmon/lm90.c | |
parent | 1179324c411edcefb28a5293f8cc6a5bd9567448 (diff) |
hwmon: (lm90) Add support for update_interval sysfs attribute
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/lm90.c')
-rw-r--r-- | drivers/hwmon/lm90.c | 97 |
1 files changed, 92 insertions, 5 deletions
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 1913f8a5d733..f9e76c757de8 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c | |||
@@ -151,6 +151,9 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, | |||
151 | #define MAX6659_REG_R_LOCAL_EMERG 0x17 | 151 | #define MAX6659_REG_R_LOCAL_EMERG 0x17 |
152 | #define MAX6659_REG_W_LOCAL_EMERG 0x17 | 152 | #define MAX6659_REG_W_LOCAL_EMERG 0x17 |
153 | 153 | ||
154 | #define LM90_DEF_CONVRATE_RVAL 6 /* Def conversion rate register value */ | ||
155 | #define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */ | ||
156 | |||
154 | /* | 157 | /* |
155 | * Device flags | 158 | * Device flags |
156 | */ | 159 | */ |
@@ -197,6 +200,7 @@ struct lm90_params { | |||
197 | u32 flags; /* Capabilities */ | 200 | u32 flags; /* Capabilities */ |
198 | u16 alert_alarms; /* Which alarm bits trigger ALERT# */ | 201 | u16 alert_alarms; /* Which alarm bits trigger ALERT# */ |
199 | /* Upper 8 bits for max6695/96 */ | 202 | /* Upper 8 bits for max6695/96 */ |
203 | u8 max_convrate; /* Maximum conversion rate register value */ | ||
200 | }; | 204 | }; |
201 | 205 | ||
202 | static const struct lm90_params lm90_params[] = { | 206 | static const struct lm90_params lm90_params[] = { |
@@ -204,48 +208,59 @@ static const struct lm90_params lm90_params[] = { | |||
204 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | 208 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
205 | | LM90_HAVE_BROKEN_ALERT, | 209 | | LM90_HAVE_BROKEN_ALERT, |
206 | .alert_alarms = 0x7c, | 210 | .alert_alarms = 0x7c, |
211 | .max_convrate = 10, | ||
207 | }, | 212 | }, |
208 | [adt7461] = { | 213 | [adt7461] = { |
209 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | 214 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT |
210 | | LM90_HAVE_BROKEN_ALERT, | 215 | | LM90_HAVE_BROKEN_ALERT, |
211 | .alert_alarms = 0x7c, | 216 | .alert_alarms = 0x7c, |
217 | .max_convrate = 10, | ||
212 | }, | 218 | }, |
213 | [lm86] = { | 219 | [lm86] = { |
214 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, | 220 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
215 | .alert_alarms = 0x7b, | 221 | .alert_alarms = 0x7b, |
222 | .max_convrate = 9, | ||
216 | }, | 223 | }, |
217 | [lm90] = { | 224 | [lm90] = { |
218 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, | 225 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
219 | .alert_alarms = 0x7b, | 226 | .alert_alarms = 0x7b, |
227 | .max_convrate = 9, | ||
220 | }, | 228 | }, |
221 | [lm99] = { | 229 | [lm99] = { |
222 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, | 230 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
223 | .alert_alarms = 0x7b, | 231 | .alert_alarms = 0x7b, |
232 | .max_convrate = 9, | ||
224 | }, | 233 | }, |
225 | [max6646] = { | 234 | [max6646] = { |
226 | .flags = LM90_HAVE_LOCAL_EXT, | 235 | .flags = LM90_HAVE_LOCAL_EXT, |
227 | .alert_alarms = 0x7c, | 236 | .alert_alarms = 0x7c, |
237 | .max_convrate = 6, | ||
228 | }, | 238 | }, |
229 | [max6657] = { | 239 | [max6657] = { |
230 | .flags = LM90_HAVE_LOCAL_EXT, | 240 | .flags = LM90_HAVE_LOCAL_EXT, |
231 | .alert_alarms = 0x7c, | 241 | .alert_alarms = 0x7c, |
242 | .max_convrate = 8, | ||
232 | }, | 243 | }, |
233 | [max6659] = { | 244 | [max6659] = { |
234 | .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY, | 245 | .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY, |
235 | .alert_alarms = 0x7c, | 246 | .alert_alarms = 0x7c, |
247 | .max_convrate = 8, | ||
236 | }, | 248 | }, |
237 | [max6680] = { | 249 | [max6680] = { |
238 | .flags = LM90_HAVE_OFFSET, | 250 | .flags = LM90_HAVE_OFFSET, |
239 | .alert_alarms = 0x7c, | 251 | .alert_alarms = 0x7c, |
252 | .max_convrate = 7, | ||
240 | }, | 253 | }, |
241 | [max6696] = { | 254 | [max6696] = { |
242 | .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY | 255 | .flags = LM90_HAVE_LOCAL_EXT | LM90_HAVE_EMERGENCY |
243 | | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3, | 256 | | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3, |
244 | .alert_alarms = 0x187c, | 257 | .alert_alarms = 0x187c, |
258 | .max_convrate = 6, | ||
245 | }, | 259 | }, |
246 | [w83l771] = { | 260 | [w83l771] = { |
247 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, | 261 | .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT, |
248 | .alert_alarms = 0x7c, | 262 | .alert_alarms = 0x7c, |
263 | .max_convrate = 8, | ||
249 | }, | 264 | }, |
250 | }; | 265 | }; |
251 | 266 | ||
@@ -261,9 +276,13 @@ struct lm90_data { | |||
261 | int kind; | 276 | int kind; |
262 | u32 flags; | 277 | u32 flags; |
263 | 278 | ||
279 | int update_interval; /* in milliseconds */ | ||
280 | |||
264 | u8 config_orig; /* Original configuration register value */ | 281 | u8 config_orig; /* Original configuration register value */ |
282 | u8 convrate_orig; /* Original conversion rate register value */ | ||
265 | u16 alert_alarms; /* Which alarm bits trigger ALERT# */ | 283 | u16 alert_alarms; /* Which alarm bits trigger ALERT# */ |
266 | /* Upper 8 bits for max6695/96 */ | 284 | /* Upper 8 bits for max6695/96 */ |
285 | u8 max_convrate; /* Maximum conversion rate */ | ||
267 | 286 | ||
268 | /* registers values */ | 287 | /* registers values */ |
269 | s8 temp8[8]; /* 0: local low limit | 288 | s8 temp8[8]; /* 0: local low limit |
@@ -385,15 +404,41 @@ static inline void lm90_select_remote_channel(struct i2c_client *client, | |||
385 | } | 404 | } |
386 | } | 405 | } |
387 | 406 | ||
407 | /* | ||
408 | * Set conversion rate. | ||
409 | * client->update_lock must be held when calling this function (unless we are | ||
410 | * in detection or initialization steps). | ||
411 | */ | ||
412 | static void lm90_set_convrate(struct i2c_client *client, struct lm90_data *data, | ||
413 | unsigned int interval) | ||
414 | { | ||
415 | int i; | ||
416 | unsigned int update_interval; | ||
417 | |||
418 | /* Shift calculations to avoid rounding errors */ | ||
419 | interval <<= 6; | ||
420 | |||
421 | /* find the nearest update rate */ | ||
422 | for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6; | ||
423 | i < data->max_convrate; i++, update_interval >>= 1) | ||
424 | if (interval >= update_interval * 3 / 4) | ||
425 | break; | ||
426 | |||
427 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i); | ||
428 | data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64); | ||
429 | } | ||
430 | |||
388 | static struct lm90_data *lm90_update_device(struct device *dev) | 431 | static struct lm90_data *lm90_update_device(struct device *dev) |
389 | { | 432 | { |
390 | struct i2c_client *client = to_i2c_client(dev); | 433 | struct i2c_client *client = to_i2c_client(dev); |
391 | struct lm90_data *data = i2c_get_clientdata(client); | 434 | struct lm90_data *data = i2c_get_clientdata(client); |
435 | unsigned long next_update; | ||
392 | 436 | ||
393 | mutex_lock(&data->update_lock); | 437 | mutex_lock(&data->update_lock); |
394 | 438 | ||
395 | if (time_after(jiffies, data->last_updated + HZ / 2 + HZ / 10) | 439 | next_update = data->last_updated |
396 | || !data->valid) { | 440 | + msecs_to_jiffies(data->update_interval) + 1; |
441 | if (time_after(jiffies, next_update) || !data->valid) { | ||
397 | u8 h, l; | 442 | u8 h, l; |
398 | u8 alarms; | 443 | u8 alarms; |
399 | 444 | ||
@@ -828,6 +873,34 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute | |||
828 | return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); | 873 | return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); |
829 | } | 874 | } |
830 | 875 | ||
876 | static ssize_t show_update_interval(struct device *dev, | ||
877 | struct device_attribute *attr, char *buf) | ||
878 | { | ||
879 | struct lm90_data *data = dev_get_drvdata(dev); | ||
880 | |||
881 | return sprintf(buf, "%u\n", data->update_interval); | ||
882 | } | ||
883 | |||
884 | static ssize_t set_update_interval(struct device *dev, | ||
885 | struct device_attribute *attr, | ||
886 | const char *buf, size_t count) | ||
887 | { | ||
888 | struct i2c_client *client = to_i2c_client(dev); | ||
889 | struct lm90_data *data = i2c_get_clientdata(client); | ||
890 | unsigned long val; | ||
891 | int err; | ||
892 | |||
893 | err = strict_strtoul(buf, 10, &val); | ||
894 | if (err) | ||
895 | return err; | ||
896 | |||
897 | mutex_lock(&data->update_lock); | ||
898 | lm90_set_convrate(client, data, val); | ||
899 | mutex_unlock(&data->update_lock); | ||
900 | |||
901 | return count; | ||
902 | } | ||
903 | |||
831 | static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4); | 904 | static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4); |
832 | static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0); | 905 | static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0); |
833 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, | 906 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, |
@@ -859,6 +932,9 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); | |||
859 | /* Raw alarm file for compatibility */ | 932 | /* Raw alarm file for compatibility */ |
860 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 933 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
861 | 934 | ||
935 | static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, | ||
936 | set_update_interval); | ||
937 | |||
862 | static struct attribute *lm90_attributes[] = { | 938 | static struct attribute *lm90_attributes[] = { |
863 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 939 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
864 | &sensor_dev_attr_temp2_input.dev_attr.attr, | 940 | &sensor_dev_attr_temp2_input.dev_attr.attr, |
@@ -879,6 +955,7 @@ static struct attribute *lm90_attributes[] = { | |||
879 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | 955 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, |
880 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | 956 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, |
881 | &dev_attr_alarms.attr, | 957 | &dev_attr_alarms.attr, |
958 | &dev_attr_update_interval.attr, | ||
882 | NULL | 959 | NULL |
883 | }; | 960 | }; |
884 | 961 | ||
@@ -1198,14 +1275,19 @@ static void lm90_remove_files(struct i2c_client *client, struct lm90_data *data) | |||
1198 | 1275 | ||
1199 | static void lm90_init_client(struct i2c_client *client) | 1276 | static void lm90_init_client(struct i2c_client *client) |
1200 | { | 1277 | { |
1201 | u8 config; | 1278 | u8 config, convrate; |
1202 | struct lm90_data *data = i2c_get_clientdata(client); | 1279 | struct lm90_data *data = i2c_get_clientdata(client); |
1203 | 1280 | ||
1281 | if (lm90_read_reg(client, LM90_REG_R_CONVRATE, &convrate) < 0) { | ||
1282 | dev_warn(&client->dev, "Failed to read convrate register!\n"); | ||
1283 | convrate = LM90_DEF_CONVRATE_RVAL; | ||
1284 | } | ||
1285 | data->convrate_orig = convrate; | ||
1286 | |||
1204 | /* | 1287 | /* |
1205 | * Start the conversions. | 1288 | * Start the conversions. |
1206 | */ | 1289 | */ |
1207 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, | 1290 | lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */ |
1208 | 5); /* 2 Hz */ | ||
1209 | if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { | 1291 | if (lm90_read_reg(client, LM90_REG_R_CONFIG1, &config) < 0) { |
1210 | dev_warn(&client->dev, "Initialization failed!\n"); | 1292 | dev_warn(&client->dev, "Initialization failed!\n"); |
1211 | return; | 1293 | return; |
@@ -1266,6 +1348,9 @@ static int lm90_probe(struct i2c_client *new_client, | |||
1266 | /* Set chip capabilities */ | 1348 | /* Set chip capabilities */ |
1267 | data->flags = lm90_params[data->kind].flags; | 1349 | data->flags = lm90_params[data->kind].flags; |
1268 | 1350 | ||
1351 | /* Set maximum conversion rate */ | ||
1352 | data->max_convrate = lm90_params[data->kind].max_convrate; | ||
1353 | |||
1269 | /* Initialize the LM90 chip */ | 1354 | /* Initialize the LM90 chip */ |
1270 | lm90_init_client(new_client); | 1355 | lm90_init_client(new_client); |
1271 | 1356 | ||
@@ -1327,6 +1412,8 @@ static int lm90_remove(struct i2c_client *client) | |||
1327 | lm90_remove_files(client, data); | 1412 | lm90_remove_files(client, data); |
1328 | 1413 | ||
1329 | /* Restore initial configuration */ | 1414 | /* Restore initial configuration */ |
1415 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, | ||
1416 | data->convrate_orig); | ||
1330 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, | 1417 | i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, |
1331 | data->config_orig); | 1418 | data->config_orig); |
1332 | 1419 | ||