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: |
