diff options
Diffstat (limited to 'drivers/hwmon/gl518sm.c')
-rw-r--r-- | drivers/hwmon/gl518sm.c | 319 |
1 files changed, 141 insertions, 178 deletions
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 1e9830513045..0212c8317bca 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -114,7 +114,8 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* Each client has this additional data */ struct gl518_data { - struct device *hwmon_dev; + struct i2c_client *client; + const struct attribute_group *groups[3]; enum chips type; struct mutex update_lock; @@ -137,33 +138,98 @@ struct gl518_data { u8 beep_enable; /* Boolean */ }; -static int gl518_probe(struct i2c_client *client, - const struct i2c_device_id *id); -static int gl518_detect(struct i2c_client *client, struct i2c_board_info *info); -static void gl518_init_client(struct i2c_client *client); -static int gl518_remove(struct i2c_client *client); -static int gl518_read_value(struct i2c_client *client, u8 reg); -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value); -static struct gl518_data *gl518_update_device(struct device *dev); +/* + * Registers 0x07 to 0x0c are word-sized, others are byte-sized + * GL518 uses a high-byte first convention, which is exactly opposite to + * the SMBus standard. + */ +static int gl518_read_value(struct i2c_client *client, u8 reg) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_read_word_swapped(client, reg); + else + return i2c_smbus_read_byte_data(client, reg); +} -static const struct i2c_device_id gl518_id[] = { - { "gl518sm", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, gl518_id); +static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) +{ + if ((reg >= 0x07) && (reg <= 0x0c)) + return i2c_smbus_write_word_swapped(client, reg, value); + else + return i2c_smbus_write_byte_data(client, reg, value); +} -/* This is the driver that will be inserted */ -static struct i2c_driver gl518_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "gl518sm", - }, - .probe = gl518_probe, - .remove = gl518_remove, - .id_table = gl518_id, - .detect = gl518_detect, - .address_list = normal_i2c, -}; +static struct gl518_data *gl518_update_device(struct device *dev) +{ + struct gl518_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int val; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Starting gl518 update\n"); + + data->alarms = gl518_read_value(client, GL518_REG_INT); + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + + val = gl518_read_value(client, GL518_REG_VDD_LIMIT); + data->voltage_min[0] = val & 0xff; + data->voltage_max[0] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); + data->voltage_min[1] = val & 0xff; + data->voltage_max[1] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); + data->voltage_min[2] = val & 0xff; + data->voltage_max[2] = (val >> 8) & 0xff; + val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); + data->voltage_min[3] = val & 0xff; + data->voltage_max[3] = (val >> 8) & 0xff; + + val = gl518_read_value(client, GL518_REG_FAN_COUNT); + data->fan_in[0] = (val >> 8) & 0xff; + data->fan_in[1] = val & 0xff; + + val = gl518_read_value(client, GL518_REG_FAN_LIMIT); + data->fan_min[0] = (val >> 8) & 0xff; + data->fan_min[1] = val & 0xff; + + data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN); + data->temp_max = + gl518_read_value(client, GL518_REG_TEMP_MAX); + data->temp_hyst = + gl518_read_value(client, GL518_REG_TEMP_HYST); + + val = gl518_read_value(client, GL518_REG_MISC); + data->fan_div[0] = (val >> 6) & 0x03; + data->fan_div[1] = (val >> 4) & 0x03; + data->fan_auto1 = (val >> 3) & 0x01; + + data->alarms &= data->alarm_mask; + + val = gl518_read_value(client, GL518_REG_CONF); + data->beep_enable = (val >> 2) & 1; + + if (data->type != gl518sm_r00) { + data->voltage_in[0] = + gl518_read_value(client, GL518_REG_VDD); + data->voltage_in[1] = + gl518_read_value(client, GL518_REG_VIN1); + data->voltage_in[2] = + gl518_read_value(client, GL518_REG_VIN2); + } + data->voltage_in[3] = + gl518_read_value(client, GL518_REG_VIN3); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} /* * Sysfs stuff @@ -228,8 +294,8 @@ static ssize_t set_##suffix(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl518_data *data = i2c_get_clientdata(client); \ + struct gl518_data *data = dev_get_drvdata(dev); \ + struct i2c_client *client = data->client; \ long val; \ int err = kstrtol(buf, 10, &val); \ if (err) \ @@ -247,8 +313,8 @@ static ssize_t set_##suffix(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl518_data *data = i2c_get_clientdata(client); \ + struct gl518_data *data = dev_get_drvdata(dev); \ + struct i2c_client *client = data->client; \ int regvalue; \ unsigned long val; \ int err = kstrtoul(buf, 10, &val); \ @@ -286,8 +352,8 @@ set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); + struct gl518_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = to_sensor_dev_attr(attr)->index; int regvalue; unsigned long val; @@ -319,8 +385,8 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); + struct gl518_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int nr = to_sensor_dev_attr(attr)->index; int regvalue; unsigned long val; @@ -420,8 +486,8 @@ static ssize_t show_beep(struct device *dev, struct device_attribute *attr, static ssize_t set_beep(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); + struct gl518_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; int bitnr = to_sensor_dev_attr(attr)->index; unsigned long bit; int err; @@ -539,52 +605,6 @@ static int gl518_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int gl518_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct gl518_data *data; - int err, revision; - - data = devm_kzalloc(&client->dev, sizeof(struct gl518_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - i2c_set_clientdata(client, data); - revision = gl518_read_value(client, GL518_REG_REVISION); - data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00; - mutex_init(&data->update_lock); - - /* Initialize the GL518SM chip */ - data->alarm_mask = 0xff; - gl518_init_client(client); - - /* Register sysfs hooks */ - err = sysfs_create_group(&client->dev.kobj, &gl518_group); - if (err) - return err; - if (data->type == gl518sm_r80) { - err = sysfs_create_group(&client->dev.kobj, &gl518_group_r80); - if (err) - goto exit_remove_files; - } - - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - err = PTR_ERR(data->hwmon_dev); - goto exit_remove_files; - } - - return 0; - -exit_remove_files: - sysfs_remove_group(&client->dev.kobj, &gl518_group); - if (data->type == gl518sm_r80) - sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); - return err; -} - - /* * Called when we have found a new GL518SM. * Note that we preserve D4:NoFan2 and D2:beep_enable. @@ -605,110 +625,53 @@ static void gl518_init_client(struct i2c_client *client) gl518_write_value(client, GL518_REG_CONF, 0x40 | regvalue); } -static int gl518_remove(struct i2c_client *client) -{ - struct gl518_data *data = i2c_get_clientdata(client); - - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &gl518_group); - if (data->type == gl518sm_r80) - sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); - - return 0; -} - -/* - * Registers 0x07 to 0x0c are word-sized, others are byte-sized - * GL518 uses a high-byte first convention, which is exactly opposite to - * the SMBus standard. - */ -static int gl518_read_value(struct i2c_client *client, u8 reg) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_read_word_swapped(client, reg); - else - return i2c_smbus_read_byte_data(client, reg); -} - -static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if ((reg >= 0x07) && (reg <= 0x0c)) - return i2c_smbus_write_word_swapped(client, reg, value); - else - return i2c_smbus_write_byte_data(client, reg, value); -} - -static struct gl518_data *gl518_update_device(struct device *dev) +static int gl518_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct i2c_client *client = to_i2c_client(dev); - struct gl518_data *data = i2c_get_clientdata(client); - int val; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - dev_dbg(&client->dev, "Starting gl518 update\n"); - - data->alarms = gl518_read_value(client, GL518_REG_INT); - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - - val = gl518_read_value(client, GL518_REG_VDD_LIMIT); - data->voltage_min[0] = val & 0xff; - data->voltage_max[0] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN1_LIMIT); - data->voltage_min[1] = val & 0xff; - data->voltage_max[1] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN2_LIMIT); - data->voltage_min[2] = val & 0xff; - data->voltage_max[2] = (val >> 8) & 0xff; - val = gl518_read_value(client, GL518_REG_VIN3_LIMIT); - data->voltage_min[3] = val & 0xff; - data->voltage_max[3] = (val >> 8) & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_COUNT); - data->fan_in[0] = (val >> 8) & 0xff; - data->fan_in[1] = val & 0xff; - - val = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = (val >> 8) & 0xff; - data->fan_min[1] = val & 0xff; - - data->temp_in = gl518_read_value(client, GL518_REG_TEMP_IN); - data->temp_max = - gl518_read_value(client, GL518_REG_TEMP_MAX); - data->temp_hyst = - gl518_read_value(client, GL518_REG_TEMP_HYST); + struct device *dev = &client->dev; + struct device *hwmon_dev; + struct gl518_data *data; + int revision; - val = gl518_read_value(client, GL518_REG_MISC); - data->fan_div[0] = (val >> 6) & 0x03; - data->fan_div[1] = (val >> 4) & 0x03; - data->fan_auto1 = (val >> 3) & 0x01; + data = devm_kzalloc(dev, sizeof(struct gl518_data), GFP_KERNEL); + if (!data) + return -ENOMEM; - data->alarms &= data->alarm_mask; + data->client = client; + revision = gl518_read_value(client, GL518_REG_REVISION); + data->type = revision == 0x80 ? gl518sm_r80 : gl518sm_r00; + mutex_init(&data->update_lock); - val = gl518_read_value(client, GL518_REG_CONF); - data->beep_enable = (val >> 2) & 1; + /* Initialize the GL518SM chip */ + data->alarm_mask = 0xff; + gl518_init_client(client); - if (data->type != gl518sm_r00) { - data->voltage_in[0] = - gl518_read_value(client, GL518_REG_VDD); - data->voltage_in[1] = - gl518_read_value(client, GL518_REG_VIN1); - data->voltage_in[2] = - gl518_read_value(client, GL518_REG_VIN2); - } - data->voltage_in[3] = - gl518_read_value(client, GL518_REG_VIN3); + /* sysfs hooks */ + data->groups[0] = &gl518_group; + if (data->type == gl518sm_r80) + data->groups[1] = &gl518_group_r80; - data->last_updated = jiffies; - data->valid = 1; - } + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, data->groups); + return PTR_ERR_OR_ZERO(hwmon_dev); +} - mutex_unlock(&data->update_lock); +static const struct i2c_device_id gl518_id[] = { + { "gl518sm", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, gl518_id); - return data; -} +static struct i2c_driver gl518_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "gl518sm", + }, + .probe = gl518_probe, + .id_table = gl518_id, + .detect = gl518_detect, + .address_list = normal_i2c, +}; module_i2c_driver(gl518_driver); |