Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

w1: Add support for DS28EA00 sequence to w1-therm

This patch provides support for the DS28EA00 digital thermometer.

The DS28EA00 provides an additional two pins for implementing a sequence
detection algorithm. This feature allows you to determine the physical
location of the chip in the 1-wire bus without needing pre-existing
knowledge of the bus ordering. Support is provided through the sysfs
w1_seq file. The file will contain a single line with an integer value
representing the device index in the bus starting at 0.

Signed-off-by: Matt Campbell <mattrcampbell@gmail.com>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Matt Campbell and committed by
Greg Kroah-Hartman
d9411e57 f7134eea

+117 -2
+6
Documentation/ABI/stable/sysfs-driver-w1_ds28ea00
··· 1 + What: /sys/bus/w1/devices/.../w1_seq 2 + Date: Apr 2015 3 + Contact: Matt Campbell <mattrcampbell@gmail.com> 4 + Description: Support for the DS28EA00 chain sequence function 5 + see Documentation/w1/slaves/w1_therm for detailed information 6 + Users: any user space application which wants to communicate with DS28EA00
+10 -1
Documentation/w1/slaves/w1_therm
··· 11 11 Description 12 12 ----------- 13 13 14 - w1_therm provides basic temperature conversion for ds18*20 devices. 14 + w1_therm provides basic temperature conversion for ds18*20 devices, and the 15 + ds28ea00 device. 15 16 supported family codes: 16 17 W1_THERM_DS18S20 0x10 17 18 W1_THERM_DS1822 0x22 18 19 W1_THERM_DS18B20 0x28 19 20 W1_THERM_DS1825 0x3B 21 + W1_THERM_DS28EA00 0x42 20 22 21 23 Support is provided through the sysfs w1_slave file. Each open and 22 24 read sequence will initiate a temperature conversion then provide two ··· 50 48 maximum current draw of 1.5mA and that a 5k pullup resistor is not 51 49 sufficient. The strong pullup is designed to provide the additional 52 50 current required. 51 + 52 + The DS28EA00 provides an additional two pins for implementing a sequence 53 + detection algorithm. This feature allows you to determine the physical 54 + location of the chip in the 1-wire bus without needing pre-existing 55 + knowledge of the bus ordering. Support is provided through the sysfs 56 + w1_seq file. The file will contain a single line with an integer value 57 + representing the device index in the bus starting at 0.
+101 -1
drivers/w1/slaves/w1_therm.c
··· 92 92 static ssize_t w1_slave_show(struct device *device, 93 93 struct device_attribute *attr, char *buf); 94 94 95 + static ssize_t w1_seq_show(struct device *device, 96 + struct device_attribute *attr, char *buf); 97 + 95 98 static DEVICE_ATTR_RO(w1_slave); 99 + static DEVICE_ATTR_RO(w1_seq); 96 100 97 101 static struct attribute *w1_therm_attrs[] = { 98 102 &dev_attr_w1_slave.attr, 99 103 NULL, 100 104 }; 105 + 106 + static struct attribute *w1_ds28ea00_attrs[] = { 107 + &dev_attr_w1_slave.attr, 108 + &dev_attr_w1_seq.attr, 109 + NULL, 110 + }; 101 111 ATTRIBUTE_GROUPS(w1_therm); 112 + ATTRIBUTE_GROUPS(w1_ds28ea00); 102 113 103 114 static struct w1_family_ops w1_therm_fops = { 104 115 .add_slave = w1_therm_add_slave, 105 116 .remove_slave = w1_therm_remove_slave, 106 117 .groups = w1_therm_groups, 118 + }; 119 + 120 + static struct w1_family_ops w1_ds28ea00_fops = { 121 + .add_slave = w1_therm_add_slave, 122 + .remove_slave = w1_therm_remove_slave, 123 + .groups = w1_ds28ea00_groups, 107 124 }; 108 125 109 126 static struct w1_family w1_therm_family_DS18S20 = { ··· 140 123 141 124 static struct w1_family w1_therm_family_DS28EA00 = { 142 125 .fid = W1_THERM_DS28EA00, 143 - .fops = &w1_therm_fops, 126 + .fops = &w1_ds28ea00_fops, 144 127 }; 145 128 146 129 static struct w1_family w1_therm_family_DS1825 = { ··· 331 314 post_unlock: 332 315 atomic_dec(THERM_REFCNT(family_data)); 333 316 return ret; 317 + } 318 + 319 + #define W1_42_CHAIN 0x99 320 + #define W1_42_CHAIN_OFF 0x3C 321 + #define W1_42_CHAIN_OFF_INV 0xC3 322 + #define W1_42_CHAIN_ON 0x5A 323 + #define W1_42_CHAIN_ON_INV 0xA5 324 + #define W1_42_CHAIN_DONE 0x96 325 + #define W1_42_CHAIN_DONE_INV 0x69 326 + #define W1_42_COND_READ 0x0F 327 + #define W1_42_SUCCESS_CONFIRM_BYTE 0xAA 328 + #define W1_42_FINISHED_BYTE 0xFF 329 + static ssize_t w1_seq_show(struct device *device, 330 + struct device_attribute *attr, char *buf) 331 + { 332 + struct w1_slave *sl = dev_to_w1_slave(device); 333 + ssize_t c = PAGE_SIZE; 334 + int rv; 335 + int i; 336 + u8 ack; 337 + u64 rn; 338 + struct w1_reg_num *reg_num; 339 + int seq = 0; 340 + 341 + mutex_lock(&sl->master->mutex); 342 + /* Place all devices in CHAIN state */ 343 + if (w1_reset_bus(sl->master)) 344 + goto error; 345 + w1_write_8(sl->master, W1_SKIP_ROM); 346 + w1_write_8(sl->master, W1_42_CHAIN); 347 + w1_write_8(sl->master, W1_42_CHAIN_ON); 348 + w1_write_8(sl->master, W1_42_CHAIN_ON_INV); 349 + msleep(sl->master->pullup_duration); 350 + 351 + /* check for acknowledgment */ 352 + ack = w1_read_8(sl->master); 353 + if (ack != W1_42_SUCCESS_CONFIRM_BYTE) 354 + goto error; 355 + 356 + /* In case the bus fails to send 0xFF, limit*/ 357 + for (i = 0; i <= 64; i++) { 358 + if (w1_reset_bus(sl->master)) 359 + goto error; 360 + 361 + w1_write_8(sl->master, W1_42_COND_READ); 362 + rv = w1_read_block(sl->master, (u8 *)&rn, 8); 363 + reg_num = (struct w1_reg_num *) &rn; 364 + if ((char)reg_num->family == W1_42_FINISHED_BYTE) 365 + break; 366 + if (sl->reg_num.id == reg_num->id) 367 + seq = i; 368 + 369 + w1_write_8(sl->master, W1_42_CHAIN); 370 + w1_write_8(sl->master, W1_42_CHAIN_DONE); 371 + w1_write_8(sl->master, W1_42_CHAIN_DONE_INV); 372 + w1_read_block(sl->master, &ack, sizeof(ack)); 373 + 374 + /* check for acknowledgment */ 375 + ack = w1_read_8(sl->master); 376 + if (ack != W1_42_SUCCESS_CONFIRM_BYTE) 377 + goto error; 378 + 379 + } 380 + 381 + /* Exit from CHAIN state */ 382 + if (w1_reset_bus(sl->master)) 383 + goto error; 384 + w1_write_8(sl->master, W1_SKIP_ROM); 385 + w1_write_8(sl->master, W1_42_CHAIN); 386 + w1_write_8(sl->master, W1_42_CHAIN_OFF); 387 + w1_write_8(sl->master, W1_42_CHAIN_OFF_INV); 388 + 389 + /* check for acknowledgment */ 390 + ack = w1_read_8(sl->master); 391 + if (ack != W1_42_SUCCESS_CONFIRM_BYTE) 392 + goto error; 393 + mutex_unlock(&sl->master->mutex); 394 + 395 + c -= snprintf(buf + PAGE_SIZE - c, c, "%d\n", seq); 396 + return PAGE_SIZE - c; 397 + error: 398 + mutex_unlock(&sl->master->bus_mutex); 399 + return -EIO; 334 400 } 335 401 336 402 static int __init w1_therm_init(void)