From 51b011307c5f2507a82b72dc070f4d3b228eda2d Mon Sep 17 00:00:00 2001 From: "Mark D. Studebaker" Date: Sat, 31 May 2003 00:24:07 +0000 Subject: [PATCH] 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 --- doc/chips/lm85 | 4 +-- kernel/chips/lm85.c | 69 +++++++++++++++++++++++++++++++------- prog/detect/sensors-detect | 7 ++++ prog/sensors/chips.c | 14 +++++--- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/doc/chips/lm85 b/doc/chips/lm85 index 08fd1daf..aa952016 100644 --- a/doc/chips/lm85 +++ b/doc/chips/lm85 @@ -503,9 +503,9 @@ chip "lm85c-*" "adm1027-*" "adt7463-*" "lm85-*" "lm85b-*" set in2_min 3.3 * 0.95 set in2_max 3.3 * 1.05 set in3_min 5.0 * 0.95 - set in4_max 5.0 * 1.05 + set in3_max 5.0 * 1.05 set in4_min 12 * 0.95 - set in3_max 12 * 1.05 + set in4_max 12 * 1.05 # Set Fan limits set fan1_min 3000 diff --git a/kernel/chips/lm85.c b/kernel/chips/lm85.c index 4f2454ac..e8b3132b 100644 --- a/kernel/chips/lm85.c +++ b/kernel/chips/lm85.c @@ -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 @@ -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); } diff --git a/prog/detect/sensors-detect b/prog/detect/sensors-detect index 2698ba50..d43974f8 100755 --- a/prog/detect/sensors-detect +++ b/prog/detect/sensors-detect @@ -804,6 +804,12 @@ use subs qw(mtp008_detect lm78_detect lm78_isa_detect lm78_alias_detect i2c_addrs => [0x2c..0x2e], i2c_detect => sub { lm85_detect 0x41, @_}, }, + { + name => "SMSC EMC6D100 and EMC6D101", + driver => "lm85", + i2c_addrs => [0x2c..0x2e], + i2c_detect => sub { lm85_detect 0x5c, @_}, + }, { name => "National Semiconductor LM87", driver => "lm87", @@ -2234,6 +2240,7 @@ sub lm80_detect # 0x3f == Version/Stepping register. # Constants used: 0x01 == National Semiconductor Vendor Id. # 0x41 == Analog Devices Vendor Id. +# 0x5c == SMSC Vendor Id. # 0x60 == Version number. The lower 4 stepping # bits are masked and ignored. sub lm85_detect diff --git a/prog/sensors/chips.c b/prog/sensors/chips.c index 89f7defa..83158aae 100644 --- a/prog/sensors/chips.c +++ b/prog/sensors/chips.c @@ -1488,11 +1488,15 @@ void print_lm85(const sensors_chip_name *name) alarms = 0; } - if (!sensors_get_feature(*name,SENSORS_ADM1027_ALARM_MASK,&cur)) - alarm_mask = cur + 0.5; - else { - printf("ERROR: Can't get alarm mask data!\n"); - alarm_mask = 0; + if( is1027 ) { + if (!sensors_get_feature(*name,SENSORS_ADM1027_ALARM_MASK,&cur)) + alarm_mask = cur + 0.5; + else { + printf("ERROR: Can't get alarm mask data!\n"); + alarm_mask = 0; + } + } else { + alarm_mask = 0 ; } if (!sensors_get_label_and_valid(*name,SENSORS_LM85_IN0,&label,&valid) &&