|
29 | 29 | #include <linux/types.h> |
30 | 30 | #include <linux/slab.h> |
31 | 31 | #include <linux/delay.h> |
| 32 | +#include <linux/uaccess.h> |
32 | 33 |
|
33 | 34 | #include "../w1.h" |
34 | 35 | #include "../w1_int.h" |
@@ -59,6 +60,9 @@ MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00)); |
59 | 60 | static int w1_strong_pullup = 1; |
60 | 61 | module_param_named(strong_pullup, w1_strong_pullup, int, 0); |
61 | 62 |
|
| 63 | +/* resolution of ds18b20, use for temperture convert */ |
| 64 | +static int w1_ds18b20_res = 3; |
| 65 | + |
62 | 66 | struct w1_therm_family_data { |
63 | 67 | uint8_t rom[9]; |
64 | 68 | atomic_t refcnt; |
@@ -95,11 +99,19 @@ static ssize_t w1_slave_show(struct device *device, |
95 | 99 | static ssize_t w1_seq_show(struct device *device, |
96 | 100 | struct device_attribute *attr, char *buf); |
97 | 101 |
|
| 102 | +static ssize_t w1_res_show(struct device *device, |
| 103 | + struct device_attribute *attr, char *buf); |
| 104 | + |
| 105 | +static ssize_t w1_res_store(struct device *device, |
| 106 | + struct device_attribute *attr, const char *buf, size_t count); |
| 107 | + |
98 | 108 | static DEVICE_ATTR_RO(w1_slave); |
99 | 109 | static DEVICE_ATTR_RO(w1_seq); |
| 110 | +static DEVICE_ATTR_RW(w1_res); |
100 | 111 |
|
101 | 112 | static struct attribute *w1_therm_attrs[] = { |
102 | 113 | &dev_attr_w1_slave.attr, |
| 114 | + &dev_attr_w1_res.attr, |
103 | 115 | NULL, |
104 | 116 | }; |
105 | 117 |
|
@@ -416,6 +428,144 @@ static ssize_t w1_seq_show(struct device *device, |
416 | 428 | return -EIO; |
417 | 429 | } |
418 | 430 |
|
| 431 | +static ssize_t w1_res_show(struct device *device, |
| 432 | + struct device_attribute *attr, char *buf) |
| 433 | +{ |
| 434 | + struct w1_slave *sl = dev_to_w1_slave(device); |
| 435 | + struct w1_master *dev = sl->master; |
| 436 | + u8 rom[9], crc, verdict; |
| 437 | + int res, ret, max_trying = 10, count = 0; |
| 438 | + u8 *family_data = sl->family_data; |
| 439 | + |
| 440 | + ret = mutex_lock_interruptible(&dev->bus_mutex); |
| 441 | + if (ret != 0) |
| 442 | + goto post_unlock; |
| 443 | + |
| 444 | + if(!sl->family_data) |
| 445 | + { |
| 446 | + ret = -ENODEV; |
| 447 | + goto pre_unlock; |
| 448 | + } |
| 449 | + |
| 450 | + /* prevent the slave from going away in sleep */ |
| 451 | + atomic_inc(THERM_REFCNT(family_data)); |
| 452 | + memset(rom, 0, sizeof(rom)); |
| 453 | + |
| 454 | + while (max_trying--) { |
| 455 | + verdict = 0; |
| 456 | + crc = 0 ; |
| 457 | + |
| 458 | + if (!w1_reset_select_slave(sl)) { |
| 459 | + w1_write_8(dev, W1_READ_SCRATCHPAD); |
| 460 | + if ((count = w1_read_block(dev, rom, 9)) != 9) { |
| 461 | + dev_warn(device, "w1_read_block() " |
| 462 | + "returned %u instead of 9.\n", |
| 463 | + count); |
| 464 | + } |
| 465 | + |
| 466 | + crc = w1_calc_crc8(rom, 8); |
| 467 | + |
| 468 | + if (rom[8] == crc) |
| 469 | + verdict = 1; |
| 470 | + } |
| 471 | + |
| 472 | + if (verdict) |
| 473 | + break; |
| 474 | + } |
| 475 | + |
| 476 | + res = (rom[4] & 0x60) >> 5; |
| 477 | + ret = sprintf(buf, "Resolution is %d\n", res); |
| 478 | + |
| 479 | +pre_unlock: |
| 480 | + mutex_unlock(&dev->bus_mutex); |
| 481 | + |
| 482 | +post_unlock: |
| 483 | + atomic_dec(THERM_REFCNT(family_data)); |
| 484 | + return ret; |
| 485 | +} |
| 486 | + |
| 487 | +static ssize_t w1_res_store(struct device *device, |
| 488 | + struct device_attribute *attr, const char *buf, size_t count) |
| 489 | +{ |
| 490 | + struct w1_slave *sl = dev_to_w1_slave(device); |
| 491 | + struct w1_master *dev = sl->master; |
| 492 | + u8 rom[9], crc, verdict; |
| 493 | + int ret, max_trying = 10, val, res; |
| 494 | + u8 *family_data = sl->family_data; |
| 495 | + |
| 496 | + ret = mutex_lock_interruptible(&dev->bus_mutex); |
| 497 | + if (ret != 0) |
| 498 | + goto post_unlock; |
| 499 | + |
| 500 | + if(!sl->family_data) |
| 501 | + { |
| 502 | + ret = -ENODEV; |
| 503 | + goto pre_unlock; |
| 504 | + } |
| 505 | + |
| 506 | + /* prevent the slave from going away in sleep */ |
| 507 | + atomic_inc(THERM_REFCNT(family_data)); |
| 508 | + memset(rom, 0, sizeof(rom)); |
| 509 | + |
| 510 | + while (max_trying--) { |
| 511 | + verdict = 0; |
| 512 | + crc = 0; |
| 513 | + |
| 514 | + if (!w1_reset_select_slave(sl)) { |
| 515 | + w1_write_8(dev, W1_READ_SCRATCHPAD); |
| 516 | + if ((count = w1_read_block(dev, rom, 9)) != 9) { |
| 517 | + dev_warn(device, "w1_read_block() " |
| 518 | + "returned %u instead of 9.\n", |
| 519 | + count); |
| 520 | + } |
| 521 | + |
| 522 | + crc = w1_calc_crc8(rom, 8); |
| 523 | + |
| 524 | + if (rom[8] == crc) |
| 525 | + verdict = 1; |
| 526 | + } |
| 527 | + |
| 528 | + if (verdict) |
| 529 | + break; |
| 530 | + } |
| 531 | + |
| 532 | + res = (rom[4] & 0x60) >> 5; |
| 533 | + |
| 534 | + ret = kstrtoint(buf, 10, &val); |
| 535 | + if (ret) |
| 536 | + { |
| 537 | + ret = -EINVAL; |
| 538 | + goto pre_unlock; |
| 539 | + } |
| 540 | + |
| 541 | + if (val == res) |
| 542 | + { |
| 543 | + dev_warn(device, "w1_res_store() " |
| 544 | + "the same resolution setting! ignore\n"); |
| 545 | + goto pre_unlock; |
| 546 | + } |
| 547 | + else |
| 548 | + res = val; |
| 549 | + |
| 550 | + rom[4] &= 0x9f; |
| 551 | + rom[4] |= (res << 5); |
| 552 | + |
| 553 | + if (!w1_reset_select_slave(sl)) { |
| 554 | + w1_write_8(dev, W1_WRITE_SCRATCHPAD); |
| 555 | + w1_write_block(dev, rom+2, 3); |
| 556 | + } |
| 557 | + |
| 558 | + w1_ds18b20_res = res; |
| 559 | + |
| 560 | +pre_unlock: |
| 561 | + mutex_unlock(&dev->bus_mutex); |
| 562 | + |
| 563 | +post_unlock: |
| 564 | + atomic_dec(THERM_REFCNT(family_data)); |
| 565 | + |
| 566 | + return sizeof(w1_ds18b20_res); |
| 567 | +} |
| 568 | + |
419 | 569 | static int __init w1_therm_init(void) |
420 | 570 | { |
421 | 571 | int err, i; |
|
0 commit comments