All of lore.kernel.org
 help / color / mirror / Atom feed
* [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821
@ 2009-08-31 20:24 ` tomaz.mertelj
  0 siblings, 0 replies; 37+ messages in thread
From: tomaz.mertelj @ 2009-08-31 20:24 UTC (permalink / raw)
  To: lm-sensors; +Cc: linux-kernel

[-- Attachment #1: Mail message body --]
[-- Type: text/plain, Size: 205 bytes --]

I have crafted a hwmon driver for Texas Instruments amc6821 SMB-bus 2-
channel temperature sensor, pwm controller. This is my first linux project 
so some corrections will be necessary.

T. Mertelj


[-- Attachment #2: amc6821.diff --]
[-- Type: application/octet-stream, Size: 31259 bytes --]

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2d50166..d231a28 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -777,6 +777,16 @@ config SENSORS_ADS7828
 	  This driver can also be built as a module.  If so, the module
 	  will be called ads7828.
 
+config SENSORS_AMC6821
+	tristate "Texas Instruments AMC6821"
+	depends on I2C
+	help
+	  If you say yes here you get support for the Texas Instruments
+	  AMC6821 hardware monitoring chips.
+
+	  This driver can also be build as a module.  If so, the module
+	  will be called amc6821.
+
 config SENSORS_THMC50
 	tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
 	depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index b793dce..431de76 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_SENSORS_SIS5595)	+= sis5595.o
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1)	+= smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+obj-$(CONFIG_SENSORS_AMC6821)	+= amc6821.o
 obj-$(CONFIG_SENSORS_THMC50)	+= thmc50.o
 obj-$(CONFIG_SENSORS_TMP401)	+= tmp401.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
new file mode 100644
index 0000000..75dee4c
--- /dev/null
+++ b/drivers/hwmon/amc6821.c
@@ -0,0 +1,851 @@
+/*
+	amc6821.c - Part of lm_sensors, Linux kernel modules for hardware
+			 monitoring
+	Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include <linux/kernel.h>	/* Needed for KERN_INFO */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+
+/*
+ * Addresses to scan.
+ */
+
+static const unsigned short normal_i2c[ ] = {0x18, 0x19, 0x1a, 0x2c,0x2d,0x2e,
+	0x4c,0x4d,0x4e,I2C_CLIENT_END};
+
+
+
+/*
+ * Insmod parameters
+ */
+
+static int pwminv = 0;	/*Inverted PWM output. */
+module_param(pwminv, int, S_IRUGO);
+
+static int init = 1; /*Power-on initialization.*/
+module_param(init, int, S_IRUGO);
+
+
+I2C_CLIENT_INSMOD_1(amc6821);
+
+#define AMC6821_REG_DEV_ID 0x3D
+#define AMC6821_REG_COMP_ID 0x3E
+#define AMC6821_REG_CONF1 0x00
+#define AMC6821_REG_CONF2 0x01
+#define AMC6821_REG_CONF3 0x3F
+#define AMC6821_REG_CONF4 0x04
+#define AMC6821_REG_STAT1 0x02
+#define AMC6821_REG_STAT2 0x03
+#define AMC6821_REG_TDATA_LOW 0x08
+#define AMC6821_REG_TDATA_HI 0x09
+#define AMC6821_REG_LTEMP_HI 0x0A
+#define AMC6821_REG_RTEMP_HI 0x0B
+#define AMC6821_REG_LTEMP_LIMIT_MIN 0x15
+#define AMC6821_REG_LTEMP_LIMIT_MAX 0x14
+#define AMC6821_REG_RTEMP_LIMIT_MIN 0x19
+#define AMC6821_REG_RTEMP_LIMIT_MAX 0x18
+#define AMC6821_REG_LTEMP_CRIT 0x1B
+#define AMC6821_REG_RTEMP_CRIT 0x1D
+#define AMC6821_REG_PSV_TEMP 0x1C
+#define AMC6821_REG_DCY 0x22
+#define AMC6821_REG_LTEMP_FAN_CTRL 0x24
+#define AMC6821_REG_RTEMP_FAN_CTRL 0x25
+#define AMC6821_REG_DCY_LOW_TEMP 0x21
+
+#define AMC6821_REG_TACH_LLIMITL 0x10
+#define AMC6821_REG_TACH_LLIMITH 0x11
+#define AMC6821_REG_TACH_HLIMITL 0x12
+#define AMC6821_REG_TACH_HLIMITH 0x13
+
+#define AMC6821_CONF1_START 0x01
+#define AMC6821_CONF1_FAN_INT_EN 0x02
+#define AMC6821_CONF1_FANIE 0x04
+#define AMC6821_CONF1_PWMINV 0x08
+#define AMC6821_CONF1_FAN_FAULT_EN 0x10
+#define AMC6821_CONF1_FDRC0 0x20
+#define AMC6821_CONF1_FDRC1 0x40
+#define AMC6821_CONF1_THERMOVIE 0x80
+
+#define AMC6821_CONF2_PWM_EN 0x01
+#define AMC6821_CONF2_TACH_MODE 0x02
+#define AMC6821_CONF2_TACH_EN 0x04
+#define AMC6821_CONF2_RTFIE 0x08
+#define AMC6821_CONF2_LTOIE 0x10
+#define AMC6821_CONF2_RTOIE 0x20
+#define AMC6821_CONF2_PSVIE 0x40
+#define AMC6821_CONF2_RST 0x80
+
+#define AMC6821_CONF3_THERM_FAN_EN 0x80
+#define AMC6821_CONF3_REV_MASK 0x0F
+
+#define AMC6821_CONF4_OVREN 0x10
+#define AMC6821_CONF4_TACH_FAST 0x20
+#define AMC6821_CONF4_PSPR 0x40
+#define AMC6821_CONF4_MODE 0x80
+
+#define AMC6821_STAT1_RPM_ALARM 0x01
+#define AMC6821_STAT1_FANS 0x02
+#define AMC6821_STAT1_RTH 0x04
+#define AMC6821_STAT1_RTL 0x08
+#define AMC6821_STAT1_R_THERM 0x10
+#define AMC6821_STAT1_RTF 0x20
+#define AMC6821_STAT1_LTH 0x40
+#define AMC6821_STAT1_LTL 0x80
+
+#define AMC6821_STAT2_RTC 0x08
+#define AMC6821_STAT2_LTC 0x10
+#define AMC6821_STAT2_LPSV 0x20
+#define AMC6821_STAT2_L_THERM 0x40
+#define AMC6821_STAT2_THERM_IN 0x80
+
+
+static int amc6821_probe(struct i2c_client *client,const struct i2c_device_id *id);
+static int amc6821_detect(struct i2c_client *client, int kind,struct i2c_board_info *info);
+static int amc6821_init_client(struct i2c_client *client);
+static int amc6821_remove(struct i2c_client *client);
+static struct amc6821_data *amc6821_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id amc6821_id[] = {
+	{ "amc6821", amc6821 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, amc6821_id);
+
+
+static struct i2c_driver amc6821_driver = {
+	.class			= I2C_CLASS_HWMON,
+	.driver = {
+		.name	= "amc6821",
+	},
+	.probe = amc6821_probe,
+	.remove = amc6821_remove,
+	.id_table = amc6821_id,
+	.detect = amc6821_detect,
+	.address_data = &addr_data,
+};
+
+
+/*
+ * Client data (each client gets its own)
+  */
+
+struct amc6821_data
+{
+	struct device *hwmon_dev;
+	struct mutex update_lock;
+	char valid; /* zero until following fields are valid */
+	unsigned long last_updated; /* in jiffies */
+
+	/* register values */
+	int temp1_input;
+	int temp1_min;
+	int temp1_max;
+	int temp1_crit;
+
+	u8 temp1_alarm;
+	int temp2_input;
+	int temp2_min;
+	int temp2_max;
+	int temp2_crit;
+	u8 temp2_alarm;
+
+	u16 fan1_input;
+	u16 fan1_min;
+	u16 fan1_max;
+	u8 fan1_div;
+
+	u8 pwm1;
+	u8 temp1_auto_point_temp[3];
+	u8 temp2_auto_point_temp[3];
+	u8 pwm1_auto_point_pwm[3];
+	u8 pwm1_enable;
+	u8 pwm1_auto_channels_temp;
+
+	u8 stat1;
+	u8 stat2;
+};
+
+
+#define get_temp_para(name) \
+static ssize_t get_##name(struct device *dev, struct device_attribute *devattr,char *buf){ \
+	struct amc6821_data *data = amc6821_update_device(dev);\
+	return sprintf(buf, "%d\n", data->name * 1000);\
+}
+
+get_temp_para(temp1_input);
+get_temp_para(temp1_min);
+get_temp_para(temp1_max);
+get_temp_para(temp2_input);
+get_temp_para(temp2_min);
+get_temp_para(temp2_max);
+get_temp_para(temp1_crit);
+get_temp_para(temp2_crit);
+
+#define set_temp_para(name,reg)\
+static ssize_t set_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct amc6821_data *data = i2c_get_clientdata(client); \
+	int val = simple_strtol(buf, NULL, 10); \
+	\
+	mutex_lock(&data->update_lock); \
+	data->name = SENSORS_LIMIT(val / 1000, -128, 127); \
+	 if (i2c_smbus_write_byte_data(client, reg, data->name)) {\
+		dev_err(&client->dev, "Register write error, aborting.\n");\
+		count= -EIO;\
+	}\
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+set_temp_para(temp1_min,AMC6821_REG_LTEMP_LIMIT_MIN);
+set_temp_para(temp1_max,AMC6821_REG_LTEMP_LIMIT_MAX);
+set_temp_para(temp2_min,AMC6821_REG_RTEMP_LIMIT_MIN);
+set_temp_para(temp2_max,AMC6821_REG_RTEMP_LIMIT_MAX);
+set_temp_para(temp1_crit,AMC6821_REG_LTEMP_CRIT);
+set_temp_para(temp2_crit,AMC6821_REG_RTEMP_CRIT);
+
+#define get_temp_alarm(name, reg, mask)\
+static ssize_t get_##name(struct device *dev, struct device_attribute *devattr,char *buf){\
+	struct amc6821_data *data = amc6821_update_device(dev);\
+	if( data->reg &  mask)\
+		return sprintf(buf, "1");\
+	else	\
+		return sprintf(buf, "0");\
+}\
+
+get_temp_alarm(temp1_min_alarm, stat1,	AMC6821_STAT1_LTL)
+get_temp_alarm(temp1_max_alarm, stat1, AMC6821_STAT1_LTH)
+get_temp_alarm(temp2_min_alarm, stat1, AMC6821_STAT1_RTL)
+get_temp_alarm(temp2_max_alarm, stat1, AMC6821_STAT1_RTH)
+get_temp_alarm(temp1_crit_alarm, stat2, AMC6821_STAT2_LTC)
+get_temp_alarm(temp2_crit_alarm, stat2, AMC6821_STAT2_RTC)
+
+
+static ssize_t get_temp2_fault(struct device *dev, struct device_attribute *devattr,char *buf){
+	struct amc6821_data *data = amc6821_update_device(dev);
+	if( data->stat1 & AMC6821_STAT1_RTF)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+static ssize_t get_pwm1(struct device *dev, struct device_attribute *devattr,char *buf){
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1);
+}
+
+static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count){
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock); \
+	data->pwm1 = SENSORS_LIMIT(val , 0, 255); \
+	 i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1); \
+	mutex_unlock(&data->update_lock); \
+	return count;
+}
+
+static ssize_t get_pwm1_enable(struct device *dev, struct device_attribute *devattr,char *buf){
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1_enable);
+}
+
+static ssize_t set_pwm1_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+
+	int config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+	   if (config < 0) {
+			dev_err(&client->dev, "Error reading configuration register, aborting.\n");
+			return -EIO;
+	}
+
+	switch (val){
+	case 1:
+		config &= ~AMC6821_CONF1_FDRC0;
+		config &= ~AMC6821_CONF1_FDRC1;
+		break;
+	case 2:
+		config &= ~AMC6821_CONF1_FDRC0;
+		config |= AMC6821_CONF1_FDRC1;
+		break;
+	case 3:
+		config |= AMC6821_CONF1_FDRC0;
+		config |= AMC6821_CONF1_FDRC1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mutex_lock(&data->update_lock);
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) {
+			dev_err(&client->dev, "Configuration register write error, aborting.\n");
+			count= -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+static ssize_t get_pwm1_auto_channels_temp(struct device *dev, struct device_attribute *devattr,char *buf){
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1_auto_channels_temp);
+}
+
+
+#define get_auto_point(name)\
+static ssize_t get_##name(struct device *dev, struct device_attribute *devattr,char *buf){\
+	int nr = to_sensor_dev_attr(devattr)->index;\
+	struct amc6821_data *data = amc6821_update_device(dev);\
+	return sprintf(buf, "%d\n", data->name[nr] *1000);\
+}
+
+get_auto_point(temp1_auto_point_temp);
+get_auto_point(temp2_auto_point_temp);
+
+static ssize_t get_pwm1_auto_point_pwm(struct device *dev, struct device_attribute *devattr,char *buf){
+	int nr = to_sensor_dev_attr(devattr)->index;
+	struct amc6821_data *data = amc6821_update_device(dev);
+	return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[nr] );
+}
+
+
+#define set_temp_auto_point_temp(name,reg)\
+static ssize_t set_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct amc6821_data *data = amc6821_update_device(dev);\
+	int nr = to_sensor_dev_attr(attr)->index;\
+	int val = simple_strtol(buf, NULL, 10); \
+	u8 tmp;\
+	\
+	mutex_lock(&data->update_lock); \
+	switch(nr){\
+		case 0:\
+			data->name[0] = SENSORS_LIMIT(val / 1000, 0,data->temp1_auto_point_temp[1]-1);\
+			data->name[0] = SENSORS_LIMIT(data->name[0], 0,data->temp2_auto_point_temp[1]-1);\
+			data->name[0] = SENSORS_LIMIT(data->name[0], 0, 63); \
+			data->valid = 0;\
+			if (i2c_smbus_write_byte_data(client, AMC6821_REG_PSV_TEMP, data->name[ 0] )) {\
+					dev_err(&client->dev, "Register write error, aborting.\n");\
+					count = -EIO;\
+			}\
+			goto EXIT;\
+			 break;\
+		case 1:\
+			data->name[1] = SENSORS_LIMIT(val / 1000, data->name[0]+1, data->name[ 2]-1); \
+			data->name[1] &= 0x7C;\
+			break;\
+		case 2:\
+			data->name[2] = SENSORS_LIMIT(val / 1000, data->name[1]+1, 127); \
+			break;\
+	}\
+	val = (16*(data->pwm1_auto_point_pwm[2]-data->pwm1_auto_point_pwm[1]))/(data->name[2]-data->name[1]);\
+	for(tmp = 4; tmp >= 0; tmp--){\
+		if( val <= (0x200 >> tmp)) break;\
+	}\
+	tmp |= ((u8) data->name[ 1] & 0x7C) << 1;\
+	if (i2c_smbus_write_byte_data(client, reg, tmp)) {\
+		dev_err(&client->dev, "Register write error, aborting.\n");\
+		count = -EIO;\
+	}\
+	data->valid = 0;\
+EXIT:\
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+set_temp_auto_point_temp(temp1_auto_point_temp, AMC6821_REG_LTEMP_FAN_CTRL);
+set_temp_auto_point_temp(temp2_auto_point_temp, AMC6821_REG_RTEMP_FAN_CTRL);
+
+static ssize_t set_pwm1_auto_point_pwm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+	u8 tmp;
+
+	mutex_lock(&data->update_lock);
+	data->pwm1_auto_point_pwm[ 1] = SENSORS_LIMIT(val, 0, 255);
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP, data->pwm1_auto_point_pwm[ 1])) {\
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+	}
+
+	val =(16 * (data->pwm1_auto_point_pwm[2]-data->pwm1_auto_point_pwm[1]))/(data->temp1_auto_point_temp[2]-data->temp1_auto_point_temp[1]);
+	for(tmp = 4; tmp >= 0; tmp--){
+		if( val <= (0x200 >> tmp)) break;
+	}
+	tmp |= ((u8) data->temp1_auto_point_temp[ 1] & 0x7C) << 1;
+	if (i2c_smbus_write_byte_data(client,  AMC6821_REG_LTEMP_FAN_CTRL, tmp)) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+	}
+	data->valid = 0;
+
+	val = (16 * (data->pwm1_auto_point_pwm[2]-data->pwm1_auto_point_pwm[1]))/(data->temp2_auto_point_temp[2]-data->temp2_auto_point_temp[1]);
+	for(tmp = 4; tmp >= 0; tmp--){
+		if( val <= (0x200 >> tmp)) break;
+	}
+	tmp |= ((u8) data->temp2_auto_point_temp[ 1] & 0x7C) << 1;
+	if (i2c_smbus_write_byte_data(client,  AMC6821_REG_RTEMP_FAN_CTRL, tmp)) {
+		dev_err(&client->dev, "Register write error, aborting.\n");
+		count = -EIO;
+	}
+	data->valid = 0;
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+#define get_fan_para(name) static ssize_t get_##name(struct device *dev, struct device_attribute *devattr,char *buf){ \
+	struct amc6821_data *data = amc6821_update_device(dev); \
+	if ( 0 == data->name) return sprintf(buf,"0");\
+	return sprintf(buf, "%d\n", (int)(6000000 / data->name)); \
+}
+
+get_fan_para(fan1_input);
+get_fan_para(fan1_min);
+get_fan_para(fan1_max);
+
+static ssize_t get_fan1_fault(struct device *dev, struct device_attribute *devattr,char *buf){
+	struct amc6821_data *data = amc6821_update_device(dev);
+	if( data->stat1 & AMC6821_STAT1_FANS)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+
+#define set_fan_para(name, reg) \
+static ssize_t set_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ \
+	struct i2c_client *client = to_i2c_client(dev); \
+	struct amc6821_data *data = i2c_get_clientdata(client); \
+	int val = simple_strtol(buf, NULL, 10); \
+	val = 1>val ? 0xFFFF : 6000000/val; \
+\
+	mutex_lock(&data->update_lock); \
+	data->name = (u16) SENSORS_LIMIT(val, 1, 0xFFFF); \
+	if (i2c_smbus_write_byte_data(client, reg, data->name & 0xFF)) { \
+		dev_err(&client->dev, "Register write error, aborting.\n");\
+		count= -EIO;\
+	}\
+	if (i2c_smbus_write_byte_data(client, reg+1, data->name >> 8 )) { \
+		dev_err(&client->dev, "Register write error, aborting.\n");\
+		count= -EIO;\
+	}\
+	mutex_unlock(&data->update_lock); \
+	return count; \
+}
+
+
+set_fan_para(fan1_min, AMC6821_REG_TACH_LLIMITL);
+set_fan_para(fan1_max, AMC6821_REG_TACH_HLIMITL);
+
+
+static ssize_t get_fan1_div(struct device *dev, struct device_attribute *devattr,char *buf){
+	struct amc6821_data *data = amc6821_update_device(dev);
+
+	return sprintf(buf, "%d\n", data->fan1_div);
+}
+
+static ssize_t set_fan1_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+	int config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
+
+	if (config < 0) {
+		dev_err(&client->dev, "Error reading configuration register, aborting.\n");
+		return -EIO;
+	}
+	mutex_lock(&data->update_lock);
+	switch (val){
+		case 2:
+			config &= ~AMC6821_CONF4_PSPR;
+			data->fan1_div=2;
+			break;
+		case 4:
+			config |= AMC6821_CONF4_PSPR;
+			data->fan1_div=4;
+			break;
+		default:
+			mutex_unlock(&data->update_lock);
+			return -EINVAL;
+	}
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, config)) {
+		dev_err(&client->dev, "Configuration register write error, aborting.\n");
+		count= -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp1_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, get_temp1_min, set_temp1_min, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, get_temp1_max, set_temp1_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, get_temp1_crit, set_temp1_crit, 0);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, get_temp1_min_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, get_temp1_max_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, get_temp1_crit_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR, get_temp2_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp2_min, set_temp2_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, get_temp2_max, set_temp2_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, get_temp2_crit, set_temp2_crit, 0);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, get_temp2_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, get_temp2_min_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, get_temp2_max_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, get_temp2_crit_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan1_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, get_fan1_min, set_fan1_min, 0);
+static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR, get_fan1_max, set_fan1_max, 0);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan1_fault, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, get_fan1_div, set_fan1_div, 0);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm1, set_pwm1,0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_pwm1_enable, set_pwm1_enable,0);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, get_pwm1_auto_point_pwm, NULL,0);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO, get_pwm1_auto_point_pwm, set_pwm1_auto_point_pwm,1);
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, get_pwm1_auto_point_pwm, NULL,2);
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO, get_pwm1_auto_channels_temp, NULL,0);
+static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO, get_temp1_auto_point_temp, NULL,0);
+static SENSOR_DEVICE_ATTR(temp1_auto_point2_temp, S_IWUSR | S_IRUGO, get_temp1_auto_point_temp, set_temp1_auto_point_temp,1);
+static SENSOR_DEVICE_ATTR(temp1_auto_point3_temp, S_IWUSR | S_IRUGO, get_temp1_auto_point_temp, set_temp1_auto_point_temp,2);
+
+static SENSOR_DEVICE_ATTR(temp2_auto_point1_temp, S_IWUSR | S_IRUGO, get_temp2_auto_point_temp, set_temp2_auto_point_temp,0);
+static SENSOR_DEVICE_ATTR(temp2_auto_point2_temp, S_IWUSR | S_IRUGO, get_temp2_auto_point_temp, set_temp2_auto_point_temp,1);
+static SENSOR_DEVICE_ATTR(temp2_auto_point3_temp, S_IWUSR | S_IRUGO, get_temp2_auto_point_temp, set_temp2_auto_point_temp,2);
+
+
+
+static struct attribute *amc6821_attrs[] = {
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit.dev_attr.attr,
+	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_max.dev_attr.attr,
+	&sensor_dev_attr_fan1_fault.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_point3_temp.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group amc6821_attr_grp = {
+	.attrs = amc6821_attrs,
+};
+
+
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int amc6821_detect(struct i2c_client *client, int kind,
+	struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+
+	dev_dbg(&adapter->dev, "amc6821_detect called, kind = %d\n", kind);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support byte read mode, skipping.\n");
+		return -ENODEV;
+	}
+	if ((kind < 0) &&
+		((i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID) & 0xDE) ||
+		(i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID) & 0xB6))){
+			dev_dbg(&adapter->dev,"amc6821: detection failed at 0x%02x.\n", address);
+		return -ENODEV;
+	}
+
+	dev_info(&adapter->dev, "amc6821: chip found at 0x%02x.\n", address);
+	strlcpy(info->type, "amc6821", I2C_NAME_SIZE);
+
+	return 0;
+}
+
+static int amc6821_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct amc6821_data *data;
+	int err;
+
+	if (!(data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL))) {
+		dev_err(&client->dev, "out of memory.\n");
+		return -ENOMEM;
+	}
+
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Initialize the amc6821 chip
+	 */
+	err = amc6821_init_client(client);
+	if (err)
+		goto err_free;
+
+	err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
+	if (err)
+		goto err_free;
+
+	data->hwmon_dev = hwmon_device_register(&client->dev);
+	if (!IS_ERR(data->hwmon_dev))
+		return 0;
+
+	err = PTR_ERR(data->hwmon_dev);
+	dev_err(&client->dev, "error registering hwmon device.\n");
+	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
+err_free:
+	kfree(data);
+	return err;
+}
+
+static int amc6821_remove(struct i2c_client *client)
+{
+	struct amc6821_data *data = i2c_get_clientdata(client);
+
+	hwmon_device_unregister(data->hwmon_dev);
+	sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
+
+	kfree(data);
+
+	return 0;
+}
+
+
+static int amc6821_init_client(struct i2c_client *client)
+{
+	int config;
+	int err = -EIO;
+
+	if( init ){
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
+
+		if (config < 0) {
+				dev_err(&client->dev, "Error reading configuration register, aborting.\n");
+				return err;
+		}
+
+		config |= AMC6821_CONF4_MODE;
+
+		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, config)) {
+			dev_err(&client->dev, "Configuration register write error, aborting.\n");
+			return err;
+		}
+
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF3);
+
+		if (config < 0) {
+			dev_err(&client->dev, "Error reading configuration register, aborting.\n");
+			return err;
+		}
+
+		config &= ~AMC6821_CONF3_THERM_FAN_EN;
+
+		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF3, config)) {
+			dev_err(&client->dev, "Configuration register write error, aborting.\n");
+			return err;
+		}
+
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF2);
+
+		if (config < 0) {
+			dev_err(&client->dev, "Error reading configuration register, aborting.\n");
+			return err;
+		}
+
+		config &= ~AMC6821_CONF2_RTFIE;
+		config &= ~AMC6821_CONF2_LTOIE;
+		config &= ~AMC6821_CONF2_RTOIE;
+		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF2, config)) {
+			dev_err(&client->dev, "Configuration register write error, aborting.\n");
+			return err;
+		}
+
+		config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+
+		if (config < 0) {
+			dev_err(&client->dev, "Error reading configuration register, aborting.\n");
+			return err;
+		}
+
+		config &= ~AMC6821_CONF1_THERMOVIE;
+		config &= ~AMC6821_CONF1_FANIE;
+		config |= AMC6821_CONF1_START;
+		if (pwminv) {
+			config |= AMC6821_CONF1_PWMINV;
+		} else {
+			config &= ~AMC6821_CONF1_PWMINV;
+		}
+
+		if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) {
+			dev_err(&client->dev, "Configuration register write error, aborting.\n");
+			return err;
+		}
+	}
+	return 0;
+}
+
+
+static struct amc6821_data *amc6821_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	int timeout = HZ;
+	u8 reg;
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + timeout) || !data->valid) {
+		data->temp1_input = i2c_smbus_read_byte_data(client, AMC6821_REG_LTEMP_HI);
+		data->temp1_min = i2c_smbus_read_byte_data(client, AMC6821_REG_LTEMP_LIMIT_MIN);
+		data->temp1_max = i2c_smbus_read_byte_data(client, AMC6821_REG_LTEMP_LIMIT_MAX);
+		data->temp1_crit = i2c_smbus_read_byte_data(client, AMC6821_REG_LTEMP_CRIT);
+
+		data->temp2_input = i2c_smbus_read_byte_data(client, AMC6821_REG_RTEMP_HI);
+		data->temp2_min = i2c_smbus_read_byte_data(client, AMC6821_REG_RTEMP_LIMIT_MIN);
+		data->temp2_max = i2c_smbus_read_byte_data(client, AMC6821_REG_RTEMP_LIMIT_MAX);
+		data->temp2_crit = i2c_smbus_read_byte_data(client, AMC6821_REG_RTEMP_CRIT);
+
+		data->stat1 = i2c_smbus_read_byte_data(client,AMC6821_REG_STAT1);
+		data->stat2 = i2c_smbus_read_byte_data(client,AMC6821_REG_STAT2);
+
+		data->pwm1 = i2c_smbus_read_byte_data(client,AMC6821_REG_DCY);
+		data->fan1_input = i2c_smbus_read_byte_data(client,AMC6821_REG_TDATA_LOW);
+		data->fan1_input += i2c_smbus_read_byte_data(client,AMC6821_REG_TDATA_HI) << 8;
+		data->fan1_min = i2c_smbus_read_byte_data(client,AMC6821_REG_TACH_LLIMITL);
+		data->fan1_min += i2c_smbus_read_byte_data(client,AMC6821_REG_TACH_LLIMITL+1) << 8;
+		data->fan1_max = i2c_smbus_read_byte_data(client,AMC6821_REG_TACH_HLIMITL);
+		data->fan1_max += i2c_smbus_read_byte_data(client,AMC6821_REG_TACH_HLIMITL+1) << 8;
+		data->fan1_div = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
+		data->fan1_div = data->fan1_div & AMC6821_CONF4_PSPR ? 4 :2;
+
+		data->pwm1_auto_point_pwm[0] = 0;
+		data->pwm1_auto_point_pwm[2] = 255;
+		data->pwm1_auto_point_pwm[1] = i2c_smbus_read_byte_data(client, AMC6821_REG_DCY_LOW_TEMP);
+
+		data->temp2_auto_point_temp[0] = data->temp1_auto_point_temp[0]=i2c_smbus_read_byte_data(client, AMC6821_REG_PSV_TEMP);
+		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_LTEMP_FAN_CTRL);
+		data->temp1_auto_point_temp[1] = (reg & 0xF8) >> 1;
+		reg &= 0x07;
+		reg=0x20 >> reg;
+		if(reg>0)
+			data->temp1_auto_point_temp[2] = data->temp1_auto_point_temp[1] + (data->pwm1_auto_point_pwm[2]-data->pwm1_auto_point_pwm[1])/reg;
+		else
+			data->temp1_auto_point_temp[2] = 255;
+
+		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_RTEMP_FAN_CTRL);
+		data->temp2_auto_point_temp[1] = (reg & 0xF8) >> 1;
+		reg &= 0x07;
+		reg=0x20 >> reg;
+		if(reg>0)
+			data->temp2_auto_point_temp[2] = data->temp2_auto_point_temp[1] + (data->pwm1_auto_point_pwm[2]-data->pwm1_auto_point_pwm[1])/reg;
+		else
+			data->temp1_auto_point_temp[2] = 255;
+
+		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+		reg=(reg >> 5) & 0x3;
+		switch(reg) {
+			case 0:
+				data->pwm1_auto_channels_temp=0;
+				data->pwm1_enable=1;
+				break;
+			case 2:
+				data->pwm1_auto_channels_temp=2;
+				data->pwm1_enable=2;
+				break;
+			case 3:
+				data->pwm1_auto_channels_temp=3;
+				data->pwm1_enable=3;
+				break;
+			case 1:
+				data->pwm1_auto_channels_temp=0;
+				data->pwm1_enable=0;
+				break;
+		}
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+
+static int __init amc6821_init(void)
+{
+	return i2c_add_driver(&amc6821_driver);
+}
+
+static void __exit amc6821_exit(void)
+{
+	i2c_del_driver(&amc6821_driver);
+}
+
+module_init(amc6821_init);
+module_exit(amc6821_exit);
+
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>");
+MODULE_DESCRIPTION("TI amc6821 hwmon driver");
+MODULE_SUPPORTED_DEVICE("amc6821");

[-- Attachment #3: Type: text/plain, Size: 153 bytes --]

_______________________________________________
lm-sensors mailing list
lm-sensors@lm-sensors.org
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors

^ permalink raw reply related	[flat|nested] 37+ messages in thread
* Re: [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments  amc6821 chip
@ 2009-09-23  9:32 tomaz.mertelj
  2009-09-30 19:44 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton
  0 siblings, 1 reply; 37+ messages in thread
From: tomaz.mertelj @ 2009-09-23  9:32 UTC (permalink / raw)
  To: Andrew Morton, Jean Delvare; +Cc: linux-kernel, lm-sensors

On Wed, 9 Sep 2009 09:34:35 +0200
Jean Delvare <khali@linux-fr.org> wrote:

> > And then do all the real work in a common function?  Rather than
> > expanding tens of copies of the same thing?
>
> Yes please. We got rid of macro-generated callbacks in most hwmon
> drivers a couple years ago already.

Here is an incremental patch to TI amc6821 chip hwmon driver:

I got rid of macro generated callbacks to reduce memory footprint.
simple_strtol was replaced by strict_strtol.
Fixed some errors in documentation.

Tomaz

--
Signed-off-by: Tomaz Mertelj tomaz.mertelj(at)guest.arnes.si


diff --git a/Documentation/hwmon/amc6821 b/Documentation/hwmon/amc6821
index b7cba86..bc3ab6c 100644
--- a/Documentation/hwmon/amc6821
+++ b/Documentation/hwmon/amc6821
@@ -46,12 +46,12 @@ fan1_div		rw	Fan divisor can be 
either 2 or 4.
 pwm1			rw	pwm1
 pwm1_enable		rw	regulator mode, 1=open loop, 2=fan 
controlled
 				by remote temperature, 3=fan 
controlled by
-				combination of on-chip temperature and
+				combination of the on-chip 
temperature and
 				remote-sensor temperature,
 pwm1_auto_channels_temp ro	1 if pwm_enable==2, 3 if pwm_enable==3
 pwm1_auto_point1_pwm	ro	Hardwired to 0, shared for both
 				temperature channels.
-pwm1_auto_point2_pwm	rw	This value, shared for both 
temperature
+pwm1_auto_point2_pwm	rw	This value is shared for both 
temperature
 				channels.
 pwm1_auto_point3_pwm	rw	Hardwired to 255, shared for both
 				temperature channels.
@@ -61,9 +61,9 @@ temp1_auto_point1_temp	ro	Hardwired to 
temp2_auto_point1_temp
 temp1_auto_point2_temp	rw	The low-temperature limit of the 
proportional
 				range. Below this temperature
 				pwm1 = pwm1_auto_point2_pwm. It can 
go from
-				0 degree C and 124 degree C in steps 
of
+				0 degree C to 124 degree C in steps of
 				4 degree C. Read it out after writing 
to get
-				actual value.
+				the actual value.
 temp1_auto_point3_temp	rw	Above this temperature fan runs at 
maximum
 				speed. It can go from 
temp1_auto_point2_temp.
 				It can only have certain discrete 
values
@@ -72,13 +72,13 @@ temp1_auto_point3_temp	rw	Above this 
temperature fan runs at maximum
 				writing to get the actual value.
 
 temp2_auto_point1_temp	rw	Must be between 0 degree C and 63 
degree C and
-				it defines passive cooling 
temperature.
+				it defines the passive cooling 
temperature.
 				Below this temperature the fan stops 
in
 				the closed loop mode.
 temp2_auto_point2_temp	rw	The low-temperature limit of the 
proportional
 				range. Below this temperature
 				pwm1 = pwm1_auto_point2_pwm. It can 
go from
-				0 degree C and 124 degree C in steps
+				0 degree C to 124 degree C in steps
 				of 4 degree C.
 
 temp2_auto_point3_temp	rw	Above this temperature fan runs at 
maximum
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index 6905c5e..26e7635 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -123,6 +123,31 @@ I2C_CLIENT_INSMOD_1(amc6821);
 #define AMC6821_STAT2_L_THERM 0x40
 #define AMC6821_STAT2_THERM_IN 0x80
 
+enum {IDX_TEMP1_INPUT = 0, IDX_TEMP1_MIN, IDX_TEMP1_MAX,
+	IDX_TEMP1_CRIT, IDX_TEMP2_INPUT, IDX_TEMP2_MIN,
+	IDX_TEMP2_MAX, IDX_TEMP2_CRIT,
+	TEMP_IDX_LEN, };
+
+static const u8 temp_reg[] = {AMC6821_REG_LTEMP_HI,
+			AMC6821_REG_LTEMP_LIMIT_MIN,
+			AMC6821_REG_LTEMP_LIMIT_MAX,
+			AMC6821_REG_LTEMP_CRIT,
+			AMC6821_REG_RTEMP_HI,
+			AMC6821_REG_RTEMP_LIMIT_MIN,
+			AMC6821_REG_RTEMP_LIMIT_MAX,
+			AMC6821_REG_RTEMP_CRIT, };
+
+enum {IDX_FAN1_INPUT = 0, IDX_FAN1_MIN, IDX_FAN1_MAX,
+	FAN1_IDX_LEN, };
+
+static const u8 fan_reg_low[] = {AMC6821_REG_TDATA_LOW,
+			AMC6821_REG_TACH_LLIMITL,
+			AMC6821_REG_TACH_HLIMITL, };
+
+
+static const u8 fan_reg_hi[] = {AMC6821_REG_TDATA_HI,
+			AMC6821_REG_TACH_LLIMITH,
+			AMC6821_REG_TACH_HLIMITH, };
 
 static int amc6821_probe(
 		struct i2c_client *client,
@@ -170,19 +195,9 @@ struct amc6821_data {
 	unsigned long last_updated; /* in jiffies */
 
 	/* register values */
-	int temp1_input;
-	int temp1_min;
-	int temp1_max;
-	int temp1_crit;
-
-	int temp2_input;
-	int temp2_min;
-	int temp2_max;
-	int temp2_crit;
-
-	u16 fan1_input;
-	u16 fan1_min;
-	u16 fan1_max;
+	int temp[TEMP_IDX_LEN];
+
+	u16 fan[FAN1_IDX_LEN];
 	u8 fan1_div;
 
 	u8 pwm1;
@@ -197,72 +212,87 @@ struct amc6821_data {
 };
 
 
-#define get_temp_para(name) \
-static ssize_t get_##name(\
-		struct device *dev,\
-		struct device_attribute *devattr,\
-		char *buf)\
-{\
-	struct amc6821_data *data = amc6821_update_device(dev);\
-	return sprintf(buf, "%d\n", data->name * 1000);\
+static ssize_t get_temp(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr(devattr)->index;
+
+	return sprintf(buf, "%d\n", data->temp[ix] * 1000);
 }
 
-get_temp_para(temp1_input);
-get_temp_para(temp1_min);
-get_temp_para(temp1_max);
-get_temp_para(temp2_input);
-get_temp_para(temp2_min);
-get_temp_para(temp2_max);
-get_temp_para(temp1_crit);
-get_temp_para(temp2_crit);
-
-#define set_temp_para(name, reg)\
-static ssize_t set_##name(\
-		struct device *dev,\
-		struct device_attribute *attr,\
-		const char *buf,\
-		size_t count)\
-{ \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct amc6821_data *data = i2c_get_clientdata(client); \
-	int val = simple_strtol(buf, NULL, 10); \
-	\
-	mutex_lock(&data->update_lock); \
-	data->name = SENSORS_LIMIT(val / 1000, -128, 127); \
-	if (i2c_smbus_write_byte_data(client, reg, data->name)) {\
-		dev_err(&client->dev, "Register write error, aborting.
\n");\
-		count = -EIO;\
-	} \
-	mutex_unlock(&data->update_lock); \
-	return count; \
+
+
+static ssize_t set_temp(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	int ix = to_sensor_dev_attr(attr)->index;
+	long val;
+
+	int ret = strict_strtol(buf, 10, &val);
+	if (ret)
+		return ret;
+	val = SENSORS_LIMIT(val / 1000, -128, 127);
+
+	mutex_lock(&data->update_lock);
+	data->temp[ix] = val;
+	if (i2c_smbus_write_byte_data(client, temp_reg[ix], data->temp
[ix])) {
+		dev_err(&client->dev, "Register write error, aborting.
\n");
+		count = -EIO;
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
 }
 
-set_temp_para(temp1_min, AMC6821_REG_LTEMP_LIMIT_MIN);
-set_temp_para(temp1_max, AMC6821_REG_LTEMP_LIMIT_MAX);
-set_temp_para(temp2_min, AMC6821_REG_RTEMP_LIMIT_MIN);
-set_temp_para(temp2_max, AMC6821_REG_RTEMP_LIMIT_MAX);
-set_temp_para(temp1_crit, AMC6821_REG_LTEMP_CRIT);
-set_temp_para(temp2_crit, AMC6821_REG_RTEMP_CRIT);
-
-#define get_temp_alarm(name, reg, mask)\
-static ssize_t get_##name(\
-	struct device *dev, \
-	struct device_attribute *devattr,\
-	char *buf)\
-{\
-	struct amc6821_data *data = amc6821_update_device(dev);\
-	if (data->reg &  mask)\
-		return sprintf(buf, "1");\
-	else	\
-		return sprintf(buf, "0");\
-} \
-
-get_temp_alarm(temp1_min_alarm, stat1,	AMC6821_STAT1_LTL)
-get_temp_alarm(temp1_max_alarm, stat1, AMC6821_STAT1_LTH)
-get_temp_alarm(temp2_min_alarm, stat1, AMC6821_STAT1_RTL)
-get_temp_alarm(temp2_max_alarm, stat1, AMC6821_STAT1_RTH)
-get_temp_alarm(temp1_crit_alarm, stat2, AMC6821_STAT2_LTC)
-get_temp_alarm(temp2_crit_alarm, stat2, AMC6821_STAT2_RTC)
+
+
+
+static ssize_t get_temp_alarm(
+	struct device *dev,
+	struct device_attribute *devattr,
+	char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr(devattr)->index;
+	u8 flag;
+
+	switch (ix) {
+	case IDX_TEMP1_MIN:
+		flag = data->stat1 & AMC6821_STAT1_LTL;
+		break;
+	case IDX_TEMP1_MAX:
+		flag = data->stat1 & AMC6821_STAT1_LTH;
+		break;
+	case IDX_TEMP1_CRIT:
+		flag = data->stat2 & AMC6821_STAT2_LTC;
+		break;
+	case IDX_TEMP2_MIN:
+		flag = data->stat1 & AMC6821_STAT1_RTL;
+		break;
+	case IDX_TEMP2_MAX:
+		flag = data->stat1 & AMC6821_STAT1_RTH;
+		break;
+	case IDX_TEMP2_CRIT:
+		flag = data->stat2 & AMC6821_STAT2_RTC;
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
+		return -EINVAL;
+	}
+	if (flag)
+		return sprintf(buf, "1");
+	else
+		return sprintf(buf, "0");
+}
+
+
 
 
 static ssize_t get_temp2_fault(
@@ -294,7 +324,10 @@ static ssize_t set_pwm1(
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct amc6821_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10);
+	long val;
+	int ret = strict_strtol(buf, 10, &val);
+	if (ret)
+		return ret;
 
 	mutex_lock(&data->update_lock);
 	data->pwm1 = SENSORS_LIMIT(val , 0, 255);
@@ -320,9 +353,12 @@ static ssize_t set_pwm1_enable(
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct amc6821_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10);
+	long val;
+	int config = strict_strtol(buf, 10, &val);
+	if (config)
+		return config;
 
-	int config = i2c_smbus_read_byte_data(client, 
AMC6821_REG_CONF1);
+	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
 	if (config < 0) {
 			dev_err(&client->dev,
 			"Error reading configuration register, 
aborting.\n");
@@ -366,101 +402,147 @@ static ssize_t get_pwm1_auto_channels_temp(
 }
 
 
-#define get_auto_point(name)\
-static ssize_t get_##name(\
-		struct device *dev,\
-		struct device_attribute *devattr,\
-		char *buf)\
-{\
-	int nr = to_sensor_dev_attr(devattr)->index;\
-	struct amc6821_data *data = amc6821_update_device(dev);\
-	return sprintf(buf, "%d\n", data->name[nr] * 1000);\
+static ssize_t get_temp_auto_point_temp(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	int ix = to_sensor_dev_attr_2(devattr)->index;
+	int nr = to_sensor_dev_attr_2(devattr)->nr;
+	struct amc6821_data *data = amc6821_update_device(dev);
+	switch (nr) {
+	case 1:
+		return sprintf(buf, "%d\n",
+			data->temp1_auto_point_temp[ix] * 1000);
+		break;
+	case 2:
+		return sprintf(buf, "%d\n",
+			data->temp2_auto_point_temp[ix] * 1000);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
+		return -EINVAL;
+	}
 }
 
-get_auto_point(temp1_auto_point_temp);
-get_auto_point(temp2_auto_point_temp);
 
 static ssize_t get_pwm1_auto_point_pwm(
 		struct device *dev,
 		struct device_attribute *devattr,
 		char *buf)
 {
-	int nr = to_sensor_dev_attr(devattr)->index;
+	int ix = to_sensor_dev_attr(devattr)->index;
 	struct amc6821_data *data = amc6821_update_device(dev);
-	return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[nr]);
+	return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[ix]);
+}
+
+
+static inline ssize_t set_slope_register(struct i2c_client *client,
+		u8 reg,
+		u8 dpwm,
+		u8 *ptemp)
+{
+	int dt;
+	u8 tmp;
+
+	dt = ptemp[2]-ptemp[1];
+	for (tmp = 4; tmp > 0; tmp--) {
+		if (dt * (0x20 >> tmp) >= dpwm)
+			break;
+	}
+	tmp |= (ptemp[1] & 0x7C) << 1;
+	if (i2c_smbus_write_byte_data(client,
+			reg, tmp)) {
+		dev_err(&client->dev, "Register write error, aborting.
\n");
+		return -EIO;
+	}
+	return 0;
 }
 
 
-#define set_temp_auto_point_temp(name, reg)\
-static ssize_t set_##name(\
-		struct device *dev,\
-		struct device_attribute *attr,\
-		const char *buf,\
-		size_t count)\
-{ \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct amc6821_data *data = amc6821_update_device(dev);\
-	int nr = to_sensor_dev_attr(attr)->index;\
-	int val = simple_strtol(buf, NULL, 10); \
-	u8 tmp;\
-	int dt;\
-	int dpwm;\
-	\
-	mutex_lock(&data->update_lock); \
-	switch (nr) {\
-	case 0:\
-		data->name[0] = SENSORS_LIMIT(val / 1000, 0,\
-				data->temp1_auto_point_temp[1]);\
-		data->name[0] = SENSORS_LIMIT(data->name[0], 0,\
-				data->temp2_auto_point_temp[1]);\
-		data->name[0] = SENSORS_LIMIT(data->name[0], 0, 63); \
-		data->valid = 0;\
-		if (i2c_smbus_write_byte_data(\
-					client,\
-					AMC6821_REG_PSV_TEMP,\
-					data->name[0])) {\
-				dev_err(&client->dev,\
-					"Register write error, 
aborting.\n");\
-				count = -EIO;\
-		} \
-		goto EXIT;\
-		break;\
-	case 1:\
-		data->name[1] = SENSORS_LIMIT(\
-					val / 1000,\
-					(data->name[0] & 0x7C) + 4,\
-					124);\
-		data->name[1] &= 0x7C;\
-		data->name[2] = SENSORS_LIMIT(\
-					data->name[2], data->name[1] 
+ 1,\
-					255);\
-		break;\
-	case 2:\
-		data->name[2] = SENSORS_LIMIT(\
-					val / 1000,\
-					data->name[1]+1,\
-					255); \
-		break;\
-	} \
-	dt = data->name[2]-data->name[1];\
-	dpwm = data->pwm1_auto_point_pwm[2] - data-
>pwm1_auto_point_pwm[1];\
-	for (tmp = 4; tmp > 0; tmp--) {\
-		if (dt * (0x20 >> tmp) >= dpwm)\
-			break;\
-	} \
-	tmp |= (data->name[1] & 0x7C) << 1;\
-	if (i2c_smbus_write_byte_data(client, reg, tmp)) {\
-		dev_err(&client->dev, "Register write error, aborting.
\n");\
-		count = -EIO;\
-	} \
-	data->valid = 0;\
-EXIT:\
-	mutex_unlock(&data->update_lock); \
-	return count; \
+
+static ssize_t set_temp_auto_point_temp(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr_2(attr)->index;
+	int nr = to_sensor_dev_attr_2(attr)->nr;
+	u8 *ptemp;
+	u8 reg;
+	int dpwm;
+	long val;
+	int ret = strict_strtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	switch (nr) {
+	case 1:
+		ptemp = data->temp1_auto_point_temp;
+		reg = AMC6821_REG_LTEMP_FAN_CTRL;
+		break;
+	case 2:
+		ptemp = data->temp2_auto_point_temp;
+		reg = AMC6821_REG_RTEMP_FAN_CTRL;
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
+		return -EINVAL;
+	}
+
+	data->valid = 0;
+	mutex_lock(&data->update_lock);
+	switch (ix) {
+	case 0:
+		ptemp[0] = SENSORS_LIMIT(val / 1000, 0,
+				data->temp1_auto_point_temp[1]);
+		ptemp[0] = SENSORS_LIMIT(ptemp[0], 0,
+				data->temp2_auto_point_temp[1]);
+		ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63);
+		if (i2c_smbus_write_byte_data(
+					client,
+					AMC6821_REG_PSV_TEMP,
+					ptemp[0])) {
+				dev_err(&client->dev,
+					"Register write error, 
aborting.\n");
+				count = -EIO;
+		}
+		goto EXIT;
+		break;
+	case 1:
+		ptemp[1] = SENSORS_LIMIT(
+					val / 1000,
+					(ptemp[0] & 0x7C) + 4,
+					124);
+		ptemp[1] &= 0x7C;
+		ptemp[2] = SENSORS_LIMIT(
+					ptemp[2], ptemp[1] + 1,
+					255);
+		break;
+	case 2:
+		ptemp[2] = SENSORS_LIMIT(
+					val / 1000,
+					ptemp[1]+1,
+					255);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr->index (%d).\n", ix);
+		count = -EINVAL;
+		goto EXIT;
+	}
+	dpwm = data->pwm1_auto_point_pwm[2] - data-
>pwm1_auto_point_pwm[1];
+	if (set_slope_register(client, reg, dpwm, ptemp))
+		count = -EIO;
+
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
 }
 
-set_temp_auto_point_temp(temp1_auto_point_temp, 
AMC6821_REG_LTEMP_FAN_CTRL);
-set_temp_auto_point_temp(temp2_auto_point_temp, 
AMC6821_REG_RTEMP_FAN_CTRL);
+
 
 static ssize_t set_pwm1_auto_point_pwm(
 		struct device *dev,
@@ -470,10 +552,11 @@ static ssize_t set_pwm1_auto_point_pwm(
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct amc6821_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10);
-	u8 tmp;
-	int dt;
 	int dpwm;
+	long val;
+	int ret = strict_strtol(buf, 10, &val);
+	if (ret)
+		return ret;
 
 	mutex_lock(&data->update_lock);
 	data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254);
@@ -481,52 +564,39 @@ static ssize_t set_pwm1_auto_point_pwm(
 			data->pwm1_auto_point_pwm[1])) {
 		dev_err(&client->dev, "Register write error, aborting.
\n");
 		count = -EIO;
+		goto EXIT;
 	}
-
 	dpwm = data->pwm1_auto_point_pwm[2] - data-
>pwm1_auto_point_pwm[1];
-	dt = data->temp1_auto_point_temp[2]-data-
>temp1_auto_point_temp[1];
-	for (tmp = 4; tmp > 0; tmp--) {
-		if (dt * (0x20 >> tmp) >= dpwm)
-			break;
-	}
-	tmp |= (data->temp1_auto_point_temp[1] & 0x7C) << 1;
-	if (i2c_smbus_write_byte_data(client,
-			AMC6821_REG_LTEMP_FAN_CTRL, tmp)) {
-		dev_err(&client->dev, "Register write error, aborting.
\n");
+	if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, 
dpwm,
+			data->temp1_auto_point_temp)) {
 		count = -EIO;
+		goto EXIT;
 	}
-
-	dt = data->temp2_auto_point_temp[2]-data-
>temp2_auto_point_temp[1];
-	for (tmp = 4; tmp > 0; tmp--) {
-		if (dt * (0x20 >> tmp) >= dpwm)
-			break;
-	}
-	tmp |= (data->temp2_auto_point_temp[1] & 0x7C) << 1;
-	if (i2c_smbus_write_byte_data(client,
-			AMC6821_REG_RTEMP_FAN_CTRL, tmp)) {
-		dev_err(&client->dev, "Register write error, aborting.
\n");
+	if (set_slope_register(client, AMC6821_REG_RTEMP_FAN_CTRL, 
dpwm,
+			data->temp2_auto_point_temp)) {
 		count = -EIO;
+		goto EXIT;
 	}
+
+EXIT:
 	data->valid = 0;
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-
-#define get_fan_para(name) static ssize_t get_##name(\
-		struct device *dev,\
-		struct device_attribute *devattr,\
-		char *buf)\
-{ \
-	struct amc6821_data *data = amc6821_update_device(dev); \
-	if (0 == data->name)\
-		return sprintf(buf, "0");\
-	return sprintf(buf, "%d\n", (int)(6000000 / data->name)); \
+static ssize_t get_fan(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	struct amc6821_data *data = amc6821_update_device(dev);
+	int ix = to_sensor_dev_attr(devattr)->index;
+	if (0 == data->fan[ix])
+		return sprintf(buf, "0");
+	return sprintf(buf, "%d\n", (int)(6000000 / data->fan[ix]));
 }
 
-get_fan_para(fan1_input);
-get_fan_para(fan1_min);
-get_fan_para(fan1_max);
+
 
 static ssize_t get_fan1_fault(
 		struct device *dev,
@@ -541,34 +611,39 @@ static ssize_t get_fan1_fault(
 }
 
 
-#define set_fan_para(name, reg) \
-static ssize_t set_##name(\
-		struct device *dev,\
-		struct device_attribute *attr,\
-		const char *buf, size_t count)\
-{ \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct amc6821_data *data = i2c_get_clientdata(client); \
-	int val = simple_strtol(buf, NULL, 10); \
-	val = 1 > val ? 0xFFFF : 6000000/val; \
-\
-	mutex_lock(&data->update_lock); \
-	data->name = (u16) SENSORS_LIMIT(val, 1, 0xFFFF); \
-	if (i2c_smbus_write_byte_data(client, reg, data->name & 
0xFF)) { \
-		dev_err(&client->dev, "Register write error, aborting.
\n");\
-		count = -EIO;\
-	} \
-	if (i2c_smbus_write_byte_data(client, reg+1, data->name >> 
8)) { \
-		dev_err(&client->dev, "Register write error, aborting.
\n");\
-		count = -EIO;\
-	} \
-	mutex_unlock(&data->update_lock); \
-	return count; \
-}
 
+static ssize_t set_fan(
+		struct device *dev,
+		struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct amc6821_data *data = i2c_get_clientdata(client);
+	long val;
+	int ix = to_sensor_dev_attr(attr)->index;
+	int ret = strict_strtol(buf, 10, &val);
+	if (ret)
+		return ret;
+	val = 1 > val ? 0xFFFF : 6000000/val;
+
+	mutex_lock(&data->update_lock);
+	data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF);
+	if (i2c_smbus_write_byte_data(client, fan_reg_low[ix],
+			data->fan[ix] & 0xFF)) {
+		dev_err(&client->dev, "Register write error, aborting.
\n");
+		count = -EIO;
+		goto EXIT;
+	}
+	if (i2c_smbus_write_byte_data(client,
+			fan_reg_hi[ix], data->fan[ix] >> 8)) {
+		dev_err(&client->dev, "Register write error, aborting.
\n");
+		count = -EIO;
+	}
+EXIT:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
 
-set_fan_para(fan1_min, AMC6821_REG_TACH_LLIMITL);
-set_fan_para(fan1_max, AMC6821_REG_TACH_HLIMITL);
 
 
 static ssize_t get_fan1_div(
@@ -587,9 +662,12 @@ static ssize_t set_fan1_div(
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct amc6821_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10);
-	int config = i2c_smbus_read_byte_data(client, 
AMC6821_REG_CONF4);
+	long val;
+	int config = strict_strtol(buf, 10, &val);
+	if (config)
+		return config;
 
+	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
 	if (config < 0) {
 		dev_err(&client->dev,
 			"Error reading configuration register, 
aborting.\n");
@@ -607,53 +685,56 @@ static ssize_t set_fan1_div(
 		break;
 	default:
 		mutex_unlock(&data->update_lock);
-		return -EINVAL;
+		count = -EINVAL;
+		goto EXIT;
 	}
 	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, 
config)) {
 		dev_err(&client->dev,
 			"Configuration register write error, aborting.
\n");
 		count = -EIO;
 	}
+EXIT:
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
 
 
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp1_input, 
NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, 
get_temp1_min,
-	set_temp1_min, 0);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, 
get_temp1_max,
-	set_temp1_max, 0);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 
get_temp1_crit,
-	set_temp1_crit, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+	get_temp, NULL, IDX_TEMP1_INPUT);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP1_MIN);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP1_MAX);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP1_CRIT);
 static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO,
-	get_temp1_min_alarm, NULL, 0);
+	get_temp_alarm, NULL, IDX_TEMP1_MIN);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
-	get_temp1_max_alarm, NULL, 0);
+	get_temp_alarm, NULL, IDX_TEMP1_MAX);
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
-	get_temp1_crit_alarm, NULL, 0);
+	get_temp_alarm, NULL, IDX_TEMP1_CRIT);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR,
-	get_temp2_input, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, 
get_temp2_min,
-	set_temp2_min, 0);
-static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, 
get_temp2_max,
-	set_temp2_max, 0);
-static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, 
get_temp2_crit,
-	set_temp2_crit, 0);
+	get_temp, NULL, IDX_TEMP2_INPUT);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP2_MIN);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP2_MAX);
+static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, get_temp,
+	set_temp, IDX_TEMP2_CRIT);
 static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO,
 	get_temp2_fault, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO,
-	get_temp2_min_alarm, NULL, 0);
+	get_temp_alarm, NULL, IDX_TEMP2_MIN);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
-	get_temp2_max_alarm, NULL, 0);
+	get_temp_alarm, NULL, IDX_TEMP2_MAX);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
-	get_temp2_crit_alarm, NULL, 0);
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan1_input, NULL, 
0);
+	get_temp_alarm, NULL, IDX_TEMP2_CRIT);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 
IDX_FAN1_INPUT);
 static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
-	get_fan1_min, set_fan1_min, 0);
+	get_fan, set_fan, IDX_FAN1_MIN);
 static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR,
-	get_fan1_max, set_fan1_max, 0);
+	get_fan, set_fan, IDX_FAN1_MAX);
 static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan1_fault, NULL, 
0);
 static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
 	get_fan1_div, set_fan1_div, 0);
@@ -669,19 +750,19 @@ static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, 
S_IRUGO,
 	get_pwm1_auto_point_pwm, NULL, 2);
 static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO,
 	get_pwm1_auto_channels_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO,
-	get_temp1_auto_point_temp, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_auto_point2_temp, S_IWUSR | S_IRUGO,
-	get_temp1_auto_point_temp, set_temp1_auto_point_temp, 1);
-static SENSOR_DEVICE_ATTR(temp1_auto_point3_temp, S_IWUSR | S_IRUGO,
-	get_temp1_auto_point_temp, set_temp1_auto_point_temp, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO,
+	get_temp_auto_point_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IWUSR | 
S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_point3_temp, S_IWUSR | 
S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 2);
 
-static SENSOR_DEVICE_ATTR(temp2_auto_point1_temp, S_IWUSR | S_IRUGO,
-	get_temp2_auto_point_temp, set_temp2_auto_point_temp, 0);
-static SENSOR_DEVICE_ATTR(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,
-	get_temp2_auto_point_temp, set_temp2_auto_point_temp, 1);
-static SENSOR_DEVICE_ATTR(temp2_auto_point3_temp, S_IWUSR | S_IRUGO,
-	get_temp2_auto_point_temp, set_temp2_auto_point_temp, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IWUSR | 
S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IWUSR | 
S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_point3_temp, S_IWUSR | 
S_IRUGO,
+	get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 2);
 
 
 
@@ -736,7 +817,7 @@ static int amc6821_detect(
 	struct i2c_adapter *adapter = client->adapter;
 	int address = client->addr;
 
-	dev_dbg(&adapter->dev, "amc6821_detect called, kind = %d\n", 
kind);
+	dev_dbg(&adapter->dev, "amc6821_detect called, kind = %d.\n", 
kind);
 
 	if (!i2c_check_functionality(adapter, 
I2C_FUNC_SMBUS_BYTE_DATA)) {
 		dev_dbg(&adapter->dev,
@@ -904,28 +985,16 @@ static struct amc6821_data 
*amc6821_update_device(struct device *dev)
 	struct amc6821_data *data = i2c_get_clientdata(client);
 	int timeout = HZ;
 	u8 reg;
+	int i;
 
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + timeout) ||
 			!data->valid) {
-		data->temp1_input = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_LTEMP_HI);
-		data->temp1_min = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_LTEMP_LIMIT_MIN);
-		data->temp1_max = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_LTEMP_LIMIT_MAX);
-		data->temp1_crit = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_LTEMP_CRIT);
-
-		data->temp2_input = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_RTEMP_HI);
-		data->temp2_min = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_RTEMP_LIMIT_MIN);
-		data->temp2_max = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_RTEMP_LIMIT_MAX);
-		data->temp2_crit = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_RTEMP_CRIT);
+
+		for (i = 0; i < TEMP_IDX_LEN; i++)
+			data->temp[i] = i2c_smbus_read_byte_data
(client,
+				temp_reg[i]);
 
 		data->stat1 = i2c_smbus_read_byte_data(client,
 			AMC6821_REG_STAT1);
@@ -934,18 +1003,14 @@ static struct amc6821_data 
*amc6821_update_device(struct device *dev)
 
 		data->pwm1 = i2c_smbus_read_byte_data(client,
 			AMC6821_REG_DCY);
-		data->fan1_input = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_TDATA_LOW);
-		data->fan1_input += i2c_smbus_read_byte_data(client,
-			AMC6821_REG_TDATA_HI) << 8;
-		data->fan1_min = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_TACH_LLIMITL);
-		data->fan1_min += i2c_smbus_read_byte_data(client,
-			AMC6821_REG_TACH_LLIMITL+1) << 8;
-		data->fan1_max = i2c_smbus_read_byte_data(client,
-			AMC6821_REG_TACH_HLIMITL);
-		data->fan1_max += i2c_smbus_read_byte_data(client,
-			AMC6821_REG_TACH_HLIMITL+1) << 8;
+		for (i = 0; i < FAN1_IDX_LEN; i++) {
+			data->fan[i] = i2c_smbus_read_byte_data(
+					client,
+					fan_reg_low[i]);
+			data->fan[i] += i2c_smbus_read_byte_data(
+					client,
+					fan_reg_hi[i]) << 8;
+		}
 		data->fan1_div = i2c_smbus_read_byte_data(client,
 			AMC6821_REG_CONF4);
 		data->fan1_div = data->fan1_div & 
AMC6821_CONF4_PSPR ? 4 : 2;



^ permalink raw reply related	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2013-01-23  4:30 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-31 20:24 [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 tomaz.mertelj
2009-08-31 20:24 ` [PATCH] hwmon: Driver for Texas Instruments amc6821 chip tomaz.mertelj
2009-09-01 17:56 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Andre Prendel
2009-09-01 17:56   ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Andre Prendel
2009-09-02  8:20   ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Tomaz Mertelj
2009-09-02  8:20     ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Tomaz Mertelj
2009-09-02  8:45 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments corentin.labbe
2009-09-02  8:45   ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip corentin.labbe
2009-09-02 23:55 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton
2009-09-02 23:55   ` [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Andrew Morton
2009-09-05 12:08 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments tomaz.mertelj
2009-09-05 12:08   ` [PATCH] hwmon: Driver for Texas Instruments amc6821 chip tomaz.mertelj
2009-09-09  0:06   ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton
2009-09-09  0:06     ` [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Andrew Morton
2009-09-09  7:34     ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Jean Delvare
2009-09-09  7:34       ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Jean Delvare
2009-09-09  8:06       ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton
2009-09-09  8:06         ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Andrew Morton
2009-09-09 12:24       ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Tomaz Mertelj
2009-09-09 12:24         ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Tomaz Mertelj
2009-09-09 12:45         ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Jean Delvare
2009-09-09 12:45           ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Jean Delvare
2009-09-21 21:44       ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton
2009-09-21 21:44         ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Andrew Morton
2009-09-22  5:59         ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Tomaz Mertelj
2009-09-22  5:59           ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Tomaz Mertelj
2009-09-22  6:02           ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton
2009-09-22  6:02             ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip Andrew Morton
2013-01-13  0:16 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments INA209 Guenter Roeck
2013-01-14 21:17 ` Ira W. Snyder
2013-01-15  6:04 ` Guenter Roeck
2013-01-15 22:10 ` Paul Hays
2013-01-15 22:56 ` Guenter Roeck
2013-01-22 21:43 ` Ira W. Snyder
2013-01-22 22:15 ` Ira W. Snyder
2013-01-23  4:30 ` Guenter Roeck
  -- strict thread matches above, loose matches on Subject: below --
2009-09-23  9:32 [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments amc6821 chip tomaz.mertelj
2009-09-30 19:44 ` [lm-sensors] [PATCH] hwmon: Driver for Texas Instruments Andrew Morton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.