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); | |
131 | ||
bc482bf0 GR |
132 | strict_strtol(buf, 10, &data->interval); |
133 | data->interval = data->interval * HZ / 1000; | |
06160327 DR |
134 | |
135 | return count; | |
136 | } | |
137 | ||
138 | #define show_type(flag) \ | |
139 | static ssize_t show_type##flag(struct device *dev, \ | |
140 | struct device_attribute *attr, char *buf) \ | |
141 | { \ | |
142 | struct i2c_client *client = to_i2c_client(dev); \ | |
143 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
144 | \ | |
145 | snprintf(buf, PAGE_SIZE - 1, \ | |
146 | data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \ | |
147 | return strlen(buf); \ | |
148 | } | |
149 | show_type(1); | |
150 | show_type(2); | |
151 | ||
152 | #define show_min(flag) \ | |
153 | static ssize_t show_min##flag(struct device *dev, \ | |
154 | struct device_attribute *attr, char *buf) \ | |
155 | { \ | |
156 | struct i2c_client *client = to_i2c_client(dev); \ | |
157 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
158 | \ | |
159 | snprintf(buf, PAGE_SIZE - 1, \ | |
160 | data->config & R##flag##DF_MASK ? \ | |
161 | "-127000\n" : "0\n"); \ | |
162 | return strlen(buf); \ | |
163 | } | |
164 | show_min(1); | |
165 | show_min(2); | |
166 | ||
167 | #define show_max(flag) \ | |
168 | static ssize_t show_max##flag(struct device *dev, \ | |
169 | struct device_attribute *attr, char *buf) \ | |
170 | { \ | |
171 | struct i2c_client *client = to_i2c_client(dev); \ | |
172 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
173 | \ | |
174 | snprintf(buf, PAGE_SIZE - 1, \ | |
175 | data->config & R##flag##DF_MASK ? \ | |
176 | "127000\n" : "255000\n"); \ | |
177 | return strlen(buf); \ | |
178 | } | |
179 | show_max(1); | |
180 | show_max(2); | |
181 | ||
182 | #define set_type(flag) \ | |
183 | static ssize_t set_type##flag(struct device *dev, \ | |
184 | struct device_attribute *attr, \ | |
185 | const char *buf, size_t count) \ | |
186 | { \ | |
187 | struct i2c_client *client = to_i2c_client(dev); \ | |
188 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
189 | \ | |
190 | long val; \ | |
191 | strict_strtol(buf, 10, &val); \ | |
192 | \ | |
193 | if ((val == 1) || (val == 2)) { \ | |
194 | \ | |
195 | mutex_lock(&data->update_lock); \ | |
196 | \ | |
197 | data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \ | |
198 | if (val == 1) { \ | |
199 | data->model |= R##flag##MS_MASK; \ | |
200 | data->trutherm |= (TT_ON << TT##flag##_SHIFT); \ | |
201 | } \ | |
202 | else { \ | |
203 | data->model &= ~R##flag##MS_MASK; \ | |
204 | data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \ | |
205 | } \ | |
206 | \ | |
207 | data->valid = 0; \ | |
208 | \ | |
209 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \ | |
210 | data->model); \ | |
211 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \ | |
212 | data->trutherm); \ | |
213 | \ | |
214 | mutex_unlock(&data->update_lock); \ | |
215 | \ | |
216 | } \ | |
217 | return count; \ | |
218 | } | |
219 | set_type(1); | |
220 | set_type(2); | |
221 | ||
222 | #define set_min(flag) \ | |
223 | static ssize_t set_min##flag(struct device *dev, \ | |
224 | struct device_attribute *devattr, const char *buf, size_t count) \ | |
225 | { \ | |
226 | struct i2c_client *client = to_i2c_client(dev); \ | |
227 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
228 | \ | |
229 | long val; \ | |
230 | strict_strtol(buf, 10, &val); \ | |
231 | \ | |
232 | mutex_lock(&data->update_lock); \ | |
233 | \ | |
234 | if (val < 0) \ | |
235 | data->config |= R##flag##DF_MASK; \ | |
236 | else \ | |
237 | data->config &= ~R##flag##DF_MASK; \ | |
238 | \ | |
239 | data->valid = 0; \ | |
240 | \ | |
241 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ | |
242 | data->config); \ | |
243 | \ | |
244 | mutex_unlock(&data->update_lock); \ | |
245 | \ | |
246 | return count; \ | |
247 | } | |
248 | set_min(1); | |
249 | set_min(2); | |
250 | ||
251 | #define set_max(flag) \ | |
252 | static ssize_t set_max##flag(struct device *dev, \ | |
253 | struct device_attribute *devattr, const char *buf, size_t count) \ | |
254 | { \ | |
255 | struct i2c_client *client = to_i2c_client(dev); \ | |
256 | struct lm95241_data *data = i2c_get_clientdata(client); \ | |
257 | \ | |
258 | long val; \ | |
259 | strict_strtol(buf, 10, &val); \ | |
260 | \ | |
261 | mutex_lock(&data->update_lock); \ | |
262 | \ | |
263 | if (val <= 127000) \ | |
264 | data->config |= R##flag##DF_MASK; \ | |
265 | else \ | |
266 | data->config &= ~R##flag##DF_MASK; \ | |
267 | \ | |
268 | data->valid = 0; \ | |
269 | \ | |
270 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ | |
271 | data->config); \ | |
272 | \ | |
273 | mutex_unlock(&data->update_lock); \ | |
274 | \ | |
275 | return count; \ | |
276 | } | |
277 | set_max(1); | |
278 | set_max(2); | |
279 | ||
280 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL); | |
281 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL); | |
282 | static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL); | |
283 | static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1); | |
284 | static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2); | |
285 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1); | |
286 | static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2); | |
287 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1); | |
288 | static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2); | |
bc482bf0 GR |
289 | static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, |
290 | set_interval); | |
06160327 DR |
291 | |
292 | static struct attribute *lm95241_attributes[] = { | |
293 | &dev_attr_temp1_input.attr, | |
294 | &dev_attr_temp2_input.attr, | |
295 | &dev_attr_temp3_input.attr, | |
296 | &dev_attr_temp2_type.attr, | |
297 | &dev_attr_temp3_type.attr, | |
298 | &dev_attr_temp2_min.attr, | |
299 | &dev_attr_temp3_min.attr, | |
300 | &dev_attr_temp2_max.attr, | |
301 | &dev_attr_temp3_max.attr, | |
bc482bf0 | 302 | &dev_attr_update_interval.attr, |
06160327 DR |
303 | NULL |
304 | }; | |
305 | ||
306 | static const struct attribute_group lm95241_group = { | |
307 | .attrs = lm95241_attributes, | |
308 | }; | |
309 | ||
797eaa4b | 310 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
310ec792 | 311 | static int lm95241_detect(struct i2c_client *new_client, |
797eaa4b | 312 | struct i2c_board_info *info) |
06160327 | 313 | { |
797eaa4b JD |
314 | struct i2c_adapter *adapter = new_client->adapter; |
315 | int address = new_client->addr; | |
52df6440 | 316 | const char *name; |
06160327 DR |
317 | |
318 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
797eaa4b | 319 | return -ENODEV; |
06160327 | 320 | |
52df6440 JD |
321 | if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) |
322 | == MANUFACTURER_ID) | |
323 | && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) | |
324 | >= DEFAULT_REVISION)) { | |
325 | name = "lm95241"; | |
326 | } else { | |
327 | dev_dbg(&adapter->dev, "LM95241 detection failed at 0x%02x\n", | |
328 | address); | |
329 | return -ENODEV; | |
06160327 DR |
330 | } |
331 | ||
797eaa4b | 332 | /* Fill the i2c board info */ |
797eaa4b JD |
333 | strlcpy(info->type, name, I2C_NAME_SIZE); |
334 | return 0; | |
335 | } | |
06160327 | 336 | |
797eaa4b JD |
337 | static int lm95241_probe(struct i2c_client *new_client, |
338 | const struct i2c_device_id *id) | |
339 | { | |
340 | struct lm95241_data *data; | |
341 | int err; | |
06160327 | 342 | |
797eaa4b JD |
343 | data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL); |
344 | if (!data) { | |
345 | err = -ENOMEM; | |
346 | goto exit; | |
347 | } | |
348 | ||
349 | i2c_set_clientdata(new_client, data); | |
350 | mutex_init(&data->update_lock); | |
06160327 DR |
351 | |
352 | /* Initialize the LM95241 chip */ | |
353 | lm95241_init_client(new_client); | |
354 | ||
355 | /* Register sysfs hooks */ | |
356 | err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group); | |
357 | if (err) | |
797eaa4b | 358 | goto exit_free; |
06160327 DR |
359 | |
360 | data->hwmon_dev = hwmon_device_register(&new_client->dev); | |
361 | if (IS_ERR(data->hwmon_dev)) { | |
362 | err = PTR_ERR(data->hwmon_dev); | |
363 | goto exit_remove_files; | |
364 | } | |
365 | ||
366 | return 0; | |
367 | ||
368 | exit_remove_files: | |
369 | sysfs_remove_group(&new_client->dev.kobj, &lm95241_group); | |
06160327 DR |
370 | exit_free: |
371 | kfree(data); | |
372 | exit: | |
373 | return err; | |
374 | } | |
375 | ||
376 | static void lm95241_init_client(struct i2c_client *client) | |
377 | { | |
378 | struct lm95241_data *data = i2c_get_clientdata(client); | |
379 | ||
bc482bf0 | 380 | data->interval = HZ; /* 1 sec default */ |
06160327 DR |
381 | data->valid = 0; |
382 | data->config = CFG_CR0076; | |
383 | data->model = 0; | |
384 | data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); | |
385 | ||
386 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, | |
387 | data->config); | |
388 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER, | |
389 | R1FE_MASK | R2FE_MASK); | |
390 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, | |
391 | data->trutherm); | |
392 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, | |
393 | data->model); | |
394 | } | |
395 | ||
797eaa4b | 396 | static int lm95241_remove(struct i2c_client *client) |
06160327 DR |
397 | { |
398 | struct lm95241_data *data = i2c_get_clientdata(client); | |
06160327 DR |
399 | |
400 | hwmon_device_unregister(data->hwmon_dev); | |
401 | sysfs_remove_group(&client->dev.kobj, &lm95241_group); | |
402 | ||
06160327 DR |
403 | kfree(data); |
404 | return 0; | |
405 | } | |
406 | ||
407 | static struct lm95241_data *lm95241_update_device(struct device *dev) | |
408 | { | |
409 | struct i2c_client *client = to_i2c_client(dev); | |
410 | struct lm95241_data *data = i2c_get_clientdata(client); | |
411 | ||
412 | mutex_lock(&data->update_lock); | |
413 | ||
bc482bf0 | 414 | if (time_after(jiffies, data->last_updated + data->interval) || |
06160327 DR |
415 | !data->valid) { |
416 | dev_dbg(&client->dev, "Updating lm95241 data.\n"); | |
417 | data->local_h = | |
418 | i2c_smbus_read_byte_data(client, | |
419 | LM95241_REG_R_LOCAL_TEMPH); | |
420 | data->local_l = | |
421 | i2c_smbus_read_byte_data(client, | |
422 | LM95241_REG_R_LOCAL_TEMPL); | |
423 | data->remote1_h = | |
424 | i2c_smbus_read_byte_data(client, | |
425 | LM95241_REG_R_REMOTE1_TEMPH); | |
426 | data->remote1_l = | |
427 | i2c_smbus_read_byte_data(client, | |
428 | LM95241_REG_R_REMOTE1_TEMPL); | |
429 | data->remote2_h = | |
430 | i2c_smbus_read_byte_data(client, | |
431 | LM95241_REG_R_REMOTE2_TEMPH); | |
432 | data->remote2_l = | |
433 | i2c_smbus_read_byte_data(client, | |
434 | LM95241_REG_R_REMOTE2_TEMPL); | |
435 | data->last_updated = jiffies; | |
436 | data->valid = 1; | |
437 | } | |
438 | ||
439 | mutex_unlock(&data->update_lock); | |
440 | ||
441 | return data; | |
442 | } | |
443 | ||
797eaa4b JD |
444 | /* Driver data (common to all clients) */ |
445 | static const struct i2c_device_id lm95241_id[] = { | |
1f86df49 | 446 | { "lm95241", 0 }, |
797eaa4b JD |
447 | { } |
448 | }; | |
449 | MODULE_DEVICE_TABLE(i2c, lm95241_id); | |
450 | ||
451 | static struct i2c_driver lm95241_driver = { | |
452 | .class = I2C_CLASS_HWMON, | |
453 | .driver = { | |
454 | .name = "lm95241", | |
455 | }, | |
456 | .probe = lm95241_probe, | |
457 | .remove = lm95241_remove, | |
458 | .id_table = lm95241_id, | |
459 | .detect = lm95241_detect, | |
c3813d6a | 460 | .address_list = normal_i2c, |
797eaa4b JD |
461 | }; |
462 | ||
06160327 DR |
463 | static int __init sensors_lm95241_init(void) |
464 | { | |
465 | return i2c_add_driver(&lm95241_driver); | |
466 | } | |
467 | ||
468 | static void __exit sensors_lm95241_exit(void) | |
469 | { | |
470 | i2c_del_driver(&lm95241_driver); | |
471 | } | |
472 | ||
473 | MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>"); | |
474 | MODULE_DESCRIPTION("LM95241 sensor driver"); | |
475 | MODULE_LICENSE("GPL"); | |
476 | ||
477 | module_init(sensors_lm95241_init); | |
478 | module_exit(sensors_lm95241_exit); |