#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-sensor.h>
-#include <linux/i2c-vid.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Type of the extra sensor */
static unsigned short extra_sensor_type;
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
-static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
/* Insmod parameters */
-SENSORS_INSMOD_1(gl520sm);
+I2C_CLIENT_INSMOD_1(gl520sm);
/* Many GL520 constants specified below
One of the inputs can be configured as either temp or voltage.
/* Driver data */
static struct i2c_driver gl520_driver = {
- .owner = THIS_MODULE,
- .name = "gl520sm",
+ .driver = {
+ .name = "gl520sm",
+ },
.id = I2C_DRIVERID_GL520,
- .flags = I2C_DF_NOTIFY,
.attach_adapter = gl520_attach_adapter,
.detach_client = gl520_detach_client,
};
/* Client data */
struct gl520_data {
struct i2c_client client;
- struct semaphore update_lock;
+ struct class_device *class_dev;
+ struct mutex update_lock;
char valid; /* zero until the following fields are valid */
unsigned long last_updated; /* in jiffies */
#define sysfs_vid(n) \
sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
-#define device_create_file_vid(client, n) \
-device_create_file(&client->dev, &dev_attr_cpu##n##_vid)
-
#define sysfs_in(n) \
sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
-#define device_create_file_in(client, n) \
-({device_create_file(&client->dev, &dev_attr_in##n##_input); \
-device_create_file(&client->dev, &dev_attr_in##n##_min); \
-device_create_file(&client->dev, &dev_attr_in##n##_max);})
-
#define sysfs_fan(n) \
sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
-#define device_create_file_fan(client, n) \
-({device_create_file(&client->dev, &dev_attr_fan##n##_input); \
-device_create_file(&client->dev, &dev_attr_fan##n##_min); \
-device_create_file(&client->dev, &dev_attr_fan##n##_div);})
-
#define sysfs_fan_off(n) \
sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
-#define device_create_file_fan_off(client, n) \
-device_create_file(&client->dev, &dev_attr_fan##n##_off)
-
#define sysfs_temp(n) \
sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
-#define device_create_file_temp(client, n) \
-({device_create_file(&client->dev, &dev_attr_temp##n##_input); \
-device_create_file(&client->dev, &dev_attr_temp##n##_max); \
-device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);})
-
#define sysfs_alarms() \
sysfs_ro(alarms, , GL520_REG_ALARMS) \
sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
-#define device_create_file_alarms(client) \
-({device_create_file(&client->dev, &dev_attr_alarms); \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask);})
-
sysfs_vid(0)
long v = simple_strtol(buf, NULL, 10);
u8 r;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
if (n == 0)
r = VDD_TO_REG(v);
else
gl520_write_value(client, reg, r);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
else
r = IN_TO_REG(v);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->in_max[n] = r;
else
gl520_write_value(client, reg, r);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
unsigned long v = simple_strtoul(buf, NULL, 10);
u8 r;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
r = FAN_TO_REG(v, data->fan_div[n - 1]);
data->fan_min[n - 1] = r;
data->beep_mask &= data->alarm_mask;
gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
return -EINVAL;
}
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->fan_div[n - 1] = r;
if (n == 1)
else
gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4));
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
{
u8 r = simple_strtoul(buf, NULL, 10)?1:0;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->fan_off = r;
gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2));
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
{
long v = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
- data->temp_max[n - 1] = TEMP_TO_REG(v);;
+ mutex_lock(&data->update_lock);
+ data->temp_max[n - 1] = TEMP_TO_REG(v);
gl520_write_value(client, reg, data->temp_max[n - 1]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
{
long v = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_max_hyst[n - 1] = TEMP_TO_REG(v);
gl520_write_value(client, reg, data->temp_max_hyst[n - 1]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
{
u8 r = simple_strtoul(buf, NULL, 10)?0:1;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->beep_enable = !r;
gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2));
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
{
u8 r = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
r &= data->alarm_mask;
data->beep_mask = r;
gl520_write_value(client, reg, r);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
+static struct attribute *gl520_attributes[] = {
+ &dev_attr_cpu0_vid.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_off.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+ NULL
+};
+
+static const struct attribute_group gl520_group = {
+ .attrs = gl520_attributes,
+};
+
+static struct attribute *gl520_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ NULL
+};
+
+static const struct attribute_group gl520_group_opt = {
+ .attrs = gl520_attributes_opt,
+};
+
/*
* Real code
{
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- return i2c_detect(adapter, &addr_data, gl520_detect);
+ return i2c_probe(adapter, &addr_data, gl520_detect);
}
static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
client structure, even though we cannot fill it completely yet.
But it allows us to access gl520_{read,write}_value. */
- if (!(data = kmalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
+ if (!(data = kzalloc(sizeof(struct gl520_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
- memset(data, 0, sizeof(struct gl520_data));
new_client = &data->client;
i2c_set_clientdata(new_client, data);
/* Fill in the remaining client fields */
strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE);
data->valid = 0;
- init_MUTEX(&data->update_lock);
+ mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
gl520_init_client(new_client);
/* Register sysfs hooks */
- device_create_file_vid(new_client, 0);
-
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- if (!data->two_temps)
- device_create_file_in(new_client, 4);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan_off(new_client, 1);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group)))
+ goto exit_detach;
+
+ if (data->two_temps) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_max_hyst)))
+ goto exit_remove_files;
+ } else {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove_files;
+ }
- device_create_file_temp(new_client, 1);
- if (data->two_temps)
- device_create_file_temp(new_client, 2);
- device_create_file_alarms(new_client);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt);
+exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
conf = oldconf = gl520_read_value(client, GL520_REG_CONF);
data->alarm_mask = 0xff;
- data->vrm = i2c_which_vrm();
+ data->vrm = vid_which_vrm();
if (extra_sensor_type == 1)
conf &= ~0x10;
static int gl520_detach_client(struct i2c_client *client)
{
+ struct gl520_data *data = i2c_get_clientdata(client);
int err;
- if ((err = i2c_detach_client(client))) {
- dev_err(&client->dev, "Client deregistration failed, "
- "client not detached.\n");
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
+
+ if ((err = i2c_detach_client(client)))
return err;
- }
- kfree(i2c_get_clientdata(client));
+ kfree(data);
return 0;
}
struct gl520_data *data = i2c_get_clientdata(client);
int val;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
data->valid = 1;
}
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return data;
}