diff --git a/doc/chips/pc87360 b/doc/chips/pc87360 index fd1ab145..8ae0f2f6 100644 --- a/doc/chips/pc87360 +++ b/doc/chips/pc87360 @@ -151,6 +151,12 @@ recommendations. Each voltage measured has associated low and high limit, each of which triggers an alarm when crossed. +When available, VID inputs are used to provide the nominal CPU Core voltage. +The driver will default to VRM 9.0, but this can be changed from user-space. +The chipsets can handle two sets of VID inputs (on dual-CPU systems), but +the driver will only export one for now. This may change later if there is +a need. + General Remarks --------------- diff --git a/etc/sensors.conf.eg b/etc/sensors.conf.eg index 794bea51..ddfa2088 100644 --- a/etc/sensors.conf.eg +++ b/etc/sensors.conf.eg @@ -2069,6 +2069,9 @@ chip "pc87366-*" # Voltage inputs +# Set VRM version (default 9.0) +# set vrm 9.0 + label in7 "Vsb" label in8 "Vdd" label in9 "Vbat" diff --git a/kernel/chips/pc87360.c b/kernel/chips/pc87360.c index fa2a1dbb..23152ed1 100644 --- a/kernel/chips/pc87360.c +++ b/kernel/chips/pc87360.c @@ -41,6 +41,7 @@ #include #include #include "version.h" +#include "sensors_vid.h" static unsigned short normal_i2c[] = { SENSORS_I2C_END }; static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; @@ -49,7 +50,7 @@ static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; static struct i2c_force_data forces[] = {{NULL}}; static u8 devid; static unsigned int extra_isa[] = { 0x0000, 0x0000, 0x0000 }; -static u8 confreg[3]; +static u8 confreg[4]; enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 }; static struct i2c_address_data addr_data = { @@ -168,6 +169,7 @@ static inline u8 PWM_TO_REG(int val, int inv) #define PC87365_REG_IN_STATUS 0x0A #define PC87365_REG_IN_ALARMS1 0x00 #define PC87365_REG_IN_ALARMS2 0x01 +#define PC87365_REG_VID 0x06 #define IN_FROM_REG(val,ref) (((val) * (ref) + 128) / 256) #define IN_TO_REG(val,ref) ((val)<0 ? 0 : \ @@ -215,6 +217,9 @@ struct pc87360_data { u8 in_crit[3]; /* Register value */ u8 in_status[14]; /* Register value */ u16 in_alarms; /* Register values, combined, masked */ + u8 vid_conf; /* Configuration register value */ + u8 vrm; + u8 vid; /* Register value */ u8 temp[3]; /* Register value */ u8 temp_min[3]; /* Register value */ @@ -255,6 +260,10 @@ void pc87365_in(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); +void pc87365_vid(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results); +void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results); void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); @@ -319,6 +328,9 @@ static struct i2c_driver pc87360_driver = { #define PC87365_SYSCTL_TEMP5_STATUS 2312 /* not for PC87365 */ #define PC87365_SYSCTL_TEMP6_STATUS 2313 /* not for PC87365 */ +#define PC87365_SYSCTL_VID 2400 +#define PC87365_SYSCTL_VRM 2401 + #define PC87365_STATUS_IN_MIN 0x02 #define PC87365_STATUS_IN_MAX 0x04 @@ -451,6 +463,10 @@ static ctl_table pc87365_dir_table_template[] = { /* PC87366 too */ &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, {PC87365_SYSCTL_TEMP6_STATUS, "temp6_status", NULL, 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_in_status}, + {PC87365_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vid}, + {PC87365_SYSCTL_VRM, "vrm", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &pc87365_vrm}, {0} }; @@ -525,16 +541,25 @@ static int pc87360_find(u8 *devid, int *address) } else if (i==1) { /* Voltages */ /* Are we using thermistors? */ if (*devid == 0xE9) { /* PC87366 */ - /* This register is not logical-device - specific, just that we won't need it if we - don't use the VLM device */ + /* These registers are not logical-device + specific, just that we won't need them if + we don't use the VLM device */ confreg[2] = superio_inb(0x2B); + confreg[3] = superio_inb(0x25); if (confreg[2] & 0x40) { printk(KERN_INFO "pc87360.o: Using " "thermistors for temperature " "monitoring\n"); } + +#ifdef DEBUG + if (confreg[3] & 0xE0) { + printk(KERN_INFO "pc87360.o: VID " + "inputs routed (mode %d)\n", + confreg[3] & 0xE0); + } +#endif } } } @@ -644,6 +669,9 @@ int pc87360_detect(struct i2c_adapter *adapter, int address, printk(KERN_DEBUG "Using %s reference voltage\n", (i&0x02) ? "external" : "internal"); #endif + + data->vid_conf = confreg[3]; + data->vrm = 90; } /* Fan clock dividers may be needed before any data is read */ @@ -960,6 +988,9 @@ static void pc87360_update_client(struct i2c_client *client) | ((pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_IN_ALARMS2) & 0x07) << 8); + data->vid = (data->vid_conf & 0xE0) ? + pc87360_read_value(data, LD_IN, + NO_BANK, PC87365_REG_VID) : 0x1F; } /* Temperatures */ @@ -1181,6 +1212,34 @@ void pc87365_in_status(struct i2c_client *client, int operation, int ctl_name, } } +void pc87365_vid(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct pc87360_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 3; + else if (operation == SENSORS_PROC_REAL_READ) { + pc87360_update_client(client); + results[0] = vid_from_reg(data->vid & 0x1f, data->vrm); + *nrels_mag = 1; + } +} + +void pc87365_vrm(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct pc87360_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + results[0] = data->vrm; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) + data->vrm = results[0]; + } +} + void pc87365_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { diff --git a/lib/chips.c b/lib/chips.c index a44b1eb9..2064fa4a 100644 --- a/lib/chips.c +++ b/lib/chips.c @@ -4617,6 +4617,10 @@ static sensors_chip_feature pc87365_features[] = NOMAP, R, PC87365_SYSCTL_TEMP5_STATUS, VALUE(1), 0 }, { SENSORS_PC87360_TEMP6_STATUS, "temp6_status", SENSORS_PC87360_TEMP6, NOMAP, R, PC87365_SYSCTL_TEMP6_STATUS, VALUE(1), 0 }, + { SENSORS_PC87360_VID, "vid", NOMAP, NOMAP, + R, PC87365_SYSCTL_VID, VALUE(1), 3 }, + { SENSORS_PC87360_VRM, "vrm", NOMAP, NOMAP, + RW, PC87365_SYSCTL_VRM, VALUE(1), 1 }, { 0 } }; diff --git a/lib/chips.h b/lib/chips.h index 5f6f4d1f..e52bd8cc 100644 --- a/lib/chips.h +++ b/lib/chips.h @@ -1749,6 +1749,9 @@ #define SENSORS_PC87360_TEMP5_STATUS 215 /* R */ #define SENSORS_PC87360_TEMP6_STATUS 216 /* R */ +#define SENSORS_PC87360_VID 240 /* R */ +#define SENSORS_PC87360_VRM 241 /* RW */ + #define SENSORS_LM92_PREFIX "lm92" #define SENSORS_LM92_TEMP_HIGH 1 /* RW */