diff options
Diffstat (limited to 'drivers/hwmon/amc6821.c')
| -rw-r--r-- | drivers/hwmon/amc6821.c | 397 | 
1 files changed, 165 insertions, 232 deletions
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c index 9f2be3dd28f3..12e851a5af48 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 @@ module_param(pwminv, int, S_IRUGO);  static int init = 1; /*Power-on initialization.*/  module_param(init, int, S_IRUGO); -  enum chips { amc6821 };  #define AMC6821_REG_DEV_ID 0x3D @@ -152,46 +147,12 @@ 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, -		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)   */  struct amc6821_data { -	struct device *hwmon_dev; +	struct i2c_client *client;  	struct mutex update_lock;  	char valid; /* zero until following fields are valid */  	unsigned long last_updated; /* in jiffies */ @@ -213,6 +174,108 @@ struct amc6821_data {  	u8 stat2;  }; +static struct amc6821_data *amc6821_update_device(struct device *dev) +{ +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client; +	int timeout = HZ; +	u8 reg; +	int i; + +	mutex_lock(&data->update_lock); + +	if (time_after(jiffies, data->last_updated + timeout) || +			!data->valid) { + +		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); +		data->stat2 = i2c_smbus_read_byte_data(client, +			AMC6821_REG_STAT2); + +		data->pwm1 = i2c_smbus_read_byte_data(client, +			AMC6821_REG_DCY); +		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; + +		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->temp1_auto_point_temp[0] = +			i2c_smbus_read_byte_data(client, +					AMC6821_REG_PSV_TEMP); +		data->temp2_auto_point_temp[0] = +				data->temp1_auto_point_temp[0]; +		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->temp2_auto_point_temp[2] = 255; + +		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); +		reg = (reg >> 5) & 0x3; +		switch (reg) { +		case 0: /*open loop: software sets pwm1*/ +			data->pwm1_auto_channels_temp = 0; +			data->pwm1_enable = 1; +			break; +		case 2: /*closed loop: remote T (temp2)*/ +			data->pwm1_auto_channels_temp = 2; +			data->pwm1_enable = 2; +			break; +		case 3: /*closed loop: local and remote T (temp2)*/ +			data->pwm1_auto_channels_temp = 3; +			data->pwm1_enable = 3; +			break; +		case 1: /* +			 * semi-open loop: software sets rpm, chip controls +			 * pwm1, currently not implemented +			 */ +			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 ssize_t get_temp(  		struct device *dev, @@ -225,16 +288,14 @@ static ssize_t get_temp(  	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); +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client;  	int ix = to_sensor_dev_attr(attr)->index;  	long val; @@ -253,9 +314,6 @@ static ssize_t set_temp(  	return count;  } - - -  static ssize_t get_temp_alarm(  	struct device *dev,  	struct device_attribute *devattr, @@ -294,9 +352,6 @@ static ssize_t get_temp_alarm(  		return sprintf(buf, "0");  } - - -  static ssize_t get_temp2_fault(  		struct device *dev,  		struct device_attribute *devattr, @@ -324,8 +379,8 @@ static ssize_t set_pwm1(  		const char *buf,  		size_t count)  { -	struct i2c_client *client = to_i2c_client(dev); -	struct amc6821_data *data = i2c_get_clientdata(client); +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client;  	long val;  	int ret = kstrtol(buf, 10, &val);  	if (ret) @@ -353,18 +408,20 @@ static ssize_t set_pwm1_enable(  		const char *buf,  		size_t count)  { -	struct i2c_client *client = to_i2c_client(dev); -	struct amc6821_data *data = i2c_get_clientdata(client); +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->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"); -			return config; +			count = config; +			goto unlock;  	}  	switch (val) { @@ -381,19 +438,19 @@ static ssize_t set_pwm1_enable(  		config |= AMC6821_CONF1_FDRC1;  		break;  	default: -		return -EINVAL; +		count = -EINVAL; +		goto unlock;  	} -	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;  	} +unlock:  	mutex_unlock(&data->update_lock);  	return count;  } -  static ssize_t get_pwm1_auto_channels_temp(  		struct device *dev,  		struct device_attribute *devattr, @@ -403,7 +460,6 @@ static ssize_t get_pwm1_auto_channels_temp(  	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, @@ -425,7 +481,6 @@ static ssize_t get_temp_auto_point_temp(  	}  } -  static ssize_t get_pwm1_auto_point_pwm(  		struct device *dev,  		struct device_attribute *devattr, @@ -436,7 +491,6 @@ static ssize_t get_pwm1_auto_point_pwm(  	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, @@ -459,16 +513,14 @@ static inline ssize_t set_slope_register(struct i2c_client *client,  	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); +	struct i2c_client *client = data->client;  	int ix = to_sensor_dev_attr_2(attr)->index;  	int nr = to_sensor_dev_attr_2(attr)->nr;  	u8 *ptemp; @@ -493,8 +545,9 @@ static ssize_t set_temp_auto_point_temp(  		return -EINVAL;  	} -	data->valid = 0;  	mutex_lock(&data->update_lock); +	data->valid = 0; +  	switch (ix) {  	case 0:  		ptemp[0] = clamp_val(val / 1000, 0, @@ -533,16 +586,14 @@ EXIT:  	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); +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client;  	int dpwm;  	long val;  	int ret = kstrtol(buf, 10, &val); @@ -587,8 +638,6 @@ static ssize_t get_fan(  	return sprintf(buf, "%d\n", (int)(6000000 / data->fan[ix]));  } - -  static ssize_t get_fan1_fault(  		struct device *dev,  		struct device_attribute *devattr, @@ -601,15 +650,13 @@ static ssize_t get_fan1_fault(  		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); +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client;  	long val;  	int ix = to_sensor_dev_attr(attr)->index;  	int ret = kstrtol(buf, 10, &val); @@ -635,8 +682,6 @@ EXIT:  	return count;  } - -  static ssize_t get_fan1_div(  		struct device *dev,  		struct device_attribute *devattr, @@ -651,20 +696,21 @@ static ssize_t set_fan1_div(  		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); +	struct amc6821_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->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"); -		return config; +		count = config; +		goto EXIT;  	} -	mutex_lock(&data->update_lock);  	switch (val) {  	case 2:  		config &= ~AMC6821_CONF4_PSPR; @@ -688,8 +734,6 @@ EXIT:  	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, @@ -754,8 +798,6 @@ static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IWUSR | S_IRUGO,  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, @@ -792,11 +834,7 @@ static struct attribute *amc6821_attrs[] = {  	NULL  }; -static struct attribute_group amc6821_attr_grp = { -	.attrs = amc6821_attrs, -}; - - +ATTRIBUTE_GROUPS(amc6821);  /* Return 0 if detection is successful, -ENODEV otherwise */  static int amc6821_detect( @@ -844,53 +882,6 @@ static int amc6821_detect(  	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; @@ -977,109 +968,51 @@ static int amc6821_init_client(struct i2c_client *client)  	return 0;  } - -static struct amc6821_data *amc6821_update_device(struct device *dev) +static int amc6821_probe(struct i2c_client *client, +			 const struct i2c_device_id *id)  { -	struct i2c_client *client = to_i2c_client(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) { - -		for (i = 0; i < TEMP_IDX_LEN; i++) -			data->temp[i] = i2c_smbus_read_byte_data(client, -				temp_reg[i]); +	struct device *dev = &client->dev; +	struct amc6821_data *data; +	struct device *hwmon_dev; +	int err; -		data->stat1 = i2c_smbus_read_byte_data(client, -			AMC6821_REG_STAT1); -		data->stat2 = i2c_smbus_read_byte_data(client, -			AMC6821_REG_STAT2); +	data = devm_kzalloc(dev, sizeof(struct amc6821_data), GFP_KERNEL); +	if (!data) +		return -ENOMEM; -		data->pwm1 = i2c_smbus_read_byte_data(client, -			AMC6821_REG_DCY); -		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; +	data->client = client; +	mutex_init(&data->update_lock); -		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); +	/* +	 * Initialize the amc6821 chip +	 */ +	err = amc6821_init_client(client); +	if (err) +		return err; -		data->temp1_auto_point_temp[0] = -			i2c_smbus_read_byte_data(client, -					AMC6821_REG_PSV_TEMP); -		data->temp2_auto_point_temp[0] = -				data->temp1_auto_point_temp[0]; -		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; +	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, +							   data, +							   amc6821_groups); +	return PTR_ERR_OR_ZERO(hwmon_dev); +} -		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->temp2_auto_point_temp[2] = 255; +static const struct i2c_device_id amc6821_id[] = { +	{ "amc6821", amc6821 }, +	{ } +}; -		reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); -		reg = (reg >> 5) & 0x3; -		switch (reg) { -		case 0: /*open loop: software sets pwm1*/ -			data->pwm1_auto_channels_temp = 0; -			data->pwm1_enable = 1; -			break; -		case 2: /*closed loop: remote T (temp2)*/ -			data->pwm1_auto_channels_temp = 2; -			data->pwm1_enable = 2; -			break; -		case 3: /*closed loop: local and remote T (temp2)*/ -			data->pwm1_auto_channels_temp = 3; -			data->pwm1_enable = 3; -			break; -		case 1: /* -			 * semi-open loop: software sets rpm, chip controls -			 * pwm1, currently not implemented -			 */ -			data->pwm1_auto_channels_temp = 0; -			data->pwm1_enable = 0; -			break; -		} +MODULE_DEVICE_TABLE(i2c, amc6821_id); -		data->last_updated = jiffies; -		data->valid = 1; -	} -	mutex_unlock(&data->update_lock); -	return data; -} +static struct i2c_driver amc6821_driver = { +	.class = I2C_CLASS_HWMON, +	.driver = { +		.name	= "amc6821", +	}, +	.probe = amc6821_probe, +	.id_table = amc6821_id, +	.detect = amc6821_detect, +	.address_list = normal_i2c, +};  module_i2c_driver(amc6821_driver);  |