Blame view

drivers/hwmon/lm80.c 19.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  /*
   * lm80.c - From lm_sensors, Linux kernel modules for hardware
   * monitoring
   * Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
   * and Philip Edelbrock <phil@netroedge.com>
   *
   * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org>
   *
   * 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.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/jiffies.h>
  #include <linux/i2c.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
28
  #include <linux/hwmon.h>
f8181762a   Jean Delvare   hwmon: (lm80) De-...
29
  #include <linux/hwmon-sysfs.h>
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
30
  #include <linux/err.h>
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
31
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  
  /* Addresses to scan */
25e9c86d5   Mark M. Hoffman   hwmon: normal_i2c...
34
35
  static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
  						0x2e, 0x2f, I2C_CLIENT_END };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  /* Many LM80 constants specified below */
  
  /* The LM80 registers */
  #define LM80_REG_IN_MAX(nr)		(0x2a + (nr) * 2)
  #define LM80_REG_IN_MIN(nr)		(0x2b + (nr) * 2)
  #define LM80_REG_IN(nr)			(0x20 + (nr))
  
  #define LM80_REG_FAN1			0x28
  #define LM80_REG_FAN2			0x29
  #define LM80_REG_FAN_MIN(nr)		(0x3b + (nr))
  
  #define LM80_REG_TEMP			0x27
  #define LM80_REG_TEMP_HOT_MAX		0x38
  #define LM80_REG_TEMP_HOT_HYST		0x39
  #define LM80_REG_TEMP_OS_MAX		0x3a
  #define LM80_REG_TEMP_OS_HYST		0x3b
  
  #define LM80_REG_CONFIG			0x00
  #define LM80_REG_ALARM1			0x01
  #define LM80_REG_ALARM2			0x02
  #define LM80_REG_MASK1			0x03
  #define LM80_REG_MASK2			0x04
  #define LM80_REG_FANDIV			0x05
  #define LM80_REG_RES			0x06
  
  
  /* Conversions. Rounding and limit checking is only done on the TO_REG
     variants. Note that you should be a bit careful with which arguments
     these macros are called: arguments may be evaluated more than once.
     Fixing this is just not worth it. */
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
67
68
  #define IN_TO_REG(val)		(SENSORS_LIMIT(((val) + 5) / 10, 0, 255))
  #define IN_FROM_REG(val)	((val) * 10)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
  
  static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div)
  {
  	if (rpm == 0)
  		return 255;
  	rpm = SENSORS_LIMIT(rpm, 1, 1000000);
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
75
  	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  }
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
77
78
  #define FAN_FROM_REG(val, div)	((val) == 0 ? -1 : \
  				(val) == 255 ? 0 : 1350000/((div) * (val)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
87
88
89
90
91
  
  static inline long TEMP_FROM_REG(u16 temp)
  {
  	long res;
  
  	temp >>= 4;
  	if (temp < 0x0800)
  		res = 625 * (long) temp;
  	else
  		res = ((long) temp - 0x01000) * 625;
  
  	return res / 10;
  }
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
92
93
  #define TEMP_LIMIT_FROM_REG(val)	(((val) > 0x80 ? \
  	(val) - 0x100 : (val)) * 1000)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
95
96
  #define TEMP_LIMIT_TO_REG(val)		SENSORS_LIMIT((val) < 0 ? \
  	((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
101
102
103
104
  
  #define DIV_FROM_REG(val)		(1 << (val))
  
  /*
   * Client data (each client gets its own)
   */
  
  struct lm80_data {
1beeffe43   Tony Jones   hwmon: Convert fr...
105
  	struct device *hwmon_dev;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
106
  	struct mutex update_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  	char valid;		/* !=0 if following fields are valid */
  	unsigned long last_updated;	/* In jiffies */
  
  	u8 in[7];		/* Register value */
  	u8 in_max[7];		/* Register value */
  	u8 in_min[7];		/* Register value */
  	u8 fan[2];		/* Register value */
  	u8 fan_min[2];		/* Register value */
  	u8 fan_div[2];		/* Register encoding, shifted right */
  	u16 temp;		/* Register values, shifted right */
  	u8 temp_hot_max;	/* Register value */
  	u8 temp_hot_hyst;	/* Register value */
  	u8 temp_os_max;		/* Register value */
  	u8 temp_os_hyst;	/* Register value */
  	u16 alarms;		/* Register encoding, combined */
  };
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
123
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
125
   * Functions declaration
   */
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
126
127
  static int lm80_probe(struct i2c_client *client,
  		      const struct i2c_device_id *id);
310ec7921   Jean Delvare   i2c: Drop the kin...
128
  static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  static void lm80_init_client(struct i2c_client *client);
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
130
  static int lm80_remove(struct i2c_client *client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
135
136
137
  static struct lm80_data *lm80_update_device(struct device *dev);
  static int lm80_read_value(struct i2c_client *client, u8 reg);
  static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value);
  
  /*
   * Driver data (common to all clients)
   */
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
138
  static const struct i2c_device_id lm80_id[] = {
1f86df49d   Jean Delvare   i2c: Drop I2C_CLI...
139
  	{ "lm80", 0 },
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
140
141
142
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, lm80_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  static struct i2c_driver lm80_driver = {
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
144
  	.class		= I2C_CLASS_HWMON,
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
145
  	.driver = {
cdaf79349   Laurent Riffard   [PATCH] i2c: Drop...
146
147
  		.name	= "lm80",
  	},
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
148
149
150
151
  	.probe		= lm80_probe,
  	.remove		= lm80_remove,
  	.id_table	= lm80_id,
  	.detect		= lm80_detect,
c3813d6af   Jean Delvare   i2c: Get rid of s...
152
  	.address_list	= normal_i2c,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
156
157
158
159
  };
  
  /*
   * Sysfs stuff
   */
  
  #define show_in(suffix, value) \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
160
161
  static ssize_t show_in_##suffix(struct device *dev, \
  	struct device_attribute *attr, char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  { \
f8181762a   Jean Delvare   hwmon: (lm80) De-...
163
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  	struct lm80_data *data = lm80_update_device(dev); \
f8181762a   Jean Delvare   hwmon: (lm80) De-...
165
166
  	return sprintf(buf, "%d
  ", IN_FROM_REG(data->value[nr])); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  }
f8181762a   Jean Delvare   hwmon: (lm80) De-...
168
169
170
  show_in(min, in_min)
  show_in(max, in_max)
  show_in(input, in)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
  
  #define set_in(suffix, value, reg) \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
173
174
  static ssize_t set_in_##suffix(struct device *dev, \
  	struct device_attribute *attr, const char *buf, size_t count) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  { \
f8181762a   Jean Delvare   hwmon: (lm80) De-...
176
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct lm80_data *data = i2c_get_clientdata(client); \
  	long val = simple_strtol(buf, NULL, 10); \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
180
  \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
181
  	mutex_lock(&data->update_lock);\
f8181762a   Jean Delvare   hwmon: (lm80) De-...
182
183
  	data->value[nr] = IN_TO_REG(val); \
  	lm80_write_value(client, reg(nr), data->value[nr]); \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
184
  	mutex_unlock(&data->update_lock);\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
  	return count; \
  }
f8181762a   Jean Delvare   hwmon: (lm80) De-...
187
188
189
190
  set_in(min, in_min, LM80_REG_IN_MIN)
  set_in(max, in_max, LM80_REG_IN_MAX)
  
  #define show_fan(suffix, value) \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
191
192
  static ssize_t show_fan_##suffix(struct device *dev, \
  	struct device_attribute *attr, char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  { \
f8181762a   Jean Delvare   hwmon: (lm80) De-...
194
  	int nr = to_sensor_dev_attr(attr)->index; \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  	struct lm80_data *data = lm80_update_device(dev); \
f8181762a   Jean Delvare   hwmon: (lm80) De-...
196
197
198
  	return sprintf(buf, "%d
  ", FAN_FROM_REG(data->value[nr], \
  		       DIV_FROM_REG(data->fan_div[nr]))); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  }
f8181762a   Jean Delvare   hwmon: (lm80) De-...
200
201
  show_fan(min, fan_min)
  show_fan(input, fan)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

f8181762a   Jean Delvare   hwmon: (lm80) De-...
203
204
205
206
207
208
209
  static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
  	char *buf)
  {
  	int nr = to_sensor_dev_attr(attr)->index;
  	struct lm80_data *data = lm80_update_device(dev);
  	return sprintf(buf, "%d
  ", DIV_FROM_REG(data->fan_div[nr]));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211

f8181762a   Jean Delvare   hwmon: (lm80) De-...
212
213
214
215
216
217
218
219
220
221
222
223
224
  static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
  	const char *buf, size_t count)
  {
  	int nr = to_sensor_dev_attr(attr)->index;
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm80_data *data = i2c_get_clientdata(client);
  	long val = simple_strtoul(buf, NULL, 10);
  
  	mutex_lock(&data->update_lock);
  	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
  	lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
  	mutex_unlock(&data->update_lock);
  	return count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
  
  /* Note: we save and restore the fan minimum here, because its value is
     determined in part by the fan divisor.  This follows the principle of
d6e05edc5   Andreas Mohr   spelling fixes
229
     least surprise; the user doesn't expect the fan minimum to change just
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
     because the divisor changed. */
f8181762a   Jean Delvare   hwmon: (lm80) De-...
231
232
  static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
  	const char *buf, size_t count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  {
f8181762a   Jean Delvare   hwmon: (lm80) De-...
234
  	int nr = to_sensor_dev_attr(attr)->index;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm80_data *data = i2c_get_clientdata(client);
  	unsigned long min, val = simple_strtoul(buf, NULL, 10);
  	u8 reg;
  
  	/* Save fan_min */
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
241
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
  	min = FAN_FROM_REG(data->fan_min[nr],
  			   DIV_FROM_REG(data->fan_div[nr]));
  
  	switch (val) {
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
246
247
248
249
250
251
252
253
254
255
256
257
  	case 1:
  		data->fan_div[nr] = 0;
  		break;
  	case 2:
  		data->fan_div[nr] = 1;
  		break;
  	case 4:
  		data->fan_div[nr] = 2;
  		break;
  	case 8:
  		data->fan_div[nr] = 3;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
  	default:
  		dev_err(&client->dev, "fan_div value %ld not "
  			"supported. Choose one of 1, 2, 4 or 8!
  ", val);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
262
  		mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
269
270
271
272
  		return -EINVAL;
  	}
  
  	reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1))))
  	    | (data->fan_div[nr] << (2 * (nr + 1)));
  	lm80_write_value(client, LM80_REG_FANDIV, reg);
  
  	/* Restore fan_min */
  	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
  	lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]);
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
273
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
  
  	return count;
  }
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
277
278
  static ssize_t show_temp_input1(struct device *dev,
  	struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
284
285
  {
  	struct lm80_data *data = lm80_update_device(dev);
  	return sprintf(buf, "%ld
  ", TEMP_FROM_REG(data->temp));
  }
  
  #define show_temp(suffix, value) \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
286
287
  static ssize_t show_temp_##suffix(struct device *dev, \
  	struct device_attribute *attr, char *buf) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
293
294
295
296
297
298
  { \
  	struct lm80_data *data = lm80_update_device(dev); \
  	return sprintf(buf, "%d
  ", TEMP_LIMIT_FROM_REG(data->value)); \
  }
  show_temp(hot_max, temp_hot_max);
  show_temp(hot_hyst, temp_hot_hyst);
  show_temp(os_max, temp_os_max);
  show_temp(os_hyst, temp_os_hyst);
  
  #define set_temp(suffix, value, reg) \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
299
300
  static ssize_t set_temp_##suffix(struct device *dev, \
  	struct device_attribute *attr, const char *buf, size_t count) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
  { \
  	struct i2c_client *client = to_i2c_client(dev); \
  	struct lm80_data *data = i2c_get_clientdata(client); \
  	long val = simple_strtoul(buf, NULL, 10); \
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
305
  \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
306
  	mutex_lock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
  	data->value = TEMP_LIMIT_TO_REG(val); \
  	lm80_write_value(client, reg, data->value); \
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
309
  	mutex_unlock(&data->update_lock); \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
314
315
  	return count; \
  }
  set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);
  set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST);
  set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX);
  set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST);
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
316
317
  static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
  			   char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
  {
  	struct lm80_data *data = lm80_update_device(dev);
  	return sprintf(buf, "%u
  ", data->alarms);
  }
e84542f5d   Jean Delvare   hwmon: (lm80) Add...
323
324
325
326
327
328
329
330
  static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
  			  char *buf)
  {
  	int bitnr = to_sensor_dev_attr(attr)->index;
  	struct lm80_data *data = lm80_update_device(dev);
  	return sprintf(buf, "%u
  ", (data->alarms >> bitnr) & 1);
  }
f8181762a   Jean Delvare   hwmon: (lm80) De-...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 0);
  static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 1);
  static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 2);
  static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 3);
  static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 4);
  static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 5);
  static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
  		show_in_min, set_in_min, 6);
  static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 0);
  static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 1);
  static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 2);
  static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 3);
  static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 4);
  static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 5);
  static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
  		show_in_max, set_in_max, 6);
  static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0);
  static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1);
  static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2);
  static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3);
  static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4);
  static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5);
  static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6);
  static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
  		show_fan_min, set_fan_min, 0);
  static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
  		show_fan_min, set_fan_min, 1);
  static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
  static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
  static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
  		show_fan_div, set_fan_div, 0);
  static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
  		show_fan_div, set_fan_div, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
  static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);
  static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max,
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
378
  	set_temp_hot_max);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst,
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
380
  	set_temp_hot_hyst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max,
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
382
  	set_temp_os_max);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
  static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst,
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
384
  	set_temp_os_hyst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
e84542f5d   Jean Delvare   hwmon: (lm80) Add...
386
387
388
389
390
391
392
393
394
395
396
  static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
  static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
  static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
  static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
  static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
  static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
  static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
  static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10);
  static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11);
  static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 8);
  static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
  
  /*
   * Real code
   */
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
401
  static struct attribute *lm80_attributes[] = {
f8181762a   Jean Delvare   hwmon: (lm80) De-...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  	&sensor_dev_attr_in0_min.dev_attr.attr,
  	&sensor_dev_attr_in1_min.dev_attr.attr,
  	&sensor_dev_attr_in2_min.dev_attr.attr,
  	&sensor_dev_attr_in3_min.dev_attr.attr,
  	&sensor_dev_attr_in4_min.dev_attr.attr,
  	&sensor_dev_attr_in5_min.dev_attr.attr,
  	&sensor_dev_attr_in6_min.dev_attr.attr,
  	&sensor_dev_attr_in0_max.dev_attr.attr,
  	&sensor_dev_attr_in1_max.dev_attr.attr,
  	&sensor_dev_attr_in2_max.dev_attr.attr,
  	&sensor_dev_attr_in3_max.dev_attr.attr,
  	&sensor_dev_attr_in4_max.dev_attr.attr,
  	&sensor_dev_attr_in5_max.dev_attr.attr,
  	&sensor_dev_attr_in6_max.dev_attr.attr,
  	&sensor_dev_attr_in0_input.dev_attr.attr,
  	&sensor_dev_attr_in1_input.dev_attr.attr,
  	&sensor_dev_attr_in2_input.dev_attr.attr,
  	&sensor_dev_attr_in3_input.dev_attr.attr,
  	&sensor_dev_attr_in4_input.dev_attr.attr,
  	&sensor_dev_attr_in5_input.dev_attr.attr,
  	&sensor_dev_attr_in6_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_min.dev_attr.attr,
  	&sensor_dev_attr_fan2_min.dev_attr.attr,
  	&sensor_dev_attr_fan1_input.dev_attr.attr,
  	&sensor_dev_attr_fan2_input.dev_attr.attr,
  	&sensor_dev_attr_fan1_div.dev_attr.attr,
  	&sensor_dev_attr_fan2_div.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
429
430
431
432
433
434
  	&dev_attr_temp1_input.attr,
  	&dev_attr_temp1_max.attr,
  	&dev_attr_temp1_max_hyst.attr,
  	&dev_attr_temp1_crit.attr,
  	&dev_attr_temp1_crit_hyst.attr,
  	&dev_attr_alarms.attr,
e84542f5d   Jean Delvare   hwmon: (lm80) Add...
435
436
437
438
439
440
441
442
443
444
445
  	&sensor_dev_attr_in0_alarm.dev_attr.attr,
  	&sensor_dev_attr_in1_alarm.dev_attr.attr,
  	&sensor_dev_attr_in2_alarm.dev_attr.attr,
  	&sensor_dev_attr_in3_alarm.dev_attr.attr,
  	&sensor_dev_attr_in4_alarm.dev_attr.attr,
  	&sensor_dev_attr_in5_alarm.dev_attr.attr,
  	&sensor_dev_attr_in6_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
  	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
  	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
446
447
448
449
450
451
  	NULL
  };
  
  static const struct attribute_group lm80_group = {
  	.attrs = lm80_attributes,
  };
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
452
  /* Return 0 if detection is successful, -ENODEV otherwise */
310ec7921   Jean Delvare   i2c: Drop the kin...
453
  static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  {
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
455
  	struct i2c_adapter *adapter = client->adapter;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
  	int i, cur;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
458
  
  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
459
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
461
  
  	/* Now, we do the remaining detection. It is lousy. */
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
462
  	if (lm80_read_value(client, LM80_REG_ALARM2) & 0xc0)
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
463
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  	for (i = 0x2a; i <= 0x3d; i++) {
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
465
466
467
468
  		cur = i2c_smbus_read_byte_data(client, i);
  		if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur)
  		 || (i2c_smbus_read_byte_data(client, i + 0x80) != cur)
  		 || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur))
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
469
  			return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	}
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
471
  	strlcpy(info->type, "lm80", I2C_NAME_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472

8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
473
474
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475

8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
  static int lm80_probe(struct i2c_client *client,
  		      const struct i2c_device_id *id)
  {
  	struct lm80_data *data;
  	int err;
  
  	data = kzalloc(sizeof(struct lm80_data), GFP_KERNEL);
  	if (!data) {
  		err = -ENOMEM;
  		goto exit;
  	}
  
  	i2c_set_clientdata(client, data);
  	mutex_init(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
  
  	/* Initialize the LM80 chip */
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
492
  	lm80_init_client(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  
  	/* A few vars need to be filled upon startup */
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
495
496
  	data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1));
  	data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  
  	/* Register sysfs hooks */
66b3b1f75   Frans Meulenbroeks   hwmon: (lm80) fix...
499
500
  	err = sysfs_create_group(&client->dev.kobj, &lm80_group);
  	if (err)
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
501
  		goto error_free;
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
502

6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
503
  	data->hwmon_dev = hwmon_device_register(&client->dev);
1beeffe43   Tony Jones   hwmon: Convert fr...
504
505
  	if (IS_ERR(data->hwmon_dev)) {
  		err = PTR_ERR(data->hwmon_dev);
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
506
  		goto error_remove;
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
507
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  	return 0;
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
509
  error_remove:
6cc37ee53   Jean Delvare   hwmon: (lm80) Var...
510
  	sysfs_remove_group(&client->dev.kobj, &lm80_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
  error_free:
  	kfree(data);
  exit:
  	return err;
  }
8c8bacc88   Jean Delvare   hwmon: (lm80) Con...
516
  static int lm80_remove(struct i2c_client *client)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  {
943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
518
  	struct lm80_data *data = i2c_get_clientdata(client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519

1beeffe43   Tony Jones   hwmon: Convert fr...
520
  	hwmon_device_unregister(data->hwmon_dev);
0501a3816   Mark M. Hoffman   hwmon: Fix unchec...
521
  	sysfs_remove_group(&client->dev.kobj, &lm80_group);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

943b0830c   Mark M. Hoffman   [PATCH] I2C hwmon...
523
  	kfree(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  	return 0;
  }
  
  static int lm80_read_value(struct i2c_client *client, u8 reg)
  {
  	return i2c_smbus_read_byte_data(client, reg);
  }
  
  static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
  {
  	return i2c_smbus_write_byte_data(client, reg, value);
  }
  
  /* Called when we have found a new LM80. */
  static void lm80_init_client(struct i2c_client *client)
  {
  	/* Reset all except Watchdog values and last conversion values
  	   This sets fan-divs to 2, among others. This makes most other
  	   initializations unnecessary */
  	lm80_write_value(client, LM80_REG_CONFIG, 0x80);
  	/* Set 11-bit temperature resolution */
  	lm80_write_value(client, LM80_REG_RES, 0x08);
  
  	/* Start monitoring */
  	lm80_write_value(client, LM80_REG_CONFIG, 0x01);
  }
  
  static struct lm80_data *lm80_update_device(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct lm80_data *data = i2c_get_clientdata(client);
  	int i;
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
556
  	mutex_lock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
  
  	if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
  		dev_dbg(&client->dev, "Starting lm80 update
  ");
  		for (i = 0; i <= 6; i++) {
  			data->in[i] =
  			    lm80_read_value(client, LM80_REG_IN(i));
  			data->in_min[i] =
  			    lm80_read_value(client, LM80_REG_IN_MIN(i));
  			data->in_max[i] =
  			    lm80_read_value(client, LM80_REG_IN_MAX(i));
  		}
  		data->fan[0] = lm80_read_value(client, LM80_REG_FAN1);
  		data->fan_min[0] =
  		    lm80_read_value(client, LM80_REG_FAN_MIN(1));
  		data->fan[1] = lm80_read_value(client, LM80_REG_FAN2);
  		data->fan_min[1] =
  		    lm80_read_value(client, LM80_REG_FAN_MIN(2));
  
  		data->temp =
  		    (lm80_read_value(client, LM80_REG_TEMP) << 8) |
  		    (lm80_read_value(client, LM80_REG_RES) & 0xf0);
  		data->temp_os_max =
  		    lm80_read_value(client, LM80_REG_TEMP_OS_MAX);
  		data->temp_os_hyst =
  		    lm80_read_value(client, LM80_REG_TEMP_OS_HYST);
  		data->temp_hot_max =
  		    lm80_read_value(client, LM80_REG_TEMP_HOT_MAX);
  		data->temp_hot_hyst =
  		    lm80_read_value(client, LM80_REG_TEMP_HOT_HYST);
  
  		i = lm80_read_value(client, LM80_REG_FANDIV);
  		data->fan_div[0] = (i >> 2) & 0x03;
  		data->fan_div[1] = (i >> 4) & 0x03;
  		data->alarms = lm80_read_value(client, LM80_REG_ALARM1) +
  		    (lm80_read_value(client, LM80_REG_ALARM2) << 8);
  		data->last_updated = jiffies;
  		data->valid = 1;
  	}
9a61bf630   Ingo Molnar   [PATCH] hwmon: Se...
596
  	mutex_unlock(&data->update_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
  
  	return data;
  }
  
  static int __init sensors_lm80_init(void)
  {
  	return i2c_add_driver(&lm80_driver);
  }
  
  static void __exit sensors_lm80_exit(void)
  {
  	i2c_del_driver(&lm80_driver);
  }
  
  MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
  	"Philip Edelbrock <phil@netroedge.com>");
  MODULE_DESCRIPTION("LM80 driver");
  MODULE_LICENSE("GPL");
  
  module_init(sensors_lm80_init);
  module_exit(sensors_lm80_exit);