hwmon: (lm80) Add detection of NatSemi/TI LM96080

Add detection of the National Semiconductor (now Texas Instruments)
LM96080. It is functionally compatible with the LM80 but detection is
completely different.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Guenter Roeck <guenter.roeck@ericsson.com>
Cc: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
This commit is contained in:
Jean Delvare 2012-01-31 09:27:11 -05:00 committed by Guenter Roeck
parent 0e190b7fa3
commit 9908ad4cd4
3 changed files with 45 additions and 12 deletions

View file

@ -7,6 +7,11 @@ Supported chips:
Addresses scanned: I2C 0x28 - 0x2f
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
* National Semiconductor LM96080
Prefix: 'lm96080'
Addresses scanned: I2C 0x28 - 0x2f
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
Authors:
Frodo Looijaard <frodol@dds.nl>,
@ -17,7 +22,9 @@ Description
This driver implements support for the National Semiconductor LM80.
It is described as a 'Serial Interface ACPI-Compatible Microprocessor
System Hardware Monitor'.
System Hardware Monitor'. The LM96080 is a more recent incarnation,
it is pin and register compatible, with a few additional features not
yet supported by the driver.
The LM80 implements one temperature sensor, two fan rotation speed sensors,
seven voltage sensors, alarms, and some miscellaneous stuff.

View file

@ -598,11 +598,11 @@ config SENSORS_LM78
will be called lm78.
config SENSORS_LM80
tristate "National Semiconductor LM80"
tristate "National Semiconductor LM80 and LM96080"
depends on I2C
help
If you say yes here you get support for National Semiconductor
LM80 sensor chips.
LM80 and LM96080 sensor chips.
This driver can also be built as a module. If so, the module
will be called lm80.

View file

@ -60,6 +60,10 @@ static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
#define LM80_REG_FANDIV 0x05
#define LM80_REG_RES 0x06
#define LM96080_REG_CONV_RATE 0x07
#define LM96080_REG_MAN_ID 0x3e
#define LM96080_REG_DEV_ID 0x3f
/*
* Conversions. Rounding and limit checking is only done on the TO_REG
@ -147,6 +151,7 @@ static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
static const struct i2c_device_id lm80_id[] = {
{ "lm80", 0 },
{ "lm96080", 1 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm80_id);
@ -490,23 +495,44 @@ static const struct attribute_group lm80_group = {
static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int i, cur;
int i, cur, man_id, dev_id;
const char *name = NULL;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Now, we do the remaining detection. It is lousy. */
if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
/* First check for unused bits, common to both chip types */
if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
|| (lm80_read_value(client, LM80_REG_CONFIG) & 0x80))
return -ENODEV;
for (i = 0x2a; i <= 0x3d; i++) {
cur = i2c_smbus_read_byte_data(client, i);
if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
|| (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
|| (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
/*
* The LM96080 has manufacturer and stepping/die rev registers so we
* can just check that. The LM80 does not have such registers so we
* have to use a more expensive trick.
*/
man_id = lm80_read_value(client, LM96080_REG_MAN_ID);
dev_id = lm80_read_value(client, LM96080_REG_DEV_ID);
if (man_id == 0x01 && dev_id == 0x08) {
/* Check more unused bits for confirmation */
if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe)
return -ENODEV;
name = "lm96080";
} else {
/* Check 6-bit addressing */
for (i = 0x2a; i <= 0x3d; i++) {
cur = i2c_smbus_read_byte_data(client, i);
if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
|| (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
|| (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
return -ENODEV;
}
name = "lm80";
}
strlcpy(info->type, "lm80", I2C_NAME_SIZE);
strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}