diff options
Diffstat (limited to 'drivers/hwmon/lm92.c')
| -rw-r--r-- | drivers/hwmon/lm92.c | 316 | 
1 files changed, 147 insertions, 169 deletions
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 7c31e6205f8..d2060e245ff 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -1,6 +1,6 @@  /*   * lm92 - Hardware monitoring driver - * Copyright (C) 2005-2008  Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2005-2008  Jean Delvare <jdelvare@suse.de>   *   * Based on the lm90 driver, with some ideas taken from the lm_sensors   * lm92 driver as well. @@ -34,10 +34,6 @@   * 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/module.h> @@ -48,9 +44,12 @@  #include <linux/hwmon-sysfs.h>  #include <linux/err.h>  #include <linux/mutex.h> +#include <linux/jiffies.h> -/* The LM92 and MAX6635 have 2 two-state pins for address selection, -   resulting in 4 possible addresses. */ +/* + * The LM92 and MAX6635 have 2 two-state pins for address selection, + * resulting in 4 possible addresses. + */  static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,  						I2C_CLIENT_END }; @@ -63,11 +62,13 @@ static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,  #define LM92_REG_TEMP_HIGH		0x05 /* 16-bit, RW */  #define LM92_REG_MAN_ID			0x07 /* 16-bit, RO, LM92 only */ -/* The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, -   left-justified in 16-bit registers. No rounding is done, with such -   a resolution it's just not worth it. Note that the MAX6635 doesn't -   make use of the 4 lower bits for limits (i.e. effective resolution -   for limits is 1 degree Celsius). */ +/* + * The LM92 uses signed 13-bit values with LSB = 0.0625 degree Celsius, + * left-justified in 16-bit registers. No rounding is done, with such + * a resolution it's just not worth it. Note that the MAX6635 doesn't + * make use of the 4 lower bits for limits (i.e. effective resolution + * for limits is 1 degree Celsius). + */  static inline int TEMP_FROM_REG(s16 reg)  {  	return reg / 8 * 625 / 10; @@ -88,46 +89,53 @@ static inline u8 ALARMS_FROM_REG(s16 reg)  	return reg & 0x0007;  } -/* Driver data (common to all clients) */ -static struct i2c_driver lm92_driver; +enum temp_index { +	t_input, +	t_crit, +	t_min, +	t_max, +	t_hyst, +	t_num_regs +}; + +static const u8 regs[t_num_regs] = { +	[t_input] = LM92_REG_TEMP, +	[t_crit] = LM92_REG_TEMP_CRIT, +	[t_min] = LM92_REG_TEMP_LOW, +	[t_max] = LM92_REG_TEMP_HIGH, +	[t_hyst] = LM92_REG_TEMP_HYST, +};  /* Client data (each client gets its own) */  struct lm92_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 */  	/* registers values */ -	s16 temp1_input, temp1_crit, temp1_min, temp1_max, temp1_hyst; +	s16 temp[t_num_regs];	/* index with enum temp_index */  }; -  /*   * Sysfs attributes and callback functions   */  static struct lm92_data *lm92_update_device(struct device *dev)  { -	struct i2c_client *client = to_i2c_client(dev); -	struct lm92_data *data = i2c_get_clientdata(client); +	struct lm92_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client; +	int i;  	mutex_lock(&data->update_lock);  	if (time_after(jiffies, data->last_updated + HZ)  	 || !data->valid) {  		dev_dbg(&client->dev, "Updating lm92 data\n"); -		data->temp1_input = swab16(i2c_smbus_read_word_data(client, -				    LM92_REG_TEMP)); -		data->temp1_hyst = swab16(i2c_smbus_read_word_data(client, -				    LM92_REG_TEMP_HYST)); -		data->temp1_crit = swab16(i2c_smbus_read_word_data(client, -				    LM92_REG_TEMP_CRIT)); -		data->temp1_min = swab16(i2c_smbus_read_word_data(client, -				    LM92_REG_TEMP_LOW)); -		data->temp1_max = swab16(i2c_smbus_read_word_data(client, -				    LM92_REG_TEMP_HIGH)); - +		for (i = 0; i < t_num_regs; i++) { +			data->temp[i] = +				i2c_smbus_read_word_swapped(client, regs[i]); +		}  		data->last_updated = jiffies;  		data->valid = 1;  	} @@ -137,73 +145,80 @@ static struct lm92_data *lm92_update_device(struct device *dev)  	return data;  } -#define show_temp(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ -	struct lm92_data *data = lm92_update_device(dev); \ -	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ -} -show_temp(temp1_input); -show_temp(temp1_crit); -show_temp(temp1_min); -show_temp(temp1_max); - -#define set_temp(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, \ -	size_t count) \ -{ \ -	struct i2c_client *client = to_i2c_client(dev); \ -	struct lm92_data *data = i2c_get_clientdata(client); \ -	long val = simple_strtol(buf, NULL, 10); \ - \ -	mutex_lock(&data->update_lock); \ -	data->value = TEMP_TO_REG(val); \ -	i2c_smbus_write_word_data(client, reg, swab16(data->value)); \ -	mutex_unlock(&data->update_lock); \ -	return count; \ +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, +			 char *buf) +{ +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); +	struct lm92_data *data = lm92_update_device(dev); + +	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));  } -set_temp(temp1_crit, LM92_REG_TEMP_CRIT); -set_temp(temp1_min, LM92_REG_TEMP_LOW); -set_temp(temp1_max, LM92_REG_TEMP_HIGH); -static ssize_t show_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, +			   const char *buf, size_t count)  { -	struct lm92_data *data = lm92_update_device(dev); -	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_crit) -		       - TEMP_FROM_REG(data->temp1_hyst)); +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); +	struct lm92_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client; +	int nr = attr->index; +	long val; +	int err; +	 +	err = kstrtol(buf, 10, &val); +	if (err) +		return err; + +	mutex_lock(&data->update_lock); +	data->temp[nr] = TEMP_TO_REG(val); +	i2c_smbus_write_word_swapped(client, regs[nr], data->temp[nr]); +	mutex_unlock(&data->update_lock); +	return count;  } -static ssize_t show_temp1_max_hyst(struct device *dev, struct device_attribute *attr, char *buf) + +static ssize_t show_temp_hyst(struct device *dev, +			      struct device_attribute *devattr, char *buf)  { +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);  	struct lm92_data *data = lm92_update_device(dev); -	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_max) -		       - TEMP_FROM_REG(data->temp1_hyst)); +	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]) +		       - TEMP_FROM_REG(data->temp[t_hyst]));  } -static ssize_t show_temp1_min_hyst(struct device *dev, struct device_attribute *attr, char *buf) + +static ssize_t show_temp_min_hyst(struct device *dev, +				  struct device_attribute *attr, char *buf)  {  	struct lm92_data *data = lm92_update_device(dev); -	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp1_min) -		       + TEMP_FROM_REG(data->temp1_hyst)); +	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) +		       + TEMP_FROM_REG(data->temp[t_hyst]));  } -static ssize_t set_temp1_crit_hyst(struct device *dev, struct device_attribute *attr, const char *buf, -	size_t count) +static ssize_t set_temp_hyst(struct device *dev, +			     struct device_attribute *devattr, +			     const char *buf, size_t count)  { -	struct i2c_client *client = to_i2c_client(dev); -	struct lm92_data *data = i2c_get_clientdata(client); -	long val = simple_strtol(buf, NULL, 10); +	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); +	struct lm92_data *data = dev_get_drvdata(dev); +	struct i2c_client *client = data->client; +	long val; +	int err; + +	err = kstrtol(buf, 10, &val); +	if (err) +		return err;  	mutex_lock(&data->update_lock); -	data->temp1_hyst = TEMP_FROM_REG(data->temp1_crit) - val; -	i2c_smbus_write_word_data(client, LM92_REG_TEMP_HYST, -				  swab16(TEMP_TO_REG(data->temp1_hyst))); +	data->temp[t_hyst] = TEMP_FROM_REG(data->temp[attr->index]) - val; +	i2c_smbus_write_word_swapped(client, LM92_REG_TEMP_HYST, +				     TEMP_TO_REG(data->temp[t_hyst]));  	mutex_unlock(&data->update_lock);  	return count;  } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +			   char *buf)  {  	struct lm92_data *data = lm92_update_device(dev); -	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp1_input)); +	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->temp[t_input]));  }  static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, @@ -211,26 +226,25 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,  {  	int bitnr = to_sensor_dev_attr(attr)->index;  	struct lm92_data *data = lm92_update_device(dev); -	return sprintf(buf, "%d\n", (data->temp1_input >> bitnr) & 1); +	return sprintf(buf, "%d\n", (data->temp[t_input] >> bitnr) & 1);  } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp1_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp1_crit, -	set_temp1_crit); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp1_crit_hyst, -	set_temp1_crit_hyst); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp1_min, -	set_temp1_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp1_min_hyst, NULL); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp1_max, -	set_temp1_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp1_max_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, t_input); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, +			  t_crit); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, +			  set_temp_hyst, t_crit); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, +			  t_min); +static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, +			  t_max); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max);  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);  static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2);  static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0);  static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); -  /*   * Detection and registration   */ @@ -246,26 +260,30 @@ static void lm92_init_client(struct i2c_client *client)  					  config & 0xFE);  } -/* The MAX6635 has no identification register, so we have to use tricks -   to identify it reliably. This is somewhat slow. -   Note that we do NOT rely on the 2 MSB of the configuration register -   always reading 0, as suggested by the datasheet, because it was once -   reported not to be true. */ +/* + * The MAX6635 has no identification register, so we have to use tricks + * to identify it reliably. This is somewhat slow. + * Note that we do NOT rely on the 2 MSB of the configuration register + * always reading 0, as suggested by the datasheet, because it was once + * reported not to be true. + */  static int max6635_check(struct i2c_client *client)  {  	u16 temp_low, temp_high, temp_hyst, temp_crit;  	u8 conf;  	int i; -	/* No manufacturer ID register, so a read from this address will -	   always return the last read value. */ +	/* +	 * No manufacturer ID register, so a read from this address will +	 * always return the last read value. +	 */  	temp_low = i2c_smbus_read_word_data(client, LM92_REG_TEMP_LOW);  	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_low)  		return 0;  	temp_high = i2c_smbus_read_word_data(client, LM92_REG_TEMP_HIGH);  	if (i2c_smbus_read_word_data(client, LM92_REG_MAN_ID) != temp_high)  		return 0; -	 +  	/* Limits are stored as integer values (signed, 9-bit). */  	if ((temp_low & 0x7f00) || (temp_high & 0x7f00))  		return 0; @@ -274,46 +292,45 @@ static int max6635_check(struct i2c_client *client)  	if ((temp_hyst & 0x7f00) || (temp_crit & 0x7f00))  		return 0; -	/* Registers addresses were found to cycle over 16-byte boundaries. -	   We don't test all registers with all offsets so as to save some -	   reads and time, but this should still be sufficient to dismiss -	   non-MAX6635 chips. */ +	/* +	 * Registers addresses were found to cycle over 16-byte boundaries. +	 * We don't test all registers with all offsets so as to save some +	 * reads and time, but this should still be sufficient to dismiss +	 * non-MAX6635 chips. +	 */  	conf = i2c_smbus_read_byte_data(client, LM92_REG_CONFIG); -	for (i=16; i<96; i*=2) { +	for (i = 16; i < 96; i *= 2) {  		if (temp_hyst != i2c_smbus_read_word_data(client, -		 		 LM92_REG_TEMP_HYST + i - 16) +				 LM92_REG_TEMP_HYST + i - 16)  		 || temp_crit != i2c_smbus_read_word_data(client, -		 		 LM92_REG_TEMP_CRIT + i) +				 LM92_REG_TEMP_CRIT + i)  		 || temp_low != i2c_smbus_read_word_data(client,  				LM92_REG_TEMP_LOW + i + 16)  		 || temp_high != i2c_smbus_read_word_data(client, -		 		 LM92_REG_TEMP_HIGH + i + 32) +				 LM92_REG_TEMP_HIGH + i + 32)  		 || conf != i2c_smbus_read_byte_data(client, -		 	    LM92_REG_CONFIG + i)) +			    LM92_REG_CONFIG + i))  			return 0;  	}  	return 1;  } -static struct attribute *lm92_attributes[] = { -	&dev_attr_temp1_input.attr, -	&dev_attr_temp1_crit.attr, -	&dev_attr_temp1_crit_hyst.attr, -	&dev_attr_temp1_min.attr, +static struct attribute *lm92_attrs[] = { +	&sensor_dev_attr_temp1_input.dev_attr.attr, +	&sensor_dev_attr_temp1_crit.dev_attr.attr, +	&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, +	&sensor_dev_attr_temp1_min.dev_attr.attr,  	&dev_attr_temp1_min_hyst.attr, -	&dev_attr_temp1_max.attr, -	&dev_attr_temp1_max_hyst.attr, +	&sensor_dev_attr_temp1_max.dev_attr.attr, +	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,  	&dev_attr_alarms.attr,  	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,  	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,  	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,  	NULL  }; - -static const struct attribute_group lm92_group = { -	.attrs = lm92_attributes, -}; +ATTRIBUTE_GROUPS(lm92);  /* Return 0 if detection is successful, -ENODEV otherwise */  static int lm92_detect(struct i2c_client *new_client, @@ -345,51 +362,24 @@ static int lm92_detect(struct i2c_client *new_client,  static int lm92_probe(struct i2c_client *new_client,  		      const struct i2c_device_id *id)  { +	struct device *hwmon_dev;  	struct lm92_data *data; -	int err; -	data = kzalloc(sizeof(struct lm92_data), GFP_KERNEL); -	if (!data) { -		err = -ENOMEM; -		goto exit; -	} +	data = devm_kzalloc(&new_client->dev, sizeof(struct lm92_data), +			    GFP_KERNEL); +	if (!data) +		return -ENOMEM; -	i2c_set_clientdata(new_client, data); -	data->valid = 0; +	data->client = new_client;  	mutex_init(&data->update_lock);  	/* Initialize the chipset */  	lm92_init_client(new_client); -	/* Register sysfs hooks */ -	if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group))) -		goto exit_free; - -	data->hwmon_dev = hwmon_device_register(&new_client->dev); -	if (IS_ERR(data->hwmon_dev)) { -		err = PTR_ERR(data->hwmon_dev); -		goto exit_remove; -	} - -	return 0; - -exit_remove: -	sysfs_remove_group(&new_client->dev.kobj, &lm92_group); -exit_free: -	kfree(data); -exit: -	return err; -} - -static int lm92_remove(struct i2c_client *client) -{ -	struct lm92_data *data = i2c_get_clientdata(client); - -	hwmon_device_unregister(data->hwmon_dev); -	sysfs_remove_group(&client->dev.kobj, &lm92_group); - -	kfree(data); -	return 0; +	hwmon_dev = devm_hwmon_device_register_with_groups(&new_client->dev, +							   new_client->name, +							   data, lm92_groups); +	return PTR_ERR_OR_ZERO(hwmon_dev);  } @@ -410,25 +400,13 @@ static struct i2c_driver lm92_driver = {  		.name	= "lm92",  	},  	.probe		= lm92_probe, -	.remove		= lm92_remove,  	.id_table	= lm92_id,  	.detect		= lm92_detect,  	.address_list	= normal_i2c,  }; -static int __init sensors_lm92_init(void) -{ -	return i2c_add_driver(&lm92_driver); -} - -static void __exit sensors_lm92_exit(void) -{ -	i2c_del_driver(&lm92_driver); -} +module_i2c_driver(lm92_driver); -MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); +MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");  MODULE_DESCRIPTION("LM92/MAX6635 driver");  MODULE_LICENSE("GPL"); - -module_init(sensors_lm92_init); -module_exit(sensors_lm92_exit);  | 
