diff options
Diffstat (limited to 'drivers/hwmon/lm95234.c')
-rw-r--r-- | drivers/hwmon/lm95234.c | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c new file mode 100644 index 000000000000..307c9eaeeb9f --- /dev/null +++ b/drivers/hwmon/lm95234.c | |||
@@ -0,0 +1,769 @@ | |||
1 | /* | ||
2 | * Driver for Texas Instruments / National Semiconductor LM95234 | ||
3 | * | ||
4 | * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net> | ||
5 | * | ||
6 | * Derived from lm95241.c | ||
7 | * Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com> | ||
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 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/jiffies.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/hwmon.h> | ||
26 | #include <linux/hwmon-sysfs.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/sysfs.h> | ||
30 | |||
31 | #define DRVNAME "lm95234" | ||
32 | |||
33 | static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END }; | ||
34 | |||
35 | /* LM95234 registers */ | ||
36 | #define LM95234_REG_MAN_ID 0xFE | ||
37 | #define LM95234_REG_CHIP_ID 0xFF | ||
38 | #define LM95234_REG_STATUS 0x02 | ||
39 | #define LM95234_REG_CONFIG 0x03 | ||
40 | #define LM95234_REG_CONVRATE 0x04 | ||
41 | #define LM95234_REG_STS_FAULT 0x07 | ||
42 | #define LM95234_REG_STS_TCRIT1 0x08 | ||
43 | #define LM95234_REG_STS_TCRIT2 0x09 | ||
44 | #define LM95234_REG_TEMPH(x) ((x) + 0x10) | ||
45 | #define LM95234_REG_TEMPL(x) ((x) + 0x20) | ||
46 | #define LM95234_REG_UTEMPH(x) ((x) + 0x19) /* Remote only */ | ||
47 | #define LM95234_REG_UTEMPL(x) ((x) + 0x29) | ||
48 | #define LM95234_REG_REM_MODEL 0x30 | ||
49 | #define LM95234_REG_REM_MODEL_STS 0x38 | ||
50 | #define LM95234_REG_OFFSET(x) ((x) + 0x31) /* Remote only */ | ||
51 | #define LM95234_REG_TCRIT1(x) ((x) + 0x40) | ||
52 | #define LM95234_REG_TCRIT2(x) ((x) + 0x49) /* Remote channel 1,2 */ | ||
53 | #define LM95234_REG_TCRIT_HYST 0x5a | ||
54 | |||
55 | #define NATSEMI_MAN_ID 0x01 | ||
56 | #define LM95234_CHIP_ID 0x79 | ||
57 | |||
58 | /* Client data (each client gets its own) */ | ||
59 | struct lm95234_data { | ||
60 | struct device *hwmon_dev; | ||
61 | struct mutex update_lock; | ||
62 | unsigned long last_updated, interval; /* in jiffies */ | ||
63 | bool valid; /* false until following fields are valid */ | ||
64 | /* registers values */ | ||
65 | int temp[5]; /* temperature (signed) */ | ||
66 | u32 status; /* fault/alarm status */ | ||
67 | u8 tcrit1[5]; /* critical temperature limit */ | ||
68 | u8 tcrit2[2]; /* high temperature limit */ | ||
69 | s8 toffset[4]; /* remote temperature offset */ | ||
70 | u8 thyst; /* common hysteresis */ | ||
71 | |||
72 | u8 sensor_type; /* temperature sensor type */ | ||
73 | }; | ||
74 | |||
75 | static int lm95234_read_temp(struct i2c_client *client, int index, int *t) | ||
76 | { | ||
77 | int val; | ||
78 | u16 temp = 0; | ||
79 | |||
80 | if (index) { | ||
81 | val = i2c_smbus_read_byte_data(client, | ||
82 | LM95234_REG_UTEMPH(index - 1)); | ||
83 | if (val < 0) | ||
84 | return val; | ||
85 | temp = val << 8; | ||
86 | val = i2c_smbus_read_byte_data(client, | ||
87 | LM95234_REG_UTEMPL(index - 1)); | ||
88 | if (val < 0) | ||
89 | return val; | ||
90 | temp |= val; | ||
91 | *t = temp; | ||
92 | } | ||
93 | /* | ||
94 | * Read signed temperature if unsigned temperature is 0, | ||
95 | * or if this is the local sensor. | ||
96 | */ | ||
97 | if (!temp) { | ||
98 | val = i2c_smbus_read_byte_data(client, | ||
99 | LM95234_REG_TEMPH(index)); | ||
100 | if (val < 0) | ||
101 | return val; | ||
102 | temp = val << 8; | ||
103 | val = i2c_smbus_read_byte_data(client, | ||
104 | LM95234_REG_TEMPL(index)); | ||
105 | if (val < 0) | ||
106 | return val; | ||
107 | temp |= val; | ||
108 | *t = (s16)temp; | ||
109 | } | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static u16 update_intervals[] = { 143, 364, 1000, 2500 }; | ||
114 | |||
115 | /* Fill value cache. Must be called with update lock held. */ | ||
116 | |||
117 | static int lm95234_fill_cache(struct i2c_client *client) | ||
118 | { | ||
119 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
120 | int i, ret; | ||
121 | |||
122 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | data->interval = msecs_to_jiffies(update_intervals[ret & 0x03]); | ||
127 | |||
128 | for (i = 0; i < ARRAY_SIZE(data->tcrit1); i++) { | ||
129 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT1(i)); | ||
130 | if (ret < 0) | ||
131 | return ret; | ||
132 | data->tcrit1[i] = ret; | ||
133 | } | ||
134 | for (i = 0; i < ARRAY_SIZE(data->tcrit2); i++) { | ||
135 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT2(i)); | ||
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | data->tcrit2[i] = ret; | ||
139 | } | ||
140 | for (i = 0; i < ARRAY_SIZE(data->toffset); i++) { | ||
141 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_OFFSET(i)); | ||
142 | if (ret < 0) | ||
143 | return ret; | ||
144 | data->toffset[i] = ret; | ||
145 | } | ||
146 | |||
147 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_TCRIT_HYST); | ||
148 | if (ret < 0) | ||
149 | return ret; | ||
150 | data->thyst = ret; | ||
151 | |||
152 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL); | ||
153 | if (ret < 0) | ||
154 | return ret; | ||
155 | data->sensor_type = ret; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int lm95234_update_device(struct i2c_client *client, | ||
161 | struct lm95234_data *data) | ||
162 | { | ||
163 | int ret; | ||
164 | |||
165 | mutex_lock(&data->update_lock); | ||
166 | |||
167 | if (time_after(jiffies, data->last_updated + data->interval) || | ||
168 | !data->valid) { | ||
169 | int i; | ||
170 | |||
171 | if (!data->valid) { | ||
172 | ret = lm95234_fill_cache(client); | ||
173 | if (ret < 0) | ||
174 | goto abort; | ||
175 | } | ||
176 | |||
177 | data->valid = false; | ||
178 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) { | ||
179 | ret = lm95234_read_temp(client, i, &data->temp[i]); | ||
180 | if (ret < 0) | ||
181 | goto abort; | ||
182 | } | ||
183 | |||
184 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_FAULT); | ||
185 | if (ret < 0) | ||
186 | goto abort; | ||
187 | data->status = ret; | ||
188 | |||
189 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT1); | ||
190 | if (ret < 0) | ||
191 | goto abort; | ||
192 | data->status |= ret << 8; | ||
193 | |||
194 | ret = i2c_smbus_read_byte_data(client, LM95234_REG_STS_TCRIT2); | ||
195 | if (ret < 0) | ||
196 | goto abort; | ||
197 | data->status |= ret << 16; | ||
198 | |||
199 | data->last_updated = jiffies; | ||
200 | data->valid = true; | ||
201 | } | ||
202 | ret = 0; | ||
203 | abort: | ||
204 | mutex_unlock(&data->update_lock); | ||
205 | |||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | static ssize_t show_temp(struct device *dev, struct device_attribute *attr, | ||
210 | char *buf) | ||
211 | { | ||
212 | struct i2c_client *client = to_i2c_client(dev); | ||
213 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
214 | int index = to_sensor_dev_attr(attr)->index; | ||
215 | int ret = lm95234_update_device(client, data); | ||
216 | |||
217 | if (ret) | ||
218 | return ret; | ||
219 | |||
220 | return sprintf(buf, "%d\n", | ||
221 | DIV_ROUND_CLOSEST(data->temp[index] * 125, 32)); | ||
222 | } | ||
223 | |||
224 | static ssize_t show_alarm(struct device *dev, | ||
225 | struct device_attribute *attr, char *buf) | ||
226 | { | ||
227 | struct i2c_client *client = to_i2c_client(dev); | ||
228 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
229 | u32 mask = to_sensor_dev_attr(attr)->index; | ||
230 | int ret = lm95234_update_device(client, data); | ||
231 | |||
232 | if (ret) | ||
233 | return ret; | ||
234 | |||
235 | return sprintf(buf, "%u", !!(data->status & mask)); | ||
236 | } | ||
237 | |||
238 | static ssize_t show_type(struct device *dev, struct device_attribute *attr, | ||
239 | char *buf) | ||
240 | { | ||
241 | struct i2c_client *client = to_i2c_client(dev); | ||
242 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
243 | u8 mask = to_sensor_dev_attr(attr)->index; | ||
244 | int ret = lm95234_update_device(client, data); | ||
245 | |||
246 | if (ret) | ||
247 | return ret; | ||
248 | |||
249 | return sprintf(buf, data->sensor_type & mask ? "1\n" : "2\n"); | ||
250 | } | ||
251 | |||
252 | static ssize_t set_type(struct device *dev, struct device_attribute *attr, | ||
253 | const char *buf, size_t count) | ||
254 | { | ||
255 | struct i2c_client *client = to_i2c_client(dev); | ||
256 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
257 | unsigned long val; | ||
258 | u8 mask = to_sensor_dev_attr(attr)->index; | ||
259 | int ret = lm95234_update_device(client, data); | ||
260 | |||
261 | if (ret) | ||
262 | return ret; | ||
263 | |||
264 | ret = kstrtoul(buf, 10, &val); | ||
265 | if (ret < 0) | ||
266 | return ret; | ||
267 | |||
268 | if (val != 1 && val != 2) | ||
269 | return -EINVAL; | ||
270 | |||
271 | mutex_lock(&data->update_lock); | ||
272 | if (val == 1) | ||
273 | data->sensor_type |= mask; | ||
274 | else | ||
275 | data->sensor_type &= ~mask; | ||
276 | data->valid = false; | ||
277 | i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL, | ||
278 | data->sensor_type); | ||
279 | mutex_unlock(&data->update_lock); | ||
280 | |||
281 | return count; | ||
282 | } | ||
283 | |||
284 | static ssize_t show_tcrit2(struct device *dev, struct device_attribute *attr, | ||
285 | char *buf) | ||
286 | { | ||
287 | struct i2c_client *client = to_i2c_client(dev); | ||
288 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
289 | int index = to_sensor_dev_attr(attr)->index; | ||
290 | int ret = lm95234_update_device(client, data); | ||
291 | |||
292 | if (ret) | ||
293 | return ret; | ||
294 | |||
295 | return sprintf(buf, "%u", data->tcrit2[index] * 1000); | ||
296 | } | ||
297 | |||
298 | static ssize_t set_tcrit2(struct device *dev, struct device_attribute *attr, | ||
299 | const char *buf, size_t count) | ||
300 | { | ||
301 | struct i2c_client *client = to_i2c_client(dev); | ||
302 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
303 | int index = to_sensor_dev_attr(attr)->index; | ||
304 | long val; | ||
305 | int ret = lm95234_update_device(client, data); | ||
306 | |||
307 | if (ret) | ||
308 | return ret; | ||
309 | |||
310 | ret = kstrtol(buf, 10, &val); | ||
311 | if (ret < 0) | ||
312 | return ret; | ||
313 | |||
314 | val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, index ? 255 : 127); | ||
315 | |||
316 | mutex_lock(&data->update_lock); | ||
317 | data->tcrit2[index] = val; | ||
318 | i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT2(index), val); | ||
319 | mutex_unlock(&data->update_lock); | ||
320 | |||
321 | return count; | ||
322 | } | ||
323 | |||
324 | static ssize_t show_tcrit2_hyst(struct device *dev, | ||
325 | struct device_attribute *attr, char *buf) | ||
326 | { | ||
327 | struct i2c_client *client = to_i2c_client(dev); | ||
328 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
329 | int index = to_sensor_dev_attr(attr)->index; | ||
330 | int ret = lm95234_update_device(client, data); | ||
331 | |||
332 | if (ret) | ||
333 | return ret; | ||
334 | |||
335 | /* Result can be negative, so be careful with unsigned operands */ | ||
336 | return sprintf(buf, "%d", | ||
337 | ((int)data->tcrit2[index] - (int)data->thyst) * 1000); | ||
338 | } | ||
339 | |||
340 | static ssize_t show_tcrit1(struct device *dev, struct device_attribute *attr, | ||
341 | char *buf) | ||
342 | { | ||
343 | struct i2c_client *client = to_i2c_client(dev); | ||
344 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
345 | int index = to_sensor_dev_attr(attr)->index; | ||
346 | |||
347 | return sprintf(buf, "%u", data->tcrit1[index] * 1000); | ||
348 | } | ||
349 | |||
350 | static ssize_t set_tcrit1(struct device *dev, struct device_attribute *attr, | ||
351 | const char *buf, size_t count) | ||
352 | { | ||
353 | struct i2c_client *client = to_i2c_client(dev); | ||
354 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
355 | int index = to_sensor_dev_attr(attr)->index; | ||
356 | long val; | ||
357 | int ret = lm95234_update_device(client, data); | ||
358 | |||
359 | if (ret) | ||
360 | return ret; | ||
361 | |||
362 | ret = kstrtol(buf, 10, &val); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | |||
366 | val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 0, 255); | ||
367 | |||
368 | mutex_lock(&data->update_lock); | ||
369 | data->tcrit1[index] = val; | ||
370 | i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT1(index), val); | ||
371 | mutex_unlock(&data->update_lock); | ||
372 | |||
373 | return count; | ||
374 | } | ||
375 | |||
376 | static ssize_t show_tcrit1_hyst(struct device *dev, | ||
377 | struct device_attribute *attr, char *buf) | ||
378 | { | ||
379 | struct i2c_client *client = to_i2c_client(dev); | ||
380 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
381 | int index = to_sensor_dev_attr(attr)->index; | ||
382 | int ret = lm95234_update_device(client, data); | ||
383 | |||
384 | if (ret) | ||
385 | return ret; | ||
386 | |||
387 | /* Result can be negative, so be careful with unsigned operands */ | ||
388 | return sprintf(buf, "%d", | ||
389 | ((int)data->tcrit1[index] - (int)data->thyst) * 1000); | ||
390 | } | ||
391 | |||
392 | static ssize_t set_tcrit1_hyst(struct device *dev, | ||
393 | struct device_attribute *attr, | ||
394 | const char *buf, size_t count) | ||
395 | { | ||
396 | struct i2c_client *client = to_i2c_client(dev); | ||
397 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
398 | int index = to_sensor_dev_attr(attr)->index; | ||
399 | long val; | ||
400 | int ret = lm95234_update_device(client, data); | ||
401 | |||
402 | if (ret) | ||
403 | return ret; | ||
404 | |||
405 | ret = kstrtol(buf, 10, &val); | ||
406 | if (ret < 0) | ||
407 | return ret; | ||
408 | |||
409 | val = DIV_ROUND_CLOSEST(val, 1000); | ||
410 | val = clamp_val((int)data->tcrit1[index] - val, 0, 31); | ||
411 | |||
412 | mutex_lock(&data->update_lock); | ||
413 | data->thyst = val; | ||
414 | i2c_smbus_write_byte_data(client, LM95234_REG_TCRIT_HYST, val); | ||
415 | mutex_unlock(&data->update_lock); | ||
416 | |||
417 | return count; | ||
418 | } | ||
419 | |||
420 | static ssize_t show_offset(struct device *dev, struct device_attribute *attr, | ||
421 | char *buf) | ||
422 | { | ||
423 | struct i2c_client *client = to_i2c_client(dev); | ||
424 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
425 | int index = to_sensor_dev_attr(attr)->index; | ||
426 | int ret = lm95234_update_device(client, data); | ||
427 | |||
428 | if (ret) | ||
429 | return ret; | ||
430 | |||
431 | return sprintf(buf, "%d", data->toffset[index] * 500); | ||
432 | } | ||
433 | |||
434 | static ssize_t set_offset(struct device *dev, struct device_attribute *attr, | ||
435 | const char *buf, size_t count) | ||
436 | { | ||
437 | struct i2c_client *client = to_i2c_client(dev); | ||
438 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
439 | int index = to_sensor_dev_attr(attr)->index; | ||
440 | long val; | ||
441 | int ret = lm95234_update_device(client, data); | ||
442 | |||
443 | if (ret) | ||
444 | return ret; | ||
445 | |||
446 | ret = kstrtol(buf, 10, &val); | ||
447 | if (ret < 0) | ||
448 | return ret; | ||
449 | |||
450 | /* Accuracy is 1/2 degrees C */ | ||
451 | val = clamp_val(DIV_ROUND_CLOSEST(val, 500), -128, 127); | ||
452 | |||
453 | mutex_lock(&data->update_lock); | ||
454 | data->toffset[index] = val; | ||
455 | i2c_smbus_write_byte_data(client, LM95234_REG_OFFSET(index), val); | ||
456 | mutex_unlock(&data->update_lock); | ||
457 | |||
458 | return count; | ||
459 | } | ||
460 | |||
461 | static ssize_t show_interval(struct device *dev, struct device_attribute *attr, | ||
462 | char *buf) | ||
463 | { | ||
464 | struct i2c_client *client = to_i2c_client(dev); | ||
465 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
466 | int ret = lm95234_update_device(client, data); | ||
467 | |||
468 | if (ret) | ||
469 | return ret; | ||
470 | |||
471 | return sprintf(buf, "%lu\n", | ||
472 | DIV_ROUND_CLOSEST(data->interval * 1000, HZ)); | ||
473 | } | ||
474 | |||
475 | static ssize_t set_interval(struct device *dev, struct device_attribute *attr, | ||
476 | const char *buf, size_t count) | ||
477 | { | ||
478 | struct i2c_client *client = to_i2c_client(dev); | ||
479 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
480 | unsigned long val; | ||
481 | u8 regval; | ||
482 | int ret = lm95234_update_device(client, data); | ||
483 | |||
484 | if (ret) | ||
485 | return ret; | ||
486 | |||
487 | ret = kstrtoul(buf, 10, &val); | ||
488 | if (ret < 0) | ||
489 | return ret; | ||
490 | |||
491 | for (regval = 0; regval < 3; regval++) { | ||
492 | if (val <= update_intervals[regval]) | ||
493 | break; | ||
494 | } | ||
495 | |||
496 | mutex_lock(&data->update_lock); | ||
497 | data->interval = msecs_to_jiffies(update_intervals[regval]); | ||
498 | i2c_smbus_write_byte_data(client, LM95234_REG_CONVRATE, regval); | ||
499 | mutex_unlock(&data->update_lock); | ||
500 | |||
501 | return count; | ||
502 | } | ||
503 | |||
504 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); | ||
505 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); | ||
506 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); | ||
507 | static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); | ||
508 | static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4); | ||
509 | |||
510 | static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, | ||
511 | BIT(0) | BIT(1)); | ||
512 | static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, | ||
513 | BIT(2) | BIT(3)); | ||
514 | static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, | ||
515 | BIT(4) | BIT(5)); | ||
516 | static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_alarm, NULL, | ||
517 | BIT(6) | BIT(7)); | ||
518 | |||
519 | static SENSOR_DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type, | ||
520 | BIT(1)); | ||
521 | static SENSOR_DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type, set_type, | ||
522 | BIT(2)); | ||
523 | static SENSOR_DEVICE_ATTR(temp4_type, S_IWUSR | S_IRUGO, show_type, set_type, | ||
524 | BIT(3)); | ||
525 | static SENSOR_DEVICE_ATTR(temp5_type, S_IWUSR | S_IRUGO, show_type, set_type, | ||
526 | BIT(4)); | ||
527 | |||
528 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_tcrit1, | ||
529 | set_tcrit1, 0); | ||
530 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_tcrit2, | ||
531 | set_tcrit2, 0); | ||
532 | static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_tcrit2, | ||
533 | set_tcrit2, 1); | ||
534 | static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_tcrit1, | ||
535 | set_tcrit1, 3); | ||
536 | static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_tcrit1, | ||
537 | set_tcrit1, 4); | ||
538 | |||
539 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_tcrit1_hyst, | ||
540 | set_tcrit1_hyst, 0); | ||
541 | static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 0); | ||
542 | static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO, show_tcrit2_hyst, NULL, 1); | ||
543 | static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 3); | ||
544 | static SENSOR_DEVICE_ATTR(temp5_max_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 4); | ||
545 | |||
546 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, | ||
547 | BIT(0 + 8)); | ||
548 | static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, | ||
549 | BIT(1 + 16)); | ||
550 | static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, | ||
551 | BIT(2 + 16)); | ||
552 | static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, | ||
553 | BIT(3 + 8)); | ||
554 | static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, show_alarm, NULL, | ||
555 | BIT(4 + 8)); | ||
556 | |||
557 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_tcrit1, | ||
558 | set_tcrit1, 1); | ||
559 | static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_tcrit1, | ||
560 | set_tcrit1, 2); | ||
561 | |||
562 | static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 1); | ||
563 | static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO, show_tcrit1_hyst, NULL, 2); | ||
564 | |||
565 | static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, | ||
566 | BIT(1 + 8)); | ||
567 | static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, | ||
568 | BIT(2 + 8)); | ||
569 | |||
570 | static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_offset, | ||
571 | set_offset, 0); | ||
572 | static SENSOR_DEVICE_ATTR(temp3_offset, S_IWUSR | S_IRUGO, show_offset, | ||
573 | set_offset, 1); | ||
574 | static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset, | ||
575 | set_offset, 2); | ||
576 | static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset, | ||
577 | set_offset, 3); | ||
578 | |||
579 | static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, | ||
580 | set_interval); | ||
581 | |||
582 | static struct attribute *lm95234_attributes[] = { | ||
583 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
584 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
585 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
586 | &sensor_dev_attr_temp4_input.dev_attr.attr, | ||
587 | &sensor_dev_attr_temp5_input.dev_attr.attr, | ||
588 | &sensor_dev_attr_temp2_fault.dev_attr.attr, | ||
589 | &sensor_dev_attr_temp3_fault.dev_attr.attr, | ||
590 | &sensor_dev_attr_temp4_fault.dev_attr.attr, | ||
591 | &sensor_dev_attr_temp5_fault.dev_attr.attr, | ||
592 | &sensor_dev_attr_temp2_type.dev_attr.attr, | ||
593 | &sensor_dev_attr_temp3_type.dev_attr.attr, | ||
594 | &sensor_dev_attr_temp4_type.dev_attr.attr, | ||
595 | &sensor_dev_attr_temp5_type.dev_attr.attr, | ||
596 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
597 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
598 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
599 | &sensor_dev_attr_temp4_max.dev_attr.attr, | ||
600 | &sensor_dev_attr_temp5_max.dev_attr.attr, | ||
601 | &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, | ||
602 | &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, | ||
603 | &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, | ||
604 | &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, | ||
605 | &sensor_dev_attr_temp5_max_hyst.dev_attr.attr, | ||
606 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
607 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | ||
608 | &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, | ||
609 | &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, | ||
610 | &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, | ||
611 | &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
612 | &sensor_dev_attr_temp3_crit.dev_attr.attr, | ||
613 | &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, | ||
614 | &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, | ||
615 | &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, | ||
616 | &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, | ||
617 | &sensor_dev_attr_temp2_offset.dev_attr.attr, | ||
618 | &sensor_dev_attr_temp3_offset.dev_attr.attr, | ||
619 | &sensor_dev_attr_temp4_offset.dev_attr.attr, | ||
620 | &sensor_dev_attr_temp5_offset.dev_attr.attr, | ||
621 | &dev_attr_update_interval.attr, | ||
622 | NULL | ||
623 | }; | ||
624 | |||
625 | static const struct attribute_group lm95234_group = { | ||
626 | .attrs = lm95234_attributes, | ||
627 | }; | ||
628 | |||
629 | static int lm95234_detect(struct i2c_client *client, | ||
630 | struct i2c_board_info *info) | ||
631 | { | ||
632 | struct i2c_adapter *adapter = client->adapter; | ||
633 | int mfg_id, chip_id, val; | ||
634 | |||
635 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
636 | return -ENODEV; | ||
637 | |||
638 | mfg_id = i2c_smbus_read_byte_data(client, LM95234_REG_MAN_ID); | ||
639 | if (mfg_id != NATSEMI_MAN_ID) | ||
640 | return -ENODEV; | ||
641 | |||
642 | chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID); | ||
643 | if (chip_id != LM95234_CHIP_ID) | ||
644 | return -ENODEV; | ||
645 | |||
646 | val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS); | ||
647 | if (val & 0x30) | ||
648 | return -ENODEV; | ||
649 | |||
650 | val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG); | ||
651 | if (val & 0xbc) | ||
652 | return -ENODEV; | ||
653 | |||
654 | val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE); | ||
655 | if (val & 0xfc) | ||
656 | return -ENODEV; | ||
657 | |||
658 | val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL); | ||
659 | if (val & 0xe1) | ||
660 | return -ENODEV; | ||
661 | |||
662 | val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS); | ||
663 | if (val & 0xe1) | ||
664 | return -ENODEV; | ||
665 | |||
666 | strlcpy(info->type, "lm95234", I2C_NAME_SIZE); | ||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static int lm95234_init_client(struct i2c_client *client) | ||
671 | { | ||
672 | int val, model; | ||
673 | |||
674 | /* start conversion if necessary */ | ||
675 | val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG); | ||
676 | if (val < 0) | ||
677 | return val; | ||
678 | if (val & 0x40) | ||
679 | i2c_smbus_write_byte_data(client, LM95234_REG_CONFIG, | ||
680 | val & ~0x40); | ||
681 | |||
682 | /* If diode type status reports an error, try to fix it */ | ||
683 | val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS); | ||
684 | if (val < 0) | ||
685 | return val; | ||
686 | model = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL); | ||
687 | if (model < 0) | ||
688 | return model; | ||
689 | if (model & val) { | ||
690 | dev_notice(&client->dev, | ||
691 | "Fixing remote diode type misconfiguration (0x%x)\n", | ||
692 | val); | ||
693 | i2c_smbus_write_byte_data(client, LM95234_REG_REM_MODEL, | ||
694 | model & ~val); | ||
695 | } | ||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int lm95234_probe(struct i2c_client *client, | ||
700 | const struct i2c_device_id *id) | ||
701 | { | ||
702 | struct device *dev = &client->dev; | ||
703 | struct lm95234_data *data; | ||
704 | int err; | ||
705 | |||
706 | data = devm_kzalloc(dev, sizeof(struct lm95234_data), GFP_KERNEL); | ||
707 | if (!data) | ||
708 | return -ENOMEM; | ||
709 | |||
710 | i2c_set_clientdata(client, data); | ||
711 | mutex_init(&data->update_lock); | ||
712 | |||
713 | /* Initialize the LM95234 chip */ | ||
714 | err = lm95234_init_client(client); | ||
715 | if (err < 0) | ||
716 | return err; | ||
717 | |||
718 | /* Register sysfs hooks */ | ||
719 | err = sysfs_create_group(&dev->kobj, &lm95234_group); | ||
720 | if (err) | ||
721 | return err; | ||
722 | |||
723 | data->hwmon_dev = hwmon_device_register(dev); | ||
724 | if (IS_ERR(data->hwmon_dev)) { | ||
725 | err = PTR_ERR(data->hwmon_dev); | ||
726 | goto exit_remove_files; | ||
727 | } | ||
728 | |||
729 | return 0; | ||
730 | |||
731 | exit_remove_files: | ||
732 | sysfs_remove_group(&dev->kobj, &lm95234_group); | ||
733 | return err; | ||
734 | } | ||
735 | |||
736 | static int lm95234_remove(struct i2c_client *client) | ||
737 | { | ||
738 | struct lm95234_data *data = i2c_get_clientdata(client); | ||
739 | |||
740 | hwmon_device_unregister(data->hwmon_dev); | ||
741 | sysfs_remove_group(&client->dev.kobj, &lm95234_group); | ||
742 | |||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | /* Driver data (common to all clients) */ | ||
747 | static const struct i2c_device_id lm95234_id[] = { | ||
748 | { "lm95234", 0 }, | ||
749 | { } | ||
750 | }; | ||
751 | MODULE_DEVICE_TABLE(i2c, lm95234_id); | ||
752 | |||
753 | static struct i2c_driver lm95234_driver = { | ||
754 | .class = I2C_CLASS_HWMON, | ||
755 | .driver = { | ||
756 | .name = DRVNAME, | ||
757 | }, | ||
758 | .probe = lm95234_probe, | ||
759 | .remove = lm95234_remove, | ||
760 | .id_table = lm95234_id, | ||
761 | .detect = lm95234_detect, | ||
762 | .address_list = normal_i2c, | ||
763 | }; | ||
764 | |||
765 | module_i2c_driver(lm95234_driver); | ||
766 | |||
767 | MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); | ||
768 | MODULE_DESCRIPTION("LM95234 sensor driver"); | ||
769 | MODULE_LICENSE("GPL"); | ||