xref: /openbmc/linux/drivers/hwmon/lm75.c (revision 1beeffe4)
18d5d45fbSJean Delvare /*
28d5d45fbSJean Delvare     lm75.c - Part of lm_sensors, Linux kernel modules for hardware
38d5d45fbSJean Delvare              monitoring
48d5d45fbSJean Delvare     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
58d5d45fbSJean Delvare 
68d5d45fbSJean Delvare     This program is free software; you can redistribute it and/or modify
78d5d45fbSJean Delvare     it under the terms of the GNU General Public License as published by
88d5d45fbSJean Delvare     the Free Software Foundation; either version 2 of the License, or
98d5d45fbSJean Delvare     (at your option) any later version.
108d5d45fbSJean Delvare 
118d5d45fbSJean Delvare     This program is distributed in the hope that it will be useful,
128d5d45fbSJean Delvare     but WITHOUT ANY WARRANTY; without even the implied warranty of
138d5d45fbSJean Delvare     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
148d5d45fbSJean Delvare     GNU General Public License for more details.
158d5d45fbSJean Delvare 
168d5d45fbSJean Delvare     You should have received a copy of the GNU General Public License
178d5d45fbSJean Delvare     along with this program; if not, write to the Free Software
188d5d45fbSJean Delvare     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
198d5d45fbSJean Delvare */
208d5d45fbSJean Delvare 
218d5d45fbSJean Delvare #include <linux/module.h>
228d5d45fbSJean Delvare #include <linux/init.h>
238d5d45fbSJean Delvare #include <linux/slab.h>
248d5d45fbSJean Delvare #include <linux/jiffies.h>
258d5d45fbSJean Delvare #include <linux/i2c.h>
26943b0830SMark M. Hoffman #include <linux/hwmon.h>
279ca8e40cSJean Delvare #include <linux/hwmon-sysfs.h>
28943b0830SMark M. Hoffman #include <linux/err.h>
299a61bf63SIngo Molnar #include <linux/mutex.h>
308d5d45fbSJean Delvare #include "lm75.h"
318d5d45fbSJean Delvare 
328d5d45fbSJean Delvare 
338d5d45fbSJean Delvare /* Addresses to scan */
348d5d45fbSJean Delvare static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
358d5d45fbSJean Delvare 					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
368d5d45fbSJean Delvare 
378d5d45fbSJean Delvare /* Insmod parameters */
38f4b50261SJean Delvare I2C_CLIENT_INSMOD_1(lm75);
398d5d45fbSJean Delvare 
408d5d45fbSJean Delvare /* Many LM75 constants specified below */
418d5d45fbSJean Delvare 
428d5d45fbSJean Delvare /* The LM75 registers */
438d5d45fbSJean Delvare #define LM75_REG_CONF		0x01
449ca8e40cSJean Delvare static const u8 LM75_REG_TEMP[3] = {
459ca8e40cSJean Delvare 	0x00,		/* input */
469ca8e40cSJean Delvare 	0x03,		/* max */
479ca8e40cSJean Delvare 	0x02,		/* hyst */
489ca8e40cSJean Delvare };
498d5d45fbSJean Delvare 
508d5d45fbSJean Delvare /* Each client has this additional data */
518d5d45fbSJean Delvare struct lm75_data {
528d5d45fbSJean Delvare 	struct i2c_client	client;
531beeffe4STony Jones 	struct device *hwmon_dev;
549a61bf63SIngo Molnar 	struct mutex		update_lock;
558d5d45fbSJean Delvare 	char			valid;		/* !=0 if following fields are valid */
568d5d45fbSJean Delvare 	unsigned long		last_updated;	/* In jiffies */
579ca8e40cSJean Delvare 	u16			temp[3];	/* Register values,
589ca8e40cSJean Delvare 						   0 = input
599ca8e40cSJean Delvare 						   1 = max
609ca8e40cSJean Delvare 						   2 = hyst */
618d5d45fbSJean Delvare };
628d5d45fbSJean Delvare 
638d5d45fbSJean Delvare static int lm75_attach_adapter(struct i2c_adapter *adapter);
648d5d45fbSJean Delvare static int lm75_detect(struct i2c_adapter *adapter, int address, int kind);
658d5d45fbSJean Delvare static void lm75_init_client(struct i2c_client *client);
668d5d45fbSJean Delvare static int lm75_detach_client(struct i2c_client *client);
678d5d45fbSJean Delvare static int lm75_read_value(struct i2c_client *client, u8 reg);
688d5d45fbSJean Delvare static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
698d5d45fbSJean Delvare static struct lm75_data *lm75_update_device(struct device *dev);
708d5d45fbSJean Delvare 
718d5d45fbSJean Delvare 
728d5d45fbSJean Delvare /* This is the driver that will be inserted */
738d5d45fbSJean Delvare static struct i2c_driver lm75_driver = {
74cdaf7934SLaurent Riffard 	.driver = {
758d5d45fbSJean Delvare 		.name	= "lm75",
76cdaf7934SLaurent Riffard 	},
778d5d45fbSJean Delvare 	.id		= I2C_DRIVERID_LM75,
788d5d45fbSJean Delvare 	.attach_adapter	= lm75_attach_adapter,
798d5d45fbSJean Delvare 	.detach_client	= lm75_detach_client,
808d5d45fbSJean Delvare };
818d5d45fbSJean Delvare 
829ca8e40cSJean Delvare static ssize_t show_temp(struct device *dev, struct device_attribute *da,
839ca8e40cSJean Delvare 			 char *buf)
849ca8e40cSJean Delvare {
859ca8e40cSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
869ca8e40cSJean Delvare 	struct lm75_data *data = lm75_update_device(dev);
879ca8e40cSJean Delvare 	return sprintf(buf, "%d\n",
889ca8e40cSJean Delvare 		       LM75_TEMP_FROM_REG(data->temp[attr->index]));
898d5d45fbSJean Delvare }
908d5d45fbSJean Delvare 
919ca8e40cSJean Delvare static ssize_t set_temp(struct device *dev, struct device_attribute *da,
929ca8e40cSJean Delvare 			const char *buf, size_t count)
939ca8e40cSJean Delvare {
949ca8e40cSJean Delvare 	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
959ca8e40cSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
969ca8e40cSJean Delvare 	struct lm75_data *data = i2c_get_clientdata(client);
979ca8e40cSJean Delvare 	int nr = attr->index;
985bfedac0SChristian Hohnstaedt 	long temp = simple_strtol(buf, NULL, 10);
999ca8e40cSJean Delvare 
1009ca8e40cSJean Delvare 	mutex_lock(&data->update_lock);
1019ca8e40cSJean Delvare 	data->temp[nr] = LM75_TEMP_TO_REG(temp);
1029ca8e40cSJean Delvare 	lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]);
1039ca8e40cSJean Delvare 	mutex_unlock(&data->update_lock);
1049ca8e40cSJean Delvare 	return count;
1058d5d45fbSJean Delvare }
1068d5d45fbSJean Delvare 
1079ca8e40cSJean Delvare static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
1089ca8e40cSJean Delvare 			show_temp, set_temp, 1);
1099ca8e40cSJean Delvare static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
1109ca8e40cSJean Delvare 			show_temp, set_temp, 2);
1119ca8e40cSJean Delvare static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
1128d5d45fbSJean Delvare 
1138d5d45fbSJean Delvare static int lm75_attach_adapter(struct i2c_adapter *adapter)
1148d5d45fbSJean Delvare {
1158d5d45fbSJean Delvare 	if (!(adapter->class & I2C_CLASS_HWMON))
1168d5d45fbSJean Delvare 		return 0;
1172ed2dc3cSJean Delvare 	return i2c_probe(adapter, &addr_data, lm75_detect);
1188d5d45fbSJean Delvare }
1198d5d45fbSJean Delvare 
120c1685f61SMark M. Hoffman static struct attribute *lm75_attributes[] = {
1219ca8e40cSJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
1229ca8e40cSJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
1239ca8e40cSJean Delvare 	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
124c1685f61SMark M. Hoffman 
125c1685f61SMark M. Hoffman 	NULL
126c1685f61SMark M. Hoffman };
127c1685f61SMark M. Hoffman 
128c1685f61SMark M. Hoffman static const struct attribute_group lm75_group = {
129c1685f61SMark M. Hoffman 	.attrs = lm75_attributes,
130c1685f61SMark M. Hoffman };
131c1685f61SMark M. Hoffman 
1322ed2dc3cSJean Delvare /* This function is called by i2c_probe */
1338d5d45fbSJean Delvare static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
1348d5d45fbSJean Delvare {
1358d5d45fbSJean Delvare 	int i;
1368d5d45fbSJean Delvare 	struct i2c_client *new_client;
1378d5d45fbSJean Delvare 	struct lm75_data *data;
1388d5d45fbSJean Delvare 	int err = 0;
1398d5d45fbSJean Delvare 	const char *name = "";
1408d5d45fbSJean Delvare 
1418d5d45fbSJean Delvare 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
1428d5d45fbSJean Delvare 				     I2C_FUNC_SMBUS_WORD_DATA))
1438d5d45fbSJean Delvare 		goto exit;
1448d5d45fbSJean Delvare 
1458d5d45fbSJean Delvare 	/* OK. For now, we presume we have a valid client. We now create the
1468d5d45fbSJean Delvare 	   client structure, even though we cannot fill it completely yet.
1478d5d45fbSJean Delvare 	   But it allows us to access lm75_{read,write}_value. */
148ba9c2e8dSDeepak Saxena 	if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) {
1498d5d45fbSJean Delvare 		err = -ENOMEM;
1508d5d45fbSJean Delvare 		goto exit;
1518d5d45fbSJean Delvare 	}
1528d5d45fbSJean Delvare 
1538d5d45fbSJean Delvare 	new_client = &data->client;
1548d5d45fbSJean Delvare 	i2c_set_clientdata(new_client, data);
1558d5d45fbSJean Delvare 	new_client->addr = address;
1568d5d45fbSJean Delvare 	new_client->adapter = adapter;
1578d5d45fbSJean Delvare 	new_client->driver = &lm75_driver;
1588d5d45fbSJean Delvare 	new_client->flags = 0;
1598d5d45fbSJean Delvare 
1608d5d45fbSJean Delvare 	/* Now, we do the remaining detection. There is no identification-
1618d5d45fbSJean Delvare 	   dedicated register so we have to rely on several tricks:
1628d5d45fbSJean Delvare 	   unused bits, registers cycling over 8-address boundaries,
1638d5d45fbSJean Delvare 	   addresses 0x04-0x07 returning the last read value.
1648d5d45fbSJean Delvare 	   The cycling+unused addresses combination is not tested,
1658d5d45fbSJean Delvare 	   since it would significantly slow the detection down and would
1668d5d45fbSJean Delvare 	   hardly add any value. */
1678d5d45fbSJean Delvare 	if (kind < 0) {
1688d5d45fbSJean Delvare 		int cur, conf, hyst, os;
1698d5d45fbSJean Delvare 
1708d5d45fbSJean Delvare 		/* Unused addresses */
1718d5d45fbSJean Delvare 		cur = i2c_smbus_read_word_data(new_client, 0);
1728d5d45fbSJean Delvare 		conf = i2c_smbus_read_byte_data(new_client, 1);
1738d5d45fbSJean Delvare 		hyst = i2c_smbus_read_word_data(new_client, 2);
1748d5d45fbSJean Delvare 		if (i2c_smbus_read_word_data(new_client, 4) != hyst
1758d5d45fbSJean Delvare 		 || i2c_smbus_read_word_data(new_client, 5) != hyst
1768d5d45fbSJean Delvare 		 || i2c_smbus_read_word_data(new_client, 6) != hyst
1778d5d45fbSJean Delvare 		 || i2c_smbus_read_word_data(new_client, 7) != hyst)
1788d5d45fbSJean Delvare 		 	goto exit_free;
1798d5d45fbSJean Delvare 		os = i2c_smbus_read_word_data(new_client, 3);
1808d5d45fbSJean Delvare 		if (i2c_smbus_read_word_data(new_client, 4) != os
1818d5d45fbSJean Delvare 		 || i2c_smbus_read_word_data(new_client, 5) != os
1828d5d45fbSJean Delvare 		 || i2c_smbus_read_word_data(new_client, 6) != os
1838d5d45fbSJean Delvare 		 || i2c_smbus_read_word_data(new_client, 7) != os)
1848d5d45fbSJean Delvare 		 	goto exit_free;
1858d5d45fbSJean Delvare 
1868d5d45fbSJean Delvare 		/* Unused bits */
1878d5d45fbSJean Delvare 		if (conf & 0xe0)
1888d5d45fbSJean Delvare 		 	goto exit_free;
1898d5d45fbSJean Delvare 
1908d5d45fbSJean Delvare 		/* Addresses cycling */
1918d5d45fbSJean Delvare 		for (i = 8; i < 0xff; i += 8)
1928d5d45fbSJean Delvare 			if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
1938d5d45fbSJean Delvare 			 || i2c_smbus_read_word_data(new_client, i + 2) != hyst
1948d5d45fbSJean Delvare 			 || i2c_smbus_read_word_data(new_client, i + 3) != os)
1958d5d45fbSJean Delvare 				goto exit_free;
1968d5d45fbSJean Delvare 	}
1978d5d45fbSJean Delvare 
1988d5d45fbSJean Delvare 	/* Determine the chip type - only one kind supported! */
1998d5d45fbSJean Delvare 	if (kind <= 0)
2008d5d45fbSJean Delvare 		kind = lm75;
2018d5d45fbSJean Delvare 
2028d5d45fbSJean Delvare 	if (kind == lm75) {
2038d5d45fbSJean Delvare 		name = "lm75";
2048d5d45fbSJean Delvare 	}
2058d5d45fbSJean Delvare 
2068d5d45fbSJean Delvare 	/* Fill in the remaining client fields and put it into the global list */
2078d5d45fbSJean Delvare 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
2088d5d45fbSJean Delvare 	data->valid = 0;
2099a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
2108d5d45fbSJean Delvare 
2118d5d45fbSJean Delvare 	/* Tell the I2C layer a new client has arrived */
2128d5d45fbSJean Delvare 	if ((err = i2c_attach_client(new_client)))
2138d5d45fbSJean Delvare 		goto exit_free;
2148d5d45fbSJean Delvare 
2158d5d45fbSJean Delvare 	/* Initialize the LM75 chip */
2168d5d45fbSJean Delvare 	lm75_init_client(new_client);
2178d5d45fbSJean Delvare 
2188d5d45fbSJean Delvare 	/* Register sysfs hooks */
219c1685f61SMark M. Hoffman 	if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
220c1685f61SMark M. Hoffman 		goto exit_detach;
221c1685f61SMark M. Hoffman 
2221beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(&new_client->dev);
2231beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
2241beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
225c1685f61SMark M. Hoffman 		goto exit_remove;
226943b0830SMark M. Hoffman 	}
227943b0830SMark M. Hoffman 
2288d5d45fbSJean Delvare 	return 0;
2298d5d45fbSJean Delvare 
230c1685f61SMark M. Hoffman exit_remove:
231c1685f61SMark M. Hoffman 	sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
232943b0830SMark M. Hoffman exit_detach:
233943b0830SMark M. Hoffman 	i2c_detach_client(new_client);
2348d5d45fbSJean Delvare exit_free:
2358d5d45fbSJean Delvare 	kfree(data);
2368d5d45fbSJean Delvare exit:
2378d5d45fbSJean Delvare 	return err;
2388d5d45fbSJean Delvare }
2398d5d45fbSJean Delvare 
2408d5d45fbSJean Delvare static int lm75_detach_client(struct i2c_client *client)
2418d5d45fbSJean Delvare {
242943b0830SMark M. Hoffman 	struct lm75_data *data = i2c_get_clientdata(client);
2431beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
244c1685f61SMark M. Hoffman 	sysfs_remove_group(&client->dev.kobj, &lm75_group);
2458d5d45fbSJean Delvare 	i2c_detach_client(client);
246943b0830SMark M. Hoffman 	kfree(data);
2478d5d45fbSJean Delvare 	return 0;
2488d5d45fbSJean Delvare }
2498d5d45fbSJean Delvare 
2508d5d45fbSJean Delvare /* All registers are word-sized, except for the configuration register.
2518d5d45fbSJean Delvare    LM75 uses a high-byte first convention, which is exactly opposite to
2528d5d45fbSJean Delvare    the usual practice. */
2538d5d45fbSJean Delvare static int lm75_read_value(struct i2c_client *client, u8 reg)
2548d5d45fbSJean Delvare {
2558d5d45fbSJean Delvare 	if (reg == LM75_REG_CONF)
2568d5d45fbSJean Delvare 		return i2c_smbus_read_byte_data(client, reg);
2578d5d45fbSJean Delvare 	else
2588d5d45fbSJean Delvare 		return swab16(i2c_smbus_read_word_data(client, reg));
2598d5d45fbSJean Delvare }
2608d5d45fbSJean Delvare 
2618d5d45fbSJean Delvare /* All registers are word-sized, except for the configuration register.
2628d5d45fbSJean Delvare    LM75 uses a high-byte first convention, which is exactly opposite to
2638d5d45fbSJean Delvare    the usual practice. */
2648d5d45fbSJean Delvare static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
2658d5d45fbSJean Delvare {
2668d5d45fbSJean Delvare 	if (reg == LM75_REG_CONF)
2678d5d45fbSJean Delvare 		return i2c_smbus_write_byte_data(client, reg, value);
2688d5d45fbSJean Delvare 	else
2698d5d45fbSJean Delvare 		return i2c_smbus_write_word_data(client, reg, swab16(value));
2708d5d45fbSJean Delvare }
2718d5d45fbSJean Delvare 
2728d5d45fbSJean Delvare static void lm75_init_client(struct i2c_client *client)
2738d5d45fbSJean Delvare {
274e647ecf1SJean Delvare 	int reg;
275e647ecf1SJean Delvare 
276e647ecf1SJean Delvare 	/* Enable if in shutdown mode */
277e647ecf1SJean Delvare 	reg = lm75_read_value(client, LM75_REG_CONF);
278e647ecf1SJean Delvare 	if (reg >= 0 && (reg & 0x01))
279e647ecf1SJean Delvare 		lm75_write_value(client, LM75_REG_CONF, reg & 0xfe);
2808d5d45fbSJean Delvare }
2818d5d45fbSJean Delvare 
2828d5d45fbSJean Delvare static struct lm75_data *lm75_update_device(struct device *dev)
2838d5d45fbSJean Delvare {
2848d5d45fbSJean Delvare 	struct i2c_client *client = to_i2c_client(dev);
2858d5d45fbSJean Delvare 	struct lm75_data *data = i2c_get_clientdata(client);
2868d5d45fbSJean Delvare 
2879a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
2888d5d45fbSJean Delvare 
2898d5d45fbSJean Delvare 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
2908d5d45fbSJean Delvare 	    || !data->valid) {
2919ca8e40cSJean Delvare 		int i;
2928d5d45fbSJean Delvare 		dev_dbg(&client->dev, "Starting lm75 update\n");
2938d5d45fbSJean Delvare 
2949ca8e40cSJean Delvare 		for (i = 0; i < ARRAY_SIZE(data->temp); i++)
2959ca8e40cSJean Delvare 			data->temp[i] = lm75_read_value(client,
2969ca8e40cSJean Delvare 							LM75_REG_TEMP[i]);
2978d5d45fbSJean Delvare 		data->last_updated = jiffies;
2988d5d45fbSJean Delvare 		data->valid = 1;
2998d5d45fbSJean Delvare 	}
3008d5d45fbSJean Delvare 
3019a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
3028d5d45fbSJean Delvare 
3038d5d45fbSJean Delvare 	return data;
3048d5d45fbSJean Delvare }
3058d5d45fbSJean Delvare 
3068d5d45fbSJean Delvare static int __init sensors_lm75_init(void)
3078d5d45fbSJean Delvare {
3088d5d45fbSJean Delvare 	return i2c_add_driver(&lm75_driver);
3098d5d45fbSJean Delvare }
3108d5d45fbSJean Delvare 
3118d5d45fbSJean Delvare static void __exit sensors_lm75_exit(void)
3128d5d45fbSJean Delvare {
3138d5d45fbSJean Delvare 	i2c_del_driver(&lm75_driver);
3148d5d45fbSJean Delvare }
3158d5d45fbSJean Delvare 
3168d5d45fbSJean Delvare MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
3178d5d45fbSJean Delvare MODULE_DESCRIPTION("LM75 driver");
3188d5d45fbSJean Delvare MODULE_LICENSE("GPL");
3198d5d45fbSJean Delvare 
3208d5d45fbSJean Delvare module_init(sensors_lm75_init);
3218d5d45fbSJean Delvare module_exit(sensors_lm75_exit);
322