diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/adt7462.c | 14 | ||||
-rw-r--r-- | drivers/hwmon/adt7470.c | 227 | ||||
-rw-r--r-- | drivers/hwmon/adt7473.c | 10 | ||||
-rw-r--r-- | drivers/hwmon/applesmc.c | 10 | ||||
-rw-r--r-- | drivers/hwmon/hwmon.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/ibmpex.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/lm75.c | 2 |
7 files changed, 223 insertions, 44 deletions
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 66107b4dc12a..1852f27bac51 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -204,8 +204,6 @@ I2C_CLIENT_INSMOD_1(adt7462); #define MASK_AND_SHIFT(value, prefix) \ (((value) & prefix##_MASK) >> prefix##_SHIFT) -#define ROUND_DIV(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) - struct adt7462_data { struct device *hwmon_dev; struct attribute_group attrs; @@ -840,7 +838,7 @@ static ssize_t set_temp_min(struct device *dev, if (strict_strtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) return -EINVAL; - temp = ROUND_DIV(temp, 1000) + 64; + temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -878,7 +876,7 @@ static ssize_t set_temp_max(struct device *dev, if (strict_strtol(buf, 10, &temp) || !temp_enabled(data, attr->index)) return -EINVAL; - temp = ROUND_DIV(temp, 1000) + 64; + temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -943,7 +941,7 @@ static ssize_t set_volt_max(struct device *dev, return -EINVAL; temp *= 1000; /* convert mV to uV */ - temp = ROUND_DIV(temp, x); + temp = DIV_ROUND_CLOSEST(temp, x); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -985,7 +983,7 @@ static ssize_t set_volt_min(struct device *dev, return -EINVAL; temp *= 1000; /* convert mV to uV */ - temp = ROUND_DIV(temp, x); + temp = DIV_ROUND_CLOSEST(temp, x); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -1250,7 +1248,7 @@ static ssize_t set_pwm_hyst(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 15); /* package things up */ @@ -1337,7 +1335,7 @@ static ssize_t set_pwm_tmin(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000) + 64; + temp = DIV_ROUND_CLOSEST(temp, 1000) + 64; temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 1311a595147e..633e1a1e9d79 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -28,6 +28,7 @@ #include <linux/mutex.h> #include <linux/delay.h> #include <linux/log2.h> +#include <linux/kthread.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; @@ -74,6 +75,7 @@ I2C_CLIENT_INSMOD_1(adt7470); #define ADT7470_REG_PWM12_CFG 0x68 #define ADT7470_PWM2_AUTO_MASK 0x40 #define ADT7470_PWM1_AUTO_MASK 0x80 +#define ADT7470_PWM_AUTO_MASK 0xC0 #define ADT7470_REG_PWM34_CFG 0x69 #define ADT7470_PWM3_AUTO_MASK 0x40 #define ADT7470_PWM4_AUTO_MASK 0x80 @@ -128,8 +130,11 @@ I2C_CLIENT_INSMOD_1(adt7470); /* How often do we reread sensor limit values? (In jiffies) */ #define LIMIT_REFRESH_INTERVAL (60 * HZ) -/* sleep 1s while gathering temperature data */ -#define TEMP_COLLECTION_TIME 1000 +/* Wait at least 200ms per sensor for 10 sensors */ +#define TEMP_COLLECTION_TIME 2000 + +/* auto update thing won't fire more than every 2s */ +#define AUTO_UPDATE_INTERVAL 2000 /* datasheet says to divide this number by the fan reading to get fan rpm */ #define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) @@ -137,8 +142,6 @@ I2C_CLIENT_INSMOD_1(adt7470); #define FAN_PERIOD_INVALID 65535 #define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) -#define ROUND_DIV(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) - struct adt7470_data { struct device *hwmon_dev; struct attribute_group attrs; @@ -148,6 +151,9 @@ struct adt7470_data { unsigned long sensors_last_updated; /* In jiffies */ unsigned long limits_last_updated; /* In jiffies */ + int num_temp_sensors; /* -1 = probe */ + int temperatures_probed; + s8 temp[ADT7470_TEMP_COUNT]; s8 temp_min[ADT7470_TEMP_COUNT]; s8 temp_max[ADT7470_TEMP_COUNT]; @@ -163,6 +169,10 @@ struct adt7470_data { u8 pwm_min[ADT7470_PWM_COUNT]; s8 pwm_tmin[ADT7470_PWM_COUNT]; u8 pwm_auto_temp[ADT7470_PWM_COUNT]; + + struct task_struct *auto_update; + struct completion auto_update_stop; + unsigned int auto_update_interval; }; static int adt7470_probe(struct i2c_client *client, @@ -220,40 +230,126 @@ static void adt7470_init_client(struct i2c_client *client) } } -static struct adt7470_data *adt7470_update_device(struct device *dev) +/* Probe for temperature sensors. Assumes lock is held */ +static int adt7470_read_temperatures(struct i2c_client *client, + struct adt7470_data *data) { - struct i2c_client *client = to_i2c_client(dev); - struct adt7470_data *data = i2c_get_clientdata(client); - unsigned long local_jiffies = jiffies; - u8 cfg; + unsigned long res; int i; + u8 cfg, pwm[4], pwm_cfg[2]; - mutex_lock(&data->lock); - if (time_before(local_jiffies, data->sensors_last_updated + - SENSOR_REFRESH_INTERVAL) - && data->sensors_valid) - goto no_sensor_update; + /* save pwm[1-4] config register */ + pwm_cfg[0] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(0)); + pwm_cfg[1] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM_CFG(2)); + + /* set manual pwm to whatever it is set to now */ + for (i = 0; i < ADT7470_FAN_COUNT; i++) + pwm[i] = i2c_smbus_read_byte_data(client, ADT7470_REG_PWM(i)); + + /* put pwm in manual mode */ + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0), + pwm_cfg[0] & ~(ADT7470_PWM_AUTO_MASK)); + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), + pwm_cfg[1] & ~(ADT7470_PWM_AUTO_MASK)); + + /* write pwm control to whatever it was */ + for (i = 0; i < ADT7470_FAN_COUNT; i++) + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(i), pwm[i]); /* start reading temperature sensors */ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); cfg |= 0x80; i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); - /* - * Delay is 200ms * number of tmp05 sensors. Too bad - * there's no way to figure out how many are connected. - * For now, assume 1s will work. - */ - msleep(TEMP_COLLECTION_TIME); + /* Delay is 200ms * number of temp sensors. */ + res = msleep_interruptible((data->num_temp_sensors >= 0 ? + data->num_temp_sensors * 200 : + TEMP_COLLECTION_TIME)); /* done reading temperature sensors */ cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); cfg &= ~0x80; i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); - for (i = 0; i < ADT7470_TEMP_COUNT; i++) + /* restore pwm[1-4] config registers */ + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(0), pwm_cfg[0]); + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_CFG(2), pwm_cfg[1]); + + if (res) { + printk(KERN_ERR "ha ha, interrupted"); + return -EAGAIN; + } + + /* Only count fans if we have to */ + if (data->num_temp_sensors >= 0) + return 0; + + for (i = 0; i < ADT7470_TEMP_COUNT; i++) { data->temp[i] = i2c_smbus_read_byte_data(client, ADT7470_TEMP_REG(i)); + if (data->temp[i]) + data->num_temp_sensors = i + 1; + } + data->temperatures_probed = 1; + return 0; +} + +static int adt7470_update_thread(void *p) +{ + struct i2c_client *client = p; + struct adt7470_data *data = i2c_get_clientdata(client); + + while (!kthread_should_stop()) { + mutex_lock(&data->lock); + adt7470_read_temperatures(client, data); + mutex_unlock(&data->lock); + if (kthread_should_stop()) + break; + msleep_interruptible(data->auto_update_interval); + } + + complete_all(&data->auto_update_stop); + return 0; +} + +static struct adt7470_data *adt7470_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + unsigned long local_jiffies = jiffies; + u8 cfg; + int i; + int need_sensors = 1; + int need_limits = 1; + + /* + * Figure out if we need to update the shadow registers. + * Lockless means that we may occasionally report out of + * date data. + */ + if (time_before(local_jiffies, data->sensors_last_updated + + SENSOR_REFRESH_INTERVAL) && + data->sensors_valid) + need_sensors = 0; + + if (time_before(local_jiffies, data->limits_last_updated + + LIMIT_REFRESH_INTERVAL) && + data->limits_valid) + need_limits = 0; + + if (!need_sensors && !need_limits) + return data; + + mutex_lock(&data->lock); + if (!need_sensors) + goto no_sensor_update; + + if (!data->temperatures_probed) + adt7470_read_temperatures(client, data); + else + for (i = 0; i < ADT7470_TEMP_COUNT; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_REG(i)); for (i = 0; i < ADT7470_FAN_COUNT; i++) data->fan[i] = adt7470_read_word_data(client, @@ -302,9 +398,7 @@ static struct adt7470_data *adt7470_update_device(struct device *dev) data->sensors_valid = 1; no_sensor_update: - if (time_before(local_jiffies, data->limits_last_updated + - LIMIT_REFRESH_INTERVAL) - && data->limits_valid) + if (!need_limits) goto out; for (i = 0; i < ADT7470_TEMP_COUNT; i++) { @@ -338,6 +432,66 @@ out: return data; } +static ssize_t show_auto_update_interval(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->auto_update_interval); +} + +static ssize_t set_auto_update_interval(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + long temp; + + if (strict_strtol(buf, 10, &temp)) + return -EINVAL; + + temp = SENSORS_LIMIT(temp, 0, 60000); + + mutex_lock(&data->lock); + data->auto_update_interval = temp; + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_num_temp_sensors(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->num_temp_sensors); +} + +static ssize_t set_num_temp_sensors(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + long temp; + + if (strict_strtol(buf, 10, &temp)) + return -EINVAL; + + temp = SENSORS_LIMIT(temp, -1, 10); + + mutex_lock(&data->lock); + data->num_temp_sensors = temp; + if (temp < 0) + data->temperatures_probed = 0; + mutex_unlock(&data->lock); + + return count; +} + static ssize_t show_temp_min(struct device *dev, struct device_attribute *devattr, char *buf) @@ -360,7 +514,7 @@ static ssize_t set_temp_min(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -394,7 +548,7 @@ static ssize_t set_temp_max(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -671,7 +825,7 @@ static ssize_t set_pwm_tmin(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = SENSORS_LIMIT(temp, 0, 255); mutex_lock(&data->lock); @@ -804,6 +958,10 @@ static ssize_t show_alarm(struct device *dev, } static DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarm_mask, NULL); +static DEVICE_ATTR(num_temp_sensors, S_IWUSR | S_IRUGO, show_num_temp_sensors, + set_num_temp_sensors); +static DEVICE_ATTR(auto_update_interval, S_IWUSR | S_IRUGO, + show_auto_update_interval, set_auto_update_interval); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max, 0); @@ -976,6 +1134,8 @@ static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, static struct attribute *adt7470_attr[] = { &dev_attr_alarm_mask.attr, + &dev_attr_num_temp_sensors.attr, + &dev_attr_auto_update_interval.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, @@ -1108,6 +1268,9 @@ static int adt7470_probe(struct i2c_client *client, goto exit; } + data->num_temp_sensors = -1; + data->auto_update_interval = AUTO_UPDATE_INTERVAL; + i2c_set_clientdata(client, data); mutex_init(&data->lock); @@ -1127,8 +1290,16 @@ static int adt7470_probe(struct i2c_client *client, goto exit_remove; } + init_completion(&data->auto_update_stop); + data->auto_update = kthread_run(adt7470_update_thread, client, + dev_name(data->hwmon_dev)); + if (IS_ERR(data->auto_update)) + goto exit_unregister; + return 0; +exit_unregister: + hwmon_device_unregister(data->hwmon_dev); exit_remove: sysfs_remove_group(&client->dev.kobj, &data->attrs); exit_free: @@ -1141,6 +1312,8 @@ static int adt7470_remove(struct i2c_client *client) { struct adt7470_data *data = i2c_get_clientdata(client); + kthread_stop(data->auto_update); + wait_for_completion(&data->auto_update_stop); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->attrs); kfree(data); diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c index 18aa30866a6c..0a6ce2367b42 100644 --- a/drivers/hwmon/adt7473.c +++ b/drivers/hwmon/adt7473.c @@ -129,8 +129,6 @@ I2C_CLIENT_INSMOD_1(adt7473); #define FAN_PERIOD_INVALID 65535 #define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) -#define ROUND_DIV(x, divisor) (((x) + ((divisor) / 2)) / (divisor)) - struct adt7473_data { struct device *hwmon_dev; struct attribute_group attrs; @@ -459,7 +457,7 @@ static ssize_t set_temp_min(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); @@ -495,7 +493,7 @@ static ssize_t set_temp_max(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); @@ -720,7 +718,7 @@ static ssize_t set_temp_tmax(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); @@ -756,7 +754,7 @@ static ssize_t set_temp_tmin(struct device *dev, if (strict_strtol(buf, 10, &temp)) return -EINVAL; - temp = ROUND_DIV(temp, 1000); + temp = DIV_ROUND_CLOSEST(temp, 1000); temp = encode_temp(data->temp_twos_complement, temp); mutex_lock(&data->lock); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 086c2a5cef0b..dca47a591baf 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -131,6 +131,10 @@ static const char* temperature_sensors_sets[][36] = { /* Set 14: iMac 6,1 */ { "TA0P", "TC0D", "TC0H", "TC0P", "TG0D", "TG0H", "TG0P", "TH0P", "TO0P", "Tp0P", NULL }, +/* Set 15: MacBook Air 2,1 */ + { "TB0T", "TB1S", "TB1T", "TB2S", "TB2T", "TC0D", "TN0D", "TTF0", + "TV0P", "TVFP", "TW0P", "Th0P", "Tp0P", "Tp1P", "TpFP", "Ts0P", + "Ts0S", NULL }, }; /* List of keys used to read/write fan speeds */ @@ -1301,11 +1305,17 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = { { .accelerometer = 0, .light = 0, .temperature_set = 13 }, /* iMac 6: light sensor only, temperature set 14 */ { .accelerometer = 0, .light = 0, .temperature_set = 14 }, +/* MacBook Air 2,1: accelerometer, backlight and temperature set 15 */ + { .accelerometer = 1, .light = 1, .temperature_set = 15 }, }; /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". * So we need to put "Apple MacBook Pro" before "Apple MacBook". */ static __initdata struct dmi_system_id applesmc_whitelist[] = { + { applesmc_dmi_match, "Apple MacBook Air 2", { + DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2") }, + &applesmc_dmi_data[15]}, { applesmc_dmi_match, "Apple MacBook Air", { DMI_MATCH(DMI_BOARD_VENDOR, "Apple"), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir") }, diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 076a59cdabe9..e15c3e7b07e9 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -76,7 +76,7 @@ void hwmon_device_unregister(struct device *dev) { int id; - if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) { + if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) { device_unregister(dev); spin_lock(&idr_lock); idr_remove(&hwmon_idr, id); diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c index 537d9fb2ff88..a36363312f2f 100644 --- a/drivers/hwmon/ibmpex.c +++ b/drivers/hwmon/ibmpex.c @@ -40,7 +40,7 @@ static inline u16 extract_value(const char *data, int offset) { - return be16_to_cpup((u16 *)&data[offset]); + return be16_to_cpup((__be16 *)&data[offset]); } #define TEMP_SENSOR 1 diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 8f9595f2fb53..55bd87c15c9a 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -190,7 +190,7 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id) } dev_info(&client->dev, "%s: sensor '%s'\n", - data->hwmon_dev->bus_id, client->name); + dev_name(data->hwmon_dev), client->name); return 0; |