mirror of
https://github.com/lm-sensors/lm-sensors
synced 2025-08-30 22:05:11 +00:00
Rework all device detection routines which use SMBus read word
transactions in address range 0x40-0x48. Some devices don't like word transactions, so we now try to do as much of the detection as possible using byte transactions, and only use word transactions when there is a good chance that the detection will succeed. git-svn-id: http://lm-sensors.org/svn/lm-sensors/branches/lm-sensors-3.0.0@5246 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
@@ -2724,6 +2724,10 @@ sub i2c_smbus_read_byte_data
|
||||
# $_[0]: Reference to an opened filehandle
|
||||
# $_[1]: Command byte (usually register number)
|
||||
# Returns: -1 on failure, the read word on success.
|
||||
# Use this function with care, some devices don't like word reads,
|
||||
# so you should do as much of the detection as possible using byte reads,
|
||||
# and only start using word reads when there is a good chance that
|
||||
# the detection will succeed.
|
||||
# Note: some devices use the wrong endiannes; use swap_bytes to correct for
|
||||
# this.
|
||||
sub i2c_smbus_read_word_data
|
||||
@@ -3587,46 +3591,42 @@ sub lm78_alias_detect
|
||||
# The DS75 is a bit different, it doesn't cycle over 8-byte boundaries, and
|
||||
# all register addresses from 0x04 to 0x0f behave like 0x04-0x07 do for
|
||||
# the LM75.
|
||||
# Not all devices enjoy SMBus read word transactions, so we use read byte
|
||||
# transactions even for the 16-bit registers. The low bits aren't very
|
||||
# useful for detection anyway.
|
||||
sub lm75_detect
|
||||
{
|
||||
my $i;
|
||||
my ($chip, $file, $addr) = @_;
|
||||
my $cur = i2c_smbus_read_word_data($file,0x00);
|
||||
my $cur = i2c_smbus_read_byte_data($file, 0x00);
|
||||
my $conf = i2c_smbus_read_byte_data($file,0x01);
|
||||
|
||||
my $hyst = i2c_smbus_read_word_data($file,0x02);
|
||||
my $hyst = i2c_smbus_read_byte_data($file, 0x02);
|
||||
my $maxreg = $chip == 1 ? 0x0f : 0x07;
|
||||
for $i (0x04 .. $maxreg) {
|
||||
return if i2c_smbus_read_word_data($file, $i) != $hyst;
|
||||
return if i2c_smbus_read_byte_data($file, $i) != $hyst;
|
||||
}
|
||||
|
||||
my $os = i2c_smbus_read_word_data($file,0x03);
|
||||
my $os = i2c_smbus_read_byte_data($file, 0x03);
|
||||
for $i (0x04 .. $maxreg) {
|
||||
return if i2c_smbus_read_word_data($file, $i) != $os;
|
||||
return if i2c_smbus_read_byte_data($file, $i) != $os;
|
||||
}
|
||||
|
||||
if ($chip == 0) {
|
||||
for ($i = 8; $i <= 248; $i += 40) {
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf
|
||||
or i2c_smbus_read_word_data($file, $i + 0x02) != $hyst
|
||||
or i2c_smbus_read_word_data($file, $i + 0x03) != $os;
|
||||
or i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst
|
||||
or i2c_smbus_read_byte_data($file, $i + 0x03) != $os;
|
||||
}
|
||||
}
|
||||
|
||||
# All registers hold the same value, obviously a misdetection
|
||||
return if $conf == ($cur & 0xff) and $cur == $hyst
|
||||
and $cur == $os;
|
||||
return if $conf == $cur and $cur == $hyst and $cur == $os;
|
||||
|
||||
$cur = swap_bytes($cur);
|
||||
$hyst = swap_bytes($hyst);
|
||||
$os = swap_bytes($os);
|
||||
# Unused bits
|
||||
return if $chip == 0 and ($conf & 0xe0);
|
||||
return if $chip == 1 and ($conf & 0x80);
|
||||
|
||||
$cur = $cur >> 8;
|
||||
$hyst = $hyst >> 8;
|
||||
$os = $os >> 8;
|
||||
# Most probable value ranges
|
||||
return 6 if $cur <= 100 and ($hyst >= 10 && $hyst <= 125)
|
||||
and ($os >= 20 && $os <= 127) and $hyst < $os;
|
||||
@@ -3645,54 +3645,65 @@ sub lm75_detect
|
||||
# 0x03: Overtemperature Shutdown
|
||||
# 0x04: Low limit
|
||||
# 0x05: High limit
|
||||
# 0x04-0x07: No registers
|
||||
# 0x06-0x07: No registers
|
||||
# The first detection step is based on the fact that the LM77 has only
|
||||
# six registers, and cycles addresses over 8-byte boundaries. We use the
|
||||
# 0x06-0x07 addresses (unused) to improve the reliability. These are not
|
||||
# real registers and will always return the last returned value. This isn't
|
||||
# documented.
|
||||
# Note that register 0x00 may change, so we can't use the modulo trick on it.
|
||||
# Not all devices enjoy SMBus read word transactions, so we use read byte
|
||||
# transactions even for the 16-bit registers at first. We only use read word
|
||||
# transactions in the end when we are already almost certain that we have an
|
||||
# LM77 chip.
|
||||
sub lm77_detect
|
||||
{
|
||||
my $i;
|
||||
my ($file,$addr) = @_;
|
||||
my $cur = i2c_smbus_read_word_data($file,0x00);
|
||||
my $cur = i2c_smbus_read_byte_data($file, 0x00);
|
||||
my $conf = i2c_smbus_read_byte_data($file,0x01);
|
||||
my $hyst = i2c_smbus_read_word_data($file,0x02);
|
||||
my $os = i2c_smbus_read_word_data($file,0x03);
|
||||
my $hyst = i2c_smbus_read_byte_data($file, 0x02);
|
||||
my $os = i2c_smbus_read_byte_data($file, 0x03);
|
||||
|
||||
my $low = i2c_smbus_read_word_data($file,0x04);
|
||||
return if i2c_smbus_read_word_data($file,0x06) != $low;
|
||||
return if i2c_smbus_read_word_data($file,0x07) != $low;
|
||||
my $low = i2c_smbus_read_byte_data($file, 0x04);
|
||||
return if i2c_smbus_read_byte_data($file, 0x06) != $low;
|
||||
return if i2c_smbus_read_byte_data($file, 0x07) != $low;
|
||||
|
||||
my $high = i2c_smbus_read_word_data($file,0x05);
|
||||
return if i2c_smbus_read_word_data($file,0x06) != $high;
|
||||
return if i2c_smbus_read_word_data($file,0x07) != $high;
|
||||
my $high = i2c_smbus_read_byte_data($file, 0x05);
|
||||
return if i2c_smbus_read_byte_data($file, 0x06) != $high;
|
||||
return if i2c_smbus_read_byte_data($file, 0x07) != $high;
|
||||
|
||||
for ($i = 8; $i <= 248; $i += 40) {
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf;
|
||||
return if i2c_smbus_read_word_data($file, $i + 0x02) != $hyst;
|
||||
return if i2c_smbus_read_word_data($file, $i + 0x03) != $os;
|
||||
return if i2c_smbus_read_word_data($file, $i + 0x04) != $low;
|
||||
return if i2c_smbus_read_word_data($file, $i + 0x05) != $high;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x03) != $os;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high;
|
||||
}
|
||||
|
||||
# All registers hold the same value, obviously a misdetection
|
||||
return if $conf == ($cur & 0xff) and $cur == $hyst
|
||||
return if $conf == $cur and $cur == $hyst
|
||||
and $cur == $os and $cur == $low and $cur == $high;
|
||||
|
||||
$cur = swap_bytes($cur);
|
||||
$os = swap_bytes($os);
|
||||
$hyst = swap_bytes($hyst);
|
||||
$low = swap_bytes($low);
|
||||
$high = swap_bytes($high);
|
||||
# Unused bits
|
||||
return if ($conf & 0xe0)
|
||||
or (($cur >> 12) != 0 && ($cur >> 12) != 0xf)
|
||||
or (($hyst >> 12) != 0 && ($hyst >> 12) != 0xf)
|
||||
or (($os >> 12) != 0 && ($os >> 12) != 0xf)
|
||||
or (($low >> 12) != 0 && ($low >> 12) != 0xf)
|
||||
or (($high >> 12) != 0 && ($high >> 12) != 0xf);
|
||||
or (($cur >> 4) != 0 && ($cur >> 4) != 0xf)
|
||||
or (($hyst >> 4) != 0 && ($hyst >> 4) != 0xf)
|
||||
or (($os >> 4) != 0 && ($os >> 4) != 0xf)
|
||||
or (($low >> 4) != 0 && ($low >> 4) != 0xf)
|
||||
or (($high >> 4) != 0 && ($high >> 4) != 0xf);
|
||||
|
||||
# Make sure the chip supports SMBus read word transactions
|
||||
$cur = i2c_smbus_read_word_data($file, 0x00);
|
||||
return if $cur < 0;
|
||||
$hyst = i2c_smbus_read_word_data($file, 0x02);
|
||||
return if $hyst < 0;
|
||||
$os = i2c_smbus_read_word_data($file, 0x03);
|
||||
return if $os < 0;
|
||||
$low = i2c_smbus_read_word_data($file, 0x04);
|
||||
return if $low < 0;
|
||||
$high = i2c_smbus_read_word_data($file, 0x05);
|
||||
return if $high < 0;
|
||||
|
||||
$cur /= 16;
|
||||
$hyst /= 16;
|
||||
@@ -3720,33 +3731,48 @@ sub lm77_detect
|
||||
# One detection step is based on the fact that the LM92 and clones have a
|
||||
# limited number of registers, which cycle modulo 16 address values.
|
||||
# Note that register 0x00 may change, so we can't use the modulo trick on it.
|
||||
# Not all devices enjoy SMBus read word transactions, so we use read byte
|
||||
# transactions even for the 16-bit registers at first. We only use read
|
||||
# word transactions in the end when we are already almost certain that we
|
||||
# have an LM92 chip or compatible.
|
||||
sub lm92_detect
|
||||
{
|
||||
my ($chip, $file, $addr) = @_;
|
||||
|
||||
my $conf = i2c_smbus_read_byte_data($file, 0x01);
|
||||
my $hyst = i2c_smbus_read_word_data($file, 0x02);
|
||||
my $crit = i2c_smbus_read_word_data($file, 0x03);
|
||||
my $low = i2c_smbus_read_word_data($file, 0x04);
|
||||
my $high = i2c_smbus_read_word_data($file, 0x05);
|
||||
my $hyst = i2c_smbus_read_byte_data($file, 0x02);
|
||||
my $crit = i2c_smbus_read_byte_data($file, 0x03);
|
||||
my $low = i2c_smbus_read_byte_data($file, 0x04);
|
||||
my $high = i2c_smbus_read_byte_data($file, 0x05);
|
||||
|
||||
return if $conf == 0 and $hyst == 0 and $crit == 0
|
||||
and $low == 0 and $high == 0;
|
||||
|
||||
return if $chip == 0
|
||||
and i2c_smbus_read_word_data($file, 0x07) != 0x0180;
|
||||
|
||||
# Unused bits
|
||||
return if ($chip == 0 || $chip == 1)
|
||||
and ($conf & 0xE0);
|
||||
|
||||
for (my $i = 0; $i < 8; $i++) {
|
||||
return if i2c_smbus_read_byte_data($file, $i*16+0x01) != $conf;
|
||||
return if i2c_smbus_read_word_data($file, $i*16+0x02) != $hyst;
|
||||
return if i2c_smbus_read_word_data($file, $i*16+0x03) != $crit;
|
||||
return if i2c_smbus_read_word_data($file, $i*16+0x04) != $low;
|
||||
return if i2c_smbus_read_word_data($file, $i*16+0x05) != $high;
|
||||
for (my $i = 0; $i <= 240; $i += 16) {
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x01) != $conf;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x02) != $hyst;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x03) != $crit;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x04) != $low;
|
||||
return if i2c_smbus_read_byte_data($file, $i + 0x05) != $high;
|
||||
}
|
||||
|
||||
return if $chip == 0
|
||||
and i2c_smbus_read_word_data($file, 0x07) != 0x0180;
|
||||
|
||||
# Make sure the chip supports SMBus read word transactions
|
||||
$hyst = i2c_smbus_read_word_data($file, 0x02);
|
||||
return if $hyst < 0;
|
||||
$crit = i2c_smbus_read_word_data($file, 0x03);
|
||||
return if $crit < 0;
|
||||
$low = i2c_smbus_read_word_data($file, 0x04);
|
||||
return if $low < 0;
|
||||
$high = i2c_smbus_read_word_data($file, 0x05);
|
||||
return if $high < 0;
|
||||
|
||||
foreach my $temp ($hyst, $crit, $low, $high) {
|
||||
return if $chip == 2 and ($temp & 0x7F00);
|
||||
return if $chip != 2 and ($temp & 0x0700);
|
||||
@@ -3763,23 +3789,38 @@ sub lm92_detect
|
||||
# 0xAA: Temperature
|
||||
# 0xA1: High limit
|
||||
# 0xA2: Low limit
|
||||
# 0xA8: Counter
|
||||
# 0xA9: Slope
|
||||
# 0xAC: Configuration
|
||||
# Detection is weak. We check if bit 4 (NVB) is clear, because it is
|
||||
# unlikely to be set (would mean that EEPROM is currently being accessed).
|
||||
# Temperature checkings will hopefully prevent LM75 or other chips from
|
||||
# being detected as a DS1621.
|
||||
# We also check the value of the counter and slope registers, the datasheet
|
||||
# doesn't mention the possible values but the conversion formula together
|
||||
# with experimental evidence suggest possible sanity checks.
|
||||
# Not all devices enjoy SMBus read word transactions, so we do as much as
|
||||
# possible with read byte transactions first, and only use read word
|
||||
# transactions second.
|
||||
sub ds1621_detect
|
||||
{
|
||||
my $i;
|
||||
my ($file,$addr) = @_;
|
||||
|
||||
my $conf = i2c_smbus_read_byte_data($file, 0xAC);
|
||||
return if ($conf & 0x10);
|
||||
|
||||
my $counter = i2c_smbus_read_byte_data($file, 0xA8);
|
||||
my $slope = i2c_smbus_read_byte_data($file, 0xA9);
|
||||
return if ($slope != 0x10 || $counter > $slope);
|
||||
|
||||
my $temp = i2c_smbus_read_word_data($file,0xAA);
|
||||
return if $temp < 0 || ($temp & 0x7f00);
|
||||
my $high = i2c_smbus_read_word_data($file,0xA1);
|
||||
return if $high < 0 || ($high & 0x7f00);
|
||||
my $low = i2c_smbus_read_word_data($file,0xA2);
|
||||
return if ($temp | $high | $low) & 0x7F00;
|
||||
my $conf = i2c_smbus_read_byte_data($file,0xAC);
|
||||
return if $low < 0 || ($low & 0x7f00);
|
||||
|
||||
return if ($temp == 0 && $high == 0 && $low == 0 && $conf == 0);
|
||||
return 3 if ($conf & 0x10) == 0x00;
|
||||
return;
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
# $_[0]: A reference to the file descriptor to access this chip.
|
||||
|
Reference in New Issue
Block a user