--- zzzz-none-000/linux-3.10.107/drivers/hwmon/lm80.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/hwmon/lm80.c 2021-02-04 17:41:59.000000000 +0000 @@ -86,140 +86,234 @@ #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ (val) == 255 ? 0 : 1350000/((div) * (val))) -static inline long TEMP_FROM_REG(u16 temp) -{ - long res; +#define TEMP_FROM_REG(reg) ((reg) * 125 / 32) +#define TEMP_TO_REG(temp) (DIV_ROUND_CLOSEST(clamp_val((temp), \ + -128000, 127000), 1000) << 8) - temp >>= 4; - if (temp < 0x0800) - res = 625 * (long) temp; - else - res = ((long) temp - 0x01000) * 625; +#define DIV_FROM_REG(val) (1 << (val)) - return res / 10; -} +enum temp_index { + t_input = 0, + t_hot_max, + t_hot_hyst, + t_os_max, + t_os_hyst, + t_num_temp +}; -#define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \ - (val) - 0x100 : (val)) * 1000) +static const u8 temp_regs[t_num_temp] = { + [t_input] = LM80_REG_TEMP, + [t_hot_max] = LM80_REG_TEMP_HOT_MAX, + [t_hot_hyst] = LM80_REG_TEMP_HOT_HYST, + [t_os_max] = LM80_REG_TEMP_OS_MAX, + [t_os_hyst] = LM80_REG_TEMP_OS_HYST, +}; -#define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \ - ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255) +enum in_index { + i_input = 0, + i_max, + i_min, + i_num_in +}; -#define DIV_FROM_REG(val) (1 << (val)) +enum fan_index { + f_input, + f_min, + f_num_fan +}; /* * Client data (each client gets its own) */ struct lm80_data { - struct device *hwmon_dev; + struct i2c_client *client; struct mutex update_lock; char error; /* !=0 if error occurred during last update */ char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 in[7]; /* Register value */ - u8 in_max[7]; /* Register value */ - u8 in_min[7]; /* Register value */ - u8 fan[2]; /* Register value */ - u8 fan_min[2]; /* Register value */ + u8 in[i_num_in][7]; /* Register value, 1st index is enum in_index */ + u8 fan[f_num_fan][2]; /* Register value, 1st index enum fan_index */ u8 fan_div[2]; /* Register encoding, shifted right */ - u16 temp; /* Register values, shifted right */ - u8 temp_hot_max; /* Register value */ - u8 temp_hot_hyst; /* Register value */ - u8 temp_os_max; /* Register value */ - u8 temp_os_hyst; /* Register value */ + s16 temp[t_num_temp]; /* Register values, normalized to 16 bit */ u16 alarms; /* Register encoding, combined */ }; -/* - * Functions declaration - */ +static int lm80_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} -static int lm80_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info); -static void lm80_init_client(struct i2c_client *client); -static int lm80_remove(struct i2c_client *client); -static struct lm80_data *lm80_update_device(struct device *dev); -static int lm80_read_value(struct i2c_client *client, u8 reg); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); +static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} -/* - * Driver data (common to all clients) - */ +/* Called when we have found a new LM80 and after read errors */ +static void lm80_init_client(struct i2c_client *client) +{ + /* + * Reset all except Watchdog values and last conversion values + * This sets fan-divs to 2, among others. This makes most other + * initializations unnecessary + */ + lm80_write_value(client, LM80_REG_CONFIG, 0x80); + /* Set 11-bit temperature resolution */ + lm80_write_value(client, LM80_REG_RES, 0x08); -static const struct i2c_device_id lm80_id[] = { - { "lm80", 0 }, - { "lm96080", 1 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, lm80_id); + /* Start monitoring */ + lm80_write_value(client, LM80_REG_CONFIG, 0x01); +} -static struct i2c_driver lm80_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "lm80", - }, - .probe = lm80_probe, - .remove = lm80_remove, - .id_table = lm80_id, - .detect = lm80_detect, - .address_list = normal_i2c, -}; +static struct lm80_data *lm80_update_device(struct device *dev) +{ + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int i; + int rv; + int prev_rv; + struct lm80_data *ret = data; + + mutex_lock(&data->update_lock); + + if (data->error) + lm80_init_client(client); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + dev_dbg(dev, "Starting lm80 update\n"); + for (i = 0; i <= 6; i++) { + rv = lm80_read_value(client, LM80_REG_IN(i)); + if (rv < 0) + goto abort; + data->in[i_input][i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); + if (rv < 0) + goto abort; + data->in[i_min][i] = rv; + + rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); + if (rv < 0) + goto abort; + data->in[i_max][i] = rv; + } + + rv = lm80_read_value(client, LM80_REG_FAN1); + if (rv < 0) + goto abort; + data->fan[f_input][0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + if (rv < 0) + goto abort; + data->fan[f_min][0] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN2); + if (rv < 0) + goto abort; + data->fan[f_input][1] = rv; + + rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); + if (rv < 0) + goto abort; + data->fan[f_min][1] = rv; + + prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_RES); + if (rv < 0) + goto abort; + data->temp[t_input] = (prev_rv << 8) | (rv & 0xf0); + + for (i = t_input + 1; i < t_num_temp; i++) { + rv = lm80_read_value(client, temp_regs[i]); + if (rv < 0) + goto abort; + data->temp[i] = rv << 8; + } + + rv = lm80_read_value(client, LM80_REG_FANDIV); + if (rv < 0) + goto abort; + data->fan_div[0] = (rv >> 2) & 0x03; + data->fan_div[1] = (rv >> 4) & 0x03; + + prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); + if (rv < 0) + goto abort; + rv = lm80_read_value(client, LM80_REG_ALARM2); + if (rv < 0) + goto abort; + data->alarms = prev_rv + (rv << 8); + + data->last_updated = jiffies; + data->valid = 1; + data->error = 0; + } + goto done; + +abort: + ret = ERR_PTR(rv); + data->valid = 0; + data->error = 1; + +done: + mutex_unlock(&data->update_lock); + + return ret; +} /* * Sysfs stuff */ -#define show_in(suffix, value) \ -static ssize_t show_in_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \ -} -show_in(min, in_min) -show_in(max, in_max) -show_in(input, in) - -#define set_in(suffix, value, reg) \ -static ssize_t set_in_##suffix(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err < 0) \ - return err; \ -\ - mutex_lock(&data->update_lock);\ - data->value[nr] = IN_TO_REG(val); \ - lm80_write_value(client, reg(nr), data->value[nr]); \ - mutex_unlock(&data->update_lock);\ - return count; \ -} -set_in(min, in_min, LM80_REG_IN_MIN) -set_in(max, in_max, LM80_REG_IN_MAX) - -#define show_fan(suffix, value) \ -static ssize_t show_fan_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int nr = to_sensor_dev_attr(attr)->index; \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \ - DIV_FROM_REG(data->fan_div[nr]))); \ +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm80_data *data = lm80_update_device(dev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr][index])); +} + +static ssize_t set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + long val; + u8 reg; + int err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + reg = nr == i_min ? LM80_REG_IN_MIN(index) : LM80_REG_IN_MAX(index); + + mutex_lock(&data->update_lock); + data->in[nr][index] = IN_TO_REG(val); + lm80_write_value(client, reg, data->in[nr][index]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + struct lm80_data *data = lm80_update_device(dev); + if (IS_ERR(data)) + return PTR_ERR(data); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr][index], + DIV_FROM_REG(data->fan_div[index]))); } -show_fan(min, fan_min) -show_fan(input, fan) static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) @@ -234,17 +328,20 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int nr = to_sensor_dev_attr(attr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long val; int err = kstrtoul(buf, 10, &val); if (err < 0) return err; mutex_lock(&data->update_lock); - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + data->fan[nr][index] = FAN_TO_REG(val, + DIV_FROM_REG(data->fan_div[index])); + lm80_write_value(client, LM80_REG_FAN_MIN(index + 1), + data->fan[nr][index]); mutex_unlock(&data->update_lock); return count; } @@ -259,8 +356,8 @@ const char *buf, size_t count) { int nr = to_sensor_dev_attr(attr)->index; - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; unsigned long min, val; u8 reg; int err = kstrtoul(buf, 10, &val); @@ -269,7 +366,7 @@ /* Save fan_min */ mutex_lock(&data->update_lock); - min = FAN_FROM_REG(data->fan_min[nr], + min = FAN_FROM_REG(data->fan[f_min][nr], DIV_FROM_REG(data->fan_div[nr])); switch (val) { @@ -286,69 +383,54 @@ data->fan_div[nr] = 3; break; default: - dev_err(&client->dev, + dev_err(dev, "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", val); mutex_unlock(&data->update_lock); return -EINVAL; } - reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) - | (data->fan_div[nr] << (2 * (nr + 1))); + reg = (lm80_read_value(client, LM80_REG_FANDIV) & + ~(3 << (2 * (nr + 1)))) | (data->fan_div[nr] << (2 * (nr + 1))); lm80_write_value(client, LM80_REG_FANDIV, reg); /* Restore fan_min */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); + data->fan[f_min][nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), + data->fan[f_min][nr]); mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_input1(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) { + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct lm80_data *data = lm80_update_device(dev); if (IS_ERR(data)) return PTR_ERR(data); - return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); } -#define show_temp(suffix, value) \ -static ssize_t show_temp_##suffix(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct lm80_data *data = lm80_update_device(dev); \ - if (IS_ERR(data)) \ - return PTR_ERR(data); \ - return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ -} -show_temp(hot_max, temp_hot_max); -show_temp(hot_hyst, temp_hot_hyst); -show_temp(os_max, temp_os_max); -show_temp(os_hyst, temp_os_hyst); - -#define set_temp(suffix, value, reg) \ -static ssize_t set_temp_##suffix(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct lm80_data *data = i2c_get_clientdata(client); \ - long val; \ - int err = kstrtol(buf, 10, &val); \ - if (err < 0) \ - return err; \ -\ - mutex_lock(&data->update_lock); \ - data->value = TEMP_LIMIT_TO_REG(val); \ - lm80_write_value(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} -set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); -set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); -set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); -set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct lm80_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int nr = attr->index; + long val; + int err = kstrtol(buf, 10, &val); + if (err < 0) + return err; + + mutex_lock(&data->update_lock); + data->temp[nr] = TEMP_TO_REG(val); + lm80_write_value(client, temp_regs[nr], data->temp[nr] >> 8); + mutex_unlock(&data->update_lock); + return count; +} static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -369,60 +451,60 @@ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); } -static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 0); -static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 1); -static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 2); -static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 3); -static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 4); -static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 5); -static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, - show_in_min, set_in_min, 6); -static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 0); -static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 1); -static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 2); -static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 3); -static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 4); -static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 5); -static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, - show_in_max, set_in_max, 6); -static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0); -static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1); -static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2); -static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3); -static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4); -static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5); -static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6); -static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, - show_fan_min, set_fan_min, 0); -static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, - show_fan_min, set_fan_min, 1); -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); -static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 0); +static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 1); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 2); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 3); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 4); +static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 5); +static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, + show_in, set_in, i_min, 6); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 0); +static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 2); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 3); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 4); +static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 5); +static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, + show_in, set_in, i_max, 6); +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, i_input, 0); +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, i_input, 1); +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, i_input, 2); +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, i_input, 3); +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, i_input, 4); +static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, i_input, 5); +static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, i_input, 6); +static SENSOR_DEVICE_ATTR_2(fan1_min, S_IWUSR | S_IRUGO, + show_fan, set_fan_min, f_min, 0); +static SENSOR_DEVICE_ATTR_2(fan2_min, S_IWUSR | S_IRUGO, + show_fan, set_fan_min, f_min, 1); +static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, f_input, 0); +static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, f_input, 1); static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 0); static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, set_fan_div, 1); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, - set_temp_hot_max); -static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, - set_temp_hot_hyst); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, - set_temp_os_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, - set_temp_os_hyst); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hot_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_hot_hyst); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_os_max); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp, + set_temp, t_os_hyst); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); @@ -440,7 +522,7 @@ * Real code */ -static struct attribute *lm80_attributes[] = { +static struct attribute *lm80_attrs[] = { &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, @@ -468,11 +550,11 @@ &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, - &dev_attr_temp1_crit.attr, - &dev_attr_temp1_crit_hyst.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &dev_attr_alarms.attr, &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, @@ -487,10 +569,7 @@ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, NULL }; - -static const struct attribute_group lm80_group = { - .attrs = lm80_attributes, -}; +ATTRIBUTE_GROUPS(lm80); /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) @@ -541,188 +620,51 @@ static int lm80_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device *dev = &client->dev; + struct device *hwmon_dev; struct lm80_data *data; - int err; - data = devm_kzalloc(&client->dev, sizeof(struct lm80_data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(struct lm80_data), GFP_KERNEL); if (!data) return -ENOMEM; - i2c_set_clientdata(client, data); + data->client = client; mutex_init(&data->update_lock); /* Initialize the LM80 chip */ lm80_init_client(client); /* A few vars need to be filled upon startup */ - data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); - data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); - - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &lm80_group); - if (err) - return err; - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto error_remove; - } - - return 0; - -error_remove: - sysfs_remove_group(&client->dev.kobj, &lm80_group); - return err; -} + data->fan[f_min][0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); + data->fan[f_min][1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); -static int lm80_remove(struct i2c_client *client) -{ - struct lm80_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &lm80_group); - - return 0; -} - -static int lm80_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, lm80_groups); -static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); + return PTR_ERR_OR_ZERO(hwmon_dev); } -/* Called when we have found a new LM80. */ -static void lm80_init_client(struct i2c_client *client) -{ - /* - * Reset all except Watchdog values and last conversion values - * This sets fan-divs to 2, among others. This makes most other - * initializations unnecessary - */ - lm80_write_value(client, LM80_REG_CONFIG, 0x80); - /* Set 11-bit temperature resolution */ - lm80_write_value(client, LM80_REG_RES, 0x08); - - /* Start monitoring */ - lm80_write_value(client, LM80_REG_CONFIG, 0x01); -} - -static struct lm80_data *lm80_update_device(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lm80_data *data = i2c_get_clientdata(client); - int i; - int rv; - int prev_rv; - struct lm80_data *ret = data; - - mutex_lock(&data->update_lock); - - if (data->error) - lm80_init_client(client); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - dev_dbg(&client->dev, "Starting lm80 update\n"); - for (i = 0; i <= 6; i++) { - rv = lm80_read_value(client, LM80_REG_IN(i)); - if (rv < 0) - goto abort; - data->in[i] = rv; - - rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); - if (rv < 0) - goto abort; - data->in_min[i] = rv; - - rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); - if (rv < 0) - goto abort; - data->in_max[i] = rv; - } - - rv = lm80_read_value(client, LM80_REG_FAN1); - if (rv < 0) - goto abort; - data->fan[0] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); - if (rv < 0) - goto abort; - data->fan_min[0] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN2); - if (rv < 0) - goto abort; - data->fan[1] = rv; - - rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); - if (rv < 0) - goto abort; - data->fan_min[1] = rv; - - prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); - if (rv < 0) - goto abort; - rv = lm80_read_value(client, LM80_REG_RES); - if (rv < 0) - goto abort; - data->temp = (prev_rv << 8) | (rv & 0xf0); - - rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); - if (rv < 0) - goto abort; - data->temp_os_max = rv; - - rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); - if (rv < 0) - goto abort; - data->temp_os_hyst = rv; - - rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); - if (rv < 0) - goto abort; - data->temp_hot_max = rv; - - rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); - if (rv < 0) - goto abort; - data->temp_hot_hyst = rv; - - rv = lm80_read_value(client, LM80_REG_FANDIV); - if (rv < 0) - goto abort; - data->fan_div[0] = (rv >> 2) & 0x03; - data->fan_div[1] = (rv >> 4) & 0x03; - - prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); - if (rv < 0) - goto abort; - rv = lm80_read_value(client, LM80_REG_ALARM2); - if (rv < 0) - goto abort; - data->alarms = prev_rv + (rv << 8); - - data->last_updated = jiffies; - data->valid = 1; - data->error = 0; - } - goto done; - -abort: - ret = ERR_PTR(rv); - data->valid = 0; - data->error = 1; +/* + * Driver data (common to all clients) + */ -done: - mutex_unlock(&data->update_lock); +static const struct i2c_device_id lm80_id[] = { + { "lm80", 0 }, + { "lm96080", 1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm80_id); - return ret; -} +static struct i2c_driver lm80_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "lm80", + }, + .probe = lm80_probe, + .id_table = lm80_id, + .detect = lm80_detect, + .address_list = normal_i2c, +}; module_i2c_driver(lm80_driver);