Commit | Line | Data |
---|---|---|
06160327 DR |
1 | /* |
2 | * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware | |
3 | * monitoring | |
4 | * Copyright (C) 2008 Davide Rizzo <elpa-rizzo@gmail.com> | |
5 | * | |
6 | * Based on the max1619 driver. The LM95241 is a sensor chip made by National | |
7 | * Semiconductors. | |
8 | * It reports up to three temperatures (its own plus up to | |
9 | * two external ones). Complete datasheet can be | |
10 | * obtained from National's website at: | |
11 | * http://www.national.com/ds.cgi/LM/LM95241.pdf | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify | |
14 | * it under the terms of the GNU General Public License as published by | |
15 | * the Free Software Foundation; either version 2 of the License, or | |
16 | * (at your option) any later version. | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with this program; if not, write to the Free Software | |
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
26 | */ | |
27 | ||
28 | #include <linux/module.h> | |
29 | #include <linux/init.h> | |
30 | #include <linux/slab.h> | |
31 | #include <linux/jiffies.h> | |
32 | #include <linux/i2c.h> | |
33 | #include <linux/hwmon.h> | |
34 | #include <linux/hwmon-sysfs.h> | |
35 | #include <linux/err.h> | |
36 | #include <linux/mutex.h> | |
37 | #include <linux/sysfs.h> | |
38 | ||
39 | static const unsigned short normal_i2c[] = { | |
40 | 0x19, 0x2a, 0x2b, I2C_CLIENT_END}; | |
41 | ||
06160327 DR |
42 | /* LM95241 registers */ |
43 | #define LM95241_REG_R_MAN_ID 0xFE | |
44 | #define LM95241_REG_R_CHIP_ID 0xFF | |
45 | #define LM95241_REG_R_STATUS 0x02 | |
46 | #define LM95241_REG_RW_CONFIG 0x03 | |
47 | #define LM95241_REG_RW_REM_FILTER 0x06 | |
48 | #define LM95241_REG_RW_TRUTHERM 0x07 | |
49 | #define LM95241_REG_W_ONE_SHOT 0x0F | |
50 | #define LM95241_REG_R_LOCAL_TEMPH 0x10 | |
51 | #define LM95241_REG_R_REMOTE1_TEMPH 0x11 | |
52 | #define LM95241_REG_R_REMOTE2_TEMPH 0x12 | |
53 | #define LM95241_REG_R_LOCAL_TEMPL 0x20 | |
54 | #define LM95241_REG_R_REMOTE1_TEMPL 0x21 | |
55 | #define LM95241_REG_R_REMOTE2_TEMPL 0x22 | |
56 | #define LM95241_REG_RW_REMOTE_MODEL 0x30 | |
57 | ||
58 | /* LM95241 specific bitfields */ | |
59 | #define CFG_STOP 0x40 | |
60 | #define CFG_CR0076 0x00 | |
61 | #define CFG_CR0182 0x10 | |
62 | #define CFG_CR1000 0x20 | |
63 | #define CFG_CR2700 0x30 | |
64 | #define R1MS_SHIFT 0 | |
65 | #define R2MS_SHIFT 2 | |
66 | #define R1MS_MASK (0x01 << (R1MS_SHIFT)) | |
67 | #define R2MS_MASK (0x01 << (R2MS_SHIFT)) | |
68 | #define R1DF_SHIFT 1 | |
69 | #define R2DF_SHIFT 2 | |
70 | #define R1DF_MASK (0x01 << (R1DF_SHIFT)) | |
71 | #define R2DF_MASK (0x01 << (R2DF_SHIFT)) | |
72 | #define R1FE_MASK 0x01 | |
73 | #define R2FE_MASK 0x05 | |
74 | #define TT1_SHIFT 0 | |
75 | #define TT2_SHIFT 4 | |
76 | #define TT_OFF 0 | |
77 | #define TT_ON 1 | |
78 | #define TT_MASK 7 | |
79 | #define MANUFACTURER_ID 0x01 | |
80 | #define DEFAULT_REVISION 0xA4 | |
81 | ||
82 | /* Conversions and various macros */ | |
83 | #define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \ | |
84 | (val_h)) * 1000 + (val_l) * 1000 / 256) | |
85 | ||
86 | /* Functions declaration */ | |
06160327 | 87 | static void lm95241_init_client(struct i2c_client *client); |
06160327 DR |
88 | static struct lm95241_data *lm95241_update_device(struct device *dev); |
89 | ||
06160327 DR |
90 | /* Client data (each client gets its own) */ |
91 | struct lm95241_data { | |
06160327 DR |
92 | struct device *hwmon_dev; |
93 | struct mutex update_lock; | |
bc482bf0 | 94 | unsigned long last_updated, interval; /* in jiffies */ |
06160327 DR |
95 | char valid; /* zero until following fields are valid */ |
96 | /* registers values */ | |
97 | u8 local_h, local_l; /* local */ | |
98 | u8 remote1_h, remote1_l; /* remote1 */ | |
99 | u8 remote2_h, remote2_l; /* remote2 */ | |
100 | u8 config, model, trutherm; | |
101 | }; | |
102 | ||
103 | /* Sysfs stuff */ | |
104 | #define show_temp(value) \ | |
105 | static ssize_t show_##value(struct device *dev, \ | |
106 | struct device_attribute *attr, char *buf) \ | |
107 | { \ | |
108 | struct lm95241_data *data = lm95241_update_device(dev); \ | |
109 | snprintf(buf, PAGE_SIZE - 1, "%d\n", \ | |
110 | TEMP_FROM_REG(data->value##_h, data->value##_l)); \ | |
111 | return strlen(buf); \ | |
112 | } | |
113 | show_temp(local); | |
114 | show_temp(remote1); | |
115 | show_temp(remote2); | |
116 | ||
bc482bf0 | 117 | static ssize_t show_interval(struct device *dev, struct device_attribute *attr, |
06160327 DR |
118 | char *buf) |
119 | { | |
120 | struct lm95241_data *data = lm95241_update_device(dev); | |
121 | ||
bc482bf0 | 122 | snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->interval / HZ); |
06160327 DR |
123 | return strlen(buf); |
124 | } | |
125 | ||
bc482bf0 | 126 | static ssize_t set_interval(struct device *dev, struct device_attribute *attr, |
06160327 DR |
127 | const char *buf, size_t count) |
128 | { | |
129 | struct i2c_client *client = to_i2c_client(dev); | |
130 | struct lm95241_data *data = i2c_get_clientdata(client); | |
61ec2da5 | 131 | unsigned long val; |
06160327 | 132 | |
61ec2da5 JD |
133 | if (strict_strtoul(buf, 10, &val) < 0) |
134 | return -EINVAL; | |
135 | ||
136 | data->interval = val * HZ / 1000; | |
06160327 DR |
137 | |
138 | return count; | |
139 | } | |
140 | ||
141 | #define show_type(flag) \ | |
142 | static ssize_t show_type##flag(struct device *dev, \ | |
143 | struct device_attribute *attr, char *buf) \ | |
144 | { \ | |
145 | struct i2c_client *client = to_i2c_client(dev); \ | |
146 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
147 | \ | |
148 | snprintf(buf, PAGE_SIZE - 1, \ | |
149 | data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \ | |
150 | return strlen(buf); \ | |
151 | } | |
152 | show_type(1); | |
153 | show_type(2); | |
154 | ||
155 | #define show_min(flag) \ | |
156 | static ssize_t show_min##flag(struct device *dev, \ | |
157 | struct device_attribute *attr, char *buf) \ | |
158 | { \ | |
159 | struct i2c_client *client = to_i2c_client(dev); \ | |
160 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
161 | \ | |
162 | snprintf(buf, PAGE_SIZE - 1, \ | |
163 | data->config & R##flag##DF_MASK ? \ | |
164 | "-127000\n" : "0\n"); \ | |
165 | return strlen(buf); \ | |
166 | } | |
167 | show_min(1); | |
168 | show_min(2); | |
169 | ||
170 | #define show_max(flag) \ | |
171 | static ssize_t show_max##flag(struct device *dev, \ | |
172 | struct device_attribute *attr, char *buf) \ | |
173 | { \ | |
174 | struct i2c_client *client = to_i2c_client(dev); \ | |
175 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
176 | \ | |
177 | snprintf(buf, PAGE_SIZE - 1, \ | |
178 | data->config & R##flag##DF_MASK ? \ | |
179 | "127000\n" : "255000\n"); \ | |
180 | return strlen(buf); \ | |
181 | } | |
182 | show_max(1); | |
183 | show_max(2); | |
184 | ||
185 | #define set_type(flag) \ | |
186 | static ssize_t set_type##flag(struct device *dev, \ | |
187 | struct device_attribute *attr, \ | |
188 | const char *buf, size_t count) \ | |
189 | { \ | |
190 | struct i2c_client *client = to_i2c_client(dev); \ | |
191 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
192 | \ | |
193 | long val; \ | |
61ec2da5 JD |
194 | \ |
195 | if (strict_strtol(buf, 10, &val) < 0) \ | |
196 | return -EINVAL; \ | |
06160327 DR |
197 | \ |
198 | if ((val == 1) || (val == 2)) { \ | |
199 | \ | |
200 | mutex_lock(&data->update_lock); \ | |
201 | \ | |
202 | data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \ | |
203 | if (val == 1) { \ | |
204 | data->model |= R##flag##MS_MASK; \ | |
205 | data->trutherm |= (TT_ON << TT##flag##_SHIFT); \ | |
206 | } \ | |
207 | else { \ | |
208 | data->model &= ~R##flag##MS_MASK; \ | |
209 | data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \ | |
210 | } \ | |
211 | \ | |
212 | data->valid = 0; \ | |
213 | \ | |
214 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \ | |
215 | data->model); \ | |
216 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \ | |
217 | data->trutherm); \ | |
218 | \ | |
219 | mutex_unlock(&data->update_lock); \ | |
220 | \ | |
221 | } \ | |
222 | return count; \ | |
223 | } | |
224 | set_type(1); | |
225 | set_type(2); | |
226 | ||
227 | #define set_min(flag) \ | |
228 | static ssize_t set_min##flag(struct device *dev, \ | |
229 | struct device_attribute *devattr, const char *buf, size_t count) \ | |
230 | { \ | |
231 | struct i2c_client *client = to_i2c_client(dev); \ | |
232 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
233 | \ | |
234 | long val; \ | |
61ec2da5 JD |
235 | \ |
236 | if (strict_strtol(buf, 10, &val) < 0) \ | |
237 | return -EINVAL;\ | |
06160327 DR |
238 | \ |
239 | mutex_lock(&data->update_lock); \ | |
240 | \ | |
241 | if (val < 0) \ | |
242 | data->config |= R##flag##DF_MASK; \ | |
243 | else \ | |
244 | data->config &= ~R##flag##DF_MASK; \ | |
245 | \ | |
246 | data->valid = 0; \ | |
247 | \ | |
248 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ | |
249 | data->config); \ | |
250 | \ | |
251 | mutex_unlock(&data->update_lock); \ | |
252 | \ | |
253 | return count; \ | |
254 | } | |
255 | set_min(1); | |
256 | set_min(2); | |
257 | ||
258 | #define set_max(flag) \ | |
259 | static ssize_t set_max##flag(struct device *dev, \ | |
260 | struct device_attribute *devattr, const char *buf, size_t count) \ | |
261 | { \ | |
262 | struct i2c_client *client = to_i2c_client(dev); \ | |
263 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
264 | \ | |
265 | long val; \ | |
61ec2da5 JD |
266 | \ |
267 | if (strict_strtol(buf, 10, &val) < 0) \ | |
268 | return -EINVAL; \ | |
06160327 DR |
269 | \ |
270 | mutex_lock(&data->update_lock); \ | |
271 | \ | |
272 | if (val <= 127000) \ | |
273 | data->config |= R##flag##DF_MASK; \ | |
274 | else \ | |
275 | data->config &= ~R##flag##DF_MASK; \ | |
276 | \ | |
277 | data->valid = 0; \ | |
278 | \ | |
279 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ | |
280 | data->config); \ | |
281 | \ | |
282 | mutex_unlock(&data->update_lock); \ | |
283 | \ | |
284 | return count; \ | |
285 | } | |
286 | set_max(1); | |
287 | set_max(2); | |
288 | ||
289 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL); | |
290 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL); | |
291 | static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL); | |
292 | static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1); | |
293 | static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2); | |
294 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1); | |
295 | static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2); | |
296 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1); | |
297 | static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2); | |
bc482bf0 GR |
298 | static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, |
299 | set_interval); | |
06160327 DR |
300 | |
301 | static struct attribute *lm95241_attributes[] = { | |
302 | &dev_attr_temp1_input.attr, | |
303 | &dev_attr_temp2_input.attr, | |
304 | &dev_attr_temp3_input.attr, | |
305 | &dev_attr_temp2_type.attr, | |
306 | &dev_attr_temp3_type.attr, | |
307 | &dev_attr_temp2_min.attr, | |
308 | &dev_attr_temp3_min.attr, | |
309 | &dev_attr_temp2_max.attr, | |
310 | &dev_attr_temp3_max.attr, | |
bc482bf0 | 311 | &dev_attr_update_interval.attr, |
06160327 DR |
312 | NULL |
313 | }; | |
314 | ||
315 | static const struct attribute_group lm95241_group = { | |
316 | .attrs = lm95241_attributes, | |
317 | }; | |
318 | ||
797eaa4b | 319 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
310ec792 | 320 | static int lm95241_detect(struct i2c_client *new_client, |
797eaa4b | 321 | struct i2c_board_info *info) |
06160327 | 322 | { |
797eaa4b JD |
323 | struct i2c_adapter *adapter = new_client->adapter; |
324 | int address = new_client->addr; | |
52df6440 | 325 | const char *name; |
06160327 DR |
326 | |
327 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
797eaa4b | 328 | return -ENODEV; |
06160327 | 329 | |
52df6440 JD |
330 | if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) |
331 | == MANUFACTURER_ID) | |
332 | && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) | |
333 | >= DEFAULT_REVISION)) { | |
334 | name = "lm95241"; | |
335 | } else { | |
336 | dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n", | |
337 | address); | |
338 | return -ENODEV; | |
06160327 DR |
339 | } |
340 | ||
797eaa4b | 341 | /* Fill the i2c board info */ |
797eaa4b JD |
342 | strlcpy(info->type, name, I2C_NAME_SIZE); |
343 | return 0; | |
344 | } | |
06160327 | 345 | |
797eaa4b JD |
346 | static int lm95241_probe(struct i2c_client *new_client, |
347 | const struct i2c_device_id *id) | |
348 | { | |
349 | struct lm95241_data *data; | |
350 | int err; | |
06160327 | 351 | |
797eaa4b JD |
352 | data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL); |
353 | if (!data) { | |
354 | err = -ENOMEM; | |
355 | goto exit; | |
356 | } | |
357 | ||
358 | i2c_set_clientdata(new_client, data); | |
359 | mutex_init(&data->update_lock); | |
06160327 DR |
360 | |
361 | /* Initialize the LM95241 chip */ | |
362 | lm95241_init_client(new_client); | |
363 | ||
364 | /* Register sysfs hooks */ | |
365 | err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group); | |
366 | if (err) | |
797eaa4b | 367 | goto exit_free; |
06160327 DR |
368 | |
369 | data->hwmon_dev = hwmon_device_register(&new_client->dev); | |
370 | if (IS_ERR(data->hwmon_dev)) { | |
371 | err = PTR_ERR(data->hwmon_dev); | |
372 | goto exit_remove_files; | |
373 | } | |
374 | ||
375 | return 0; | |
376 | ||
377 | exit_remove_files: | |
378 | sysfs_remove_group(&new_client->dev.kobj, &lm95241_group); | |
06160327 DR |
379 | exit_free: |
380 | kfree(data); | |
381 | exit: | |
382 | return err; | |
383 | } | |
384 | ||
385 | static void lm95241_init_client(struct i2c_client *client) | |
386 | { | |
387 | struct lm95241_data *data = i2c_get_clientdata(client); | |
388 | ||
bc482bf0 | 389 | data->interval = HZ; /* 1 sec default */ |
06160327 DR |
390 | data->valid = 0; |
391 | data->config = CFG_CR0076; | |
392 | data->model = 0; | |
393 | data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); | |
394 | ||
395 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, | |
396 | data->config); | |
397 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER, | |
398 | R1FE_MASK | R2FE_MASK); | |
399 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, | |
400 | data->trutherm); | |
401 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, | |
402 | data->model); | |
403 | } | |
404 | ||
797eaa4b | 405 | static int lm95241_remove(struct i2c_client *client) |
06160327 DR |
406 | { |
407 | struct lm95241_data *data = i2c_get_clientdata(client); | |
06160327 DR |
408 | |
409 | hwmon_device_unregister(data->hwmon_dev); | |
410 | sysfs_remove_group(&client->dev.kobj, &lm95241_group); | |
411 | ||
06160327 DR |
412 | kfree(data); |
413 | return 0; | |
414 | } | |
415 | ||
416 | static struct lm95241_data *lm95241_update_device(struct device *dev) | |
417 | { | |
418 | struct i2c_client *client = to_i2c_client(dev); | |
419 | struct lm95241_data *data = i2c_get_clientdata(client); | |
420 | ||
421 | mutex_lock(&data->update_lock); | |
422 | ||
bc482bf0 | 423 | if (time_after(jiffies, data->last_updated + data->interval) || |
06160327 DR |
424 | !data->valid) { |
425 | dev_dbg(&client->dev, "Updating lm95241 data.\n"); | |
426 | data->local_h = | |
427 | i2c_smbus_read_byte_data(client, | |
428 | LM95241_REG_R_LOCAL_TEMPH); | |
429 | data->local_l = | |
430 | i2c_smbus_read_byte_data(client, | |
431 | LM95241_REG_R_LOCAL_TEMPL); | |
432 | data->remote1_h = | |
433 | i2c_smbus_read_byte_data(client, | |
434 | LM95241_REG_R_REMOTE1_TEMPH); | |
435 | data->remote1_l = | |
436 | i2c_smbus_read_byte_data(client, | |
437 | LM95241_REG_R_REMOTE1_TEMPL); | |
438 | data->remote2_h = | |
439 | i2c_smbus_read_byte_data(client, | |
440 | LM95241_REG_R_REMOTE2_TEMPH); | |
441 | data->remote2_l = | |
442 | i2c_smbus_read_byte_data(client, | |
443 | LM95241_REG_R_REMOTE2_TEMPL); | |
444 | data->last_updated = jiffies; | |
445 | data->valid = 1; | |
446 | } | |
447 | ||
448 | mutex_unlock(&data->update_lock); | |
449 | ||
450 | return data; | |
451 | } | |
452 | ||
797eaa4b JD |
453 | /* Driver data (common to all clients) */ |
454 | static const struct i2c_device_id lm95241_id[] = { | |
1f86df49 | 455 | { "lm95241", 0 }, |
797eaa4b JD |
456 | { } |
457 | }; | |
458 | MODULE_DEVICE_TABLE(i2c, lm95241_id); | |
459 | ||
460 | static struct i2c_driver lm95241_driver = { | |
461 | .class = I2C_CLASS_HWMON, | |
462 | .driver = { | |
463 | .name = "lm95241", | |
464 | }, | |
465 | .probe = lm95241_probe, | |
466 | .remove = lm95241_remove, | |
467 | .id_table = lm95241_id, | |
468 | .detect = lm95241_detect, | |
c3813d6a | 469 | .address_list = normal_i2c, |
797eaa4b JD |
470 | }; |
471 | ||
06160327 DR |
472 | static int __init sensors_lm95241_init(void) |
473 | { | |
474 | return i2c_add_driver(&lm95241_driver); | |
475 | } | |
476 | ||
477 | static void __exit sensors_lm95241_exit(void) | |
478 | { | |
479 | i2c_del_driver(&lm95241_driver); | |
480 | } | |
481 | ||
482 | MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>"); | |
483 | MODULE_DESCRIPTION("LM95241 sensor driver"); | |
484 | MODULE_LICENSE("GPL"); | |
485 | ||
486 | module_init(sensors_lm95241_init); | |
487 | module_exit(sensors_lm95241_exit); |