Patch from Philip Pokorny

This patch fixes a race condition in the lm85 driver and adds support for the
SMC EMC6D100 and EMC6D101.  The EMC6D100 and 101 chips have some additional
features that *are not* currently implemented in the driver, but the chip is
detected (by sensors-detect and the lm85 driver).


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1740 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Mark D. Studebaker committed 2003-05-31 00:24:07 +00:00
1 parent 7eb36a199a
commit 51b011307c
4 files changed
+74 -20

No files matched your search

+56 -13
View File
@@ -1,4 +1,3 @@
#define DEBUG 1
/*
lm85.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
@@ -52,6 +51,7 @@
2003-03-08 Fixed problem with pseudo 16-bit registers
Cleaned up some compiler warnings.
Fixed problem with Operating Point and THERM counting
2003-03-21 Initial support for EMC6D100 and EMC6D101 chips
*/
#include <linux/version.h>
@@ -80,7 +80,7 @@ static unsigned int normal_isa[] = { SENSORS_ISA_END };
static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
/* Insmod parameters */
SENSORS_INSMOD_4(lm85b, lm85c, adm1027, adt7463);
SENSORS_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d101);
/* Many LM85 constants specified below */
@@ -112,6 +112,7 @@ SENSORS_INSMOD_4(lm85b, lm85c, adm1027, adt7463);
#define LM85_DEVICE_ADX 0x27
#define LM85_COMPANY_NATIONAL 0x01
#define LM85_COMPANY_ANALOG_DEV 0x41
#define LM85_COMPANY_SMSC 0x5c
#define LM85_VERSTEP_GENERIC 0x60
#define LM85_VERSTEP_LM85C 0x60
#define LM85_VERSTEP_LM85B 0x62
@@ -351,15 +352,9 @@ static int ZONE_TO_REG( int zone )
#define LM85_DATA_INTERVAL (1 * HZ)
#define LM85_CONFIG_INTERVAL (5 * 60 * HZ)
/* There are some complications in a module like this. There might be
several LM85 chips available (well, actually, that is probably never
done; but it is a clean illustration of how to handle a case like
that). */
/* For each registered LM85, we need to keep some data in memory. That
data is pointed to by lm85_list[NR]->data. The structure itself is
dynamically allocated, at the same time when a new lm85 client is
allocated. */
data is pointed to by client->data. The structure itself is
dynamically allocated, when a new lm85 client is allocated. */
/* LM85 can automatically adjust fan speeds based on temperature
* This structure encapsulates an entire Zone config. There are
@@ -773,6 +768,11 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
printk("lm85: Unrecgonized version/stepping 0x%02x"
" Defaulting to ADM1027.\n", verstep );
kind = adm1027 ;
} else if( company == LM85_COMPANY_SMSC
&& (verstep & 0xf0) == LM85_VERSTEP_GENERIC ) {
printk("lm85: Your EMC6D10x has version/stepping 0x%02x"
" Please notify lm_sensors team.\n", verstep );
kind = emc6d101 ;
} else if( kind == 0 && (verstep & 0xf0) == 0x60) {
printk("lm85: Generic LM85 Version 6 detected\n");
/* Leave kind as "any_chip" */
@@ -824,6 +824,16 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
memcpy( template+template_used, adm1027_specific, sizeof(adm1027_specific) );
template_used += CTLTBL_ADM1027 ;
break ;
case emc6d100 :
type_name = "emc6d100";
strcpy(new_client->name, "SMSC EMC6D100");
template_used = 0 ;
break ;
case emc6d101 :
type_name = "emc6d101";
strcpy(new_client->name, "SMSC EMC6D101");
template_used = 0 ;
break ;
default :
printk("lm85: Internal error, invalid kind (%d)!", kind);
err = -EFAULT ;
@@ -832,13 +842,11 @@ int lm85_detect(struct i2c_adapter *adapter, int address,
/* Fill in the remaining client fields */
new_client->id = lm85_id++;
#ifdef DEBUG
printk("lm85: Assigning ID %d to %s at %d,0x%02x\n",
new_client->id, new_client->name,
i2c_adapter_id(new_client->adapter),
new_client->addr
);
#endif
/* Housekeeping values */
data->type = kind;
@@ -1076,7 +1084,7 @@ void lm85_update_client(struct i2c_client *client)
break ;
default :
data->extend_adc = 0 ;
break ;
break ;
}
for (i = 0; i <= 4; ++i) {
@@ -1250,6 +1258,7 @@ void lm85_in(struct i2c_client *client, int operation, int ctl_name,
results[2] = INSEXT_FROM_REG(nr,data->in[nr],ext);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 1) {
data->in_max[nr] = INS_TO_REG(nr,results[1]);
lm85_write_value(client, LM85_REG_IN_MAX(nr),
@@ -1260,6 +1269,7 @@ void lm85_in(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_IN_MIN(nr),
data->in_min[nr]);
}
up(&data->update_lock);
}
}
@@ -1280,11 +1290,13 @@ void lm85_fan(struct i2c_client *client, int operation, int ctl_name,
results[1] = FAN_FROM_REG(data->fan[nr]);
*nrels_mag = 2;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 0) {
data->fan_min[nr] = FAN_TO_REG(results[0]);
lm85_write_value(client, LM85_REG_FAN_MIN(nr),
data->fan_min[nr]);
}
up(&data->update_lock);
}
}
@@ -1312,6 +1324,7 @@ void lm85_temp(struct i2c_client *client, int operation, int ctl_name,
results[2] = TEMPEXT_FROM_REG(data->temp[nr],ext);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 1) {
data->temp_max[nr] = TEMP_TO_REG(results[1]);
lm85_write_value(client, LM85_REG_TEMP_MAX(nr),
@@ -1322,6 +1335,7 @@ void lm85_temp(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_TEMP_MIN(nr),
data->temp_min[nr]);
}
up(&data->update_lock);
}
}
@@ -1345,12 +1359,14 @@ void lm85_pwm(struct i2c_client *client, int operation, int ctl_name,
results[1] = pwm_zone != 0 && pwm_zone != -1 ;
*nrels_mag = 2;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
/* PWM enable is read-only */
if (*nrels_mag > 0) {
data->pwm[nr] = PWM_TO_REG(results[0]);
lm85_write_value(client, LM85_REG_PWM(nr),
data->pwm[nr]);
}
up(&data->update_lock);
}
}
@@ -1385,9 +1401,11 @@ void lm85_vrm(struct i2c_client *client, int operation, int ctl_name,
results[0] = data->vrm ;
*nrels_mag = 1;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 0) {
data->vrm = results[0] ;
}
up(&data->update_lock);
}
}
@@ -1426,6 +1444,7 @@ void lm85_spinup_ctl(struct i2c_client *client, int operation, int ctl_name,
results[2] = (data->spinup_ctl & 4) != 0 ;
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
old = data->spinup_ctl ;
if (*nrels_mag > 2) {
old = (old & (~4)) | (results[2]?4:0) ;
@@ -1438,6 +1457,7 @@ void lm85_spinup_ctl(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_SPINUP_CTL, old);
data->spinup_ctl = old ;
}
up(&data->update_lock);
}
}
@@ -1461,6 +1481,7 @@ void lm85_tach_mode(struct i2c_client *client, int operation, int ctl_name,
results[2] = (data->tach_mode & 0x30) >> 4 ;
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
old = data->tach_mode ;
if (*nrels_mag > 2) {
old = (old & (~0x30)) | ((results[2]&3) << 4) ;
@@ -1473,6 +1494,7 @@ void lm85_tach_mode(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_TACH_MODE, old);
data->tach_mode = old ;
}
up(&data->update_lock);
}
}
@@ -1497,6 +1519,7 @@ void adm1027_tach_mode(struct i2c_client *client, int operation, int ctl_name,
results[3] = (data->tach_mode & 0x80) != 0 ;
*nrels_mag = 4;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
old = data->tach_mode ;
if (*nrels_mag > 3) {
old = (old & (~0x80)) | (results[3] ? 0x80 : 0) ;
@@ -1516,6 +1539,7 @@ void adm1027_tach_mode(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, ADM1027_REG_CONFIG3, old);
data->tach_mode = old ;
}
up(&data->update_lock);
}
}
@@ -1543,6 +1567,7 @@ void lm85_pwm_config(struct i2c_client *client, int operation, int ctl_name,
*nrels_mag = 5;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
int old_config ;
down(&data->update_lock);
old_config = data->autofan[nr].config ;
if (*nrels_mag > 4) {
old_config = (old_config & (~0x10)) | (results[4]?0x10:0) ;
@@ -1575,6 +1600,7 @@ void lm85_pwm_config(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr), old_config);
data->autofan[nr].config = old_config ;
}
up(&data->update_lock);
}
}
@@ -1595,6 +1621,7 @@ void lm85_smooth(struct i2c_client *client, int operation, int ctl_name,
*nrels_mag = 1;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if( *nrels_mag > 0 ) {
data->smooth[nr] = SMOOTH_TO_REG(results[0]);
}
@@ -1610,6 +1637,7 @@ void lm85_smooth(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_AFAN_SPIKE2,
(data->smooth[1] << 4) | data->smooth[2]);
}
up(&data->update_lock);
}
}
@@ -1636,6 +1664,7 @@ void lm85_zone(struct i2c_client *client, int operation, int ctl_name,
*nrels_mag = 4;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 3) {
data->zone[nr].critical = TEMP_TO_REG(results[3]*10);
lm85_write_value(client, LM85_REG_AFAN_CRITICAL(nr),
@@ -1667,6 +1696,7 @@ void lm85_zone(struct i2c_client *client, int operation, int ctl_name,
data->zone[nr].limit
);
}
up(&data->update_lock);
}
}
@@ -1686,6 +1716,7 @@ void lm85_pwm_zone(struct i2c_client *client, int operation, int ctl_name,
results[0] = ZONE_FROM_REG(data->autofan[nr].config);
*nrels_mag = 1;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 0) {
data->autofan[nr].config =
(data->autofan[nr].config & (~0xe0))
@@ -1693,6 +1724,7 @@ void lm85_pwm_zone(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, LM85_REG_AFAN_CONFIG(nr),
data->autofan[nr].config);
}
up(&data->update_lock);
}
}
@@ -1720,6 +1752,7 @@ void adm1027_temp_offset(struct i2c_client *client, int operation, int ctl_name,
}
*nrels_mag = 1;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 0) {
switch( data->type ) {
case adm1027 :
@@ -1733,6 +1766,7 @@ void adm1027_temp_offset(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, ADM1027_REG_TEMP_OFFSET(nr),
data->temp_offset[nr]);
}
up(&data->update_lock);
}
}
@@ -1755,6 +1789,7 @@ void adm1027_fan_ppr(struct i2c_client *client, int operation, int ctl_name,
results[3] = PPR_FROM_REG(data->fan_ppr,3);
*nrels_mag = 4;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
old = data->fan_ppr ;
if (*nrels_mag > 3) {
old = (old & ~PPR_MASK(3)) | PPR_TO_REG(results[3],3);
@@ -1770,6 +1805,7 @@ void adm1027_fan_ppr(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, ADM1027_REG_FAN_PPR, old);
data->fan_ppr = old ;
}
up(&data->update_lock);
}
}
@@ -1788,11 +1824,13 @@ void adm1027_alarm_mask(struct i2c_client *client, int operation,
results[0] = INTMASK_FROM_REG(data->alarm_mask);
*nrels_mag = 1;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
if (*nrels_mag > 0) {
data->alarm_mask = INTMASK_TO_REG(results[0]);
lm85_write_value(client, ADM1027_REG_INTMASK,
data->alarm_mask);
}
up(&data->update_lock);
}
}
@@ -1816,6 +1854,7 @@ void adt7463_tmin_ctl(struct i2c_client *client, int operation, int ctl_name,
results[3] = OPPOINT_FROM_REG(data->oppoint[nr]);
*nrels_mag = 4;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
old = data->tmin_ctl ;
if (*nrels_mag > 3) {
data->oppoint[nr] = OPPOINT_TO_REG(results[3]);
@@ -1842,6 +1881,7 @@ void adt7463_tmin_ctl(struct i2c_client *client, int operation, int ctl_name,
lm85_write_value(client, ADT7463_REG_TMIN_CTL, old);
data->tmin_ctl = old ;
}
up(&data->update_lock);
}
}
@@ -1876,18 +1916,21 @@ void adt7463_therm_signal(struct i2c_client *client, int operation,
results[2] = data->therm_ovfl ;
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
down(&data->update_lock);
/* therm_total and therm_ovfl are read only */
if (*nrels_mag > 0) {
data->therm_limit = SENSORS_LIMIT(results[0],0,255);
lm85_write_value(client, ADT7463_REG_THERM_LIMIT,
data->therm_limit);
};
up(&data->update_lock);
}
}
static int __init sm_lm85_init(void)
{
printk("lm85 version %s (%s)\n", LM_VERSION, LM_DATE);
printk("lm85: See http://www.penguincomputing.com/lm_sensors for more info.\n" );
return i2c_add_driver(&lm85_driver);
}