lm75.c 9.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
    lm75.c - Part of lm_sensors, Linux kernel modules for hardware
             monitoring
    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
26
#include <linux/hwmon.h>
27
#include <linux/hwmon-sysfs.h>
28
#include <linux/err.h>
29
#include <linux/mutex.h>
L
Linus Torvalds 已提交
30 31 32
#include "lm75.h"


D
David Brownell 已提交
33 34 35 36 37 38 39
/*
 * This driver handles the LM75 and compatible digital temperature sensors.
 * Compatibles include at least the DS75, DS1775, MCP980x, STDS75, TCN75,
 * TMP100, TMP101, TMP75, TMP175, and TMP275.
 */

/* Addresses scanned by legacy style driver binding */
40
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
L
Linus Torvalds 已提交
41 42
					0x4d, 0x4e, 0x4f, I2C_CLIENT_END };

D
David Brownell 已提交
43
/* Insmod parameters (only for legacy style driver binding) */
44
I2C_CLIENT_INSMOD_1(lm75);
L
Linus Torvalds 已提交
45 46 47 48


/* The LM75 registers */
#define LM75_REG_CONF		0x01
49 50 51 52 53
static const u8 LM75_REG_TEMP[3] = {
	0x00,		/* input */
	0x03,		/* max */
	0x02,		/* hyst */
};
L
Linus Torvalds 已提交
54 55 56 57

/* Each client has this additional data */
struct lm75_data {
	struct i2c_client	client;
D
David Brownell 已提交
58
	struct device		*hwmon_dev;
59
	struct mutex		update_lock;
D
David Brownell 已提交
60
	char			valid;		/* !=0 if registers are valid */
L
Linus Torvalds 已提交
61
	unsigned long		last_updated;	/* In jiffies */
62 63 64 65
	u16			temp[3];	/* Register values,
						   0 = input
						   1 = max
						   2 = hyst */
L
Linus Torvalds 已提交
66 67 68 69 70 71 72 73
};

static void lm75_init_client(struct i2c_client *client);
static int lm75_read_value(struct i2c_client *client, u8 reg);
static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value);
static struct lm75_data *lm75_update_device(struct device *dev);


D
David Brownell 已提交
74 75 76
/*-----------------------------------------------------------------------*/

/* sysfs attributes for hwmon */
L
Linus Torvalds 已提交
77

78 79 80 81 82 83 84
static ssize_t show_temp(struct device *dev, struct device_attribute *da,
			 char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct lm75_data *data = lm75_update_device(dev);
	return sprintf(buf, "%d\n",
		       LM75_TEMP_FROM_REG(data->temp[attr->index]));
L
Linus Torvalds 已提交
85
}
86 87 88 89 90 91 92 93

static ssize_t set_temp(struct device *dev, struct device_attribute *da,
			const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
	struct i2c_client *client = to_i2c_client(dev);
	struct lm75_data *data = i2c_get_clientdata(client);
	int nr = attr->index;
94
	long temp = simple_strtol(buf, NULL, 10);
95 96 97 98 99 100

	mutex_lock(&data->update_lock);
	data->temp[nr] = LM75_TEMP_TO_REG(temp);
	lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]);
	mutex_unlock(&data->update_lock);
	return count;
L
Linus Torvalds 已提交
101 102
}

103 104 105 106 107
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
			show_temp, set_temp, 1);
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
			show_temp, set_temp, 2);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
L
Linus Torvalds 已提交
108

109
static struct attribute *lm75_attributes[] = {
110 111 112
	&sensor_dev_attr_temp1_input.dev_attr.attr,
	&sensor_dev_attr_temp1_max.dev_attr.attr,
	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
113 114 115 116 117 118 119 120

	NULL
};

static const struct attribute_group lm75_group = {
	.attrs = lm75_attributes,
};

D
David Brownell 已提交
121 122 123 124 125 126
/*-----------------------------------------------------------------------*/

/* "Legacy" I2C driver binding */

static struct i2c_driver lm75_driver;

127
/* This function is called by i2c_probe */
L
Linus Torvalds 已提交
128 129 130 131 132 133 134 135 136 137 138
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
{
	int i;
	struct i2c_client *new_client;
	struct lm75_data *data;
	int err = 0;

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
				     I2C_FUNC_SMBUS_WORD_DATA))
		goto exit;

D
David Brownell 已提交
139 140 141
	/* OK. For now, we presume we have a valid address. We create the
	   client structure, even though there may be no sensor present.
	   But it allows us to use i2c_smbus_read_*_data() calls. */
D
Deepak Saxena 已提交
142
	if (!(data = kzalloc(sizeof(struct lm75_data), GFP_KERNEL))) {
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
		err = -ENOMEM;
		goto exit;
	}

	new_client = &data->client;
	i2c_set_clientdata(new_client, data);
	new_client->addr = address;
	new_client->adapter = adapter;
	new_client->driver = &lm75_driver;
	new_client->flags = 0;

	/* Now, we do the remaining detection. There is no identification-
	   dedicated register so we have to rely on several tricks:
	   unused bits, registers cycling over 8-address boundaries,
	   addresses 0x04-0x07 returning the last read value.
	   The cycling+unused addresses combination is not tested,
	   since it would significantly slow the detection down and would
	   hardly add any value. */
	if (kind < 0) {
		int cur, conf, hyst, os;

		/* Unused addresses */
		cur = i2c_smbus_read_word_data(new_client, 0);
		conf = i2c_smbus_read_byte_data(new_client, 1);
		hyst = i2c_smbus_read_word_data(new_client, 2);
		if (i2c_smbus_read_word_data(new_client, 4) != hyst
		 || i2c_smbus_read_word_data(new_client, 5) != hyst
		 || i2c_smbus_read_word_data(new_client, 6) != hyst
		 || i2c_smbus_read_word_data(new_client, 7) != hyst)
D
David Brownell 已提交
172
			goto exit_free;
L
Linus Torvalds 已提交
173 174 175 176 177
		os = i2c_smbus_read_word_data(new_client, 3);
		if (i2c_smbus_read_word_data(new_client, 4) != os
		 || i2c_smbus_read_word_data(new_client, 5) != os
		 || i2c_smbus_read_word_data(new_client, 6) != os
		 || i2c_smbus_read_word_data(new_client, 7) != os)
D
David Brownell 已提交
178
			goto exit_free;
L
Linus Torvalds 已提交
179 180 181

		/* Unused bits */
		if (conf & 0xe0)
D
David Brownell 已提交
182
			goto exit_free;
L
Linus Torvalds 已提交
183 184 185 186 187 188 189 190 191

		/* Addresses cycling */
		for (i = 8; i < 0xff; i += 8)
			if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
			 || i2c_smbus_read_word_data(new_client, i + 2) != hyst
			 || i2c_smbus_read_word_data(new_client, i + 3) != os)
				goto exit_free;
	}

D
David Brownell 已提交
192 193
	/* NOTE: we treat "force=..." and "force_lm75=..." the same. */
	strlcpy(new_client->name, "lm75", I2C_NAME_SIZE);
L
Linus Torvalds 已提交
194 195 196

	/* Fill in the remaining client fields and put it into the global list */
	data->valid = 0;
197
	mutex_init(&data->update_lock);
L
Linus Torvalds 已提交
198 199 200 201 202 203 204

	/* Tell the I2C layer a new client has arrived */
	if ((err = i2c_attach_client(new_client)))
		goto exit_free;

	/* Initialize the LM75 chip */
	lm75_init_client(new_client);
D
David Brownell 已提交
205

L
Linus Torvalds 已提交
206
	/* Register sysfs hooks */
207 208 209
	if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
		goto exit_detach;

210 211 212
	data->hwmon_dev = hwmon_device_register(&new_client->dev);
	if (IS_ERR(data->hwmon_dev)) {
		err = PTR_ERR(data->hwmon_dev);
213
		goto exit_remove;
214 215
	}

L
Linus Torvalds 已提交
216 217
	return 0;

218 219
exit_remove:
	sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
220 221
exit_detach:
	i2c_detach_client(new_client);
L
Linus Torvalds 已提交
222 223 224 225 226 227
exit_free:
	kfree(data);
exit:
	return err;
}

D
David Brownell 已提交
228 229 230 231 232 233 234
static int lm75_attach_adapter(struct i2c_adapter *adapter)
{
	if (!(adapter->class & I2C_CLASS_HWMON))
		return 0;
	return i2c_probe(adapter, &addr_data, lm75_detect);
}

L
Linus Torvalds 已提交
235 236
static int lm75_detach_client(struct i2c_client *client)
{
237
	struct lm75_data *data = i2c_get_clientdata(client);
238
	hwmon_device_unregister(data->hwmon_dev);
239
	sysfs_remove_group(&client->dev.kobj, &lm75_group);
L
Linus Torvalds 已提交
240
	i2c_detach_client(client);
241
	kfree(data);
L
Linus Torvalds 已提交
242 243 244
	return 0;
}

D
David Brownell 已提交
245 246 247 248 249 250 251 252 253 254 255 256
static struct i2c_driver lm75_driver = {
	.driver = {
		.name	= "lm75",
	},
	.attach_adapter	= lm75_attach_adapter,
	.detach_client	= lm75_detach_client,
};

/*-----------------------------------------------------------------------*/

/* register access */

L
Linus Torvalds 已提交
257 258
/* All registers are word-sized, except for the configuration register.
   LM75 uses a high-byte first convention, which is exactly opposite to
259
   the SMBus standard. */
L
Linus Torvalds 已提交
260 261
static int lm75_read_value(struct i2c_client *client, u8 reg)
{
262 263
	int value;

L
Linus Torvalds 已提交
264 265
	if (reg == LM75_REG_CONF)
		return i2c_smbus_read_byte_data(client, reg);
266 267 268

	value = i2c_smbus_read_word_data(client, reg);
	return (value < 0) ? value : swab16(value);
L
Linus Torvalds 已提交
269 270 271 272 273 274 275 276 277 278 279 280
}

static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
{
	if (reg == LM75_REG_CONF)
		return i2c_smbus_write_byte_data(client, reg, value);
	else
		return i2c_smbus_write_word_data(client, reg, swab16(value));
}

static void lm75_init_client(struct i2c_client *client)
{
281 282 283 284 285 286
	int reg;

	/* Enable if in shutdown mode */
	reg = lm75_read_value(client, LM75_REG_CONF);
	if (reg >= 0 && (reg & 0x01))
		lm75_write_value(client, LM75_REG_CONF, reg & 0xfe);
L
Linus Torvalds 已提交
287 288 289 290 291 292 293
}

static struct lm75_data *lm75_update_device(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct lm75_data *data = i2c_get_clientdata(client);

294
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
295 296 297

	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
	    || !data->valid) {
298
		int i;
L
Linus Torvalds 已提交
299 300
		dev_dbg(&client->dev, "Starting lm75 update\n");

301 302 303 304 305 306 307 308 309 310
		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
			int status;

			status = lm75_read_value(client, LM75_REG_TEMP[i]);
			if (status < 0)
				dev_dbg(&client->dev, "reg %d, err %d\n",
						LM75_REG_TEMP[i], status);
			else
				data->temp[i] = status;
		}
L
Linus Torvalds 已提交
311 312 313 314
		data->last_updated = jiffies;
		data->valid = 1;
	}

315
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
316 317 318 319

	return data;
}

D
David Brownell 已提交
320 321 322 323
/*-----------------------------------------------------------------------*/

/* module glue */

L
Linus Torvalds 已提交
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
static int __init sensors_lm75_init(void)
{
	return i2c_add_driver(&lm75_driver);
}

static void __exit sensors_lm75_exit(void)
{
	i2c_del_driver(&lm75_driver);
}

MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
MODULE_DESCRIPTION("LM75 driver");
MODULE_LICENSE("GPL");

module_init(sensors_lm75_init);
module_exit(sensors_lm75_exit);