Root/
1 | /* |
2 | * lm80.c - From lm_sensors, Linux kernel modules for hardware |
3 | * monitoring |
4 | * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> |
5 | * and Philip Edelbrock <phil@netroedge.com> |
6 | * |
7 | * Ported to Linux 2.6 by Tiago Sousa <mirage@kaotik.org> |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | */ |
23 | |
24 | #include <linux/module.h> |
25 | #include <linux/init.h> |
26 | #include <linux/slab.h> |
27 | #include <linux/jiffies.h> |
28 | #include <linux/i2c.h> |
29 | #include <linux/hwmon.h> |
30 | #include <linux/hwmon-sysfs.h> |
31 | #include <linux/err.h> |
32 | #include <linux/mutex.h> |
33 | |
34 | /* Addresses to scan */ |
35 | static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, |
36 | 0x2e, 0x2f, I2C_CLIENT_END }; |
37 | |
38 | /* Many LM80 constants specified below */ |
39 | |
40 | /* The LM80 registers */ |
41 | #define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2) |
42 | #define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2) |
43 | #define LM80_REG_IN(nr) (0x20 + (nr)) |
44 | |
45 | #define LM80_REG_FAN1 0x28 |
46 | #define LM80_REG_FAN2 0x29 |
47 | #define LM80_REG_FAN_MIN(nr) (0x3b + (nr)) |
48 | |
49 | #define LM80_REG_TEMP 0x27 |
50 | #define LM80_REG_TEMP_HOT_MAX 0x38 |
51 | #define LM80_REG_TEMP_HOT_HYST 0x39 |
52 | #define LM80_REG_TEMP_OS_MAX 0x3a |
53 | #define LM80_REG_TEMP_OS_HYST 0x3b |
54 | |
55 | #define LM80_REG_CONFIG 0x00 |
56 | #define LM80_REG_ALARM1 0x01 |
57 | #define LM80_REG_ALARM2 0x02 |
58 | #define LM80_REG_MASK1 0x03 |
59 | #define LM80_REG_MASK2 0x04 |
60 | #define LM80_REG_FANDIV 0x05 |
61 | #define LM80_REG_RES 0x06 |
62 | |
63 | #define LM96080_REG_CONV_RATE 0x07 |
64 | #define LM96080_REG_MAN_ID 0x3e |
65 | #define LM96080_REG_DEV_ID 0x3f |
66 | |
67 | |
68 | /* |
69 | * Conversions. Rounding and limit checking is only done on the TO_REG |
70 | * variants. Note that you should be a bit careful with which arguments |
71 | * these macros are called: arguments may be evaluated more than once. |
72 | * Fixing this is just not worth it. |
73 | */ |
74 | |
75 | #define IN_TO_REG(val) (clamp_val(((val) + 5) / 10, 0, 255)) |
76 | #define IN_FROM_REG(val) ((val) * 10) |
77 | |
78 | static inline unsigned char FAN_TO_REG(unsigned rpm, unsigned div) |
79 | { |
80 | if (rpm == 0) |
81 | return 255; |
82 | rpm = clamp_val(rpm, 1, 1000000); |
83 | return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); |
84 | } |
85 | |
86 | #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : \ |
87 | (val) == 255 ? 0 : 1350000/((div) * (val))) |
88 | |
89 | static inline long TEMP_FROM_REG(u16 temp) |
90 | { |
91 | long res; |
92 | |
93 | temp >>= 4; |
94 | if (temp < 0x0800) |
95 | res = 625 * (long) temp; |
96 | else |
97 | res = ((long) temp - 0x01000) * 625; |
98 | |
99 | return res / 10; |
100 | } |
101 | |
102 | #define TEMP_LIMIT_FROM_REG(val) (((val) > 0x80 ? \ |
103 | (val) - 0x100 : (val)) * 1000) |
104 | |
105 | #define TEMP_LIMIT_TO_REG(val) clamp_val((val) < 0 ? \ |
106 | ((val) - 500) / 1000 : ((val) + 500) / 1000, 0, 255) |
107 | |
108 | #define DIV_FROM_REG(val) (1 << (val)) |
109 | |
110 | /* |
111 | * Client data (each client gets its own) |
112 | */ |
113 | |
114 | struct lm80_data { |
115 | struct device *hwmon_dev; |
116 | struct mutex update_lock; |
117 | char error; /* !=0 if error occurred during last update */ |
118 | char valid; /* !=0 if following fields are valid */ |
119 | unsigned long last_updated; /* In jiffies */ |
120 | |
121 | u8 in[7]; /* Register value */ |
122 | u8 in_max[7]; /* Register value */ |
123 | u8 in_min[7]; /* Register value */ |
124 | u8 fan[2]; /* Register value */ |
125 | u8 fan_min[2]; /* Register value */ |
126 | u8 fan_div[2]; /* Register encoding, shifted right */ |
127 | u16 temp; /* Register values, shifted right */ |
128 | u8 temp_hot_max; /* Register value */ |
129 | u8 temp_hot_hyst; /* Register value */ |
130 | u8 temp_os_max; /* Register value */ |
131 | u8 temp_os_hyst; /* Register value */ |
132 | u16 alarms; /* Register encoding, combined */ |
133 | }; |
134 | |
135 | /* |
136 | * Functions declaration |
137 | */ |
138 | |
139 | static int lm80_probe(struct i2c_client *client, |
140 | const struct i2c_device_id *id); |
141 | static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info); |
142 | static void lm80_init_client(struct i2c_client *client); |
143 | static int lm80_remove(struct i2c_client *client); |
144 | static struct lm80_data *lm80_update_device(struct device *dev); |
145 | static int lm80_read_value(struct i2c_client *client, u8 reg); |
146 | static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value); |
147 | |
148 | /* |
149 | * Driver data (common to all clients) |
150 | */ |
151 | |
152 | static const struct i2c_device_id lm80_id[] = { |
153 | { "lm80", 0 }, |
154 | { "lm96080", 1 }, |
155 | { } |
156 | }; |
157 | MODULE_DEVICE_TABLE(i2c, lm80_id); |
158 | |
159 | static struct i2c_driver lm80_driver = { |
160 | .class = I2C_CLASS_HWMON, |
161 | .driver = { |
162 | .name = "lm80", |
163 | }, |
164 | .probe = lm80_probe, |
165 | .remove = lm80_remove, |
166 | .id_table = lm80_id, |
167 | .detect = lm80_detect, |
168 | .address_list = normal_i2c, |
169 | }; |
170 | |
171 | /* |
172 | * Sysfs stuff |
173 | */ |
174 | |
175 | #define show_in(suffix, value) \ |
176 | static ssize_t show_in_##suffix(struct device *dev, \ |
177 | struct device_attribute *attr, char *buf) \ |
178 | { \ |
179 | int nr = to_sensor_dev_attr(attr)->index; \ |
180 | struct lm80_data *data = lm80_update_device(dev); \ |
181 | if (IS_ERR(data)) \ |
182 | return PTR_ERR(data); \ |
183 | return sprintf(buf, "%d\n", IN_FROM_REG(data->value[nr])); \ |
184 | } |
185 | show_in(min, in_min) |
186 | show_in(max, in_max) |
187 | show_in(input, in) |
188 | |
189 | #define set_in(suffix, value, reg) \ |
190 | static ssize_t set_in_##suffix(struct device *dev, \ |
191 | struct device_attribute *attr, const char *buf, size_t count) \ |
192 | { \ |
193 | int nr = to_sensor_dev_attr(attr)->index; \ |
194 | struct i2c_client *client = to_i2c_client(dev); \ |
195 | struct lm80_data *data = i2c_get_clientdata(client); \ |
196 | long val; \ |
197 | int err = kstrtol(buf, 10, &val); \ |
198 | if (err < 0) \ |
199 | return err; \ |
200 | \ |
201 | mutex_lock(&data->update_lock);\ |
202 | data->value[nr] = IN_TO_REG(val); \ |
203 | lm80_write_value(client, reg(nr), data->value[nr]); \ |
204 | mutex_unlock(&data->update_lock);\ |
205 | return count; \ |
206 | } |
207 | set_in(min, in_min, LM80_REG_IN_MIN) |
208 | set_in(max, in_max, LM80_REG_IN_MAX) |
209 | |
210 | #define show_fan(suffix, value) \ |
211 | static ssize_t show_fan_##suffix(struct device *dev, \ |
212 | struct device_attribute *attr, char *buf) \ |
213 | { \ |
214 | int nr = to_sensor_dev_attr(attr)->index; \ |
215 | struct lm80_data *data = lm80_update_device(dev); \ |
216 | if (IS_ERR(data)) \ |
217 | return PTR_ERR(data); \ |
218 | return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[nr], \ |
219 | DIV_FROM_REG(data->fan_div[nr]))); \ |
220 | } |
221 | show_fan(min, fan_min) |
222 | show_fan(input, fan) |
223 | |
224 | static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, |
225 | char *buf) |
226 | { |
227 | int nr = to_sensor_dev_attr(attr)->index; |
228 | struct lm80_data *data = lm80_update_device(dev); |
229 | if (IS_ERR(data)) |
230 | return PTR_ERR(data); |
231 | return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); |
232 | } |
233 | |
234 | static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, |
235 | const char *buf, size_t count) |
236 | { |
237 | int nr = to_sensor_dev_attr(attr)->index; |
238 | struct i2c_client *client = to_i2c_client(dev); |
239 | struct lm80_data *data = i2c_get_clientdata(client); |
240 | unsigned long val; |
241 | int err = kstrtoul(buf, 10, &val); |
242 | if (err < 0) |
243 | return err; |
244 | |
245 | mutex_lock(&data->update_lock); |
246 | data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); |
247 | lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); |
248 | mutex_unlock(&data->update_lock); |
249 | return count; |
250 | } |
251 | |
252 | /* |
253 | * Note: we save and restore the fan minimum here, because its value is |
254 | * determined in part by the fan divisor. This follows the principle of |
255 | * least surprise; the user doesn't expect the fan minimum to change just |
256 | * because the divisor changed. |
257 | */ |
258 | static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, |
259 | const char *buf, size_t count) |
260 | { |
261 | int nr = to_sensor_dev_attr(attr)->index; |
262 | struct i2c_client *client = to_i2c_client(dev); |
263 | struct lm80_data *data = i2c_get_clientdata(client); |
264 | unsigned long min, val; |
265 | u8 reg; |
266 | int err = kstrtoul(buf, 10, &val); |
267 | if (err < 0) |
268 | return err; |
269 | |
270 | /* Save fan_min */ |
271 | mutex_lock(&data->update_lock); |
272 | min = FAN_FROM_REG(data->fan_min[nr], |
273 | DIV_FROM_REG(data->fan_div[nr])); |
274 | |
275 | switch (val) { |
276 | case 1: |
277 | data->fan_div[nr] = 0; |
278 | break; |
279 | case 2: |
280 | data->fan_div[nr] = 1; |
281 | break; |
282 | case 4: |
283 | data->fan_div[nr] = 2; |
284 | break; |
285 | case 8: |
286 | data->fan_div[nr] = 3; |
287 | break; |
288 | default: |
289 | dev_err(&client->dev, |
290 | "fan_div value %ld not supported. Choose one of 1, 2, 4 or 8!\n", |
291 | val); |
292 | mutex_unlock(&data->update_lock); |
293 | return -EINVAL; |
294 | } |
295 | |
296 | reg = (lm80_read_value(client, LM80_REG_FANDIV) & ~(3 << (2 * (nr + 1)))) |
297 | | (data->fan_div[nr] << (2 * (nr + 1))); |
298 | lm80_write_value(client, LM80_REG_FANDIV, reg); |
299 | |
300 | /* Restore fan_min */ |
301 | data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); |
302 | lm80_write_value(client, LM80_REG_FAN_MIN(nr + 1), data->fan_min[nr]); |
303 | mutex_unlock(&data->update_lock); |
304 | |
305 | return count; |
306 | } |
307 | |
308 | static ssize_t show_temp_input1(struct device *dev, |
309 | struct device_attribute *attr, char *buf) |
310 | { |
311 | struct lm80_data *data = lm80_update_device(dev); |
312 | if (IS_ERR(data)) |
313 | return PTR_ERR(data); |
314 | return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp)); |
315 | } |
316 | |
317 | #define show_temp(suffix, value) \ |
318 | static ssize_t show_temp_##suffix(struct device *dev, \ |
319 | struct device_attribute *attr, char *buf) \ |
320 | { \ |
321 | struct lm80_data *data = lm80_update_device(dev); \ |
322 | if (IS_ERR(data)) \ |
323 | return PTR_ERR(data); \ |
324 | return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \ |
325 | } |
326 | show_temp(hot_max, temp_hot_max); |
327 | show_temp(hot_hyst, temp_hot_hyst); |
328 | show_temp(os_max, temp_os_max); |
329 | show_temp(os_hyst, temp_os_hyst); |
330 | |
331 | #define set_temp(suffix, value, reg) \ |
332 | static ssize_t set_temp_##suffix(struct device *dev, \ |
333 | struct device_attribute *attr, const char *buf, size_t count) \ |
334 | { \ |
335 | struct i2c_client *client = to_i2c_client(dev); \ |
336 | struct lm80_data *data = i2c_get_clientdata(client); \ |
337 | long val; \ |
338 | int err = kstrtol(buf, 10, &val); \ |
339 | if (err < 0) \ |
340 | return err; \ |
341 | \ |
342 | mutex_lock(&data->update_lock); \ |
343 | data->value = TEMP_LIMIT_TO_REG(val); \ |
344 | lm80_write_value(client, reg, data->value); \ |
345 | mutex_unlock(&data->update_lock); \ |
346 | return count; \ |
347 | } |
348 | set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX); |
349 | set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST); |
350 | set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX); |
351 | set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST); |
352 | |
353 | static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, |
354 | char *buf) |
355 | { |
356 | struct lm80_data *data = lm80_update_device(dev); |
357 | if (IS_ERR(data)) |
358 | return PTR_ERR(data); |
359 | return sprintf(buf, "%u\n", data->alarms); |
360 | } |
361 | |
362 | static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, |
363 | char *buf) |
364 | { |
365 | int bitnr = to_sensor_dev_attr(attr)->index; |
366 | struct lm80_data *data = lm80_update_device(dev); |
367 | if (IS_ERR(data)) |
368 | return PTR_ERR(data); |
369 | return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); |
370 | } |
371 | |
372 | static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, |
373 | show_in_min, set_in_min, 0); |
374 | static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, |
375 | show_in_min, set_in_min, 1); |
376 | static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, |
377 | show_in_min, set_in_min, 2); |
378 | static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, |
379 | show_in_min, set_in_min, 3); |
380 | static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, |
381 | show_in_min, set_in_min, 4); |
382 | static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, |
383 | show_in_min, set_in_min, 5); |
384 | static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, |
385 | show_in_min, set_in_min, 6); |
386 | static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, |
387 | show_in_max, set_in_max, 0); |
388 | static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, |
389 | show_in_max, set_in_max, 1); |
390 | static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, |
391 | show_in_max, set_in_max, 2); |
392 | static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, |
393 | show_in_max, set_in_max, 3); |
394 | static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, |
395 | show_in_max, set_in_max, 4); |
396 | static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, |
397 | show_in_max, set_in_max, 5); |
398 | static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, |
399 | show_in_max, set_in_max, 6); |
400 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0); |
401 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1); |
402 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2); |
403 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3); |
404 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4); |
405 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5); |
406 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6); |
407 | static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, |
408 | show_fan_min, set_fan_min, 0); |
409 | static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, |
410 | show_fan_min, set_fan_min, 1); |
411 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); |
412 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); |
413 | static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, |
414 | show_fan_div, set_fan_div, 0); |
415 | static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, |
416 | show_fan_div, set_fan_div, 1); |
417 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL); |
418 | static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, |
419 | set_temp_hot_max); |
420 | static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, |
421 | set_temp_hot_hyst); |
422 | static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, |
423 | set_temp_os_max); |
424 | static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, |
425 | set_temp_os_hyst); |
426 | static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); |
427 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); |
428 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); |
429 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); |
430 | static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); |
431 | static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4); |
432 | static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5); |
433 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); |
434 | static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10); |
435 | static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11); |
436 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 8); |
437 | static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 13); |
438 | |
439 | /* |
440 | * Real code |
441 | */ |
442 | |
443 | static struct attribute *lm80_attributes[] = { |
444 | &sensor_dev_attr_in0_min.dev_attr.attr, |
445 | &sensor_dev_attr_in1_min.dev_attr.attr, |
446 | &sensor_dev_attr_in2_min.dev_attr.attr, |
447 | &sensor_dev_attr_in3_min.dev_attr.attr, |
448 | &sensor_dev_attr_in4_min.dev_attr.attr, |
449 | &sensor_dev_attr_in5_min.dev_attr.attr, |
450 | &sensor_dev_attr_in6_min.dev_attr.attr, |
451 | &sensor_dev_attr_in0_max.dev_attr.attr, |
452 | &sensor_dev_attr_in1_max.dev_attr.attr, |
453 | &sensor_dev_attr_in2_max.dev_attr.attr, |
454 | &sensor_dev_attr_in3_max.dev_attr.attr, |
455 | &sensor_dev_attr_in4_max.dev_attr.attr, |
456 | &sensor_dev_attr_in5_max.dev_attr.attr, |
457 | &sensor_dev_attr_in6_max.dev_attr.attr, |
458 | &sensor_dev_attr_in0_input.dev_attr.attr, |
459 | &sensor_dev_attr_in1_input.dev_attr.attr, |
460 | &sensor_dev_attr_in2_input.dev_attr.attr, |
461 | &sensor_dev_attr_in3_input.dev_attr.attr, |
462 | &sensor_dev_attr_in4_input.dev_attr.attr, |
463 | &sensor_dev_attr_in5_input.dev_attr.attr, |
464 | &sensor_dev_attr_in6_input.dev_attr.attr, |
465 | &sensor_dev_attr_fan1_min.dev_attr.attr, |
466 | &sensor_dev_attr_fan2_min.dev_attr.attr, |
467 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
468 | &sensor_dev_attr_fan2_input.dev_attr.attr, |
469 | &sensor_dev_attr_fan1_div.dev_attr.attr, |
470 | &sensor_dev_attr_fan2_div.dev_attr.attr, |
471 | &dev_attr_temp1_input.attr, |
472 | &dev_attr_temp1_max.attr, |
473 | &dev_attr_temp1_max_hyst.attr, |
474 | &dev_attr_temp1_crit.attr, |
475 | &dev_attr_temp1_crit_hyst.attr, |
476 | &dev_attr_alarms.attr, |
477 | &sensor_dev_attr_in0_alarm.dev_attr.attr, |
478 | &sensor_dev_attr_in1_alarm.dev_attr.attr, |
479 | &sensor_dev_attr_in2_alarm.dev_attr.attr, |
480 | &sensor_dev_attr_in3_alarm.dev_attr.attr, |
481 | &sensor_dev_attr_in4_alarm.dev_attr.attr, |
482 | &sensor_dev_attr_in5_alarm.dev_attr.attr, |
483 | &sensor_dev_attr_in6_alarm.dev_attr.attr, |
484 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, |
485 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, |
486 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, |
487 | &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, |
488 | NULL |
489 | }; |
490 | |
491 | static const struct attribute_group lm80_group = { |
492 | .attrs = lm80_attributes, |
493 | }; |
494 | |
495 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
496 | static int lm80_detect(struct i2c_client *client, struct i2c_board_info *info) |
497 | { |
498 | struct i2c_adapter *adapter = client->adapter; |
499 | int i, cur, man_id, dev_id; |
500 | const char *name = NULL; |
501 | |
502 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
503 | return -ENODEV; |
504 | |
505 | /* First check for unused bits, common to both chip types */ |
506 | if ((lm80_read_value(client, LM80_REG_ALARM2) & 0xc0) |
507 | || (lm80_read_value(client, LM80_REG_CONFIG) & 0x80)) |
508 | return -ENODEV; |
509 | |
510 | /* |
511 | * The LM96080 has manufacturer and stepping/die rev registers so we |
512 | * can just check that. The LM80 does not have such registers so we |
513 | * have to use a more expensive trick. |
514 | */ |
515 | man_id = lm80_read_value(client, LM96080_REG_MAN_ID); |
516 | dev_id = lm80_read_value(client, LM96080_REG_DEV_ID); |
517 | if (man_id == 0x01 && dev_id == 0x08) { |
518 | /* Check more unused bits for confirmation */ |
519 | if (lm80_read_value(client, LM96080_REG_CONV_RATE) & 0xfe) |
520 | return -ENODEV; |
521 | |
522 | name = "lm96080"; |
523 | } else { |
524 | /* Check 6-bit addressing */ |
525 | for (i = 0x2a; i <= 0x3d; i++) { |
526 | cur = i2c_smbus_read_byte_data(client, i); |
527 | if ((i2c_smbus_read_byte_data(client, i + 0x40) != cur) |
528 | || (i2c_smbus_read_byte_data(client, i + 0x80) != cur) |
529 | || (i2c_smbus_read_byte_data(client, i + 0xc0) != cur)) |
530 | return -ENODEV; |
531 | } |
532 | |
533 | name = "lm80"; |
534 | } |
535 | |
536 | strlcpy(info->type, name, I2C_NAME_SIZE); |
537 | |
538 | return 0; |
539 | } |
540 | |
541 | static int lm80_probe(struct i2c_client *client, |
542 | const struct i2c_device_id *id) |
543 | { |
544 | struct lm80_data *data; |
545 | int err; |
546 | |
547 | data = devm_kzalloc(&client->dev, sizeof(struct lm80_data), GFP_KERNEL); |
548 | if (!data) |
549 | return -ENOMEM; |
550 | |
551 | i2c_set_clientdata(client, data); |
552 | mutex_init(&data->update_lock); |
553 | |
554 | /* Initialize the LM80 chip */ |
555 | lm80_init_client(client); |
556 | |
557 | /* A few vars need to be filled upon startup */ |
558 | data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); |
559 | data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); |
560 | |
561 | /* Register sysfs hooks */ |
562 | err = sysfs_create_group(&client->dev.kobj, &lm80_group); |
563 | if (err) |
564 | return err; |
565 | |
566 | data->hwmon_dev = hwmon_device_register(&client->dev); |
567 | if (IS_ERR(data->hwmon_dev)) { |
568 | err = PTR_ERR(data->hwmon_dev); |
569 | goto error_remove; |
570 | } |
571 | |
572 | return 0; |
573 | |
574 | error_remove: |
575 | sysfs_remove_group(&client->dev.kobj, &lm80_group); |
576 | return err; |
577 | } |
578 | |
579 | static int lm80_remove(struct i2c_client *client) |
580 | { |
581 | struct lm80_data *data = i2c_get_clientdata(client); |
582 | |
583 | hwmon_device_unregister(data->hwmon_dev); |
584 | sysfs_remove_group(&client->dev.kobj, &lm80_group); |
585 | |
586 | return 0; |
587 | } |
588 | |
589 | static int lm80_read_value(struct i2c_client *client, u8 reg) |
590 | { |
591 | return i2c_smbus_read_byte_data(client, reg); |
592 | } |
593 | |
594 | static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value) |
595 | { |
596 | return i2c_smbus_write_byte_data(client, reg, value); |
597 | } |
598 | |
599 | /* Called when we have found a new LM80. */ |
600 | static void lm80_init_client(struct i2c_client *client) |
601 | { |
602 | /* |
603 | * Reset all except Watchdog values and last conversion values |
604 | * This sets fan-divs to 2, among others. This makes most other |
605 | * initializations unnecessary |
606 | */ |
607 | lm80_write_value(client, LM80_REG_CONFIG, 0x80); |
608 | /* Set 11-bit temperature resolution */ |
609 | lm80_write_value(client, LM80_REG_RES, 0x08); |
610 | |
611 | /* Start monitoring */ |
612 | lm80_write_value(client, LM80_REG_CONFIG, 0x01); |
613 | } |
614 | |
615 | static struct lm80_data *lm80_update_device(struct device *dev) |
616 | { |
617 | struct i2c_client *client = to_i2c_client(dev); |
618 | struct lm80_data *data = i2c_get_clientdata(client); |
619 | int i; |
620 | int rv; |
621 | int prev_rv; |
622 | struct lm80_data *ret = data; |
623 | |
624 | mutex_lock(&data->update_lock); |
625 | |
626 | if (data->error) |
627 | lm80_init_client(client); |
628 | |
629 | if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { |
630 | dev_dbg(&client->dev, "Starting lm80 update\n"); |
631 | for (i = 0; i <= 6; i++) { |
632 | rv = lm80_read_value(client, LM80_REG_IN(i)); |
633 | if (rv < 0) |
634 | goto abort; |
635 | data->in[i] = rv; |
636 | |
637 | rv = lm80_read_value(client, LM80_REG_IN_MIN(i)); |
638 | if (rv < 0) |
639 | goto abort; |
640 | data->in_min[i] = rv; |
641 | |
642 | rv = lm80_read_value(client, LM80_REG_IN_MAX(i)); |
643 | if (rv < 0) |
644 | goto abort; |
645 | data->in_max[i] = rv; |
646 | } |
647 | |
648 | rv = lm80_read_value(client, LM80_REG_FAN1); |
649 | if (rv < 0) |
650 | goto abort; |
651 | data->fan[0] = rv; |
652 | |
653 | rv = lm80_read_value(client, LM80_REG_FAN_MIN(1)); |
654 | if (rv < 0) |
655 | goto abort; |
656 | data->fan_min[0] = rv; |
657 | |
658 | rv = lm80_read_value(client, LM80_REG_FAN2); |
659 | if (rv < 0) |
660 | goto abort; |
661 | data->fan[1] = rv; |
662 | |
663 | rv = lm80_read_value(client, LM80_REG_FAN_MIN(2)); |
664 | if (rv < 0) |
665 | goto abort; |
666 | data->fan_min[1] = rv; |
667 | |
668 | prev_rv = rv = lm80_read_value(client, LM80_REG_TEMP); |
669 | if (rv < 0) |
670 | goto abort; |
671 | rv = lm80_read_value(client, LM80_REG_RES); |
672 | if (rv < 0) |
673 | goto abort; |
674 | data->temp = (prev_rv << 8) | (rv & 0xf0); |
675 | |
676 | rv = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); |
677 | if (rv < 0) |
678 | goto abort; |
679 | data->temp_os_max = rv; |
680 | |
681 | rv = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); |
682 | if (rv < 0) |
683 | goto abort; |
684 | data->temp_os_hyst = rv; |
685 | |
686 | rv = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); |
687 | if (rv < 0) |
688 | goto abort; |
689 | data->temp_hot_max = rv; |
690 | |
691 | rv = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); |
692 | if (rv < 0) |
693 | goto abort; |
694 | data->temp_hot_hyst = rv; |
695 | |
696 | rv = lm80_read_value(client, LM80_REG_FANDIV); |
697 | if (rv < 0) |
698 | goto abort; |
699 | data->fan_div[0] = (rv >> 2) & 0x03; |
700 | data->fan_div[1] = (rv >> 4) & 0x03; |
701 | |
702 | prev_rv = rv = lm80_read_value(client, LM80_REG_ALARM1); |
703 | if (rv < 0) |
704 | goto abort; |
705 | rv = lm80_read_value(client, LM80_REG_ALARM2); |
706 | if (rv < 0) |
707 | goto abort; |
708 | data->alarms = prev_rv + (rv << 8); |
709 | |
710 | data->last_updated = jiffies; |
711 | data->valid = 1; |
712 | data->error = 0; |
713 | } |
714 | goto done; |
715 | |
716 | abort: |
717 | ret = ERR_PTR(rv); |
718 | data->valid = 0; |
719 | data->error = 1; |
720 | |
721 | done: |
722 | mutex_unlock(&data->update_lock); |
723 | |
724 | return ret; |
725 | } |
726 | |
727 | module_i2c_driver(lm80_driver); |
728 | |
729 | MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " |
730 | "Philip Edelbrock <phil@netroedge.com>"); |
731 | MODULE_DESCRIPTION("LM80 driver"); |
732 | MODULE_LICENSE("GPL"); |
733 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9