aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/lm90.c
diff options
context:
space:
mode:
authorGuenter Roeck <guenter.roeck@ericsson.com>2010-10-28 14:31:44 -0400
committerJean Delvare <khali@endymion.delvare>2010-10-28 14:31:44 -0400
commit0c01b644f77a3df892a48a59901997469aeab0a7 (patch)
treeb202fe917771ed4816e4f71730571f364441d468 /drivers/hwmon/lm90.c
parent1179324c411edcefb28a5293f8cc6a5bd9567448 (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.c97
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
202static const struct lm90_params lm90_params[] = { 206static 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 */
412static 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
388static struct lm90_data *lm90_update_device(struct device *dev) 431static 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
876static 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
884static 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
831static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4); 904static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4);
832static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0); 905static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0);
833static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, 906static 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 */
860static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 933static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
861 934
935static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval,
936 set_update_interval);
937
862static struct attribute *lm90_attributes[] = { 938static 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
1199static void lm90_init_client(struct i2c_client *client) 1276static 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