aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/fschmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/fschmd.c')
-rw-r--r--drivers/hwmon/fschmd.c90
1 files changed, 88 insertions, 2 deletions
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index d427ea5623fb..b7c9eef0f928 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -41,6 +41,7 @@
41#include <linux/err.h> 41#include <linux/err.h>
42#include <linux/mutex.h> 42#include <linux/mutex.h>
43#include <linux/sysfs.h> 43#include <linux/sysfs.h>
44#include <linux/dmi.h>
44 45
45/* Addresses to scan */ 46/* Addresses to scan */
46static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; 47static unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
@@ -210,6 +211,13 @@ struct fschmd_data {
210 u8 fan_ripple[6]; /* divider for rps */ 211 u8 fan_ripple[6]; /* divider for rps */
211}; 212};
212 213
214/* Global variables to hold information read from special DMI tables, which are
215 available on FSC machines with an fscher or later chip. */
216static int dmi_mult[3] = { 490, 200, 100 };
217static int dmi_offset[3] = { 0, 0, 0 };
218static int dmi_vref = -1;
219
220
213/* 221/*
214 * Sysfs attr show / store functions 222 * Sysfs attr show / store functions
215 */ 223 */
@@ -221,8 +229,13 @@ static ssize_t show_in_value(struct device *dev,
221 int index = to_sensor_dev_attr(devattr)->index; 229 int index = to_sensor_dev_attr(devattr)->index;
222 struct fschmd_data *data = fschmd_update_device(dev); 230 struct fschmd_data *data = fschmd_update_device(dev);
223 231
224 return sprintf(buf, "%d\n", (data->volt[index] * 232 /* fscher / fschrc - 1 as data->kind is an array index, not a chips */
225 max_reading[index] + 128) / 255); 233 if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1))
234 return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
235 dmi_mult[index]) / 255 + dmi_offset[index]);
236 else
237 return sprintf(buf, "%d\n", (data->volt[index] *
238 max_reading[index] + 128) / 255);
226} 239}
227 240
228 241
@@ -525,6 +538,68 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
525 * Real code 538 * Real code
526 */ 539 */
527 540
541/* DMI decode routine to read voltage scaling factors from special DMI tables,
542 which are available on FSC machines with an fscher or later chip. */
543static void fschmd_dmi_decode(const struct dmi_header *header)
544{
545 int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
546
547 /* dmi code ugliness, we get passed the address of the contents of
548 a complete DMI record, but in the form of a dmi_header pointer, in
549 reality this address holds header->length bytes of which the header
550 are the first 4 bytes */
551 u8 *dmi_data = (u8 *)header;
552
553 /* We are looking for OEM-specific type 185 */
554 if (header->type != 185)
555 return;
556
557 /* we are looking for what Siemens calls "subtype" 19, the subtype
558 is stored in byte 5 of the dmi block */
559 if (header->length < 5 || dmi_data[4] != 19)
560 return;
561
562 /* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
563 consisting of what Siemens calls an "Entity" number, followed by
564 2 16-bit words in LSB first order */
565 for (i = 6; (i + 4) < header->length; i += 5) {
566 /* entity 1 - 3: voltage multiplier and offset */
567 if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
568 /* Our in sensors order and the DMI order differ */
569 const int shuffle[3] = { 1, 0, 2 };
570 int in = shuffle[dmi_data[i] - 1];
571
572 /* Check for twice the same entity */
573 if (found & (1 << in))
574 return;
575
576 mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
577 offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
578
579 found |= 1 << in;
580 }
581
582 /* entity 7: reference voltage */
583 if (dmi_data[i] == 7) {
584 /* Check for twice the same entity */
585 if (found & 0x08)
586 return;
587
588 vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
589
590 found |= 0x08;
591 }
592 }
593
594 if (found == 0x0F) {
595 for (i = 0; i < 3; i++) {
596 dmi_mult[i] = mult[i] * 10;
597 dmi_offset[i] = offset[i] * 10;
598 }
599 dmi_vref = vref;
600 }
601}
602
528static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) 603static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
529{ 604{
530 struct i2c_client *client; 605 struct i2c_client *client;
@@ -586,6 +661,17 @@ static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind)
586 data->temp_max[2] = 50 + 128; 661 data->temp_max[2] = 50 + 128;
587 } 662 }
588 663
664 /* Read the special DMI table for fscher and newer chips */
665 if (kind == fscher || kind >= fschrc) {
666 dmi_walk(fschmd_dmi_decode);
667 if (dmi_vref == -1) {
668 printk(KERN_WARNING FSCHMD_NAME
669 ": Couldn't get voltage scaling factors from "
670 "BIOS DMI table, using builtin defaults\n");
671 dmi_vref = 33;
672 }
673 }
674
589 /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ 675 /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
590 data->kind = kind - 1; 676 data->kind = kind - 1;
591 strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE); 677 strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE);