Commit c7461a66 authored by Grant Coady's avatar Grant Coady Committed by Greg Kroah-Hartman
Browse files

[PATCH] hwmon: adm9240 driver update - dynamic sysfs



hwmon: adm9240 update 2/2: convert to use dynamic sysfs accessors

This patch converts adm9240 to use Yani Ioannou's dynamic sysfs callbacks,
reducing driver memory footprint from 16312 to 14104 bytes on 2.6.14-rc1,
removing the old driver macro mess.

Run tested on Intel SE440BX-2 mobo.

Signed-off-by: default avatarGrant Coady <gcoady@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 205cf13e
Loading
Loading
Loading
Loading
+166 −176
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
@@ -69,8 +70,7 @@ I2C_CLIENT_INSMOD_3(adm9240, ds1780, lm81);
#define ADM9240_REG_INT(nr)		(0x41 + (nr))
#define ADM9240_REG_INT_MASK(nr)	(0x43 + (nr))
#define ADM9240_REG_TEMP		0x27
#define ADM9240_REG_TEMP_HIGH		0x39
#define ADM9240_REG_TEMP_HYST		0x3a
#define ADM9240_REG_TEMP_MAX(nr)	(0x39 + (nr)) /* 0, 1 = high, hyst */
#define ADM9240_REG_ANALOG_OUT		0x19
#define ADM9240_REG_CHASSIS_CLEAR	0x46
#define ADM9240_REG_VID_FAN_DIV		0x47
@@ -162,8 +162,7 @@ struct adm9240_data {
	u8 fan_min[2];		/* rw	fan1_min */
	u8 fan_div[2];		/* rw	fan1_div, read-only accessor */
	s16 temp;		/* ro	temp1_input, 9-bit sign-extended */
	s8 temp_high;		/* rw	temp1_max */
	s8 temp_hyst;		/* rw	temp1_max_hyst */
	s8 temp_max[2];		/* rw	0 -> temp_max, 1 -> temp_max_hyst */
	u16 alarms;		/* ro	alarms */
	u8 aout;		/* rw	aout_output */
	u8 vid;			/* ro	vid */
@@ -173,157 +172,143 @@ struct adm9240_data {
/*** sysfs accessors ***/

/* temperature */
#define show_temp(value, scale)					\
static ssize_t show_##value(struct device *dev,			\
			    struct device_attribute *attr,	\
			    char *buf)				\
{								\
	struct adm9240_data *data = adm9240_update_device(dev);	\
	return sprintf(buf, "%d\n", data->value * scale);	\
}
show_temp(temp_high, 1000);
show_temp(temp_hyst, 1000);
show_temp(temp, 500); /* 0.5'C per bit */

#define set_temp(value, reg)					\
static ssize_t set_##value(struct device *dev, 			\
			   struct device_attribute *attr,	\
			   const char *buf, size_t count)	\
{								\
	struct i2c_client *client = to_i2c_client(dev);		\
	struct adm9240_data *data = adm9240_update_device(dev);	\
	long temp = simple_strtoul(buf, NULL, 10);		\
								\
	down(&data->update_lock);				\
	data->value = TEMP_TO_REG(temp);			\
	i2c_smbus_write_byte_data(client, reg, data->value);	\
	up(&data->update_lock);					\
	return count;						\
}

set_temp(temp_high, ADM9240_REG_TEMP_HIGH);
set_temp(temp_hyst, ADM9240_REG_TEMP_HYST);

static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
		show_temp_high, set_temp_high);
static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
		show_temp_hyst, set_temp_hyst);
static ssize_t show_temp(struct device *dev, struct device_attribute *dummy,
		char *buf)
{
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", data->temp * 500); /* 9-bit value */
}

static ssize_t show_max(struct device *dev, struct device_attribute *devattr,
		char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", data->temp_max[attr->index] * 1000);
}

static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
		const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct adm9240_data *data = i2c_get_clientdata(client);
	long val = simple_strtol(buf, NULL, 10);

	down(&data->update_lock);
	data->temp_max[attr->index] = TEMP_TO_REG(val);
	i2c_smbus_write_byte_data(client, ADM9240_REG_TEMP_MAX(attr->index),
			data->temp_max[attr->index]);
	up(&data->update_lock);
	return count;
}

static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
		show_max, set_max, 0);
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
		show_max, set_max, 1);

/* voltage */
static ssize_t show_in(struct device *dev, char *buf, int nr)
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
		char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], nr));
	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index],
				attr->index));
}

static ssize_t show_in_min(struct device *dev, char *buf, int nr)
static ssize_t show_in_min(struct device *dev, struct device_attribute *devattr,
		char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], nr));
	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index],
				attr->index));
}

static ssize_t show_in_max(struct device *dev, char *buf, int nr)
static ssize_t show_in_max(struct device *dev, struct device_attribute *devattr,
		char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], nr));
	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index],
				attr->index));
}

static ssize_t set_in_min(struct device *dev, const char *buf,
		size_t count, int nr)
static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
		const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct adm9240_data *data = i2c_get_clientdata(client);
	unsigned long val = simple_strtoul(buf, NULL, 10);

	down(&data->update_lock);
	data->in_min[nr] = IN_TO_REG(val, nr);
	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(nr),
			data->in_min[nr]);
	data->in_min[attr->index] = IN_TO_REG(val, attr->index);
	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MIN(attr->index),
			data->in_min[attr->index]);
	up(&data->update_lock);
	return count;
}

static ssize_t set_in_max(struct device *dev, const char *buf,
		size_t count, int nr)
static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
		const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct adm9240_data *data = i2c_get_clientdata(client);
	unsigned long val = simple_strtoul(buf, NULL, 10);

	down(&data->update_lock);
	data->in_max[nr] = IN_TO_REG(val, nr);
	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(nr),
			data->in_max[nr]);
	data->in_max[attr->index] = IN_TO_REG(val, attr->index);
	i2c_smbus_write_byte_data(client, ADM9240_REG_IN_MAX(attr->index),
			data->in_max[attr->index]);
	up(&data->update_lock);
	return count;
}

#define show_in_offset(offset)						\
static ssize_t show_in##offset(struct device *dev,			\
			       struct device_attribute *attr,		\
			       char *buf)				\
{									\
	return show_in(dev, buf, offset);				\
}									\
static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);	\
static ssize_t show_in##offset##_min(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	return show_in_min(dev, buf, offset);				\
}									\
static ssize_t show_in##offset##_max(struct device *dev,		\
				     struct device_attribute *attr,	\
				     char *buf)				\
{									\
	return show_in_max(dev, buf, offset);				\
}									\
static ssize_t								\
set_in##offset##_min(struct device *dev,				\
		     struct device_attribute *attr, const char *buf,	\
		     size_t count)					\
{									\
	return set_in_min(dev, buf, count, offset);			\
}									\
static ssize_t								\
set_in##offset##_max(struct device *dev,				\
		     struct device_attribute *attr, const char *buf,	\
		     size_t count)					\
{									\
	return set_in_max(dev, buf, count, offset);			\
}									\
static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,			\
		show_in##offset##_min, set_in##offset##_min);		\
static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,			\
		show_in##offset##_max, set_in##offset##_max);

show_in_offset(0);
show_in_offset(1);
show_in_offset(2);
show_in_offset(3);
show_in_offset(4);
show_in_offset(5);
#define vin(nr)							\
static SENSOR_DEVICE_ATTR(in##nr##_input, S_IRUGO, 		\
		show_in, NULL, nr);				\
static SENSOR_DEVICE_ATTR(in##nr##_min, S_IRUGO | S_IWUSR,	\
		show_in_min, set_in_min, nr);			\
static SENSOR_DEVICE_ATTR(in##nr##_max, S_IRUGO | S_IWUSR,	\
		show_in_max, set_in_max, nr);

vin(0);
vin(1);
vin(2);
vin(3);
vin(4);
vin(5);

/* fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr)
static ssize_t show_fan(struct device *dev,
		struct device_attribute *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
				1 << data->fan_div[nr]));
	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index],
				1 << data->fan_div[attr->index]));
}

static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
static ssize_t show_fan_min(struct device *dev,
		struct device_attribute *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr],
				1 << data->fan_div[nr]));
	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[attr->index],
				1 << data->fan_div[attr->index]));
}

static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
static ssize_t show_fan_div(struct device *dev,
		struct device_attribute *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct adm9240_data *data = adm9240_update_device(dev);
	return sprintf(buf, "%d\n", 1 << data->fan_div[nr]);
	return sprintf(buf, "%d\n", 1 << data->fan_div[attr->index]);
}

/* write new fan div, callers must hold data->update_lock */
@@ -352,12 +337,15 @@ static void adm9240_write_fan_div(struct i2c_client *client, int nr,
 * - otherwise: select fan clock divider to suit fan speed low limit,
 *   measurement code may adjust registers to ensure fan speed reading
 */
static ssize_t set_fan_min(struct device *dev, const char *buf,
		size_t count, int nr)
static ssize_t set_fan_min(struct device *dev,
		struct device_attribute *devattr,
		const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct adm9240_data *data = i2c_get_clientdata(client);
	unsigned long val = simple_strtoul(buf, NULL, 10);
	int nr = attr->index;
	u8 new_div;

	down(&data->update_lock);
@@ -404,40 +392,16 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
	return count;
}

#define show_fan_offset(offset)						\
static ssize_t show_fan_##offset (struct device *dev,			\
				  struct device_attribute *attr,	\
				  char *buf)				\
{									\
return show_fan(dev, buf, offset - 1);					\
}									\
static ssize_t show_fan_##offset##_div (struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
return show_fan_div(dev, buf, offset - 1);				\
}									\
static ssize_t show_fan_##offset##_min (struct device *dev,		\
					struct device_attribute *attr,	\
					char *buf)			\
{									\
return show_fan_min(dev, buf, offset - 1);				\
}									\
static ssize_t set_fan_##offset##_min (struct device *dev, 		\
				       struct device_attribute *attr,	\
				       const char *buf, size_t count)	\
{									\
return set_fan_min(dev, buf, count, offset - 1);			\
}									\
static DEVICE_ATTR(fan##offset##_input, S_IRUGO, 			\
		show_fan_##offset, NULL);				\
static DEVICE_ATTR(fan##offset##_div, S_IRUGO, 				\
		show_fan_##offset##_div, NULL);				\
static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
		show_fan_##offset##_min, set_fan_##offset##_min);

show_fan_offset(1);
show_fan_offset(2);
#define fan(nr)							\
static SENSOR_DEVICE_ATTR(fan##nr##_input, S_IRUGO,		\
		show_fan, NULL, nr - 1);			\
static SENSOR_DEVICE_ATTR(fan##nr##_div, S_IRUGO,		\
		show_fan_div, NULL, nr - 1);			\
static SENSOR_DEVICE_ATTR(fan##nr##_min, S_IRUGO | S_IWUSR,	\
		show_fan_min, set_fan_min, nr - 1);

fan(1);
fan(2);

/* alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
@@ -580,33 +544,59 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
		goto exit_detach;
	}

	device_create_file(&new_client->dev, &dev_attr_in0_input);
	device_create_file(&new_client->dev, &dev_attr_in0_min);
	device_create_file(&new_client->dev, &dev_attr_in0_max);
	device_create_file(&new_client->dev, &dev_attr_in1_input);
	device_create_file(&new_client->dev, &dev_attr_in1_min);
	device_create_file(&new_client->dev, &dev_attr_in1_max);
	device_create_file(&new_client->dev, &dev_attr_in2_input);
	device_create_file(&new_client->dev, &dev_attr_in2_min);
	device_create_file(&new_client->dev, &dev_attr_in2_max);
	device_create_file(&new_client->dev, &dev_attr_in3_input);
	device_create_file(&new_client->dev, &dev_attr_in3_min);
	device_create_file(&new_client->dev, &dev_attr_in3_max);
	device_create_file(&new_client->dev, &dev_attr_in4_input);
	device_create_file(&new_client->dev, &dev_attr_in4_min);
	device_create_file(&new_client->dev, &dev_attr_in4_max);
	device_create_file(&new_client->dev, &dev_attr_in5_input);
	device_create_file(&new_client->dev, &dev_attr_in5_min);
	device_create_file(&new_client->dev, &dev_attr_in5_max);
	device_create_file(&new_client->dev, &dev_attr_temp1_max);
	device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in0_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in0_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in0_max.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in1_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in1_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in1_max.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in2_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in2_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in2_max.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in3_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in3_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in3_max.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in4_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in4_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in4_max.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in5_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in5_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_in5_max.dev_attr);
	device_create_file(&new_client->dev, &dev_attr_temp1_input);
	device_create_file(&new_client->dev, &dev_attr_fan1_input);
	device_create_file(&new_client->dev, &dev_attr_fan1_div);
	device_create_file(&new_client->dev, &dev_attr_fan1_min);
	device_create_file(&new_client->dev, &dev_attr_fan2_input);
	device_create_file(&new_client->dev, &dev_attr_fan2_div);
	device_create_file(&new_client->dev, &dev_attr_fan2_min);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_temp1_max.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_temp1_max_hyst.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_fan1_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_fan1_div.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_fan1_min.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_fan2_input.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_fan2_div.dev_attr);
	device_create_file(&new_client->dev,
			&sensor_dev_attr_fan2_min.dev_attr);
	device_create_file(&new_client->dev, &dev_attr_alarms);
	device_create_file(&new_client->dev, &dev_attr_aout_output);
	device_create_file(&new_client->dev, &dev_attr_chassis_clear);
@@ -674,9 +664,9 @@ static void adm9240_init_client(struct i2c_client *client)
		i2c_smbus_write_byte_data(client,
				ADM9240_REG_FAN_MIN(1), 255);
		i2c_smbus_write_byte_data(client,
				ADM9240_REG_TEMP_HIGH, 127);
				ADM9240_REG_TEMP_MAX(0), 127);
		i2c_smbus_write_byte_data(client,
				ADM9240_REG_TEMP_HYST, 127);
				ADM9240_REG_TEMP_MAX(1), 127);

		/* start measurement cycle */
		i2c_smbus_write_byte_data(client, ADM9240_REG_CONFIG, 1);
@@ -753,10 +743,10 @@ static struct adm9240_data *adm9240_update_device(struct device *dev)
			data->fan_min[i] = i2c_smbus_read_byte_data(client,
					ADM9240_REG_FAN_MIN(i));
		}
		data->temp_high = i2c_smbus_read_byte_data(client,
				ADM9240_REG_TEMP_HIGH);
		data->temp_hyst = i2c_smbus_read_byte_data(client,
				ADM9240_REG_TEMP_HYST);
		data->temp_max[0] = i2c_smbus_read_byte_data(client,
				ADM9240_REG_TEMP_MAX(0));
		data->temp_max[1] = i2c_smbus_read_byte_data(client,
				ADM9240_REG_TEMP_MAX(1));

		/* read fan divs and 5-bit VID */
		i = i2c_smbus_read_byte_data(client, ADM9240_REG_VID_FAN_DIV);