diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hwmon/acpi_power_meter.c | 5 | ||||
-rw-r--r-- | drivers/hwmon/jz4740-hwmon.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/lm75.c | 3 | ||||
-rw-r--r-- | drivers/hwmon/lm90.c | 327 | ||||
-rw-r--r-- | drivers/hwmon/nct6775.c | 91 |
6 files changed, 318 insertions, 111 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b3ab9d43bb3..52d548f1dc1 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -656,6 +656,7 @@ config SENSORS_LM75 - Analog Devices ADT75 - Dallas Semiconductor DS75, DS1775 and DS7505 + - Global Mixed-mode Technology (GMT) G751 - Maxim MAX6625 and MAX6626 - Microchip MCP980x - National Semiconductor LM75, LM75A diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 8d40da314a8..6a34f7f48eb 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -602,9 +602,8 @@ static int read_domain_devices(struct acpi_power_meter_resource *resource) /* Create a symlink to domain objects */ resource->domain_devices[i] = NULL; - status = acpi_bus_get_device(element->reference.handle, - &resource->domain_devices[i]); - if (ACPI_FAILURE(status)) + if (acpi_bus_get_device(element->reference.handle, + &resource->domain_devices[i])) continue; obj = resource->domain_devices[i]; diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index e0d66b9590a..a183e488db7 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -66,7 +66,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, mutex_lock(&hwmon->lock); - INIT_COMPLETION(*completion); + reinit_completion(completion); enable_irq(hwmon->irq); hwmon->cell->enable(to_platform_device(dev)); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index c03b490bba8..7e3ef134f1d 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -39,6 +39,7 @@ enum lm75_type { /* keep sorted in alphabetical order */ ds1775, ds75, ds7505, + g751, lm75, lm75a, max6625, @@ -208,6 +209,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) data->resolution = 12; data->sample_time = HZ / 4; break; + case g751: case lm75: case lm75a: data->resolution = 9; @@ -296,6 +298,7 @@ static const struct i2c_device_id lm75_ids[] = { { "ds1775", ds1775, }, { "ds75", ds75, }, { "ds7505", ds7505, }, + { "g751", g751, }, { "lm75", lm75, }, { "lm75a", lm75a, }, { "max6625", max6625, }, diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index cdff7428295..4c4c1421bf2 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -60,6 +60,11 @@ * This driver also supports the G781 from GMT. This device is compatible * with the ADM1032. * + * This driver also supports TMP451 from Texas Instruments. This device is + * supported in both compatibility and extended mode. It's mostly compatible + * with ADT7461 except for local temperature low byte register and max + * conversion rate. + * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and * concern all supported chipsets, unless mentioned otherwise. @@ -89,6 +94,8 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> +#include <linux/interrupt.h> +#include <linux/regulator/consumer.h> /* * Addresses to scan @@ -110,7 +117,7 @@ static const unsigned short normal_i2c[] = { 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, - max6646, w83l771, max6696, sa56004, g781 }; + max6646, w83l771, max6696, sa56004, g781, tmp451 }; /* * The LM90 registers @@ -167,6 +174,9 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, #define LM90_DEF_CONVRATE_RVAL 6 /* Def conversion rate register value */ #define LM90_MAX_CONVRATE_MS 16000 /* Maximum conversion rate in ms */ +/* TMP451 registers */ +#define TMP451_REG_R_LOCAL_TEMPL 0x15 + /* * Device flags */ @@ -179,6 +189,23 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, #define LM90_HAVE_TEMP3 (1 << 6) /* 3rd temperature sensor */ #define LM90_HAVE_BROKEN_ALERT (1 << 7) /* Broken alert */ +/* LM90 status */ +#define LM90_STATUS_LTHRM (1 << 0) /* local THERM limit tripped */ +#define LM90_STATUS_RTHRM (1 << 1) /* remote THERM limit tripped */ +#define LM90_STATUS_ROPEN (1 << 2) /* remote is an open circuit */ +#define LM90_STATUS_RLOW (1 << 3) /* remote low temp limit tripped */ +#define LM90_STATUS_RHIGH (1 << 4) /* remote high temp limit tripped */ +#define LM90_STATUS_LLOW (1 << 5) /* local low temp limit tripped */ +#define LM90_STATUS_LHIGH (1 << 6) /* local high temp limit tripped */ + +#define MAX6696_STATUS2_R2THRM (1 << 1) /* remote2 THERM limit tripped */ +#define MAX6696_STATUS2_R2OPEN (1 << 2) /* remote2 is an open circuit */ +#define MAX6696_STATUS2_R2LOW (1 << 3) /* remote2 low temp limit tripped */ +#define MAX6696_STATUS2_R2HIGH (1 << 4) /* remote2 high temp limit tripped */ +#define MAX6696_STATUS2_ROT2 (1 << 5) /* remote emergency limit tripped */ +#define MAX6696_STATUS2_R2OT2 (1 << 6) /* remote2 emergency limit tripped */ +#define MAX6696_STATUS2_LOT2 (1 << 7) /* local emergency limit tripped */ + /* * Driver data (common to all clients) */ @@ -205,6 +232,7 @@ static const struct i2c_device_id lm90_id[] = { { "nct1008", adt7461 }, { "w83l771", w83l771 }, { "sa56004", sa56004 }, + { "tmp451", tmp451 }, { } }; MODULE_DEVICE_TABLE(i2c, lm90_id); @@ -278,7 +306,7 @@ static const struct lm90_params lm90_params[] = { [max6696] = { .flags = LM90_HAVE_EMERGENCY | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3, - .alert_alarms = 0x187c, + .alert_alarms = 0x1c7c, .max_convrate = 6, .reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL, }, @@ -293,6 +321,43 @@ static const struct lm90_params lm90_params[] = { .max_convrate = 9, .reg_local_ext = SA56004_REG_R_LOCAL_TEMPL, }, + [tmp451] = { + .flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT + | LM90_HAVE_BROKEN_ALERT, + .alert_alarms = 0x7c, + .max_convrate = 9, + .reg_local_ext = TMP451_REG_R_LOCAL_TEMPL, + } +}; + +/* + * TEMP8 register index + */ +enum lm90_temp8_reg_index { + LOCAL_LOW = 0, + LOCAL_HIGH, + LOCAL_CRIT, + REMOTE_CRIT, + LOCAL_EMERG, /* max6659 and max6695/96 */ + REMOTE_EMERG, /* max6659 and max6695/96 */ + REMOTE2_CRIT, /* max6695/96 only */ + REMOTE2_EMERG, /* max6695/96 only */ + TEMP8_REG_NUM +}; + +/* + * TEMP11 register index + */ +enum lm90_temp11_reg_index { + REMOTE_TEMP = 0, + REMOTE_LOW, + REMOTE_HIGH, + REMOTE_OFFSET, /* except max6646, max6657/58/59, and max6695/96 */ + LOCAL_TEMP, + REMOTE2_TEMP, /* max6695/96 only */ + REMOTE2_LOW, /* max6695/96 only */ + REMOTE2_HIGH, /* max6695/96 only */ + TEMP11_REG_NUM }; /* @@ -302,6 +367,7 @@ static const struct lm90_params lm90_params[] = { struct lm90_data { struct device *hwmon_dev; struct mutex update_lock; + struct regulator *regulator; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ int kind; @@ -317,25 +383,8 @@ struct lm90_data { u8 reg_local_ext; /* local extension register offset */ /* registers values */ - s8 temp8[8]; /* 0: local low limit - * 1: local high limit - * 2: local critical limit - * 3: remote critical limit - * 4: local emergency limit (max6659 and max6695/96) - * 5: remote emergency limit (max6659 and max6695/96) - * 6: remote 2 critical limit (max6695/96 only) - * 7: remote 2 emergency limit (max6695/96 only) - */ - s16 temp11[8]; /* 0: remote input - * 1: remote low limit - * 2: remote high limit - * 3: remote offset (except max6646, max6657/58/59, - * and max6695/96) - * 4: local input - * 5: remote 2 input (max6695/96 only) - * 6: remote 2 low limit (max6695/96 only) - * 7: remote 2 high limit (max6695/96 only) - */ + s8 temp8[TEMP8_REG_NUM]; + s16 temp11[TEMP11_REG_NUM]; u8 temp_hyst; u16 alarms; /* bitvector (upper 8 bits for max6695/96) */ }; @@ -477,37 +526,42 @@ static struct lm90_data *lm90_update_device(struct device *dev) u8 alarms; dev_dbg(&client->dev, "Updating lm90 data.\n"); - lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, &data->temp8[0]); - lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, &data->temp8[1]); - lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, &data->temp8[2]); - lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, &data->temp8[3]); + lm90_read_reg(client, LM90_REG_R_LOCAL_LOW, + &data->temp8[LOCAL_LOW]); + lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH, + &data->temp8[LOCAL_HIGH]); + lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT, + &data->temp8[LOCAL_CRIT]); + lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, + &data->temp8[REMOTE_CRIT]); lm90_read_reg(client, LM90_REG_R_TCRIT_HYST, &data->temp_hyst); if (data->reg_local_ext) { lm90_read16(client, LM90_REG_R_LOCAL_TEMP, data->reg_local_ext, - &data->temp11[4]); + &data->temp11[LOCAL_TEMP]); } else { if (lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP, &h) == 0) - data->temp11[4] = h << 8; + data->temp11[LOCAL_TEMP] = h << 8; } lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, - LM90_REG_R_REMOTE_TEMPL, &data->temp11[0]); + LM90_REG_R_REMOTE_TEMPL, + &data->temp11[REMOTE_TEMP]); if (lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h) == 0) { - data->temp11[1] = h << 8; + data->temp11[REMOTE_LOW] = h << 8; if ((data->flags & LM90_HAVE_REM_LIMIT_EXT) && lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL, &l) == 0) - data->temp11[1] |= l; + data->temp11[REMOTE_LOW] |= l; } if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h) == 0) { - data->temp11[2] = h << 8; + data->temp11[REMOTE_HIGH] = h << 8; if ((data->flags & LM90_HAVE_REM_LIMIT_EXT) && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) - data->temp11[2] |= l; + data->temp11[REMOTE_HIGH] |= l; } if (data->flags & LM90_HAVE_OFFSET) { @@ -515,13 +569,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) &h) == 0 && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL, &l) == 0) - data->temp11[3] = (h << 8) | l; + data->temp11[REMOTE_OFFSET] = (h << 8) | l; } if (data->flags & LM90_HAVE_EMERGENCY) { lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG, - &data->temp8[4]); + &data->temp8[LOCAL_EMERG]); lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG, - &data->temp8[5]); + &data->temp8[REMOTE_EMERG]); } lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); data->alarms = alarms; /* save as 16 bit value */ @@ -529,15 +583,16 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (data->kind == max6696) { lm90_select_remote_channel(client, data, 1); lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT, - &data->temp8[6]); + &data->temp8[REMOTE2_CRIT]); lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG, - &data->temp8[7]); + &data->temp8[REMOTE2_EMERG]); lm90_read16(client, LM90_REG_R_REMOTE_TEMPH, - LM90_REG_R_REMOTE_TEMPL, &data->temp11[5]); + LM90_REG_R_REMOTE_TEMPL, + &data->temp11[REMOTE2_TEMP]); if (!lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH, &h)) - data->temp11[6] = h << 8; + data->temp11[REMOTE2_LOW] = h << 8; if (!lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &h)) - data->temp11[7] = h << 8; + data->temp11[REMOTE2_HIGH] = h << 8; lm90_select_remote_channel(client, data, 0); if (!lm90_read_reg(client, MAX6696_REG_R_STATUS2, @@ -709,7 +764,7 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, struct lm90_data *data = lm90_update_device(dev); int temp; - if (data->kind == adt7461) + if (data->kind == adt7461 || data->kind == tmp451) temp = temp_from_u8_adt7461(data, data->temp8[attr->index]); else if (data->kind == max6646) temp = temp_from_u8(data->temp8[attr->index]); @@ -726,7 +781,7 @@ static ssize_t show_temp8(struct device *dev, struct device_attribute *devattr, static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - static const u8 reg[8] = { + static const u8 reg[TEMP8_REG_NUM] = { LM90_REG_W_LOCAL_LOW, LM90_REG_W_LOCAL_HIGH, LM90_REG_W_LOCAL_CRIT, @@ -753,7 +808,7 @@ static ssize_t set_temp8(struct device *dev, struct device_attribute *devattr, val -= 16000; mutex_lock(&data->update_lock); - if (data->kind == adt7461) + if (data->kind == adt7461 || data->kind == tmp451) data->temp8[nr] = temp_to_u8_adt7461(data, val); else if (data->kind == max6646) data->temp8[nr] = temp_to_u8(val); @@ -775,7 +830,7 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, struct lm90_data *data = lm90_update_device(dev); int temp; - if (data->kind == adt7461) + if (data->kind == adt7461 || data->kind == tmp451) temp = temp_from_u16_adt7461(data, data->temp11[attr->index]); else if (data->kind == max6646) temp = temp_from_u16(data->temp11[attr->index]); @@ -821,7 +876,7 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, val -= 16000; mutex_lock(&data->update_lock); - if (data->kind == adt7461) + if (data->kind == adt7461 || data->kind == tmp451) data->temp11[index] = temp_to_u16_adt7461(data, val); else if (data->kind == max6646) data->temp11[index] = temp_to_u8(val) << 8; @@ -850,7 +905,7 @@ static ssize_t show_temphyst(struct device *dev, struct lm90_data *data = lm90_update_device(dev); int temp; - if (data->kind == adt7461) + if (data->kind == adt7461 || data->kind == tmp451) temp = temp_from_u8_adt7461(data, data->temp8[attr->index]); else if (data->kind == max6646) temp = temp_from_u8(data->temp8[attr->index]); @@ -878,12 +933,12 @@ static ssize_t set_temphyst(struct device *dev, struct device_attribute *dummy, return err; mutex_lock(&data->update_lock); - if (data->kind == adt7461) - temp = temp_from_u8_adt7461(data, data->temp8[2]); + if (data->kind == adt7461 || data->kind == tmp451) + temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]); else if (data->kind == max6646) - temp = temp_from_u8(data->temp8[2]); + temp = temp_from_u8(data->temp8[LOCAL_CRIT]); else - temp = temp_from_s8(data->temp8[2]); + temp = temp_from_s8(data->temp8[LOCAL_CRIT]); data->temp_hyst = hyst_to_reg(temp - val); i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST, @@ -937,25 +992,28 @@ static ssize_t set_update_interval(struct device *dev, return count; } -static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, 0, 4); -static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp11, NULL, + 0, LOCAL_TEMP); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp11, NULL, + 0, REMOTE_TEMP); static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 0); + set_temp8, LOCAL_LOW); static SENSOR_DEVICE_ATTR_2(temp2_min, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 0, 1); + set_temp11, 0, REMOTE_LOW); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 1); + set_temp8, LOCAL_HIGH); static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 1, 2); + set_temp11, 1, REMOTE_HIGH); static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 2); + set_temp8, LOCAL_CRIT); static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 3); + set_temp8, REMOTE_CRIT); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, - set_temphyst, 2); -static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 3); + set_temphyst, LOCAL_CRIT); +static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, + REMOTE_CRIT); static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 2, 3); + set_temp11, 2, REMOTE_OFFSET); /* Individual alarm files */ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); @@ -1003,13 +1061,13 @@ static const struct attribute_group lm90_group = { * Additional attributes for devices with emergency sensors */ static SENSOR_DEVICE_ATTR(temp1_emergency, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 4); + set_temp8, LOCAL_EMERG); static SENSOR_DEVICE_ATTR(temp2_emergency, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 5); + set_temp8, REMOTE_EMERG); static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO, show_temphyst, - NULL, 4); + NULL, LOCAL_EMERG); static SENSOR_DEVICE_ATTR(temp2_emergency_hyst, S_IRUGO, show_temphyst, - NULL, 5); + NULL, REMOTE_EMERG); static struct attribute *lm90_emergency_attributes[] = { &sensor_dev_attr_temp1_emergency.dev_attr.attr, @@ -1039,18 +1097,20 @@ static const struct attribute_group lm90_emergency_alarm_group = { /* * Additional attributes for devices with 3 temperature sensors */ -static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp11, NULL, 0, 5); +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp11, NULL, + 0, REMOTE2_TEMP); static SENSOR_DEVICE_ATTR_2(temp3_min, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 3, 6); + set_temp11, 3, REMOTE2_LOW); static SENSOR_DEVICE_ATTR_2(temp3_max, S_IWUSR | S_IRUGO, show_temp11, - set_temp11, 4, 7); + set_temp11, 4, REMOTE2_HIGH); static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 6); -static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL, 6); + set_temp8, REMOTE2_CRIT); +static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_temphyst, NULL, + REMOTE2_CRIT); static SENSOR_DEVICE_ATTR(temp3_emergency, S_IWUSR | S_IRUGO, show_temp8, - set_temp8, 7); + set_temp8, REMOTE2_EMERG); static SENSOR_DEVICE_ATTR(temp3_emergency_hyst, S_IRUGO, show_temphyst, - NULL, 7); + NULL, REMOTE2_EMERG); static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 9); static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 10); @@ -1306,6 +1366,19 @@ static int lm90_detect(struct i2c_client *client, && (config1 & 0x3F) == 0x00 && convrate <= 0x08) name = "g781"; + } else + if (address == 0x4C + && man_id == 0x55) { /* Texas Instruments */ + int local_ext; + + local_ext = i2c_smbus_read_byte_data(client, + TMP451_REG_R_LOCAL_TEMPL); + + if (chip_id == 0x00 /* TMP451 */ + && (config1 & 0x1B) == 0x00 + && convrate <= 0x09 + && (local_ext & 0x0F) == 0x00) + name = "tmp451"; } if (!name) { /* identification failed */ @@ -1367,7 +1440,7 @@ static void lm90_init_client(struct i2c_client *client) data->config_orig = config; /* Check Temperature Range Select */ - if (data->kind == adt7461) { + if (data->kind == adt7461 || data->kind == tmp451) { if (config & 0x04) data->flags |= LM90_FLAG_ADT7461_EXT; } @@ -1391,14 +1464,74 @@ static void lm90_init_client(struct i2c_client *client) i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config); } +static bool lm90_is_tripped(struct i2c_client *client, u16 *status) +{ + struct lm90_data *data = i2c_get_clientdata(client); + u8 st, st2 = 0; + + lm90_read_reg(client, LM90_REG_R_STATUS, &st); + + if (data->kind == max6696) + lm90_read_reg(client, MAX6696_REG_R_STATUS2, &st2); + + *status = st | (st2 << 8); + + if ((st & 0x7f) == 0 && (st2 & 0xfe) == 0) + return false; + + if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) || + (st2 & MAX6696_STATUS2_LOT2)) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 1); + if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) || + (st2 & MAX6696_STATUS2_ROT2)) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 2); + if (st & LM90_STATUS_ROPEN) + dev_warn(&client->dev, + "temp%d diode open, please check!\n", 2); + if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH | + MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2)) + dev_warn(&client->dev, + "temp%d out of range, please check!\n", 3); + if (st2 & MAX6696_STATUS2_R2OPEN) + dev_warn(&client->dev, + "temp%d diode open, please check!\n", 3); + + return true; +} + +static irqreturn_t lm90_irq_thread(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + u16 status; + + if (lm90_is_tripped(client, &status)) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + static int lm90_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct i2c_adapter *adapter = to_i2c_adapter(dev->parent); struct lm90_data *data; + struct regulator *regulator; int err; + regulator = devm_regulator_get(dev, "vcc"); + if (IS_ERR(regulator)) + return PTR_ERR(regulator); + + err = regulator_enable(regulator); + if (err < 0) { + dev_err(&client->dev, + "Failed to enable regulator: %d\n", err); + return err; + } + data = devm_kzalloc(&client->dev, sizeof(struct lm90_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -1406,6 +1539,8 @@ static int lm90_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); + data->regulator = regulator; + /* Set the device type */ data->kind = id->driver_data; if (data->kind == adm1032) { @@ -1467,12 +1602,26 @@ static int lm90_probe(struct i2c_client *client, goto exit_remove_files; } + if (client->irq) { + dev_dbg(dev, "IRQ: %d\n", client->irq); + err = devm_request_threaded_irq(dev, client->irq, + NULL, lm90_irq_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "lm90", client); + if (err < 0) { + dev_err(dev, "cannot request IRQ %d\n", client->irq); + goto exit_remove_files; + } + } + return 0; exit_remove_files: lm90_remove_files(client, data); exit_restore: lm90_restore_conf(client, data); + regulator_disable(data->regulator); + return err; } @@ -1483,49 +1632,33 @@ static int lm90_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); lm90_remove_files(client, data); lm90_restore_conf(client, data); + regulator_disable(data->regulator); return 0; } static void lm90_alert(struct i2c_client *client, unsigned int flag) { - struct lm90_data *data = i2c_get_clientdata(client); - u8 config, alarms, alarms2 = 0; - - lm90_read_reg(client, LM90_REG_R_STATUS, &alarms); - - if (data->kind == max6696) - lm90_read_reg(client, MAX6696_REG_R_STATUS2, &alarms2); - - if ((alarms & 0x7f) == 0 && (alarms2 & 0xfe) == 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); - - if (alarms2 & 0x18) - dev_warn(&client->dev, - "temp%d out of range, please check!\n", 3); + u16 alarms; + if (lm90_is_tripped(client, &alarms)) { /* * Disable ALERT# output, because these chips don't implement * SMBus alert correctly; they should only hold the alert line * low briefly. */ + struct lm90_data *data = i2c_get_clientdata(client); + if ((data->flags & LM90_HAVE_BROKEN_ALERT) && (alarms & data->alert_alarms)) { + u8 config; 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); } + } else { + dev_info(&client->dev, "Everything OK\n"); } } diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index d17325db0ea..cf811c1a147 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -274,6 +274,8 @@ static const u16 NCT6775_FAN_PULSE_SHIFT[] = { 0, 0, 0, 0, 0, 0 }; static const u16 NCT6775_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x62b, 0x62c, 0x62d }; +static const u16 NCT6775_REG_TEMP_MON[] = { 0x73, 0x75, 0x77 }; + static const u16 NCT6775_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6775_REG_TEMP)] = { 0, 0x152, 0x252, 0x628, 0x629, 0x62A }; static const u16 NCT6775_REG_TEMP_HYST[ARRAY_SIZE(NCT6775_REG_TEMP)] = { @@ -454,6 +456,7 @@ static const u16 NCT6779_REG_CRITICAL_PWM[] = { 0x137, 0x237, 0x337, 0x837, 0x937, 0xa37 }; static const u16 NCT6779_REG_TEMP[] = { 0x27, 0x150 }; +static const u16 NCT6779_REG_TEMP_MON[] = { 0x73, 0x75, 0x77, 0x79, 0x7b }; static const u16 NCT6779_REG_TEMP_CONFIG[ARRAY_SIZE(NCT6779_REG_TEMP)] = { 0x18, 0x152 }; static const u16 NCT6779_REG_TEMP_HYST[ARRAY_SIZE(NCT6779_REG_TEMP)] = { @@ -507,6 +510,13 @@ static const u16 NCT6779_REG_TEMP_CRIT[ARRAY_SIZE(nct6779_temp_label) - 1] #define NCT6791_REG_HM_IO_SPACE_LOCK_ENABLE 0x28 +static const u16 NCT6791_REG_WEIGHT_TEMP_SEL[6] = { 0, 0x239 }; +static const u16 NCT6791_REG_WEIGHT_TEMP_STEP[6] = { 0, 0x23a }; +static const u16 NCT6791_REG_WEIGHT_TEMP_STEP_TOL[6] = { 0, 0x23b }; +static const u16 NCT6791_REG_WEIGHT_DUTY_STEP[6] = { 0, 0x23c }; +static const u16 NCT6791_REG_WEIGHT_TEMP_BASE[6] = { 0, 0x23d }; +static const u16 NCT6791_REG_WEIGHT_DUTY_BASE[6] = { 0, 0x23e }; + static const u16 NCT6791_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B, 0x568, 0x45D }; @@ -534,6 +544,7 @@ static const u16 NCT6106_REG_IN[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09 }; static const u16 NCT6106_REG_TEMP[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15 }; +static const u16 NCT6106_REG_TEMP_MON[] = { 0x18, 0x19, 0x1a }; static const u16 NCT6106_REG_TEMP_HYST[] = { 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd7 }; static const u16 NCT6106_REG_TEMP_OVER[] = { @@ -1307,6 +1318,9 @@ static void nct6775_update_pwm(struct device *dev) if (reg & 0x80) data->pwm[2][i] = 0; + if (!data->REG_WEIGHT_TEMP_SEL[i]) + continue; + reg = nct6775_read_value(data, data->REG_WEIGHT_TEMP_SEL[i]); data->pwm_weight_temp_sel[i] = reg & 0x1f; /* If weight is disabled, report weight source as 0 */ @@ -2852,6 +2866,9 @@ static umode_t nct6775_pwm_is_visible(struct kobject *kobj, if (!(data->has_pwm & (1 << pwm))) return 0; + if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */ + if (!data->REG_WEIGHT_TEMP_SEL[pwm]) + return 0; if (nr == 19 && data->REG_PWM[3] == NULL) /* pwm_max */ return 0; if (nr == 20 && data->REG_PWM[4] == NULL) /* pwm_step */ @@ -2945,11 +2962,11 @@ static struct sensor_device_template *nct6775_attributes_pwm_template[] = { &sensor_dev_template_pwm_step_down_time, &sensor_dev_template_pwm_start, &sensor_dev_template_pwm_floor, - &sensor_dev_template_pwm_weight_temp_sel, + &sensor_dev_template_pwm_weight_temp_sel, /* 14 */ &sensor_dev_template_pwm_weight_temp_step, &sensor_dev_template_pwm_weight_temp_step_tol, &sensor_dev_template_pwm_weight_temp_step_base, - &sensor_dev_template_pwm_weight_duty_step, + &sensor_dev_template_pwm_weight_duty_step, /* 18 */ &sensor_dev_template_pwm_max, /* 19 */ &sensor_dev_template_pwm_step, /* 20 */ &sensor_dev_template_pwm_weight_duty_base, /* 21 */ @@ -3253,9 +3270,9 @@ static int nct6775_probe(struct platform_device *pdev) int i, s, err = 0; int src, mask, available; const u16 *reg_temp, *reg_temp_over, *reg_temp_hyst, *reg_temp_config; - const u16 *reg_temp_alternate, *reg_temp_crit; + const u16 *reg_temp_mon, *reg_temp_alternate, *reg_temp_crit; const u16 *reg_temp_crit_l = NULL, *reg_temp_crit_h = NULL; - int num_reg_temp; + int num_reg_temp, num_reg_temp_mon; u8 cr2a; struct attribute_group *group; struct device *hwmon_dev; @@ -3338,7 +3355,9 @@ static int nct6775_probe(struct platform_device *pdev) data->BEEP_BITS = NCT6106_BEEP_BITS; reg_temp = NCT6106_REG_TEMP; + reg_temp_mon = NCT6106_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6106_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6106_REG_TEMP_MON); reg_temp_over = NCT6106_REG_TEMP_OVER; reg_temp_hyst = NCT6106_REG_TEMP_HYST; reg_temp_config = NCT6106_REG_TEMP_CONFIG; @@ -3410,7 +3429,9 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_BEEP = NCT6775_REG_BEEP; reg_temp = NCT6775_REG_TEMP; + reg_temp_mon = NCT6775_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON); reg_temp_over = NCT6775_REG_TEMP_OVER; reg_temp_hyst = NCT6775_REG_TEMP_HYST; reg_temp_config = NCT6775_REG_TEMP_CONFIG; @@ -3480,7 +3501,9 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_BEEP = NCT6776_REG_BEEP; reg_temp = NCT6775_REG_TEMP; + reg_temp_mon = NCT6775_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6775_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6775_REG_TEMP_MON); reg_temp_over = NCT6775_REG_TEMP_OVER; reg_temp_hyst = NCT6775_REG_TEMP_HYST; reg_temp_config = NCT6776_REG_TEMP_CONFIG; @@ -3554,7 +3577,9 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_BEEP = NCT6776_REG_BEEP; reg_temp = NCT6779_REG_TEMP; + reg_temp_mon = NCT6779_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); reg_temp_over = NCT6779_REG_TEMP_OVER; reg_temp_hyst = NCT6779_REG_TEMP_HYST; reg_temp_config = NCT6779_REG_TEMP_CONFIG; @@ -3603,8 +3628,8 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_PWM[0] = NCT6775_REG_PWM; data->REG_PWM[1] = NCT6775_REG_FAN_START_OUTPUT; data->REG_PWM[2] = NCT6775_REG_FAN_STOP_OUTPUT; - data->REG_PWM[5] = NCT6775_REG_WEIGHT_DUTY_STEP; - data->REG_PWM[6] = NCT6776_REG_WEIGHT_DUTY_BASE; + data->REG_PWM[5] = NCT6791_REG_WEIGHT_DUTY_STEP; + data->REG_PWM[6] = NCT6791_REG_WEIGHT_DUTY_BASE; data->REG_PWM_READ = NCT6775_REG_PWM_READ; data->REG_PWM_MODE = NCT6776_REG_PWM_MODE; data->PWM_MODE_MASK = NCT6776_PWM_MODE_MASK; @@ -3620,15 +3645,17 @@ static int nct6775_probe(struct platform_device *pdev) data->REG_TEMP_OFFSET = NCT6779_REG_TEMP_OFFSET; data->REG_TEMP_SOURCE = NCT6775_REG_TEMP_SOURCE; data->REG_TEMP_SEL = NCT6775_REG_TEMP_SEL; - data->REG_WEIGHT_TEMP_SEL = NCT6775_REG_WEIGHT_TEMP_SEL; - data->REG_WEIGHT_TEMP[0] = NCT6775_REG_WEIGHT_TEMP_STEP; - data->REG_WEIGHT_TEMP[1] = NCT6775_REG_WEIGHT_TEMP_STEP_TOL; - data->REG_WEIGHT_TEMP[2] = NCT6775_REG_WEIGHT_TEMP_BASE; + data->REG_WEIGHT_TEMP_SEL = NCT6791_REG_WEIGHT_TEMP_SEL; + data->REG_WEIGHT_TEMP[0] = NCT6791_REG_WEIGHT_TEMP_STEP; + data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL; + data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE; data->REG_ALARM = NCT6791_REG_ALARM; data->REG_BEEP = NCT6776_REG_BEEP; reg_temp = NCT6779_REG_TEMP; + reg_temp_mon = NCT6779_REG_TEMP_MON; num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP); + num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON); reg_temp_over = NCT6779_REG_TEMP_OVER; reg_temp_hyst = NCT6779_REG_TEMP_HYST; reg_temp_config = NCT6779_REG_TEMP_CONFIG; @@ -3729,6 +3756,50 @@ static int nct6775_probe(struct platform_device *pdev) s++; } + /* + * Repeat with temperatures used for fan control. + * This set of registers does not support limits. + */ + for (i = 0; i < num_reg_temp_mon; i++) { + if (reg_temp_mon[i] == 0) + continue; + + src = nct6775_read_value(data, data->REG_TEMP_SEL[i]) & 0x1f; + if (!src || (mask & (1 << src))) + continue; + + if (src >= data->temp_label_num || + !strlen(data->temp_label[src])) { + dev_info(dev, + "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", + src, i, data->REG_TEMP_SEL[i], + reg_temp_mon[i]); + continue; + } + + mask |= 1 << src; + + /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ + if (src <= data->temp_fixed_num) { + if (data->have_temp & (1 << (src - 1))) + continue; + data->have_temp |= 1 << (src - 1); + data->have_temp_fixed |= 1 << (src - 1); + data->reg_temp[0][src - 1] = reg_temp_mon[i]; + data->temp_src[src - 1] = src; + continue; + } + + if (s >= NUM_TEMP) + continue; + + /* Use dynamic index for other sources */ + data->have_temp |= 1 << s; + data->reg_temp[0][s] = reg_temp_mon[i]; + data->temp_src[s] = src; + s++; + } + #ifdef USE_ALTERNATE /* * Go through the list of alternate temp registers and enable |