hwmon: (amc6821) Avoid forward declaration

Reorder functions to avoid forward declaration.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c
index 8a67ec6..29c17fc 100644
--- a/drivers/hwmon/amc6821.c
+++ b/drivers/hwmon/amc6821.c
@@ -21,7 +21,6 @@
  * 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>
@@ -33,7 +32,6 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 
-
 /*
  * Addresses to scan.
  */
@@ -41,8 +39,6 @@
 static const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e,
 	0x4c, 0x4d, 0x4e, I2C_CLIENT_END};
 
-
-
 /*
  * Insmod parameters
  */
@@ -53,7 +49,6 @@
 static int init = 1; /*Power-on initialization.*/
 module_param(init, int, S_IRUGO);
 
-
 enum chips { amc6821 };
 
 #define AMC6821_REG_DEV_ID 0x3D
@@ -152,40 +147,6 @@
 			AMC6821_REG_TACH_LLIMITH,
 			AMC6821_REG_TACH_HLIMITH, };
 
-static int amc6821_probe(
-		struct i2c_client *client,
-		const struct i2c_device_id *id);
-static int amc6821_detect(
-		struct i2c_client *client,
-		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_list = normal_i2c,
-};
-
-
 /*
  * Client data (each client gets its own)
  */
@@ -213,776 +174,6 @@
 	u8 stat2;
 };
 
-
-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);
-}
-
-
-
-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 = kstrtol(buf, 10, &val);
-	if (ret)
-		return ret;
-	val = clamp_val(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;
-}
-
-
-
-
-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(
-		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);
-	long val;
-	int ret = kstrtol(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	mutex_lock(&data->update_lock);
-	data->pwm1 = clamp_val(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);
-	long val;
-	int config = kstrtol(buf, 10, &val);
-	if (config)
-		return config;
-
-	mutex_lock(&data->update_lock);
-	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
-	if (config < 0) {
-			dev_err(&client->dev,
-			"Error reading configuration register, aborting.\n");
-			count = config;
-			goto unlock;
-	}
-
-	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:
-		count = -EINVAL;
-		goto unlock;
-	}
-	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) {
-			dev_err(&client->dev,
-			"Configuration register write error, aborting.\n");
-			count = -EIO;
-	}
-unlock:
-	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);
-}
-
-
-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);
-	case 2:
-		return sprintf(buf, "%d\n",
-			data->temp2_auto_point_temp[ix] * 1000);
-	default:
-		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
-		return -EINVAL;
-	}
-}
-
-
-static ssize_t get_pwm1_auto_point_pwm(
-		struct device *dev,
-		struct device_attribute *devattr,
-		char *buf)
-{
-	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[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;
-}
-
-
-
-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 = kstrtol(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;
-	}
-
-	mutex_lock(&data->update_lock);
-	data->valid = 0;
-
-	switch (ix) {
-	case 0:
-		ptemp[0] = clamp_val(val / 1000, 0,
-				     data->temp1_auto_point_temp[1]);
-		ptemp[0] = clamp_val(ptemp[0], 0,
-				     data->temp2_auto_point_temp[1]);
-		ptemp[0] = clamp_val(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;
-	case 1:
-		ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
-		ptemp[1] &= 0x7C;
-		ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255);
-		break;
-	case 2:
-		ptemp[2] = clamp_val(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;
-}
-
-
-
-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 dpwm;
-	long val;
-	int ret = kstrtol(buf, 10, &val);
-	if (ret)
-		return ret;
-
-	mutex_lock(&data->update_lock);
-	data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254);
-	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;
-		goto EXIT;
-	}
-	dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1];
-	if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, dpwm,
-			data->temp1_auto_point_temp)) {
-		count = -EIO;
-		goto EXIT;
-	}
-	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;
-}
-
-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]));
-}
-
-
-
-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");
-}
-
-
-
-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 = kstrtol(buf, 10, &val);
-	if (ret)
-		return ret;
-	val = 1 > val ? 0xFFFF : 6000000/val;
-
-	mutex_lock(&data->update_lock);
-	data->fan[ix] = (u16) clamp_val(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;
-}
-
-
-
-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);
-	long val;
-	int config = kstrtol(buf, 10, &val);
-	if (config)
-		return config;
-
-	mutex_lock(&data->update_lock);
-	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
-	if (config < 0) {
-		dev_err(&client->dev,
-			"Error reading configuration register, aborting.\n");
-		count = config;
-		goto EXIT;
-	}
-	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:
-		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_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_temp_alarm, NULL, IDX_TEMP1_MIN);
-static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
-	get_temp_alarm, NULL, IDX_TEMP1_MAX);
-static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
-	get_temp_alarm, NULL, IDX_TEMP1_CRIT);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
-	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_temp_alarm, NULL, IDX_TEMP2_MIN);
-static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
-	get_temp_alarm, NULL, IDX_TEMP2_MAX);
-static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
-	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_fan, set_fan, IDX_FAN1_MIN);
-static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR,
-	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);
-
-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_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_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);
-
-
-
-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,
-		struct i2c_board_info *info)
-{
-	struct i2c_adapter *adapter = client->adapter;
-	int address = client->addr;
-	int dev_id, comp_id;
-
-	dev_dbg(&adapter->dev, "amc6821_detect called.\n");
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-		dev_dbg(&adapter->dev,
-			"amc6821: I2C bus doesn't support byte mode, "
-			"skipping.\n");
-		return -ENODEV;
-	}
-
-	dev_id = i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID);
-	comp_id = i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID);
-	if (dev_id != 0x21 || comp_id != 0x49) {
-		dev_dbg(&adapter->dev,
-			"amc6821: detection failed at 0x%02x.\n",
-			address);
-		return -ENODEV;
-	}
-
-	/*
-	 * Bit 7 of the address register is ignored, so we can check the
-	 * ID registers again
-	 */
-	dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID);
-	comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID);
-	if (dev_id != 0x21 || comp_id != 0x49) {
-		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;
-
-	data = devm_kzalloc(&client->dev, sizeof(struct amc6821_data),
-			    GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	i2c_set_clientdata(client, data);
-	mutex_init(&data->update_lock);
-
-	/*
-	 * Initialize the amc6821 chip
-	 */
-	err = amc6821_init_client(client);
-	if (err)
-		return err;
-
-	err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
-	if (err)
-		return err;
-
-	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);
-	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);
-
-	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;
-		}
-
-		dev_info(&client->dev, "Revision %d\n", config & 0x0f);
-
-		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);
@@ -1086,6 +277,763 @@
 	return data;
 }
 
+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);
+}
+
+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 = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+	val = clamp_val(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;
+}
+
+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(
+		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);
+	long val;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->pwm1 = clamp_val(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);
+	long val;
+	int config = kstrtol(buf, 10, &val);
+	if (config)
+		return config;
+
+	mutex_lock(&data->update_lock);
+	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1);
+	if (config < 0) {
+			dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+			count = config;
+			goto unlock;
+	}
+
+	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:
+		count = -EINVAL;
+		goto unlock;
+	}
+	if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) {
+			dev_err(&client->dev,
+			"Configuration register write error, aborting.\n");
+			count = -EIO;
+	}
+unlock:
+	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);
+}
+
+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);
+	case 2:
+		return sprintf(buf, "%d\n",
+			data->temp2_auto_point_temp[ix] * 1000);
+	default:
+		dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
+		return -EINVAL;
+	}
+}
+
+static ssize_t get_pwm1_auto_point_pwm(
+		struct device *dev,
+		struct device_attribute *devattr,
+		char *buf)
+{
+	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[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;
+}
+
+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 = kstrtol(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;
+	}
+
+	mutex_lock(&data->update_lock);
+	data->valid = 0;
+
+	switch (ix) {
+	case 0:
+		ptemp[0] = clamp_val(val / 1000, 0,
+				     data->temp1_auto_point_temp[1]);
+		ptemp[0] = clamp_val(ptemp[0], 0,
+				     data->temp2_auto_point_temp[1]);
+		ptemp[0] = clamp_val(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;
+	case 1:
+		ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
+		ptemp[1] &= 0x7C;
+		ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255);
+		break;
+	case 2:
+		ptemp[2] = clamp_val(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;
+}
+
+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 dpwm;
+	long val;
+	int ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	mutex_lock(&data->update_lock);
+	data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254);
+	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;
+		goto EXIT;
+	}
+	dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1];
+	if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, dpwm,
+			data->temp1_auto_point_temp)) {
+		count = -EIO;
+		goto EXIT;
+	}
+	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;
+}
+
+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]));
+}
+
+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");
+}
+
+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 = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+	val = 1 > val ? 0xFFFF : 6000000/val;
+
+	mutex_lock(&data->update_lock);
+	data->fan[ix] = (u16) clamp_val(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;
+}
+
+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);
+	long val;
+	int config = kstrtol(buf, 10, &val);
+	if (config)
+		return config;
+
+	mutex_lock(&data->update_lock);
+	config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4);
+	if (config < 0) {
+		dev_err(&client->dev,
+			"Error reading configuration register, aborting.\n");
+		count = config;
+		goto EXIT;
+	}
+	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:
+		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_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_temp_alarm, NULL, IDX_TEMP1_MIN);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP1_MAX);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP1_CRIT);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
+	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_temp_alarm, NULL, IDX_TEMP2_MIN);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO,
+	get_temp_alarm, NULL, IDX_TEMP2_MAX);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO,
+	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_fan, set_fan, IDX_FAN1_MIN);
+static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR,
+	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);
+
+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_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_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);
+
+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,
+		struct i2c_board_info *info)
+{
+	struct i2c_adapter *adapter = client->adapter;
+	int address = client->addr;
+	int dev_id, comp_id;
+
+	dev_dbg(&adapter->dev, "amc6821_detect called.\n");
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_dbg(&adapter->dev,
+			"amc6821: I2C bus doesn't support byte mode, "
+			"skipping.\n");
+		return -ENODEV;
+	}
+
+	dev_id = i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID);
+	comp_id = i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID);
+	if (dev_id != 0x21 || comp_id != 0x49) {
+		dev_dbg(&adapter->dev,
+			"amc6821: detection failed at 0x%02x.\n",
+			address);
+		return -ENODEV;
+	}
+
+	/*
+	 * Bit 7 of the address register is ignored, so we can check the
+	 * ID registers again
+	 */
+	dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID);
+	comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID);
+	if (dev_id != 0x21 || comp_id != 0x49) {
+		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_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;
+		}
+
+		dev_info(&client->dev, "Revision %d\n", config & 0x0f);
+
+		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 int amc6821_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct amc6821_data *data;
+	int err;
+
+	data = devm_kzalloc(&client->dev, sizeof(struct amc6821_data),
+			    GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, data);
+	mutex_init(&data->update_lock);
+
+	/*
+	 * Initialize the amc6821 chip
+	 */
+	err = amc6821_init_client(client);
+	if (err)
+		return err;
+
+	err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
+	if (err)
+		return err;
+
+	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);
+	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);
+
+	return 0;
+}
+
+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_list = normal_i2c,
+};
+
 module_i2c_driver(amc6821_driver);
 
 MODULE_LICENSE("GPL");