Completed the LM80 driver. Untested.

git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@115 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Frodo Looijaard committed 1998-12-25 19:30:44 +00:00
1 parent e55205a604
commit e5249883ec
10 files changed
+312 -334

No files matched your search

+2 -1
View File
@@ -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
+3 -1
View File
@@ -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;
}
}
-1
View File
@@ -1,4 +1,3 @@
/*
lm78.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
+123 -164
View File
@@ -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);
}
}
}
+28
View File
@@ -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 */
+2 -1
View File
@@ -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
+3 -1
View File
@@ -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;
}
}
-1
View File
@@ -1,4 +1,3 @@
/*
lm78.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
+123 -164
View File
@@ -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);
}
}
}
+28
View File
@@ -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 */