1 /* 2 * w1_therm.c 3 * 4 * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> 5 * 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the therms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include <asm/types.h> 23 24 #include <linux/kernel.h> 25 #include <linux/module.h> 26 #include <linux/moduleparam.h> 27 #include <linux/sched.h> 28 #include <linux/device.h> 29 #include <linux/types.h> 30 #include <linux/slab.h> 31 #include <linux/delay.h> 32 33 #include <linux/w1.h> 34 35 #define W1_THERM_DS18S20 0x10 36 #define W1_THERM_DS1822 0x22 37 #define W1_THERM_DS18B20 0x28 38 #define W1_THERM_DS1825 0x3B 39 #define W1_THERM_DS28EA00 0x42 40 41 /* Allow the strong pullup to be disabled, but default to enabled. 42 * If it was disabled a parasite powered device might not get the require 43 * current to do a temperature conversion. If it is enabled parasite powered 44 * devices have a better chance of getting the current required. 45 * In case the parasite power-detection is not working (seems to be the case 46 * for some DS18S20) the strong pullup can also be forced, regardless of the 47 * power state of the devices. 48 * 49 * Summary of options: 50 * - strong_pullup = 0 Disable strong pullup completely 51 * - strong_pullup = 1 Enable automatic strong pullup detection 52 * - strong_pullup = 2 Force strong pullup 53 */ 54 static int w1_strong_pullup = 1; 55 module_param_named(strong_pullup, w1_strong_pullup, int, 0); 56 57 struct w1_therm_family_data { 58 uint8_t rom[9]; 59 atomic_t refcnt; 60 }; 61 62 /* return the address of the refcnt in the family data */ 63 #define THERM_REFCNT(family_data) \ 64 (&((struct w1_therm_family_data *)family_data)->refcnt) 65 66 static int w1_therm_add_slave(struct w1_slave *sl) 67 { 68 sl->family_data = kzalloc(sizeof(struct w1_therm_family_data), 69 GFP_KERNEL); 70 if (!sl->family_data) 71 return -ENOMEM; 72 atomic_set(THERM_REFCNT(sl->family_data), 1); 73 return 0; 74 } 75 76 static void w1_therm_remove_slave(struct w1_slave *sl) 77 { 78 int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data)); 79 80 while (refcnt) { 81 msleep(1000); 82 refcnt = atomic_read(THERM_REFCNT(sl->family_data)); 83 } 84 kfree(sl->family_data); 85 sl->family_data = NULL; 86 } 87 88 static ssize_t w1_slave_show(struct device *device, 89 struct device_attribute *attr, char *buf); 90 91 static ssize_t w1_slave_store(struct device *device, 92 struct device_attribute *attr, const char *buf, size_t size); 93 94 static ssize_t w1_seq_show(struct device *device, 95 struct device_attribute *attr, char *buf); 96 97 static DEVICE_ATTR_RW(w1_slave); 98 static DEVICE_ATTR_RO(w1_seq); 99 100 static struct attribute *w1_therm_attrs[] = { 101 &dev_attr_w1_slave.attr, 102 NULL, 103 }; 104 105 static struct attribute *w1_ds28ea00_attrs[] = { 106 &dev_attr_w1_slave.attr, 107 &dev_attr_w1_seq.attr, 108 NULL, 109 }; 110 ATTRIBUTE_GROUPS(w1_therm); 111 ATTRIBUTE_GROUPS(w1_ds28ea00); 112 113 static struct w1_family_ops w1_therm_fops = { 114 .add_slave = w1_therm_add_slave, 115 .remove_slave = w1_therm_remove_slave, 116 .groups = w1_therm_groups, 117 }; 118 119 static struct w1_family_ops w1_ds28ea00_fops = { 120 .add_slave = w1_therm_add_slave, 121 .remove_slave = w1_therm_remove_slave, 122 .groups = w1_ds28ea00_groups, 123 }; 124 125 static struct w1_family w1_therm_family_DS18S20 = { 126 .fid = W1_THERM_DS18S20, 127 .fops = &w1_therm_fops, 128 }; 129 130 static struct w1_family w1_therm_family_DS18B20 = { 131 .fid = W1_THERM_DS18B20, 132 .fops = &w1_therm_fops, 133 }; 134 135 static struct w1_family w1_therm_family_DS1822 = { 136 .fid = W1_THERM_DS1822, 137 .fops = &w1_therm_fops, 138 }; 139 140 static struct w1_family w1_therm_family_DS28EA00 = { 141 .fid = W1_THERM_DS28EA00, 142 .fops = &w1_ds28ea00_fops, 143 }; 144 145 static struct w1_family w1_therm_family_DS1825 = { 146 .fid = W1_THERM_DS1825, 147 .fops = &w1_therm_fops, 148 }; 149 150 struct w1_therm_family_converter { 151 u8 broken; 152 u16 reserved; 153 struct w1_family *f; 154 int (*convert)(u8 rom[9]); 155 int (*precision)(struct device *device, int val); 156 int (*eeprom)(struct device *device); 157 }; 158 159 /* write configuration to eeprom */ 160 static inline int w1_therm_eeprom(struct device *device); 161 162 /* Set precision for conversion */ 163 static inline int w1_DS18B20_precision(struct device *device, int val); 164 static inline int w1_DS18S20_precision(struct device *device, int val); 165 166 /* The return value is millidegrees Centigrade. */ 167 static inline int w1_DS18B20_convert_temp(u8 rom[9]); 168 static inline int w1_DS18S20_convert_temp(u8 rom[9]); 169 170 static struct w1_therm_family_converter w1_therm_families[] = { 171 { 172 .f = &w1_therm_family_DS18S20, 173 .convert = w1_DS18S20_convert_temp, 174 .precision = w1_DS18S20_precision, 175 .eeprom = w1_therm_eeprom 176 }, 177 { 178 .f = &w1_therm_family_DS1822, 179 .convert = w1_DS18B20_convert_temp, 180 .precision = w1_DS18S20_precision, 181 .eeprom = w1_therm_eeprom 182 }, 183 { 184 .f = &w1_therm_family_DS18B20, 185 .convert = w1_DS18B20_convert_temp, 186 .precision = w1_DS18B20_precision, 187 .eeprom = w1_therm_eeprom 188 }, 189 { 190 .f = &w1_therm_family_DS28EA00, 191 .convert = w1_DS18B20_convert_temp, 192 .precision = w1_DS18S20_precision, 193 .eeprom = w1_therm_eeprom 194 }, 195 { 196 .f = &w1_therm_family_DS1825, 197 .convert = w1_DS18B20_convert_temp, 198 .precision = w1_DS18S20_precision, 199 .eeprom = w1_therm_eeprom 200 } 201 }; 202 203 static inline int w1_therm_eeprom(struct device *device) 204 { 205 struct w1_slave *sl = dev_to_w1_slave(device); 206 struct w1_master *dev = sl->master; 207 u8 rom[9], external_power; 208 int ret, max_trying = 10; 209 u8 *family_data = sl->family_data; 210 211 ret = mutex_lock_interruptible(&dev->bus_mutex); 212 if (ret != 0) 213 goto post_unlock; 214 215 if (!sl->family_data) { 216 ret = -ENODEV; 217 goto pre_unlock; 218 } 219 220 /* prevent the slave from going away in sleep */ 221 atomic_inc(THERM_REFCNT(family_data)); 222 memset(rom, 0, sizeof(rom)); 223 224 while (max_trying--) { 225 if (!w1_reset_select_slave(sl)) { 226 unsigned int tm = 10; 227 unsigned long sleep_rem; 228 229 /* check if in parasite mode */ 230 w1_write_8(dev, W1_READ_PSUPPLY); 231 external_power = w1_read_8(dev); 232 233 if (w1_reset_select_slave(sl)) 234 continue; 235 236 /* 10ms strong pullup/delay after the copy command */ 237 if (w1_strong_pullup == 2 || 238 (!external_power && w1_strong_pullup)) 239 w1_next_pullup(dev, tm); 240 241 w1_write_8(dev, W1_COPY_SCRATCHPAD); 242 243 if (external_power) { 244 mutex_unlock(&dev->bus_mutex); 245 246 sleep_rem = msleep_interruptible(tm); 247 if (sleep_rem != 0) { 248 ret = -EINTR; 249 goto post_unlock; 250 } 251 252 ret = mutex_lock_interruptible(&dev->bus_mutex); 253 if (ret != 0) 254 goto post_unlock; 255 } else if (!w1_strong_pullup) { 256 sleep_rem = msleep_interruptible(tm); 257 if (sleep_rem != 0) { 258 ret = -EINTR; 259 goto pre_unlock; 260 } 261 } 262 263 break; 264 } 265 } 266 267 pre_unlock: 268 mutex_unlock(&dev->bus_mutex); 269 270 post_unlock: 271 atomic_dec(THERM_REFCNT(family_data)); 272 return ret; 273 } 274 275 /* DS18S20 does not feature configuration register */ 276 static inline int w1_DS18S20_precision(struct device *device, int val) 277 { 278 return 0; 279 } 280 281 static inline int w1_DS18B20_precision(struct device *device, int val) 282 { 283 struct w1_slave *sl = dev_to_w1_slave(device); 284 struct w1_master *dev = sl->master; 285 u8 rom[9], crc; 286 int ret, max_trying = 10; 287 u8 *family_data = sl->family_data; 288 uint8_t precision_bits; 289 uint8_t mask = 0x60; 290 291 if (val > 12 || val < 9) { 292 pr_warn("Unsupported precision\n"); 293 return -1; 294 } 295 296 ret = mutex_lock_interruptible(&dev->bus_mutex); 297 if (ret != 0) 298 goto post_unlock; 299 300 if (!sl->family_data) { 301 ret = -ENODEV; 302 goto pre_unlock; 303 } 304 305 /* prevent the slave from going away in sleep */ 306 atomic_inc(THERM_REFCNT(family_data)); 307 memset(rom, 0, sizeof(rom)); 308 309 /* translate precision to bitmask (see datasheet page 9) */ 310 switch (val) { 311 case 9: 312 precision_bits = 0x00; 313 break; 314 case 10: 315 precision_bits = 0x20; 316 break; 317 case 11: 318 precision_bits = 0x40; 319 break; 320 case 12: 321 default: 322 precision_bits = 0x60; 323 break; 324 } 325 326 while (max_trying--) { 327 crc = 0; 328 329 if (!w1_reset_select_slave(sl)) { 330 int count = 0; 331 332 /* read values to only alter precision bits */ 333 w1_write_8(dev, W1_READ_SCRATCHPAD); 334 count = w1_read_block(dev, rom, 9); 335 if (count != 9) 336 dev_warn(device, "w1_read_block() returned %u instead of 9.\n", count); 337 338 crc = w1_calc_crc8(rom, 8); 339 if (rom[8] == crc) { 340 rom[4] = (rom[4] & ~mask) | (precision_bits & mask); 341 342 if (!w1_reset_select_slave(sl)) { 343 w1_write_8(dev, W1_WRITE_SCRATCHPAD); 344 w1_write_8(dev, rom[2]); 345 w1_write_8(dev, rom[3]); 346 w1_write_8(dev, rom[4]); 347 348 break; 349 } 350 } 351 } 352 } 353 354 pre_unlock: 355 mutex_unlock(&dev->bus_mutex); 356 357 post_unlock: 358 atomic_dec(THERM_REFCNT(family_data)); 359 return ret; 360 } 361 362 static inline int w1_DS18B20_convert_temp(u8 rom[9]) 363 { 364 s16 t = le16_to_cpup((__le16 *)rom); 365 366 return t*1000/16; 367 } 368 369 static inline int w1_DS18S20_convert_temp(u8 rom[9]) 370 { 371 int t, h; 372 373 if (!rom[7]) 374 return 0; 375 376 if (rom[1] == 0) 377 t = ((s32)rom[0] >> 1)*1000; 378 else 379 t = 1000*(-1*(s32)(0x100-rom[0]) >> 1); 380 381 t -= 250; 382 h = 1000*((s32)rom[7] - (s32)rom[6]); 383 h /= (s32)rom[7]; 384 t += h; 385 386 return t; 387 } 388 389 static inline int w1_convert_temp(u8 rom[9], u8 fid) 390 { 391 int i; 392 393 for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) 394 if (w1_therm_families[i].f->fid == fid) 395 return w1_therm_families[i].convert(rom); 396 397 return 0; 398 } 399 400 static ssize_t w1_slave_store(struct device *device, 401 struct device_attribute *attr, const char *buf, 402 size_t size) 403 { 404 int val, ret; 405 struct w1_slave *sl = dev_to_w1_slave(device); 406 int i; 407 408 ret = kstrtoint(buf, 0, &val); 409 if (ret) 410 return ret; 411 412 for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { 413 if (w1_therm_families[i].f->fid == sl->family->fid) { 414 /* zero value indicates to write current configuration to eeprom */ 415 if (val == 0) 416 ret = w1_therm_families[i].eeprom(device); 417 else 418 ret = w1_therm_families[i].precision(device, val); 419 break; 420 } 421 } 422 return ret ? : size; 423 } 424 425 static ssize_t w1_slave_show(struct device *device, 426 struct device_attribute *attr, char *buf) 427 { 428 struct w1_slave *sl = dev_to_w1_slave(device); 429 struct w1_master *dev = sl->master; 430 u8 rom[9], crc, verdict, external_power; 431 int i, ret, max_trying = 10; 432 ssize_t c = PAGE_SIZE; 433 u8 *family_data = sl->family_data; 434 435 ret = mutex_lock_interruptible(&dev->bus_mutex); 436 if (ret != 0) 437 goto post_unlock; 438 439 if (!sl->family_data) { 440 ret = -ENODEV; 441 goto pre_unlock; 442 } 443 444 /* prevent the slave from going away in sleep */ 445 atomic_inc(THERM_REFCNT(family_data)); 446 memset(rom, 0, sizeof(rom)); 447 448 while (max_trying--) { 449 450 verdict = 0; 451 crc = 0; 452 453 if (!w1_reset_select_slave(sl)) { 454 int count = 0; 455 unsigned int tm = 750; 456 unsigned long sleep_rem; 457 458 w1_write_8(dev, W1_READ_PSUPPLY); 459 external_power = w1_read_8(dev); 460 461 if (w1_reset_select_slave(sl)) 462 continue; 463 464 /* 750ms strong pullup (or delay) after the convert */ 465 if (w1_strong_pullup == 2 || 466 (!external_power && w1_strong_pullup)) 467 w1_next_pullup(dev, tm); 468 469 w1_write_8(dev, W1_CONVERT_TEMP); 470 471 if (external_power) { 472 mutex_unlock(&dev->bus_mutex); 473 474 sleep_rem = msleep_interruptible(tm); 475 if (sleep_rem != 0) { 476 ret = -EINTR; 477 goto post_unlock; 478 } 479 480 ret = mutex_lock_interruptible(&dev->bus_mutex); 481 if (ret != 0) 482 goto post_unlock; 483 } else if (!w1_strong_pullup) { 484 sleep_rem = msleep_interruptible(tm); 485 if (sleep_rem != 0) { 486 ret = -EINTR; 487 goto pre_unlock; 488 } 489 } 490 491 if (!w1_reset_select_slave(sl)) { 492 493 w1_write_8(dev, W1_READ_SCRATCHPAD); 494 count = w1_read_block(dev, rom, 9); 495 if (count != 9) { 496 dev_warn(device, "w1_read_block() " 497 "returned %u instead of 9.\n", 498 count); 499 } 500 501 crc = w1_calc_crc8(rom, 8); 502 503 if (rom[8] == crc) 504 verdict = 1; 505 } 506 } 507 508 if (verdict) 509 break; 510 } 511 512 for (i = 0; i < 9; ++i) 513 c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", rom[i]); 514 c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n", 515 crc, (verdict) ? "YES" : "NO"); 516 if (verdict) 517 memcpy(family_data, rom, sizeof(rom)); 518 else 519 dev_warn(device, "Read failed CRC check\n"); 520 521 for (i = 0; i < 9; ++i) 522 c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", 523 ((u8 *)family_data)[i]); 524 525 c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n", 526 w1_convert_temp(rom, sl->family->fid)); 527 ret = PAGE_SIZE - c; 528 529 pre_unlock: 530 mutex_unlock(&dev->bus_mutex); 531 532 post_unlock: 533 atomic_dec(THERM_REFCNT(family_data)); 534 return ret; 535 } 536 537 #define W1_42_CHAIN 0x99 538 #define W1_42_CHAIN_OFF 0x3C 539 #define W1_42_CHAIN_OFF_INV 0xC3 540 #define W1_42_CHAIN_ON 0x5A 541 #define W1_42_CHAIN_ON_INV 0xA5 542 #define W1_42_CHAIN_DONE 0x96 543 #define W1_42_CHAIN_DONE_INV 0x69 544 #define W1_42_COND_READ 0x0F 545 #define W1_42_SUCCESS_CONFIRM_BYTE 0xAA 546 #define W1_42_FINISHED_BYTE 0xFF 547 static ssize_t w1_seq_show(struct device *device, 548 struct device_attribute *attr, char *buf) 549 { 550 struct w1_slave *sl = dev_to_w1_slave(device); 551 ssize_t c = PAGE_SIZE; 552 int rv; 553 int i; 554 u8 ack; 555 u64 rn; 556 struct w1_reg_num *reg_num; 557 int seq = 0; 558 559 mutex_lock(&sl->master->bus_mutex); 560 /* Place all devices in CHAIN state */ 561 if (w1_reset_bus(sl->master)) 562 goto error; 563 w1_write_8(sl->master, W1_SKIP_ROM); 564 w1_write_8(sl->master, W1_42_CHAIN); 565 w1_write_8(sl->master, W1_42_CHAIN_ON); 566 w1_write_8(sl->master, W1_42_CHAIN_ON_INV); 567 msleep(sl->master->pullup_duration); 568 569 /* check for acknowledgment */ 570 ack = w1_read_8(sl->master); 571 if (ack != W1_42_SUCCESS_CONFIRM_BYTE) 572 goto error; 573 574 /* In case the bus fails to send 0xFF, limit*/ 575 for (i = 0; i <= 64; i++) { 576 if (w1_reset_bus(sl->master)) 577 goto error; 578 579 w1_write_8(sl->master, W1_42_COND_READ); 580 rv = w1_read_block(sl->master, (u8 *)&rn, 8); 581 reg_num = (struct w1_reg_num *) &rn; 582 if (reg_num->family == W1_42_FINISHED_BYTE) 583 break; 584 if (sl->reg_num.id == reg_num->id) 585 seq = i; 586 587 w1_write_8(sl->master, W1_42_CHAIN); 588 w1_write_8(sl->master, W1_42_CHAIN_DONE); 589 w1_write_8(sl->master, W1_42_CHAIN_DONE_INV); 590 w1_read_block(sl->master, &ack, sizeof(ack)); 591 592 /* check for acknowledgment */ 593 ack = w1_read_8(sl->master); 594 if (ack != W1_42_SUCCESS_CONFIRM_BYTE) 595 goto error; 596 597 } 598 599 /* Exit from CHAIN state */ 600 if (w1_reset_bus(sl->master)) 601 goto error; 602 w1_write_8(sl->master, W1_SKIP_ROM); 603 w1_write_8(sl->master, W1_42_CHAIN); 604 w1_write_8(sl->master, W1_42_CHAIN_OFF); 605 w1_write_8(sl->master, W1_42_CHAIN_OFF_INV); 606 607 /* check for acknowledgment */ 608 ack = w1_read_8(sl->master); 609 if (ack != W1_42_SUCCESS_CONFIRM_BYTE) 610 goto error; 611 mutex_unlock(&sl->master->bus_mutex); 612 613 c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq); 614 return PAGE_SIZE - c; 615 error: 616 mutex_unlock(&sl->master->bus_mutex); 617 return -EIO; 618 } 619 620 static int __init w1_therm_init(void) 621 { 622 int err, i; 623 624 for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { 625 err = w1_register_family(w1_therm_families[i].f); 626 if (err) 627 w1_therm_families[i].broken = 1; 628 } 629 630 return 0; 631 } 632 633 static void __exit w1_therm_fini(void) 634 { 635 int i; 636 637 for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) 638 if (!w1_therm_families[i].broken) 639 w1_unregister_family(w1_therm_families[i].f); 640 } 641 642 module_init(w1_therm_init); 643 module_exit(w1_therm_fini); 644 645 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); 646 MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family."); 647 MODULE_LICENSE("GPL"); 648 MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18S20)); 649 MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1822)); 650 MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS18B20)); 651 MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS1825)); 652 MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00)); 653