diff options
author | Jean Delvare <khali@linux-fr.org> | 2005-10-26 15:39:40 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 17:02:14 -0400 |
commit | c3df5806cdae6fac678c662b527cb974bef4b60c (patch) | |
tree | a510da8447852247907dd6896cdf51c7e3d60844 /drivers | |
parent | 8256fe0f40f1cd72f80f2c46fe0ab1638f03a98d (diff) |
[PATCH] hwmon: Add PEC support to the lm90 driver
Add PEC support to the lm90 driver. Only the ADM1032 chip supports it,
and in a rather tricky way, which is why this patch comes with
documentation reinforcements. At least, this demonstrates that the new
PEC support logic in i2c-core can properly deal with chips with partial
PEC support.
As enabling PEC causes a significant performance drop, it can be
disabled through a sysfs file (unsurprisingly named "pec").
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwmon/lm90.c | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 5acc12ae4e36..fa0793e684fd 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c | |||
@@ -345,15 +345,63 @@ static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, | |||
345 | static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); | 345 | static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); |
346 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); | 346 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
347 | 347 | ||
348 | /* pec used for ADM1032 only */ | ||
349 | static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, | ||
350 | char *buf) | ||
351 | { | ||
352 | struct i2c_client *client = to_i2c_client(dev); | ||
353 | return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); | ||
354 | } | ||
355 | |||
356 | static ssize_t set_pec(struct device *dev, struct device_attribute *dummy, | ||
357 | const char *buf, size_t count) | ||
358 | { | ||
359 | struct i2c_client *client = to_i2c_client(dev); | ||
360 | long val = simple_strtol(buf, NULL, 10); | ||
361 | |||
362 | switch (val) { | ||
363 | case 0: | ||
364 | client->flags &= ~I2C_CLIENT_PEC; | ||
365 | break; | ||
366 | case 1: | ||
367 | client->flags |= I2C_CLIENT_PEC; | ||
368 | break; | ||
369 | default: | ||
370 | return -EINVAL; | ||
371 | } | ||
372 | |||
373 | return count; | ||
374 | } | ||
375 | |||
376 | static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec); | ||
377 | |||
348 | /* | 378 | /* |
349 | * Real code | 379 | * Real code |
350 | */ | 380 | */ |
351 | 381 | ||
382 | /* The ADM1032 supports PEC but not on write byte transactions, so we need | ||
383 | to explicitely ask for a transaction without PEC. */ | ||
384 | static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value) | ||
385 | { | ||
386 | return i2c_smbus_xfer(client->adapter, client->addr, | ||
387 | client->flags & ~I2C_CLIENT_PEC, | ||
388 | I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); | ||
389 | } | ||
390 | |||
391 | /* It is assumed that client->update_lock is held (unless we are in | ||
392 | detection or initialization steps). This matters when PEC is enabled, | ||
393 | because we don't want the address pointer to change between the write | ||
394 | byte and the read byte transactions. */ | ||
352 | static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) | 395 | static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) |
353 | { | 396 | { |
354 | int err; | 397 | int err; |
355 | 398 | ||
356 | err = i2c_smbus_read_byte_data(client, reg); | 399 | if (client->flags & I2C_CLIENT_PEC) { |
400 | err = adm1032_write_byte(client, reg); | ||
401 | if (err >= 0) | ||
402 | err = i2c_smbus_read_byte(client); | ||
403 | } else | ||
404 | err = i2c_smbus_read_byte_data(client, reg); | ||
357 | 405 | ||
358 | if (err < 0) { | 406 | if (err < 0) { |
359 | dev_warn(&client->dev, "Register %#02x read failed (%d)\n", | 407 | dev_warn(&client->dev, "Register %#02x read failed (%d)\n", |
@@ -494,6 +542,10 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) | |||
494 | name = "lm90"; | 542 | name = "lm90"; |
495 | } else if (kind == adm1032) { | 543 | } else if (kind == adm1032) { |
496 | name = "adm1032"; | 544 | name = "adm1032"; |
545 | /* The ADM1032 supports PEC, but only if combined | ||
546 | transactions are not used. */ | ||
547 | if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) | ||
548 | new_client->flags |= I2C_CLIENT_PEC; | ||
497 | } else if (kind == lm99) { | 549 | } else if (kind == lm99) { |
498 | name = "lm99"; | 550 | name = "lm99"; |
499 | } else if (kind == lm86) { | 551 | } else if (kind == lm86) { |
@@ -546,6 +598,9 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) | |||
546 | &sensor_dev_attr_temp2_crit_hyst.dev_attr); | 598 | &sensor_dev_attr_temp2_crit_hyst.dev_attr); |
547 | device_create_file(&new_client->dev, &dev_attr_alarms); | 599 | device_create_file(&new_client->dev, &dev_attr_alarms); |
548 | 600 | ||
601 | if (new_client->flags & I2C_CLIENT_PEC) | ||
602 | device_create_file(&new_client->dev, &dev_attr_pec); | ||
603 | |||
549 | return 0; | 604 | return 0; |
550 | 605 | ||
551 | exit_detach: | 606 | exit_detach: |