diff --git a/kernel/Module.mk b/kernel/Module.mk index 46abb93d..afb57a60 100644 --- a/kernel/Module.mk +++ b/kernel/Module.mk @@ -26,7 +26,8 @@ SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o \ $(MODULE_DIR)/lm78.o $(MODULE_DIR)/sensors.o \ $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/lm75.o \ $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \ - $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o + $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \ + $(MODULE_DIR)/lm80.o SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \ $(MODULE_DIR)/smbus.h diff --git a/kernel/chips/gl518sm.c b/kernel/chips/gl518sm.c index c5400b06..b0aa613f 100644 --- a/kernel/chips/gl518sm.c +++ b/kernel/chips/gl518sm.c @@ -66,6 +66,8 @@ #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) #define DIV_FROM_REG(val) (1 << (val)) +#define ALARMS_FROM_REG(val) val + #define BEEP_ENABLE_TO_REG(val) ((val)?0:1) #define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) @@ -565,7 +567,7 @@ void gl518_alarms(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { gl518_update_client(client); - results[0] = data->alarms; + results[0] = ALARMS_FROM_REG(data->alarms); *nrels_mag = 1; } } diff --git a/kernel/chips/lm78.c b/kernel/chips/lm78.c index d1e7033a..0dae05b7 100644 --- a/kernel/chips/lm78.c +++ b/kernel/chips/lm78.c @@ -1,4 +1,3 @@ - /* lm78.c - Part of lm_sensors, Linux kernel modules for hardware monitoring diff --git a/kernel/chips/lm80.c b/kernel/chips/lm80.c index 1d3c8067..87205255 100644 --- a/kernel/chips/lm80.c +++ b/kernel/chips/lm80.c @@ -1,4 +1,3 @@ - /* lm80.c - Part of lm_sensors, Linux kernel modules for hardware monitoring @@ -42,48 +41,54 @@ #define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) #define LM80_REG_IN(nr) (0x20 + (nr)) -#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) -#define LM80_REG_FAN(nr) (0x27 + (nr)) +#define LM80_REG_FAN1_MIN 0x3c +#define LM80_REG_FAN2_MIN 0x3d +#define LM80_REG_FAN1 0x28 +#define LM80_REG_FAN2 0x29 #define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_OVER 0x39 -#define LM80_REG_TEMP_HYST 0x3a +#define LM80_REG_TEMP_HOT_MAX 0x38 +#define LM80_REG_TEMP_HOT_HYST 0x39 +#define LM80_REG_TEMP_OS_MAX 0x3a +#define LM80_REG_TEMP_OS_HYST 0x3b -#define LM80_REG_ALARM1 0x41 -#define LM80_REG_ALARM2 0x42 - -#define LM80_REG_VID_FANDIV 0x47 - -#define LM80_REG_CONFIG 0x40 -#define LM80_REG_CHIPID 0x49 +#define LM80_REG_CONFIG 0x00 +#define LM80_REG_ALARM1 0x01 +#define LM80_REG_ALARM2 0x02 +#define LM80_REG_MASK1 0x03 +#define LM80_REG_MASK2 0x04 +#define LM80_REG_FANDIV 0x05 +#define LM80_REG_RES 0x06 /* Conversions. Rounding is only done on the TO_REG variants. */ -#define IN_TO_REG(val,nr) (((((val) * 100000 / lm80_in_conv[nr]) + 8) / 16) \ - & 0xff) -#define IN_FROM_REG(val,nr) (((val) * 16 * lm80_in_conv[nr]) / 100000) +#define IN_TO_REG(val,nr) ((val) & 0xff) +#define IN_FROM_REG(val,nr) (val) -#define FAN_TO_REG(val) ((val)==0?255:((1350000+(val))/((val)*2)) & 0xff) -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==255?0:1350000/((val)*2)) +#define FAN_TO_REG(val,div) ((val)==0?255:\ + ((1350000+(val)*(div))/((val)*(div)*2)) & 0xff) +#define FAN_FROM_REG(val,div) ((val)==0?-1:\ + (val)==255?0:1350000/((div)*(val)*2)) -#define TEMP_TO_REG(val) (((val)<0?(((val)-5)/10)&0xff:((val)+5)/10) & 0xff) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) +#define TEMP_FROM_REG(val) lm80_temp_from_reg(val) -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - (val)>=0x06?0:205-(val)*5) -#define ALARMS_FROM_REG(val) (val) +#define TEMP_LIMIT_TO_REG(val) (((val)<0?(((val)-50)/100)&0xff:\ + ((val)+50)/100) & 0xff) +#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100) + +#define ALARMS_FROM_REG(val) (val) #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) /* Initial limits */ -#define LM80_INIT_IN_0 (vid==350?280:vid) -#define LM80_INIT_IN_1 (vid==350?280:vid) -#define LM80_INIT_IN_2 330 -#define LM80_INIT_IN_3 500 -#define LM80_INIT_IN_4 1200 -#define LM80_INIT_IN_5 -1200 -#define LM80_INIT_IN_6 -500 +#define LM80_INIT_IN_0 190 +#define LM80_INIT_IN_1 190 +#define LM80_INIT_IN_2 190 +#define LM80_INIT_IN_3 190 +#define LM80_INIT_IN_4 190 +#define LM80_INIT_IN_5 190 +#define LM80_INIT_IN_6 190 #define LM80_INIT_IN_PERCENTAGE 10 @@ -118,26 +123,22 @@ #define LM80_INIT_FAN_MIN_1 3000 #define LM80_INIT_FAN_MIN_2 3000 -#define LM80_INIT_FAN_MIN_3 3000 -#define LM80_INIT_TEMP_OVER 600 -#define LM80_INIT_TEMP_HYST 500 +#define LM80_INIT_TEMP_OS_MAX 600 +#define LM80_INIT_TEMP_OS_HYST 500 +#define LM80_INIT_TEMP_HOT_MAX 700 +#define LM80_INIT_TEMP_HOT_HYST 600 #ifdef MODULE extern int init_module(void); extern int cleanup_module(void); #endif /* MODULE */ -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - /* For each registered LM80, we need to keep some data in memory. That data is pointed to by lm80_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new lm80 client is allocated. */ struct lm80_data { - struct semaphore lock; int sysctl_id; struct semaphore update_lock; @@ -147,13 +148,14 @@ struct lm80_data { u8 in[7]; /* Register value */ u8 in_max[7]; /* Register value */ u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ + u16 temp; /* Register values, shifted right */ + u8 temp_hot_max; /* Register value */ + u8 temp_hot_hyst; /* Register value */ + u8 temp_os_max; /* Register value */ + u8 temp_os_hyst; /* Register value */ u16 alarms; /* Register encoding, combined */ }; @@ -162,9 +164,7 @@ static int lm80_init(void); static int lm80_cleanup(void); static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detect_smbus(struct i2c_adapter *adapter); static int lm80_detach_client(struct i2c_client *client); -static int lm80_detach_smbus(struct i2c_client *client); static int lm80_new_client(struct i2c_adapter *adapter, struct i2c_client *new_client); static void lm80_remove_client(struct i2c_client *client); @@ -173,6 +173,8 @@ static int lm80_command(struct i2c_client *client, unsigned int cmd, static void lm80_inc_use (struct i2c_client *client); static void lm80_dec_use (struct i2c_client *client); +static long lm80_temp_from_reg(u16 regs); + static int lm80_read_value(struct i2c_client *client, u8 register); static int lm80_write_value(struct i2c_client *client, u8 register, u8 value); static void lm80_update_client(struct i2c_client *client); @@ -185,8 +187,6 @@ static void lm80_fan(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void lm80_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); -static void lm80_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); static void lm80_alarms(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, @@ -239,12 +239,8 @@ static ctl_table lm80_dir_table_template[] = { &sensors_sysctl_real, NULL, &lm80_fan }, { LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &lm80_fan }, - { LM80_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_fan }, { LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &lm80_temp }, - { LM80_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_vid }, { LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &lm80_fan_div }, { LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, @@ -253,25 +249,7 @@ static ctl_table lm80_dir_table_template[] = { }; -/* This function is called when: - * lm80_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm80_driver is still present) */ int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - return lm80_detect_smbus(adapter); -} - -/* This function is called whenever a client should be removed: - * lm80_driver is removed (when this module is unloaded) - * when an adapter is removed which has a lm80 client (and lm80_driver - is still present). */ -int lm80_detach_client(struct i2c_client *client) -{ - return lm80_detach_smbus(client); -} - -int lm80_detect_smbus(struct i2c_adapter *adapter) { int address,err; struct i2c_client *new_client; @@ -289,15 +267,13 @@ int lm80_detect_smbus(struct i2c_adapter *adapter) /* Real detection code goes here */ - err = smbus_read_byte_data(adapter,address,LM80_REG_CHIPID) & 0xfe; - printk("lm80.o: LM80 detected\n"); type_name = "lm80"; client_name = "LM80 chip"; /* Allocate space for a new client structure. To counter memory - ragmentation somewhat, we only do one kmalloc. */ + fragmentation somewhat, we only do one kmalloc. */ if (! (new_client = kmalloc(sizeof(struct i2c_client) + sizeof(struct lm80_data), GFP_KERNEL))) { @@ -339,7 +315,7 @@ ERROR2: return err; } -int lm80_detach_smbus(struct i2c_client *client) +int lm80_detach_client(struct i2c_client *client) { int err,i; for (i = 0; i < MAX_LM80_NR; i++) @@ -385,7 +361,6 @@ int lm80_new_client(struct i2c_adapter *adapter, new_client->driver = &lm80_driver; data = new_client->data; data->valid = 0; - data->lock = MUTEX; data->update_lock = MUTEX; return 0; } @@ -405,7 +380,6 @@ int lm80_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -/* Nothing here yet */ void lm80_inc_use (struct i2c_client *client) { #ifdef MODULE @@ -413,7 +387,6 @@ void lm80_inc_use (struct i2c_client *client) #endif } -/* Nothing here yet */ void lm80_dec_use (struct i2c_client *client) { #ifdef MODULE @@ -422,55 +395,37 @@ void lm80_dec_use (struct i2c_client *client) } -/* The SMBus locks itself, but ISA access must be locked explicitely! - We ignore the LM80 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM80 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int lm80_read_value(struct i2c_client *client, u8 reg) +long lm80_temp_from_reg(u16 temp) { - int res; - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,(((struct isa_client *) client)->isa_addr) + - LM80_ADDR_REG_OFFSET); - res = inb_p((((struct isa_client *) client)->isa_addr) + - LM80_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return res; - } else - return smbus_read_byte_data(client->adapter,client->addr, reg); + long res; + res = ((temp & 0xff00) >> 8) * 10000 + ((temp & 0x10) >> 4) * 5000 + + ((temp & 0x20) >> 5) * 2500 + ((temp & 0x40) >> 6) * 1250 + + ((temp & 0x80) >> 7) * 625; + temp /= 100; + if (temp >= 0x80 * 100) + temp = - (0x100 * 100 - temp); + return temp; +} + +int lm80_read_value(struct i2c_client *client, u8 reg) +{ + return smbus_read_byte_data(client->adapter,client->addr, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitely! - We ignore the LM80 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM80 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) { - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,((struct isa_client *) client)->isa_addr + LM80_ADDR_REG_OFFSET); - outb_p(value,((struct isa_client *) client)->isa_addr + LM80_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return 0; - } else - return smbus_write_byte_data(client->adapter, client->addr, reg,value); + return smbus_write_byte_data(client->adapter, client->addr, reg,value); } /* Called when we have found a new LM80. It should set limits, etc. */ void lm80_init_client(struct i2c_client *client) { - int vid; - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ + This sets fan-divs to 2, among others. This makes most other + initializations unnecessary */ lm80_write_value(client,LM80_REG_CONFIG,0x80); - - vid = lm80_read_value(client,LM80_REG_VID_FANDIV) & 0x0f; - vid |= (lm80_read_value(client,LM80_REG_CHIPID) & 0x01) >> 4; - vid = VID_FROM_REG(vid); + /* Set 11-bit temperature resolution */ + lm80_write_value(client,LM80_REG_RES,0x08); lm80_write_value(client,LM80_REG_IN_MIN(0),IN_TO_REG(LM80_INIT_IN_MIN_0,0)); lm80_write_value(client,LM80_REG_IN_MAX(0),IN_TO_REG(LM80_INIT_IN_MAX_0,0)); @@ -486,16 +441,19 @@ void lm80_init_client(struct i2c_client *client) lm80_write_value(client,LM80_REG_IN_MAX(5),IN_TO_REG(LM80_INIT_IN_MAX_5,5)); lm80_write_value(client,LM80_REG_IN_MIN(6),IN_TO_REG(LM80_INIT_IN_MIN_6,6)); lm80_write_value(client,LM80_REG_IN_MAX(6),IN_TO_REG(LM80_INIT_IN_MAX_6,6)); - lm80_write_value(client,LM80_REG_FAN_MIN(1),FAN_TO_REG(LM80_INIT_FAN_MIN_1)); - lm80_write_value(client,LM80_REG_FAN_MIN(2),FAN_TO_REG(LM80_INIT_FAN_MIN_2)); - lm80_write_value(client,LM80_REG_FAN_MIN(3),FAN_TO_REG(LM80_INIT_FAN_MIN_3)); - lm80_write_value(client,LM80_REG_TEMP_OVER,TEMP_TO_REG(LM80_INIT_TEMP_OVER)); - lm80_write_value(client,LM80_REG_TEMP_HYST,TEMP_TO_REG(LM80_INIT_TEMP_HYST)); + lm80_write_value(client,LM80_REG_FAN1_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_1,2)); + lm80_write_value(client,LM80_REG_FAN2_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_2,2)); + lm80_write_value(client,LM80_REG_TEMP_HOT_MAX, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX)); + lm80_write_value(client,LM80_REG_TEMP_HOT_HYST, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST)); + lm80_write_value(client,LM80_REG_TEMP_OS_MAX, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX)); + lm80_write_value(client,LM80_REG_TEMP_OS_HYST, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST)); /* Start monitoring */ - lm80_write_value(client,LM80_REG_CONFIG, - (lm80_read_value(client,LM80_REG_CONFIG) & 0xf7) | 0x01); - + lm80_write_value(client,LM80_REG_CONFIG,0x01); } void lm80_update_client(struct i2c_client *client) @@ -505,7 +463,7 @@ void lm80_update_client(struct i2c_client *client) down(&data->update_lock); - if ((jiffies - data->last_updated > HZ+HZ/2 ) || + if ((jiffies - data->last_updated > 2*HZ ) || (jiffies < data->last_updated) || ! data->valid) { #ifdef DEBUG @@ -516,20 +474,23 @@ void lm80_update_client(struct i2c_client *client) data->in_min[i] = lm80_read_value(client,LM80_REG_IN_MIN(i)); data->in_max[i] = lm80_read_value(client,LM80_REG_IN_MAX(i)); } - for (i = 1; i <= 3; i++) { - data->fan[i-1] = lm80_read_value(client,LM80_REG_FAN(i)); - data->fan_min[i-1] = lm80_read_value(client,LM80_REG_FAN_MIN(i)); - } - data->temp = lm80_read_value(client,LM80_REG_TEMP); - data->temp_over = lm80_read_value(client,LM80_REG_TEMP_OVER); - data->temp_hyst = lm80_read_value(client,LM80_REG_TEMP_HYST); - i = lm80_read_value(client,LM80_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (lm80_read_value(client,LM80_REG_CHIPID) & 0x01) >> 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; + data->fan[0] = lm80_read_value(client,LM80_REG_FAN1); + data->fan_min[0] = lm80_read_value(client,LM80_REG_FAN1_MIN); + data->fan[1] = lm80_read_value(client,LM80_REG_FAN2); + data->fan_min[1] = lm80_read_value(client,LM80_REG_FAN2_MIN); + + data->temp = (lm80_read_value(client,LM80_REG_TEMP) << 8) | + (lm80_read_value(client,LM80_REG_RES) & 0xf0); + data->temp_os_max = lm80_read_value(client,LM80_REG_TEMP_OS_MAX); + data->temp_os_hyst = lm80_read_value(client,LM80_REG_TEMP_OS_HYST); + data->temp_hot_max = lm80_read_value(client,LM80_REG_TEMP_HOT_MAX); + data->temp_hot_hyst = lm80_read_value(client,LM80_REG_TEMP_HOT_HYST); + + i = lm80_read_value(client,LM80_REG_FANDIV); + data->fan_div[0] = (i >> 2) & 0x03; + data->fan_div[1] = (i >> 4) & 0x03; data->alarms = lm80_read_value(client,LM80_REG_ALARM1) + - (lm80_read_value(client,LM80_REG_ALARM2) >> 8); + (lm80_read_value(client,LM80_REG_ALARM2) << 8); data->last_updated = jiffies; data->valid = 1; } @@ -587,13 +548,14 @@ void lm80_fan(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { lm80_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr-1]); - results[1] = FAN_FROM_REG(data->fan[nr-1]); + results[0] = FAN_FROM_REG(data->fan_min[nr-1],data->fan_div[nr-1]); + results[1] = FAN_FROM_REG(data->fan[nr-1],data->fan_div[nr-1]); *nrels_mag = 2; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { - data->fan_min[nr-1] = FAN_TO_REG(results[0]); - lm80_write_value(client,LM80_REG_FAN_MIN(nr),data->fan_min[nr-1]); + data->fan_min[nr-1] = FAN_TO_REG(results[0],data->fan_div[nr-1]); + lm80_write_value(client,nr==1?LM80_REG_FAN1_MIN:LM80_REG_FAN2_MIN, + data->fan_min[nr-1]); } } } @@ -607,32 +569,29 @@ void lm80_temp(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 1; else if (operation == SENSORS_PROC_REAL_READ) { lm80_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; + results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max); + results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst); + results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max); + results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); + results[4] = TEMP_FROM_REG(data->temp); + *nrels_mag = 5; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - lm80_write_value(client,LM80_REG_TEMP_OVER,data->temp_over); + data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]); + lm80_write_value(client,LM80_REG_TEMP_HOT_MAX,data->temp_hot_max); } if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - lm80_write_value(client,LM80_REG_TEMP_HYST,data->temp_hyst); + data->temp_hot_hyst = TEMP_LIMIT_TO_REG(results[1]); + lm80_write_value(client,LM80_REG_TEMP_HOT_HYST,data->temp_hot_hyst); + } + if (*nrels_mag >= 3) { + data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]); + lm80_write_value(client,LM80_REG_TEMP_OS_MAX,data->temp_os_max); + } + if (*nrels_mag >= 4) { + data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]); + lm80_write_value(client,LM80_REG_TEMP_OS_HYST,data->temp_os_hyst); } - } -} - -void lm80_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; } } @@ -664,15 +623,15 @@ void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, results[2] = 2; *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm80_read_value(client,LM80_REG_VID_FANDIV); + old = lm80_read_value(client,LM80_REG_FANDIV); if (*nrels_mag >= 2) { data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); + old = (old & 0xcf) | (data->fan_div[1] << 4); } if (*nrels_mag >= 1) { data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - lm80_write_value(client,LM80_REG_VID_FANDIV,old); + old = (old & 0xf3) | (data->fan_div[0] << 2); + lm80_write_value(client,LM80_REG_FANDIV,old); } } } diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h index e5184306..6a197113 100644 --- a/kernel/include/sensors.h +++ b/kernel/include/sensors.h @@ -87,6 +87,7 @@ extern void sensors_deregister_entry(int id); #define I2C_DRIVERID_GL518 1004 #define I2C_DRIVERID_EEPROM 1005 #define I2C_DRIVERID_W83781D 1006 +#define I2C_DRIVERID_LM80 1007 /* Sysctl IDs */ #ifdef DEV_HWMON @@ -198,4 +199,31 @@ struct sensors_chips_data { #define EEPROM_SYSCTL7 1006 #define EEPROM_SYSCTL8 1007 +#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM80_SYSCTL_IN1 1001 +#define LM80_SYSCTL_IN2 1002 +#define LM80_SYSCTL_IN3 1003 +#define LM80_SYSCTL_IN4 1004 +#define LM80_SYSCTL_IN5 1005 +#define LM80_SYSCTL_IN6 1006 +#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM80_SYSCTL_FAN2 1102 +#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM80_ALARM_IN0 0x0001 +#define LM80_ALARM_IN1 0x0002 +#define LM80_ALARM_IN2 0x0004 +#define LM80_ALARM_IN3 0x0008 +#define LM80_ALARM_IN4 0x0010 +#define LM80_ALARM_IN5 0x0020 +#define LM80_ALARM_IN6 0x0040 +#define LM80_ALARM_FAN1 0x0400 +#define LM80_ALARM_FAN2 0x0800 +#define LM80_ALARM_TEMP_HOT 0x0100 +#define LM80_ALARM_TEMP_OS 0x2000 +#define LM80_ALARM_CHAS 0x1000 +#define LM80_ALARM_BTI 0x0200 +#define LM80_ALARM_INT_IN 0x0080 #endif /* def SENSORS_SENSORS_H */ diff --git a/src/Module.mk b/src/Module.mk index 46abb93d..afb57a60 100644 --- a/src/Module.mk +++ b/src/Module.mk @@ -26,7 +26,8 @@ SRCTARGETS := $(MODULE_DIR)/smbus.o $(MODULE_DIR)/piix4.o $(MODULE_DIR)/isa.o \ $(MODULE_DIR)/lm78.o $(MODULE_DIR)/sensors.o \ $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/lm75.o \ $(MODULE_DIR)/i2c-proc.o $(MODULE_DIR)/gl518sm.o \ - $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o + $(MODULE_DIR)/eeprom.o $(MODULE_DIR)/w83781d.o \ + $(MODULE_DIR)/lm80.o SRCHEADERFILES := $(MODULE_DIR)/sensors.h $(MODULE_DIR)/isa.h \ $(MODULE_DIR)/smbus.h diff --git a/src/gl518sm.c b/src/gl518sm.c index c5400b06..b0aa613f 100644 --- a/src/gl518sm.c +++ b/src/gl518sm.c @@ -66,6 +66,8 @@ #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) #define DIV_FROM_REG(val) (1 << (val)) +#define ALARMS_FROM_REG(val) val + #define BEEP_ENABLE_TO_REG(val) ((val)?0:1) #define BEEP_ENABLE_FROM_REG(val) ((val)?0:1) @@ -565,7 +567,7 @@ void gl518_alarms(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { gl518_update_client(client); - results[0] = data->alarms; + results[0] = ALARMS_FROM_REG(data->alarms); *nrels_mag = 1; } } diff --git a/src/lm78.c b/src/lm78.c index d1e7033a..0dae05b7 100644 --- a/src/lm78.c +++ b/src/lm78.c @@ -1,4 +1,3 @@ - /* lm78.c - Part of lm_sensors, Linux kernel modules for hardware monitoring diff --git a/src/lm80.c b/src/lm80.c index 1d3c8067..87205255 100644 --- a/src/lm80.c +++ b/src/lm80.c @@ -1,4 +1,3 @@ - /* lm80.c - Part of lm_sensors, Linux kernel modules for hardware monitoring @@ -42,48 +41,54 @@ #define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) #define LM80_REG_IN(nr) (0x20 + (nr)) -#define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) -#define LM80_REG_FAN(nr) (0x27 + (nr)) +#define LM80_REG_FAN1_MIN 0x3c +#define LM80_REG_FAN2_MIN 0x3d +#define LM80_REG_FAN1 0x28 +#define LM80_REG_FAN2 0x29 #define LM80_REG_TEMP 0x27 -#define LM80_REG_TEMP_OVER 0x39 -#define LM80_REG_TEMP_HYST 0x3a +#define LM80_REG_TEMP_HOT_MAX 0x38 +#define LM80_REG_TEMP_HOT_HYST 0x39 +#define LM80_REG_TEMP_OS_MAX 0x3a +#define LM80_REG_TEMP_OS_HYST 0x3b -#define LM80_REG_ALARM1 0x41 -#define LM80_REG_ALARM2 0x42 - -#define LM80_REG_VID_FANDIV 0x47 - -#define LM80_REG_CONFIG 0x40 -#define LM80_REG_CHIPID 0x49 +#define LM80_REG_CONFIG 0x00 +#define LM80_REG_ALARM1 0x01 +#define LM80_REG_ALARM2 0x02 +#define LM80_REG_MASK1 0x03 +#define LM80_REG_MASK2 0x04 +#define LM80_REG_FANDIV 0x05 +#define LM80_REG_RES 0x06 /* Conversions. Rounding is only done on the TO_REG variants. */ -#define IN_TO_REG(val,nr) (((((val) * 100000 / lm80_in_conv[nr]) + 8) / 16) \ - & 0xff) -#define IN_FROM_REG(val,nr) (((val) * 16 * lm80_in_conv[nr]) / 100000) +#define IN_TO_REG(val,nr) ((val) & 0xff) +#define IN_FROM_REG(val,nr) (val) -#define FAN_TO_REG(val) ((val)==0?255:((1350000+(val))/((val)*2)) & 0xff) -#define FAN_FROM_REG(val) ((val)==0?-1:(val)==255?0:1350000/((val)*2)) +#define FAN_TO_REG(val,div) ((val)==0?255:\ + ((1350000+(val)*(div))/((val)*(div)*2)) & 0xff) +#define FAN_FROM_REG(val,div) ((val)==0?-1:\ + (val)==255?0:1350000/((div)*(val)*2)) -#define TEMP_TO_REG(val) (((val)<0?(((val)-5)/10)&0xff:((val)+5)/10) & 0xff) -#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) +#define TEMP_FROM_REG(val) lm80_temp_from_reg(val) -#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ - (val)>=0x06?0:205-(val)*5) -#define ALARMS_FROM_REG(val) (val) +#define TEMP_LIMIT_TO_REG(val) (((val)<0?(((val)-50)/100)&0xff:\ + ((val)+50)/100) & 0xff) +#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100) + +#define ALARMS_FROM_REG(val) (val) #define DIV_FROM_REG(val) (1 << (val)) #define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) /* Initial limits */ -#define LM80_INIT_IN_0 (vid==350?280:vid) -#define LM80_INIT_IN_1 (vid==350?280:vid) -#define LM80_INIT_IN_2 330 -#define LM80_INIT_IN_3 500 -#define LM80_INIT_IN_4 1200 -#define LM80_INIT_IN_5 -1200 -#define LM80_INIT_IN_6 -500 +#define LM80_INIT_IN_0 190 +#define LM80_INIT_IN_1 190 +#define LM80_INIT_IN_2 190 +#define LM80_INIT_IN_3 190 +#define LM80_INIT_IN_4 190 +#define LM80_INIT_IN_5 190 +#define LM80_INIT_IN_6 190 #define LM80_INIT_IN_PERCENTAGE 10 @@ -118,26 +123,22 @@ #define LM80_INIT_FAN_MIN_1 3000 #define LM80_INIT_FAN_MIN_2 3000 -#define LM80_INIT_FAN_MIN_3 3000 -#define LM80_INIT_TEMP_OVER 600 -#define LM80_INIT_TEMP_HYST 500 +#define LM80_INIT_TEMP_OS_MAX 600 +#define LM80_INIT_TEMP_OS_HYST 500 +#define LM80_INIT_TEMP_HOT_MAX 700 +#define LM80_INIT_TEMP_HOT_HYST 600 #ifdef MODULE extern int init_module(void); extern int cleanup_module(void); #endif /* MODULE */ -/* This module may seem overly long and complicated. In fact, it is not so - bad. Quite a lot of bookkeeping is done. A real driver can often cut - some corners. */ - /* For each registered LM80, we need to keep some data in memory. That data is pointed to by lm80_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new lm80 client is allocated. */ struct lm80_data { - struct semaphore lock; int sysctl_id; struct semaphore update_lock; @@ -147,13 +148,14 @@ struct lm80_data { u8 in[7]; /* Register value */ u8 in_max[7]; /* Register value */ u8 in_min[7]; /* Register value */ - u8 fan[3]; /* Register value */ - u8 fan_min[3]; /* Register value */ - u8 temp; /* Register value */ - u8 temp_over; /* Register value */ - u8 temp_hyst; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ u8 fan_div[2]; /* Register encoding, shifted right */ - u8 vid; /* Register encoding, combined */ + u16 temp; /* Register values, shifted right */ + u8 temp_hot_max; /* Register value */ + u8 temp_hot_hyst; /* Register value */ + u8 temp_os_max; /* Register value */ + u8 temp_os_hyst; /* Register value */ u16 alarms; /* Register encoding, combined */ }; @@ -162,9 +164,7 @@ static int lm80_init(void); static int lm80_cleanup(void); static int lm80_attach_adapter(struct i2c_adapter *adapter); -static int lm80_detect_smbus(struct i2c_adapter *adapter); static int lm80_detach_client(struct i2c_client *client); -static int lm80_detach_smbus(struct i2c_client *client); static int lm80_new_client(struct i2c_adapter *adapter, struct i2c_client *new_client); static void lm80_remove_client(struct i2c_client *client); @@ -173,6 +173,8 @@ static int lm80_command(struct i2c_client *client, unsigned int cmd, static void lm80_inc_use (struct i2c_client *client); static void lm80_dec_use (struct i2c_client *client); +static long lm80_temp_from_reg(u16 regs); + static int lm80_read_value(struct i2c_client *client, u8 register); static int lm80_write_value(struct i2c_client *client, u8 register, u8 value); static void lm80_update_client(struct i2c_client *client); @@ -185,8 +187,6 @@ static void lm80_fan(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void lm80_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); -static void lm80_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results); static void lm80_alarms(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, @@ -239,12 +239,8 @@ static ctl_table lm80_dir_table_template[] = { &sensors_sysctl_real, NULL, &lm80_fan }, { LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &lm80_fan }, - { LM80_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_fan }, { LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &lm80_temp }, - { LM80_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real, - &sensors_sysctl_real, NULL, &lm80_vid }, { LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, &sensors_sysctl_real, NULL, &lm80_fan_div }, { LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real, @@ -253,25 +249,7 @@ static ctl_table lm80_dir_table_template[] = { }; -/* This function is called when: - * lm80_driver is inserted (when this module is loaded), for each - available adapter - * when a new adapter is inserted (and lm80_driver is still present) */ int lm80_attach_adapter(struct i2c_adapter *adapter) -{ - return lm80_detect_smbus(adapter); -} - -/* This function is called whenever a client should be removed: - * lm80_driver is removed (when this module is unloaded) - * when an adapter is removed which has a lm80 client (and lm80_driver - is still present). */ -int lm80_detach_client(struct i2c_client *client) -{ - return lm80_detach_smbus(client); -} - -int lm80_detect_smbus(struct i2c_adapter *adapter) { int address,err; struct i2c_client *new_client; @@ -289,15 +267,13 @@ int lm80_detect_smbus(struct i2c_adapter *adapter) /* Real detection code goes here */ - err = smbus_read_byte_data(adapter,address,LM80_REG_CHIPID) & 0xfe; - printk("lm80.o: LM80 detected\n"); type_name = "lm80"; client_name = "LM80 chip"; /* Allocate space for a new client structure. To counter memory - ragmentation somewhat, we only do one kmalloc. */ + fragmentation somewhat, we only do one kmalloc. */ if (! (new_client = kmalloc(sizeof(struct i2c_client) + sizeof(struct lm80_data), GFP_KERNEL))) { @@ -339,7 +315,7 @@ ERROR2: return err; } -int lm80_detach_smbus(struct i2c_client *client) +int lm80_detach_client(struct i2c_client *client) { int err,i; for (i = 0; i < MAX_LM80_NR; i++) @@ -385,7 +361,6 @@ int lm80_new_client(struct i2c_adapter *adapter, new_client->driver = &lm80_driver; data = new_client->data; data->valid = 0; - data->lock = MUTEX; data->update_lock = MUTEX; return 0; } @@ -405,7 +380,6 @@ int lm80_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -/* Nothing here yet */ void lm80_inc_use (struct i2c_client *client) { #ifdef MODULE @@ -413,7 +387,6 @@ void lm80_inc_use (struct i2c_client *client) #endif } -/* Nothing here yet */ void lm80_dec_use (struct i2c_client *client) { #ifdef MODULE @@ -422,55 +395,37 @@ void lm80_dec_use (struct i2c_client *client) } -/* The SMBus locks itself, but ISA access must be locked explicitely! - We ignore the LM80 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM80 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ -int lm80_read_value(struct i2c_client *client, u8 reg) +long lm80_temp_from_reg(u16 temp) { - int res; - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,(((struct isa_client *) client)->isa_addr) + - LM80_ADDR_REG_OFFSET); - res = inb_p((((struct isa_client *) client)->isa_addr) + - LM80_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return res; - } else - return smbus_read_byte_data(client->adapter,client->addr, reg); + long res; + res = ((temp & 0xff00) >> 8) * 10000 + ((temp & 0x10) >> 4) * 5000 + + ((temp & 0x20) >> 5) * 2500 + ((temp & 0x40) >> 6) * 1250 + + ((temp & 0x80) >> 7) * 625; + temp /= 100; + if (temp >= 0x80 * 100) + temp = - (0x100 * 100 - temp); + return temp; +} + +int lm80_read_value(struct i2c_client *client, u8 reg) +{ + return smbus_read_byte_data(client->adapter,client->addr, reg); } -/* The SMBus locks itself, but ISA access muse be locked explicitely! - We ignore the LM80 BUSY flag at this moment - it could lead to deadlocks, - would slow down the LM80 access and should not be necessary. - There are some ugly typecasts here, but the good new is - they should - nowhere else be necessary! */ int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) { - if (i2c_is_isa_client(client)) { - down((struct semaphore *) (client->data)); - outb_p(reg,((struct isa_client *) client)->isa_addr + LM80_ADDR_REG_OFFSET); - outb_p(value,((struct isa_client *) client)->isa_addr + LM80_DATA_REG_OFFSET); - up((struct semaphore *) (client->data)); - return 0; - } else - return smbus_write_byte_data(client->adapter, client->addr, reg,value); + return smbus_write_byte_data(client->adapter, client->addr, reg,value); } /* Called when we have found a new LM80. It should set limits, etc. */ void lm80_init_client(struct i2c_client *client) { - int vid; - /* Reset all except Watchdog values and last conversion values - This sets fan-divs to 2, among others */ + This sets fan-divs to 2, among others. This makes most other + initializations unnecessary */ lm80_write_value(client,LM80_REG_CONFIG,0x80); - - vid = lm80_read_value(client,LM80_REG_VID_FANDIV) & 0x0f; - vid |= (lm80_read_value(client,LM80_REG_CHIPID) & 0x01) >> 4; - vid = VID_FROM_REG(vid); + /* Set 11-bit temperature resolution */ + lm80_write_value(client,LM80_REG_RES,0x08); lm80_write_value(client,LM80_REG_IN_MIN(0),IN_TO_REG(LM80_INIT_IN_MIN_0,0)); lm80_write_value(client,LM80_REG_IN_MAX(0),IN_TO_REG(LM80_INIT_IN_MAX_0,0)); @@ -486,16 +441,19 @@ void lm80_init_client(struct i2c_client *client) lm80_write_value(client,LM80_REG_IN_MAX(5),IN_TO_REG(LM80_INIT_IN_MAX_5,5)); lm80_write_value(client,LM80_REG_IN_MIN(6),IN_TO_REG(LM80_INIT_IN_MIN_6,6)); lm80_write_value(client,LM80_REG_IN_MAX(6),IN_TO_REG(LM80_INIT_IN_MAX_6,6)); - lm80_write_value(client,LM80_REG_FAN_MIN(1),FAN_TO_REG(LM80_INIT_FAN_MIN_1)); - lm80_write_value(client,LM80_REG_FAN_MIN(2),FAN_TO_REG(LM80_INIT_FAN_MIN_2)); - lm80_write_value(client,LM80_REG_FAN_MIN(3),FAN_TO_REG(LM80_INIT_FAN_MIN_3)); - lm80_write_value(client,LM80_REG_TEMP_OVER,TEMP_TO_REG(LM80_INIT_TEMP_OVER)); - lm80_write_value(client,LM80_REG_TEMP_HYST,TEMP_TO_REG(LM80_INIT_TEMP_HYST)); + lm80_write_value(client,LM80_REG_FAN1_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_1,2)); + lm80_write_value(client,LM80_REG_FAN2_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_2,2)); + lm80_write_value(client,LM80_REG_TEMP_HOT_MAX, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX)); + lm80_write_value(client,LM80_REG_TEMP_HOT_HYST, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST)); + lm80_write_value(client,LM80_REG_TEMP_OS_MAX, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX)); + lm80_write_value(client,LM80_REG_TEMP_OS_HYST, + TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST)); /* Start monitoring */ - lm80_write_value(client,LM80_REG_CONFIG, - (lm80_read_value(client,LM80_REG_CONFIG) & 0xf7) | 0x01); - + lm80_write_value(client,LM80_REG_CONFIG,0x01); } void lm80_update_client(struct i2c_client *client) @@ -505,7 +463,7 @@ void lm80_update_client(struct i2c_client *client) down(&data->update_lock); - if ((jiffies - data->last_updated > HZ+HZ/2 ) || + if ((jiffies - data->last_updated > 2*HZ ) || (jiffies < data->last_updated) || ! data->valid) { #ifdef DEBUG @@ -516,20 +474,23 @@ void lm80_update_client(struct i2c_client *client) data->in_min[i] = lm80_read_value(client,LM80_REG_IN_MIN(i)); data->in_max[i] = lm80_read_value(client,LM80_REG_IN_MAX(i)); } - for (i = 1; i <= 3; i++) { - data->fan[i-1] = lm80_read_value(client,LM80_REG_FAN(i)); - data->fan_min[i-1] = lm80_read_value(client,LM80_REG_FAN_MIN(i)); - } - data->temp = lm80_read_value(client,LM80_REG_TEMP); - data->temp_over = lm80_read_value(client,LM80_REG_TEMP_OVER); - data->temp_hyst = lm80_read_value(client,LM80_REG_TEMP_HYST); - i = lm80_read_value(client,LM80_REG_VID_FANDIV); - data->vid = i & 0x0f; - data->vid |= (lm80_read_value(client,LM80_REG_CHIPID) & 0x01) >> 4; - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = i >> 6; + data->fan[0] = lm80_read_value(client,LM80_REG_FAN1); + data->fan_min[0] = lm80_read_value(client,LM80_REG_FAN1_MIN); + data->fan[1] = lm80_read_value(client,LM80_REG_FAN2); + data->fan_min[1] = lm80_read_value(client,LM80_REG_FAN2_MIN); + + data->temp = (lm80_read_value(client,LM80_REG_TEMP) << 8) | + (lm80_read_value(client,LM80_REG_RES) & 0xf0); + data->temp_os_max = lm80_read_value(client,LM80_REG_TEMP_OS_MAX); + data->temp_os_hyst = lm80_read_value(client,LM80_REG_TEMP_OS_HYST); + data->temp_hot_max = lm80_read_value(client,LM80_REG_TEMP_HOT_MAX); + data->temp_hot_hyst = lm80_read_value(client,LM80_REG_TEMP_HOT_HYST); + + i = lm80_read_value(client,LM80_REG_FANDIV); + data->fan_div[0] = (i >> 2) & 0x03; + data->fan_div[1] = (i >> 4) & 0x03; data->alarms = lm80_read_value(client,LM80_REG_ALARM1) + - (lm80_read_value(client,LM80_REG_ALARM2) >> 8); + (lm80_read_value(client,LM80_REG_ALARM2) << 8); data->last_updated = jiffies; data->valid = 1; } @@ -587,13 +548,14 @@ void lm80_fan(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { lm80_update_client(client); - results[0] = FAN_FROM_REG(data->fan_min[nr-1]); - results[1] = FAN_FROM_REG(data->fan[nr-1]); + results[0] = FAN_FROM_REG(data->fan_min[nr-1],data->fan_div[nr-1]); + results[1] = FAN_FROM_REG(data->fan[nr-1],data->fan_div[nr-1]); *nrels_mag = 2; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { - data->fan_min[nr-1] = FAN_TO_REG(results[0]); - lm80_write_value(client,LM80_REG_FAN_MIN(nr),data->fan_min[nr-1]); + data->fan_min[nr-1] = FAN_TO_REG(results[0],data->fan_div[nr-1]); + lm80_write_value(client,nr==1?LM80_REG_FAN1_MIN:LM80_REG_FAN2_MIN, + data->fan_min[nr-1]); } } } @@ -607,32 +569,29 @@ void lm80_temp(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 1; else if (operation == SENSORS_PROC_REAL_READ) { lm80_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_over); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; + results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max); + results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst); + results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max); + results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst); + results[4] = TEMP_FROM_REG(data->temp); + *nrels_mag = 5; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { - data->temp_over = TEMP_TO_REG(results[0]); - lm80_write_value(client,LM80_REG_TEMP_OVER,data->temp_over); + data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]); + lm80_write_value(client,LM80_REG_TEMP_HOT_MAX,data->temp_hot_max); } if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - lm80_write_value(client,LM80_REG_TEMP_HYST,data->temp_hyst); + data->temp_hot_hyst = TEMP_LIMIT_TO_REG(results[1]); + lm80_write_value(client,LM80_REG_TEMP_HOT_HYST,data->temp_hot_hyst); + } + if (*nrels_mag >= 3) { + data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]); + lm80_write_value(client,LM80_REG_TEMP_OS_MAX,data->temp_os_max); + } + if (*nrels_mag >= 4) { + data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]); + lm80_write_value(client,LM80_REG_TEMP_OS_HYST,data->temp_os_hyst); } - } -} - -void lm80_vid(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm80_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - lm80_update_client(client); - results[0] = VID_FROM_REG(data->vid); - *nrels_mag = 1; } } @@ -664,15 +623,15 @@ void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name, results[2] = 2; *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { - old = lm80_read_value(client,LM80_REG_VID_FANDIV); + old = lm80_read_value(client,LM80_REG_FANDIV); if (*nrels_mag >= 2) { data->fan_div[1] = DIV_TO_REG(results[1]); - old = (old & 0x3f) | (data->fan_div[1] << 6); + old = (old & 0xcf) | (data->fan_div[1] << 4); } if (*nrels_mag >= 1) { data->fan_div[0] = DIV_TO_REG(results[0]); - old = (old & 0xcf) | (data->fan_div[0] << 4); - lm80_write_value(client,LM80_REG_VID_FANDIV,old); + old = (old & 0xf3) | (data->fan_div[0] << 2); + lm80_write_value(client,LM80_REG_FANDIV,old); } } } diff --git a/src/sensors.h b/src/sensors.h index e5184306..6a197113 100644 --- a/src/sensors.h +++ b/src/sensors.h @@ -87,6 +87,7 @@ extern void sensors_deregister_entry(int id); #define I2C_DRIVERID_GL518 1004 #define I2C_DRIVERID_EEPROM 1005 #define I2C_DRIVERID_W83781D 1006 +#define I2C_DRIVERID_LM80 1007 /* Sysctl IDs */ #ifdef DEV_HWMON @@ -198,4 +199,31 @@ struct sensors_chips_data { #define EEPROM_SYSCTL7 1006 #define EEPROM_SYSCTL8 1007 +#define LM80_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM80_SYSCTL_IN1 1001 +#define LM80_SYSCTL_IN2 1002 +#define LM80_SYSCTL_IN3 1003 +#define LM80_SYSCTL_IN4 1004 +#define LM80_SYSCTL_IN5 1005 +#define LM80_SYSCTL_IN6 1006 +#define LM80_SYSCTL_FAN1 1101 /* Rotations/min */ +#define LM80_SYSCTL_FAN2 1102 +#define LM80_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */ +#define LM80_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM80_SYSCTL_ALARMS 2001 /* bitvector */ + +#define LM80_ALARM_IN0 0x0001 +#define LM80_ALARM_IN1 0x0002 +#define LM80_ALARM_IN2 0x0004 +#define LM80_ALARM_IN3 0x0008 +#define LM80_ALARM_IN4 0x0010 +#define LM80_ALARM_IN5 0x0020 +#define LM80_ALARM_IN6 0x0040 +#define LM80_ALARM_FAN1 0x0400 +#define LM80_ALARM_FAN2 0x0800 +#define LM80_ALARM_TEMP_HOT 0x0100 +#define LM80_ALARM_TEMP_OS 0x2000 +#define LM80_ALARM_CHAS 0x1000 +#define LM80_ALARM_BTI 0x0200 +#define LM80_ALARM_INT_IN 0x0080 #endif /* def SENSORS_SENSORS_H */