mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-11-07 16:01:34 +00:00
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:
1 parent
e55205a604
commit
e5249883ec
10 files changed
+312
-334
No files matched your search
+2
-1
@@ -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
|
||||
|
||||
@@ -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,4 +1,3 @@
|
||||
|
||||
/*
|
||||
lm78.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
+123
-164
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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,4 +1,3 @@
|
||||
|
||||
/*
|
||||
lm78.c - Part of lm_sensors, Linux kernel modules for hardware
|
||||
monitoring
|
||||
|
||||
+123
-164
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
Reference in new issue
Block a user