lm83.c 12.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * lm83.c - Part of lm_sensors, Linux kernel modules for hardware
 *          monitoring
4
 * Copyright (C) 2003-2009  Jean Delvare <khali@linux-fr.org>
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14
 *
 * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
 * a sensor chip made by National Semiconductor. It reports up to four
 * temperatures (its own plus up to three external ones) with a 1 deg
 * resolution and a 3-4 deg accuracy. Complete datasheet can be obtained
 * from National's website at:
 *   http://www.national.com/pf/LM/LM83.html
 * Since the datasheet omits to give the chip stepping code, I give it
 * here: 0x03 (at register 0xff).
 *
J
Jordan Crouse 已提交
15 16 17 18
 * Also supports the LM82 temp sensor, which is basically a stripped down
 * model of the LM83.  Datasheet is here:
 * http://www.national.com/pf/LM/LM82.html
 *
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 * 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>
39
#include <linux/hwmon-sysfs.h>
40 41
#include <linux/hwmon.h>
#include <linux/err.h>
42
#include <linux/mutex.h>
43
#include <linux/sysfs.h>
L
Linus Torvalds 已提交
44 45 46 47 48 49 50

/*
 * Addresses to scan
 * Address is selected using 2 three-level pins, resulting in 9 possible
 * addresses.
 */

51 52
static const unsigned short normal_i2c[] = {
	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
L
Linus Torvalds 已提交
53

J
Jean Delvare 已提交
54
enum chips { lm83, lm82 };
L
Linus Torvalds 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

/*
 * The LM83 registers
 * Manufacturer ID is 0x01 for National Semiconductor.
 */

#define LM83_REG_R_MAN_ID		0xFE
#define LM83_REG_R_CHIP_ID		0xFF
#define LM83_REG_R_CONFIG		0x03
#define LM83_REG_W_CONFIG		0x09
#define LM83_REG_R_STATUS1		0x02
#define LM83_REG_R_STATUS2		0x35
#define LM83_REG_R_LOCAL_TEMP		0x00
#define LM83_REG_R_LOCAL_HIGH		0x05
#define LM83_REG_W_LOCAL_HIGH		0x0B
#define LM83_REG_R_REMOTE1_TEMP		0x30
#define LM83_REG_R_REMOTE1_HIGH		0x38
#define LM83_REG_W_REMOTE1_HIGH		0x50
#define LM83_REG_R_REMOTE2_TEMP		0x01
#define LM83_REG_R_REMOTE2_HIGH		0x07
#define LM83_REG_W_REMOTE2_HIGH		0x0D
#define LM83_REG_R_REMOTE3_TEMP		0x31
#define LM83_REG_R_REMOTE3_HIGH		0x3A
#define LM83_REG_W_REMOTE3_HIGH		0x52
#define LM83_REG_R_TCRIT		0x42
#define LM83_REG_W_TCRIT		0x5A

/*
 * Conversions and various macros
84
 * The LM83 uses signed 8-bit values with LSB = 1 degree Celsius.
L
Linus Torvalds 已提交
85 86 87 88 89 90 91 92 93 94 95 96
 */

#define TEMP_FROM_REG(val)	((val) * 1000)
#define TEMP_TO_REG(val)	((val) <= -128000 ? -128 : \
				 (val) >= 127000 ? 127 : \
				 (val) < 0 ? ((val) - 500) / 1000 : \
				 ((val) + 500) / 1000)

static const u8 LM83_REG_R_TEMP[] = {
	LM83_REG_R_LOCAL_TEMP,
	LM83_REG_R_REMOTE1_TEMP,
	LM83_REG_R_REMOTE2_TEMP,
97
	LM83_REG_R_REMOTE3_TEMP,
L
Linus Torvalds 已提交
98 99 100
	LM83_REG_R_LOCAL_HIGH,
	LM83_REG_R_REMOTE1_HIGH,
	LM83_REG_R_REMOTE2_HIGH,
101 102
	LM83_REG_R_REMOTE3_HIGH,
	LM83_REG_R_TCRIT,
L
Linus Torvalds 已提交
103 104 105 106 107 108
};

static const u8 LM83_REG_W_HIGH[] = {
	LM83_REG_W_LOCAL_HIGH,
	LM83_REG_W_REMOTE1_HIGH,
	LM83_REG_W_REMOTE2_HIGH,
109 110
	LM83_REG_W_REMOTE3_HIGH,
	LM83_REG_W_TCRIT,
L
Linus Torvalds 已提交
111 112 113 114 115 116
};

/*
 * Functions declaration
 */

117
static int lm83_detect(struct i2c_client *new_client,
118 119 120 121
		       struct i2c_board_info *info);
static int lm83_probe(struct i2c_client *client,
		      const struct i2c_device_id *id);
static int lm83_remove(struct i2c_client *client);
L
Linus Torvalds 已提交
122 123 124 125 126
static struct lm83_data *lm83_update_device(struct device *dev);

/*
 * Driver data (common to all clients)
 */
127

128 129 130 131 132 133 134
static const struct i2c_device_id lm83_id[] = {
	{ "lm83", lm83 },
	{ "lm82", lm82 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, lm83_id);

L
Linus Torvalds 已提交
135
static struct i2c_driver lm83_driver = {
136
	.class		= I2C_CLASS_HWMON,
137 138 139
	.driver = {
		.name	= "lm83",
	},
140 141 142 143
	.probe		= lm83_probe,
	.remove		= lm83_remove,
	.id_table	= lm83_id,
	.detect		= lm83_detect,
144
	.address_list	= normal_i2c,
L
Linus Torvalds 已提交
145 146 147 148 149 150 151
};

/*
 * Client data (each client gets its own)
 */

struct lm83_data {
152
	struct device *hwmon_dev;
153
	struct mutex update_lock;
L
Linus Torvalds 已提交
154 155 156 157
	char valid; /* zero until following fields are valid */
	unsigned long last_updated; /* in jiffies */

	/* registers values */
158 159 160
	s8 temp[9];	/* 0..3: input 1-4,
			   4..7: high limit 1-4,
			   8   : critical limit */
L
Linus Torvalds 已提交
161 162 163 164 165 166 167
	u16 alarms; /* bitvector, combined */
};

/*
 * Sysfs stuff
 */

168 169 170 171 172 173
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 lm83_data *data = lm83_update_device(dev);
	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
L
Linus Torvalds 已提交
174
}
175 176 177 178 179 180 181

static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
			const char *buf, size_t count)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct i2c_client *client = to_i2c_client(dev);
	struct lm83_data *data = i2c_get_clientdata(client);
182
	long val;
183
	int nr = attr->index;
184 185 186 187 188
	int err;

	err = kstrtol(buf, 10, &val);
	if (err < 0)
		return err;
189

190
	mutex_lock(&data->update_lock);
191 192 193
	data->temp[nr] = TEMP_TO_REG(val);
	i2c_smbus_write_byte_data(client, LM83_REG_W_HIGH[nr - 4],
				  data->temp[nr]);
194
	mutex_unlock(&data->update_lock);
195
	return count;
L
Linus Torvalds 已提交
196 197
}

198 199
static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
			   char *buf)
L
Linus Torvalds 已提交
200 201 202 203 204
{
	struct lm83_data *data = lm83_update_device(dev);
	return sprintf(buf, "%d\n", data->alarms);
}

205 206 207 208 209 210 211 212 213 214
static ssize_t show_alarm(struct device *dev, struct device_attribute
			  *devattr, char *buf)
{
	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
	struct lm83_data *data = lm83_update_device(dev);
	int bitnr = attr->index;

	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp,
	set_temp, 4);
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp,
	set_temp, 5);
static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp,
	set_temp, 6);
static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp,
	set_temp, 7);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, 8);
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
	set_temp, 8);
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
232 233 234 235

/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
236
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
237 238 239 240
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
241
static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
242
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
243
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
244 245
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
/* Raw alarm file for compatibility */
L
Linus Torvalds 已提交
246 247
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);

248 249 250 251 252 253 254 255 256 257
static struct attribute *lm83_attributes[] = {
	&sensor_dev_attr_temp1_input.dev_attr.attr,
	&sensor_dev_attr_temp3_input.dev_attr.attr,
	&sensor_dev_attr_temp1_max.dev_attr.attr,
	&sensor_dev_attr_temp3_max.dev_attr.attr,
	&sensor_dev_attr_temp1_crit.dev_attr.attr,
	&sensor_dev_attr_temp3_crit.dev_attr.attr,

	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
258
	&sensor_dev_attr_temp3_fault.dev_attr.attr,
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
	&dev_attr_alarms.attr,
	NULL
};

static const struct attribute_group lm83_group = {
	.attrs = lm83_attributes,
};

static struct attribute *lm83_attributes_opt[] = {
	&sensor_dev_attr_temp2_input.dev_attr.attr,
	&sensor_dev_attr_temp4_input.dev_attr.attr,
	&sensor_dev_attr_temp2_max.dev_attr.attr,
	&sensor_dev_attr_temp4_max.dev_attr.attr,
	&sensor_dev_attr_temp2_crit.dev_attr.attr,
	&sensor_dev_attr_temp4_crit.dev_attr.attr,

	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
	&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
279
	&sensor_dev_attr_temp4_fault.dev_attr.attr,
280
	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
281
	&sensor_dev_attr_temp2_fault.dev_attr.attr,
282 283 284 285 286 287 288 289
	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
	NULL
};

static const struct attribute_group lm83_group_opt = {
	.attrs = lm83_attributes_opt,
};

L
Linus Torvalds 已提交
290 291 292 293
/*
 * Real code
 */

294
/* Return 0 if detection is successful, -ENODEV otherwise */
295
static int lm83_detect(struct i2c_client *new_client,
296
		       struct i2c_board_info *info)
L
Linus Torvalds 已提交
297
{
298
	struct i2c_adapter *adapter = new_client->adapter;
299 300
	const char *name;
	u8 man_id, chip_id;
L
Linus Torvalds 已提交
301 302

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
303
		return -ENODEV;
L
Linus Torvalds 已提交
304

305 306 307 308 309 310 311
	/* Detection */
	if ((i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS1) & 0xA8) ||
	    (i2c_smbus_read_byte_data(new_client, LM83_REG_R_STATUS2) & 0x48) ||
	    (i2c_smbus_read_byte_data(new_client, LM83_REG_R_CONFIG) & 0x41)) {
		dev_dbg(&adapter->dev, "LM83 detection failed at 0x%02x\n",
			new_client->addr);
		return -ENODEV;
L
Linus Torvalds 已提交
312 313
	}

314 315 316 317
	/* Identification */
	man_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_MAN_ID);
	if (man_id != 0x01)	/* National Semiconductor */
		return -ENODEV;
L
Linus Torvalds 已提交
318

319 320 321
	chip_id = i2c_smbus_read_byte_data(new_client, LM83_REG_R_CHIP_ID);
	switch (chip_id) {
	case 0x03:
L
Linus Torvalds 已提交
322
		name = "lm83";
323 324
		break;
	case 0x01:
J
Jordan Crouse 已提交
325
		name = "lm82";
326 327 328 329 330 331 332
		break;
	default:
		/* identification failed */
		dev_info(&adapter->dev,
			 "Unsupported chip (man_id=0x%02X, chip_id=0x%02X)\n",
			 man_id, chip_id);
		return -ENODEV;
L
Linus Torvalds 已提交
333 334
	}

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
	strlcpy(info->type, name, I2C_NAME_SIZE);

	return 0;
}

static int lm83_probe(struct i2c_client *new_client,
		      const struct i2c_device_id *id)
{
	struct lm83_data *data;
	int err;

	data = kzalloc(sizeof(struct lm83_data), GFP_KERNEL);
	if (!data) {
		err = -ENOMEM;
		goto exit;
	}

	i2c_set_clientdata(new_client, data);
L
Linus Torvalds 已提交
353
	data->valid = 0;
354
	mutex_init(&data->update_lock);
L
Linus Torvalds 已提交
355 356

	/*
357
	 * Register sysfs hooks
J
Jordan Crouse 已提交
358 359 360 361 362
	 * The LM82 can only monitor one external diode which is
	 * at the same register as the LM83 temp3 entry - so we
	 * declare 1 and 3 common, and then 2 and 4 only for the LM83.
	 */

363 364
	err = sysfs_create_group(&new_client->dev.kobj, &lm83_group);
	if (err)
365
		goto exit_free;
L
Linus Torvalds 已提交
366

367
	if (id->driver_data == lm83) {
368 369 370
		err = sysfs_create_group(&new_client->dev.kobj,
					 &lm83_group_opt);
		if (err)
371 372 373
			goto exit_remove_files;
	}

374 375 376
	data->hwmon_dev = hwmon_device_register(&new_client->dev);
	if (IS_ERR(data->hwmon_dev)) {
		err = PTR_ERR(data->hwmon_dev);
377
		goto exit_remove_files;
J
Jordan Crouse 已提交
378 379
	}

L
Linus Torvalds 已提交
380 381
	return 0;

382 383 384
exit_remove_files:
	sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
	sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
L
Linus Torvalds 已提交
385 386 387 388 389 390
exit_free:
	kfree(data);
exit:
	return err;
}

391
static int lm83_remove(struct i2c_client *client)
L
Linus Torvalds 已提交
392
{
393
	struct lm83_data *data = i2c_get_clientdata(client);
L
Linus Torvalds 已提交
394

395
	hwmon_device_unregister(data->hwmon_dev);
396 397
	sysfs_remove_group(&client->dev.kobj, &lm83_group);
	sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
398 399

	kfree(data);
L
Linus Torvalds 已提交
400 401 402 403 404 405 406 407
	return 0;
}

static struct lm83_data *lm83_update_device(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct lm83_data *data = i2c_get_clientdata(client);

408
	mutex_lock(&data->update_lock);
L
Linus Torvalds 已提交
409 410 411 412 413

	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
		int nr;

		dev_dbg(&client->dev, "Updating lm83 data.\n");
414 415
		for (nr = 0; nr < 9; nr++) {
			data->temp[nr] =
L
Linus Torvalds 已提交
416 417 418 419 420 421 422 423 424 425 426 427
			    i2c_smbus_read_byte_data(client,
			    LM83_REG_R_TEMP[nr]);
		}
		data->alarms =
		    i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS1)
		    + (i2c_smbus_read_byte_data(client, LM83_REG_R_STATUS2)
		    << 8);

		data->last_updated = jiffies;
		data->valid = 1;
	}

428
	mutex_unlock(&data->update_lock);
L
Linus Torvalds 已提交
429 430 431 432

	return data;
}

433
module_i2c_driver(lm83_driver);
L
Linus Torvalds 已提交
434 435 436 437

MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("LM83 driver");
MODULE_LICENSE("GPL");