diff options
-rw-r--r-- | Documentation/hwmon/lm90 | 39 | ||||
-rw-r--r-- | Documentation/hwmon/sysfs-interface | 3 | ||||
-rw-r--r-- | drivers/hwmon/lm90.c | 57 |
3 files changed, 96 insertions, 3 deletions
diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90 index 2c4cf39471f4..70abf93ea376 100644 --- a/Documentation/hwmon/lm90 +++ b/Documentation/hwmon/lm90 | |||
@@ -71,8 +71,8 @@ increased resolution of the remote temperature measurement. | |||
71 | 71 | ||
72 | The different chipsets of the family are not strictly identical, although | 72 | The different chipsets of the family are not strictly identical, although |
73 | very similar. This driver doesn't handle any specific feature for now, | 73 | very similar. This driver doesn't handle any specific feature for now, |
74 | but could if there ever was a need for it. For reference, here comes a | 74 | with the exception of SMBus PEC. For reference, here comes a non-exhaustive |
75 | non-exhaustive list of specific features: | 75 | list of specific features: |
76 | 76 | ||
77 | LM90: | 77 | LM90: |
78 | * Filter and alert configuration register at 0xBF. | 78 | * Filter and alert configuration register at 0xBF. |
@@ -91,6 +91,7 @@ ADM1032: | |||
91 | * Conversion averaging. | 91 | * Conversion averaging. |
92 | * Up to 64 conversions/s. | 92 | * Up to 64 conversions/s. |
93 | * ALERT is triggered by open remote sensor. | 93 | * ALERT is triggered by open remote sensor. |
94 | * SMBus PEC support for Write Byte and Receive Byte transactions. | ||
94 | 95 | ||
95 | ADT7461 | 96 | ADT7461 |
96 | * Extended temperature range (breaks compatibility) | 97 | * Extended temperature range (breaks compatibility) |
@@ -119,3 +120,37 @@ The lm90 driver will not update its values more frequently than every | |||
119 | other second; reading them more often will do no harm, but will return | 120 | other second; reading them more often will do no harm, but will return |
120 | 'old' values. | 121 | 'old' values. |
121 | 122 | ||
123 | PEC Support | ||
124 | ----------- | ||
125 | |||
126 | The ADM1032 is the only chip of the family which supports PEC. It does | ||
127 | not support PEC on all transactions though, so some care must be taken. | ||
128 | |||
129 | When reading a register value, the PEC byte is computed and sent by the | ||
130 | ADM1032 chip. However, in the case of a combined transaction (SMBus Read | ||
131 | Byte), the ADM1032 computes the CRC value over only the second half of | ||
132 | the message rather than its entirety, because it thinks the first half | ||
133 | of the message belongs to a different transaction. As a result, the CRC | ||
134 | value differs from what the SMBus master expects, and all reads fail. | ||
135 | |||
136 | For this reason, the lm90 driver will enable PEC for the ADM1032 only if | ||
137 | the bus supports the SMBus Send Byte and Receive Byte transaction types. | ||
138 | These transactions will be used to read register values, instead of | ||
139 | SMBus Read Byte, and PEC will work properly. | ||
140 | |||
141 | Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC. | ||
142 | Instead, it will try to write the PEC value to the register (because the | ||
143 | SMBus Send Byte transaction with PEC is similar to a Write Byte transaction | ||
144 | without PEC), which is not what we want. Thus, PEC is explicitely disabled | ||
145 | on SMBus Send Byte transactions in the lm90 driver. | ||
146 | |||
147 | PEC on byte data transactions represents a significant increase in bandwidth | ||
148 | usage (+33% for writes, +25% for reads) in normal conditions. With the need | ||
149 | to use two SMBus transaction for reads, this overhead jumps to +50%. Worse, | ||
150 | two transactions will typically mean twice as much delay waiting for | ||
151 | transaction completion, effectively doubling the register cache refresh time. | ||
152 | I guess reliability comes at a price, but it's quite expensive this time. | ||
153 | |||
154 | So, as not everyone might enjoy the slowdown, PEC can be disabled through | ||
155 | sysfs. Just write 0 to the "pec" file and PEC will be disabled. Write 1 | ||
156 | to that file to enable PEC again. | ||
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 346400519d0d..764cdc5480e7 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface | |||
@@ -272,3 +272,6 @@ beep_mask Bitmask for beep. | |||
272 | 272 | ||
273 | eeprom Raw EEPROM data in binary form. | 273 | eeprom Raw EEPROM data in binary form. |
274 | Read only. | 274 | Read only. |
275 | |||
276 | pec Enable or disable PEC (SMBus only) | ||
277 | Read/Write | ||
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: |