X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fhwmon%2Flm90.c;h=7cc2708871abb7784afda170bd839517604ccb2d;hb=5afd06ccd6b309f6a47d7e8fa4ea349b25738d97;hp=b2d9b3f0946d11e5eb962fb9b1888b491107d86d;hpb=cea50fe2fdea36174aa24b58c69c4eb9770e7c49;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index b2d9b3f..7cc2708 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -1,7 +1,7 @@ /* * lm90.c - Part of lm_sensors, Linux kernel modules for hardware * monitoring - * Copyright (C) 2003-2008 Jean Delvare + * Copyright (C) 2003-2010 Jean Delvare * * Based on the lm83 driver. The LM90 is a sensor chip made by National * Semiconductor. It reports up to two temperatures (its own plus up to @@ -12,9 +12,9 @@ * made by National Semiconductor. Both have an increased remote * temperature measurement accuracy (1 degree), and the LM99 * additionally shifts remote temperatures (measured and limits) by 16 - * degrees, which allows for higher temperatures measurement. The - * driver doesn't handle it since it can be done easily in user-space. + * degrees, which allows for higher temperatures measurement. * Note that there is no way to differentiate between both chips. + * When device is auto-detected, the driver will assume an LM99. * * This driver also supports the LM86, another sensor chip made by * National Semiconductor. It is exactly similar to the LM90 except it @@ -32,16 +32,20 @@ * supported by this driver. These chips lack the remote temperature * offset feature. * + * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and + * MAX6692 chips made by Maxim. These are again similar to the LM86, + * but they use unsigned temperature values and can report temperatures + * from 0 to 145 degrees. + * * This driver also supports the MAX6680 and MAX6681, two other sensor * chips made by Maxim. These are quite similar to the other Maxim * chips. The MAX6680 and MAX6681 only differ in the pinout so they can * be treated identically. * - * This driver also supports the ADT7461 chip from Analog Devices but - * only in its "compatability mode". If an ADT7461 chip is found but - * is configured in non-compatible mode (where its temperature - * register values are decoded differently) it is ignored by this - * driver. + * This driver also supports the ADT7461 chip from Analog Devices. + * It's supported in both compatibility and extended mode. It is mostly + * compatible with LM90 except for a data format difference for the + * temperature value registers. * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -77,9 +81,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659, MAX6680 and MAX6681. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658 - * have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657 + * and MAX6658 have address 0x4c. + * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d. + * MAX6647 has address 0x4e. * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported). * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, * 0x4c, 0x4d or 0x4e. @@ -88,11 +93,8 @@ static const unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; -/* - * Insmod parameters - */ - -I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680); +enum chips { lm90, adm1032, lm99, lm86, max6657, adt7461, max6680, max6646, + w83l771 }; /* * The LM90 registers @@ -133,19 +135,24 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680); #define LM90_REG_R_TCRIT_HYST 0x21 #define LM90_REG_W_TCRIT_HYST 0x21 -/* MAX6657-specific registers */ +/* MAX6646/6647/6649/6657/6658/6659 registers */ #define MAX6657_REG_R_LOCAL_TEMPL 0x11 /* + * Device flags + */ +#define LM90_FLAG_ADT7461_EXT 0x01 /* ADT7461 extended mode */ + +/* * Functions declaration */ -static int lm90_detect(struct i2c_client *client, int kind, - struct i2c_board_info *info); +static int lm90_detect(struct i2c_client *client, struct i2c_board_info *info); static int lm90_probe(struct i2c_client *client, const struct i2c_device_id *id); static void lm90_init_client(struct i2c_client *client); +static void lm90_alert(struct i2c_client *client, unsigned int flag); static int lm90_remove(struct i2c_client *client); static struct lm90_data *lm90_update_device(struct device *dev); @@ -158,13 +165,17 @@ static const struct i2c_device_id lm90_id[] = { { "adt7461", adt7461 }, { "lm90", lm90 }, { "lm86", lm86 }, - { "lm89", lm99 }, - { "lm99", lm99 }, /* Missing temperature offset */ + { "lm89", lm86 }, + { "lm99", lm99 }, + { "max6646", max6646 }, + { "max6647", max6646 }, + { "max6649", max6646 }, { "max6657", max6657 }, { "max6658", max6657 }, { "max6659", max6657 }, { "max6680", max6680 }, { "max6681", max6680 }, + { "w83l771", w83l771 }, { } }; MODULE_DEVICE_TABLE(i2c, lm90_id); @@ -176,9 +187,10 @@ static struct i2c_driver lm90_driver = { }, .probe = lm90_probe, .remove = lm90_remove, + .alert = lm90_alert, .id_table = lm90_id, .detect = lm90_detect, - .address_data = &addr_data, + .address_list = normal_i2c, }; /* @@ -191,6 +203,10 @@ struct lm90_data { char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ int kind; + int flags; + + u8 config_orig; /* Original configuration register value */ + u8 alert_alarms; /* Which alarm bits trigger ALERT# */ /* registers values */ s8 temp8[4]; /* 0: local low limit @@ -200,7 +216,7 @@ struct lm90_data { s16 temp11[5]; /* 0: remote input 1: remote low limit 2: remote high limit - 3: remote offset (except max6657) + 3: remote offset (except max6646 and max6657) 4: local input */ u8 temp_hyst; u8 alarms; /* bitvector */ @@ -211,20 +227,31 @@ struct lm90_data { * For local temperatures and limits, critical limits and the hysteresis * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius. * For remote temperatures and limits, it uses signed 11-bit values with - * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. + * LSB = 0.125 degree Celsius, left-justified in 16-bit registers. Some + * Maxim chips use unsigned values. */ -static inline int temp1_from_reg(s8 val) +static inline int temp_from_s8(s8 val) +{ + return val * 1000; +} + +static inline int temp_from_u8(u8 val) { return val * 1000; } -static inline int temp2_from_reg(s16 val) +static inline int temp_from_s16(s16 val) { return val / 32 * 125; } -static s8 temp1_to_reg(long val) +static inline int temp_from_u16(u16 val) +{ + return val / 32 * 125; +} + +static s8 temp_to_s8(long val) { if (val <= -128000) return -128; @@ -235,7 +262,16 @@ static s8 temp1_to_reg(long val) return (val + 500) / 1000; } -static s16 temp2_to_reg(long val) +static u8 temp_to_u8(long val) +{ + if (val <= 0) + return 0; + if (val >= 255000) + return 255; + return (val + 500) / 1000; +} + +static s16 temp_to_s16(long val) { if (val <= -128000) return 0x8000; @@ -256,26 +292,61 @@ static u8 hyst_to_reg(long val) } /* - * ADT7461 is almost identical to LM90 except that attempts to write - * values that are outside the range 0 < temp < 127 are treated as - * the boundary value. + * ADT7461 in compatibility mode is almost identical to LM90 except that + * attempts to write values that are outside the range 0 < temp < 127 are + * treated as the boundary value. + * + * ADT7461 in "extended mode" operation uses unsigned integers offset by + * 64 (e.g., 0 -> -64 degC). The range is restricted to -64..191 degC. */ -static u8 temp1_to_reg_adt7461(long val) +static inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val) { - if (val <= 0) - return 0; - if (val >= 127000) - return 127; - return (val + 500) / 1000; + if (data->flags & LM90_FLAG_ADT7461_EXT) + return (val - 64) * 1000; + else + return temp_from_s8(val); } -static u16 temp2_to_reg_adt7461(long val) +static inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val) { - if (val <= 0) - return 0; - if (val >= 127750) - return 0x7FC0; - return (val + 125) / 250 * 64; + if (data->flags & LM90_FLAG_ADT7461_EXT) + return (val - 0x4000) / 64 * 250; + else + return temp_from_s16(val); +} + +static u8 temp_to_u8_adt7461(struct lm90_data *data, long val) +{ + if (data->flags & LM90_FLAG_ADT7461_EXT) { + if (val <= -64000) + return 0; + if (val >= 191000) + return 0xFF; + return (val + 500 + 64000) / 1000; + } else { + if (val <= 0) + return 0; + if (val >= 127000) + return 127; + return (val + 500) / 1000; + } +} + +static u16 temp_to_u16_adt7461(struct lm90_data *data, long val) +{ + if (data->flags & LM90_FLAG_ADT7461_EXT) { + if (val <= -64000) + return 0; + if (val >= 191750) + return 0xFFC0; + return (val + 64000 + 125) / 250 * 64; + } else { + if (val <= 0) + return 0; + if (val >= 127750) + return 0x7FC0; + return (val + 125) / 250 * 64; + } } /* @@ -287,7 +358,20 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", temp1_from_reg(data->temp8[attr->index])); + int temp; + + if (data->kind == adt7461) + temp = temp_from_u8_adt7461(data, data->temp8[attr->index]); + else if (data->kind == max6646) + temp = temp_from_u8(data->temp8[attr->index]); + else + temp = temp_from_s8(data->temp8[attr->index]); + + /* +16 degrees offset for temp2 for the LM99 */ + if (data->kind == lm99 && attr->index == 3) + temp += 16000; + + return sprintf(buf, "%d\n", temp); } static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, @@ -306,11 +390,17 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, long val = simple_strtol(buf, NULL, 10); int nr = attr->index; + /* +16 degrees offset for temp2 for the LM99 */ + if (data->kind == lm99 && attr->index == 3) + val -= 16000; + mutex_lock(&data->update_lock); if (data->kind == adt7461) - data->temp8[nr] = temp1_to_reg_adt7461(val); + data->temp8[nr] = temp_to_u8_adt7461(data, val); + else if (data->kind == max6646) + data->temp8[nr] = temp_to_u8(val); else - data->temp8[nr] = temp1_to_reg(val); + data->temp8[nr] = temp_to_s8(val); i2c_smbus_write_byte_data(client, reg[nr], data->temp8[nr]); mutex_unlock(&data->update_lock); return count; @@ -321,7 +411,20 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", temp2_from_reg(data->temp11[attr->index])); + int temp; + + if (data->kind == adt7461) + temp = temp_from_u16_adt7461(data, data->temp11[attr->index]); + else if (data->kind == max6646) + temp = temp_from_u16(data->temp11[attr->index]); + else + temp = temp_from_s16(data->temp11[attr->index]); + + /* +16 degrees offset for temp2 for the LM99 */ + if (data->kind == lm99 && attr->index <= 2) + temp += 16000; + + return sprintf(buf, "%d\n", temp); } static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, @@ -342,17 +445,24 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, long val = simple_strtol(buf, NULL, 10); int nr = attr->index; + /* +16 degrees offset for temp2 for the LM99 */ + if (data->kind == lm99 && attr->index <= 2) + val -= 16000; + mutex_lock(&data->update_lock); if (data->kind == adt7461) - data->temp11[nr] = temp2_to_reg_adt7461(val); + data->temp11[nr] = temp_to_u16_adt7461(data, val); else if (data->kind == max6657 || data->kind == max6680) - data->temp11[nr] = temp1_to_reg(val) << 8; + data->temp11[nr] = temp_to_s8(val) << 8; + else if (data->kind == max6646) + data->temp11[nr] = temp_to_u8(val) << 8; else - data->temp11[nr] = temp2_to_reg(val); + data->temp11[nr] = temp_to_s16(val); i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2], data->temp11[nr] >> 8); - if (data->kind != max6657 && data->kind != max6680) + if (data->kind != max6657 && data->kind != max6680 + && data->kind != max6646) i2c_smbus_write_byte_data(client, reg[(nr - 1) * 2 + 1], data->temp11[nr] & 0xff); mutex_unlock(&data->update_lock); @@ -364,8 +474,20 @@ static ssize_t show_temphyst(struct device *dev, struct device_attribute *devatt { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm90_data *data = lm90_update_device(dev); - return sprintf(buf, "%d\n", temp1_from_reg(data->temp8[attr->index]) - - temp1_from_reg(data->temp_hyst)); + int temp; + + if (data->kind == adt7461) + temp = temp_from_u8_adt7461(data, data->temp8[attr->index]); + else if (data->kind == max6646) + temp = temp_from_u8(data->temp8[attr->index]); + else + temp = temp_from_s8(data->temp8[attr->index]); + + /* +16 degrees offset for temp2 for the LM99 */ + if (data->kind == lm99 && attr->index == 3) + temp += 16000; + + return sprintf(buf, "%d\n", temp - temp_from_s8(data->temp_hyst)); } static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, @@ -374,12 +496,19 @@ static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, struct i2c_client *client = to_i2c_client(dev); struct lm90_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); - long hyst; + int temp; mutex_lock(&data->update_lock); - hyst = temp1_from_reg(data->temp8[2]) - val; + if (data->kind == adt7461) + temp = temp_from_u8_adt7461(data, data->temp8[2]); + else if (data->kind == max6646) + temp = temp_from_u8(data->temp8[2]); + else + temp = temp_from_s8(data->temp8[2]); + + data->temp_hyst = hyst_to_reg(temp - val); i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, - hyst_to_reg(hyst)); + data->temp_hyst); mutex_unlock(&data->update_lock); return count; } @@ -528,138 +657,131 @@ static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value) } /* Return 0 if detection is successful, -ENODEV otherwise */ -static int lm90_detect(struct i2c_client *new_client, int kind, +static int lm90_detect(struct i2c_client *new_client, struct i2c_board_info *info) { struct i2c_adapter *adapter = new_client->adapter; int address = new_client->addr; - const char *name = ""; + const char *name = NULL; + int man_id, chip_id, reg_config1, reg_convrate; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - */ - - /* Default to an LM90 if forced */ - if (kind == 0) - kind = lm90; - - if (kind < 0) { /* detection and identification */ - int man_id, chip_id, reg_config1, reg_convrate; - - if ((man_id = i2c_smbus_read_byte_data(new_client, + /* detection and identification */ + if ((man_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_MAN_ID)) < 0 - || (chip_id = i2c_smbus_read_byte_data(new_client, + || (chip_id = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CHIP_ID)) < 0 - || (reg_config1 = i2c_smbus_read_byte_data(new_client, + || (reg_config1 = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONFIG1)) < 0 - || (reg_convrate = i2c_smbus_read_byte_data(new_client, + || (reg_convrate = i2c_smbus_read_byte_data(new_client, LM90_REG_R_CONVRATE)) < 0) + return -ENODEV; + + if ((address == 0x4C || address == 0x4D) + && man_id == 0x01) { /* National Semiconductor */ + int reg_config2; + + reg_config2 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG2); + if (reg_config2 < 0) return -ENODEV; - - if ((address == 0x4C || address == 0x4D) - && man_id == 0x01) { /* National Semiconductor */ - int reg_config2; - - if ((reg_config2 = i2c_smbus_read_byte_data(new_client, - LM90_REG_R_CONFIG2)) < 0) - return -ENODEV; - - if ((reg_config1 & 0x2A) == 0x00 - && (reg_config2 & 0xF8) == 0x00 - && reg_convrate <= 0x09) { - if (address == 0x4C - && (chip_id & 0xF0) == 0x20) { /* LM90 */ - kind = lm90; - } else - if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ - kind = lm99; - } else - if (address == 0x4C - && (chip_id & 0xF0) == 0x10) { /* LM86 */ - kind = lm86; - } - } - } else - if ((address == 0x4C || address == 0x4D) - && man_id == 0x41) { /* Analog Devices */ - if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ - && (reg_config1 & 0x3F) == 0x00 - && reg_convrate <= 0x0A) { - kind = adm1032; + + if ((reg_config1 & 0x2A) == 0x00 + && (reg_config2 & 0xF8) == 0x00 + && reg_convrate <= 0x09) { + if (address == 0x4C + && (chip_id & 0xF0) == 0x20) { /* LM90 */ + name = "lm90"; } else - if (chip_id == 0x51 /* ADT7461 */ - && (reg_config1 & 0x1F) == 0x00 /* check compat mode */ - && reg_convrate <= 0x0A) { - kind = adt7461; - } - } else - if (man_id == 0x4D) { /* Maxim */ - /* - * The MAX6657, MAX6658 and MAX6659 do NOT have a - * chip_id register. Reading from that address will - * return the last read value, which in our case is - * those of the man_id register. Likewise, the config1 - * register seems to lack a low nibble, so the value - * will be those of the previous read, so in our case - * those of the man_id register. - */ - if (chip_id == man_id - && (address == 0x4C || address == 0x4D) - && (reg_config1 & 0x1F) == (man_id & 0x0F) - && reg_convrate <= 0x09) { - kind = max6657; + if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */ + name = "lm99"; + dev_info(&adapter->dev, + "Assuming LM99 chip at 0x%02x\n", + address); + dev_info(&adapter->dev, + "If it is an LM89, instantiate it " + "with the new_device sysfs " + "interface\n"); } else - /* The chip_id register of the MAX6680 and MAX6681 - * holds the revision of the chip. - * the lowest bit of the config1 register is unused - * and should return zero when read, so should the - * second to last bit of config1 (software reset) - */ - if (chip_id == 0x01 - && (reg_config1 & 0x03) == 0x00 - && reg_convrate <= 0x07) { - kind = max6680; + if (address == 0x4C + && (chip_id & 0xF0) == 0x10) { /* LM86 */ + name = "lm86"; } } - - if (kind <= 0) { /* identification failed */ - dev_info(&adapter->dev, - "Unsupported chip (man_id=0x%02X, " - "chip_id=0x%02X).\n", man_id, chip_id); - return -ENODEV; + } else + if ((address == 0x4C || address == 0x4D) + && man_id == 0x41) { /* Analog Devices */ + if ((chip_id & 0xF0) == 0x40 /* ADM1032 */ + && (reg_config1 & 0x3F) == 0x00 + && reg_convrate <= 0x0A) { + name = "adm1032"; + /* The ADM1032 supports PEC, but only if combined + transactions are not used. */ + if (i2c_check_functionality(adapter, + I2C_FUNC_SMBUS_BYTE)) + info->flags |= I2C_CLIENT_PEC; + } else + if (chip_id == 0x51 /* ADT7461 */ + && (reg_config1 & 0x1B) == 0x00 + && reg_convrate <= 0x0A) { + name = "adt7461"; + } + } else + if (man_id == 0x4D) { /* Maxim */ + /* + * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id + * register. Reading from that address will return the last + * read value, which in our case is those of the man_id + * register. Likewise, the config1 register seems to lack a + * low nibble, so the value will be those of the previous + * read, so in our case those of the man_id register. + */ + if (chip_id == man_id + && (address == 0x4C || address == 0x4D) + && (reg_config1 & 0x1F) == (man_id & 0x0F) + && reg_convrate <= 0x09) { + name = "max6657"; + } else + /* + * The chip_id register of the MAX6680 and MAX6681 holds the + * revision of the chip. The lowest bit of the config1 register + * is unused and should return zero when read, so should the + * second to last bit of config1 (software reset). + */ + if (chip_id == 0x01 + && (reg_config1 & 0x03) == 0x00 + && reg_convrate <= 0x07) { + name = "max6680"; + } else + /* + * The chip_id register of the MAX6646/6647/6649 holds the + * revision of the chip. The lowest 6 bits of the config1 + * register are unused and should return zero when read. + */ + if (chip_id == 0x59 + && (reg_config1 & 0x3f) == 0x00 + && reg_convrate <= 0x07) { + name = "max6646"; + } + } else + if (address == 0x4C + && man_id == 0x5C) { /* Winbond/Nuvoton */ + if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */ + && (reg_config1 & 0x2A) == 0x00 + && reg_convrate <= 0x08) { + name = "w83l771"; } } - /* Fill the i2c board info */ - if (kind == lm90) { - name = "lm90"; - } else if (kind == adm1032) { - name = "adm1032"; - /* The ADM1032 supports PEC, but only if combined - transactions are not used. */ - if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) - info->flags |= I2C_CLIENT_PEC; - } else if (kind == lm99) { - name = "lm99"; - } else if (kind == lm86) { - name = "lm86"; - } else if (kind == max6657) { - name = "max6657"; - } else if (kind == max6680) { - name = "max6680"; - } else if (kind == adt7461) { - name = "adt7461"; + if (!name) { /* identification failed */ + dev_dbg(&adapter->dev, + "Unsupported chip at 0x%02x (man_id=0x%02X, " + "chip_id=0x%02X)\n", address, man_id, chip_id); + return -ENODEV; } + strlcpy(info->type, name, I2C_NAME_SIZE); return 0; @@ -687,6 +809,19 @@ static int lm90_probe(struct i2c_client *new_client, new_client->flags &= ~I2C_CLIENT_PEC; } + /* Different devices have different alarm bits triggering the + * ALERT# output */ + switch (data->kind) { + case lm90: + case lm99: + case lm86: + data->alert_alarms = 0x7b; + break; + default: + data->alert_alarms = 0x7c; + break; + } + /* Initialize the LM90 chip */ lm90_init_client(new_client); @@ -698,7 +833,7 @@ static int lm90_probe(struct i2c_client *new_client, &dev_attr_pec))) goto exit_remove_files; } - if (data->kind != max6657) { + if (data->kind != max6657 && data->kind != max6646) { if ((err = device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr))) goto exit_remove_files; @@ -723,7 +858,7 @@ exit: static void lm90_init_client(struct i2c_client *client) { - u8 config, config_orig; + u8 config; struct lm90_data *data = i2c_get_clientdata(client); /* @@ -735,7 +870,13 @@ static void lm90_init_client(struct i2c_client *client) dev_warn(&client->dev, "Initialization failed!\n"); return; } - config_orig = config; + data->config_orig = config; + + /* Check Temperature Range Select */ + if (data->kind == adt7461) { + if (config & 0x04) + data->flags |= LM90_FLAG_ADT7461_EXT; + } /* * Put MAX6680/MAX8881 into extended resolution (bit 0x10, @@ -747,7 +888,7 @@ static void lm90_init_client(struct i2c_client *client) } config &= 0xBF; /* run */ - if (config != config_orig) /* Only write if changed */ + if (config != data->config_orig) /* Only write if changed */ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); } @@ -758,14 +899,50 @@ static int lm90_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm90_group); device_remove_file(&client->dev, &dev_attr_pec); - if (data->kind != max6657) + if (data->kind != max6657 && data->kind != max6646) device_remove_file(&client->dev, &sensor_dev_attr_temp2_offset.dev_attr); + /* Restore initial configuration */ + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, + data->config_orig); + kfree(data); return 0; } +static void lm90_alert(struct i2c_client *client, unsigned int flag) +{ + struct lm90_data *data = i2c_get_clientdata(client); + u8 config, alarms; + + lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); + if ((alarms & 0x7f) == 0) { + dev_info(&client->dev, "Everything OK\n"); + } else { + if (alarms & 0x61) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 1); + if (alarms & 0x1a) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 2); + if (alarms & 0x04) + dev_warn(&client->dev, + "temp%d diode open, please check!\n", 2); + + /* Disable ALERT# output, because these chips don't implement + SMBus alert correctly; they should only hold the alert line + low briefly. */ + if ((data->kind == adm1032 || data->kind == adt7461) + && (alarms & data->alert_alarms)) { + dev_dbg(&client->dev, "Disabling ALERT#\n"); + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); + i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, + config | 0x80); + } + } +} + static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) { int err; @@ -815,7 +992,7 @@ static struct lm90_data *lm90_update_device(struct device *dev) lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]); lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst); - if (data->kind == max6657) { + if (data->kind == max6657 || data->kind == max6646) { lm90_read16(client, LM90_REG_R_LOCAL_TEMP, MAX6657_REG_R_LOCAL_TEMPL, &data->temp11[4]); @@ -830,6 +1007,7 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) { data->temp11[1] = h << 8; if (data->kind != max6657 && data->kind != max6680 + && data->kind != max6646 && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, &l) == 0) data->temp11[1] |= l; @@ -837,12 +1015,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) { data->temp11[2] = h << 8; if (data->kind != max6657 && data->kind != max6680 + && data->kind != max6646 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) data->temp11[2] |= l; } - if (data->kind != max6657) { + if (data->kind != max6657 && data->kind != max6646) { if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH, &h) == 0 && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL, @@ -851,6 +1030,21 @@ static struct lm90_data *lm90_update_device(struct device *dev) } lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); + /* Re-enable ALERT# output if it was originally enabled and + * relevant alarms are all clear */ + if ((data->config_orig & 0x80) == 0 + && (data->alarms & data->alert_alarms) == 0) { + u8 config; + + lm90_read_reg(client, LM90_REG_R_CONFIG1, &config); + if (config & 0x80) { + dev_dbg(&client->dev, "Re-enabling ALERT#\n"); + i2c_smbus_write_byte_data(client, + LM90_REG_W_CONFIG1, + config & ~0x80); + } + } + data->last_updated = jiffies; data->valid = 1; }