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

w1: Add 1-wire slave device driver for DS28E04-100

Signed-off-by: Markus Franke <franm@hrz.tu-chemnitz.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Markus Franke and committed by
Greg Kroah-Hartman
fbf7f7b4 a59d6293

+535
+15
Documentation/ABI/stable/sysfs-driver-w1_ds28e04
··· 1 + What: /sys/bus/w1/devices/.../pio 2 + Date: May 2012 3 + Contact: Markus Franke <franm@hrz.tu-chemnitz.de> 4 + Description: read/write the contents of the two PIO's of the DS28E04-100 5 + see Documentation/w1/slaves/w1_ds28e04 for detailed information 6 + Users: any user space application which wants to communicate with DS28E04-100 7 + 8 + 9 + 10 + What: /sys/bus/w1/devices/.../eeprom 11 + Date: May 2012 12 + Contact: Markus Franke <franm@hrz.tu-chemnitz.de> 13 + Description: read/write the contents of the EEPROM memory of the DS28E04-100 14 + see Documentation/w1/slaves/w1_ds28e04 for detailed information 15 + Users: any user space application which wants to communicate with DS28E04-100
+36
Documentation/w1/slaves/w1_ds28e04
··· 1 + Kernel driver w1_ds28e04 2 + ======================== 3 + 4 + Supported chips: 5 + * Maxim DS28E04-100 4096-Bit Addressable 1-Wire EEPROM with PIO 6 + 7 + supported family codes: 8 + W1_FAMILY_DS28E04 0x1C 9 + 10 + Author: Markus Franke, <franke.m@sebakmt.com> <franm@hrz.tu-chemnitz.de> 11 + 12 + Description 13 + ----------- 14 + 15 + Support is provided through the sysfs files "eeprom" and "pio". CRC checking 16 + during memory accesses can optionally be enabled/disabled via the device 17 + attribute "crccheck". The strong pull-up can optionally be enabled/disabled 18 + via the module parameter "w1_strong_pullup". 19 + 20 + Memory Access 21 + 22 + A read operation on the "eeprom" file reads the given amount of bytes 23 + from the EEPROM of the DS28E04. 24 + 25 + A write operation on the "eeprom" file writes the given byte sequence 26 + to the EEPROM of the DS28E04. If CRC checking mode is enabled only 27 + fully alligned blocks of 32 bytes with valid CRC16 values (in bytes 30 28 + and 31) are allowed to be written. 29 + 30 + PIO Access 31 + 32 + The 2 PIOs of the DS28E04-100 are accessible via the "pio" sysfs file. 33 + 34 + The current status of the PIO's is returned as an 8 bit value. Bit 0/1 35 + represent the state of PIO_0/PIO_1. Bits 2..7 do not care. The PIO's are 36 + driven low-active, i.e. the driver delivers/expects low-active values.
+13
drivers/w1/slaves/Kconfig
··· 94 94 95 95 If you are unsure, say N. 96 96 97 + config W1_SLAVE_DS28E04 98 + tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)" 99 + depends on W1 100 + select CRC16 101 + help 102 + If you enable this you will have the DS28E04-100 103 + chip support. 104 + 105 + Say Y here if you want to use a 1-wire 106 + 4kb EEPROM with PIO family device (DS28E04). 107 + 108 + If you are unsure, say N. 109 + 97 110 config W1_SLAVE_BQ27000 98 111 tristate "BQ27000 slave support" 99 112 depends on W1
+1
drivers/w1/slaves/Makefile
··· 12 12 obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o 13 13 obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o 14 14 obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o 15 + obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
+469
drivers/w1/slaves/w1_ds28e04.c
··· 1 + /* 2 + * w1_ds28e04.c - w1 family 1C (DS28E04) driver 3 + * 4 + * Copyright (c) 2012 Markus Franke <franke.m@sebakmt.com> 5 + * 6 + * This source code is licensed under the GNU General Public License, 7 + * Version 2. See the file COPYING for more details. 8 + */ 9 + 10 + #include <linux/kernel.h> 11 + #include <linux/module.h> 12 + #include <linux/moduleparam.h> 13 + #include <linux/device.h> 14 + #include <linux/types.h> 15 + #include <linux/delay.h> 16 + #include <linux/slab.h> 17 + #include <linux/crc16.h> 18 + #include <linux/uaccess.h> 19 + 20 + #define CRC16_INIT 0 21 + #define CRC16_VALID 0xb001 22 + 23 + #include "../w1.h" 24 + #include "../w1_int.h" 25 + #include "../w1_family.h" 26 + 27 + MODULE_LICENSE("GPL"); 28 + MODULE_AUTHOR("Markus Franke <franke.m@sebakmt.com>, <franm@hrz.tu-chemnitz.de>"); 29 + MODULE_DESCRIPTION("w1 family 1C driver for DS28E04, 4kb EEPROM and PIO"); 30 + 31 + /* Allow the strong pullup to be disabled, but default to enabled. 32 + * If it was disabled a parasite powered device might not get the required 33 + * current to copy the data from the scratchpad to EEPROM. If it is enabled 34 + * parasite powered devices have a better chance of getting the current 35 + * required. 36 + */ 37 + static int w1_strong_pullup = 1; 38 + module_param_named(strong_pullup, w1_strong_pullup, int, 0); 39 + 40 + /* enable/disable CRC checking on DS28E04-100 memory accesses */ 41 + static char w1_enable_crccheck = 1; 42 + 43 + #define W1_EEPROM_SIZE 512 44 + #define W1_PAGE_COUNT 16 45 + #define W1_PAGE_SIZE 32 46 + #define W1_PAGE_BITS 5 47 + #define W1_PAGE_MASK 0x1F 48 + 49 + #define W1_F1C_READ_EEPROM 0xF0 50 + #define W1_F1C_WRITE_SCRATCH 0x0F 51 + #define W1_F1C_READ_SCRATCH 0xAA 52 + #define W1_F1C_COPY_SCRATCH 0x55 53 + #define W1_F1C_ACCESS_WRITE 0x5A 54 + 55 + #define W1_1C_REG_LOGIC_STATE 0x220 56 + 57 + struct w1_f1C_data { 58 + u8 memory[W1_EEPROM_SIZE]; 59 + u32 validcrc; 60 + }; 61 + 62 + /** 63 + * Check the file size bounds and adjusts count as needed. 64 + * This would not be needed if the file size didn't reset to 0 after a write. 65 + */ 66 + static inline size_t w1_f1C_fix_count(loff_t off, size_t count, size_t size) 67 + { 68 + if (off > size) 69 + return 0; 70 + 71 + if ((off + count) > size) 72 + return size - off; 73 + 74 + return count; 75 + } 76 + 77 + static int w1_f1C_refresh_block(struct w1_slave *sl, struct w1_f1C_data *data, 78 + int block) 79 + { 80 + u8 wrbuf[3]; 81 + int off = block * W1_PAGE_SIZE; 82 + 83 + if (data->validcrc & (1 << block)) 84 + return 0; 85 + 86 + if (w1_reset_select_slave(sl)) { 87 + data->validcrc = 0; 88 + return -EIO; 89 + } 90 + 91 + wrbuf[0] = W1_F1C_READ_EEPROM; 92 + wrbuf[1] = off & 0xff; 93 + wrbuf[2] = off >> 8; 94 + w1_write_block(sl->master, wrbuf, 3); 95 + w1_read_block(sl->master, &data->memory[off], W1_PAGE_SIZE); 96 + 97 + /* cache the block if the CRC is valid */ 98 + if (crc16(CRC16_INIT, &data->memory[off], W1_PAGE_SIZE) == CRC16_VALID) 99 + data->validcrc |= (1 << block); 100 + 101 + return 0; 102 + } 103 + 104 + static int w1_f1C_read(struct w1_slave *sl, int addr, int len, char *data) 105 + { 106 + u8 wrbuf[3]; 107 + 108 + /* read directly from the EEPROM */ 109 + if (w1_reset_select_slave(sl)) 110 + return -EIO; 111 + 112 + wrbuf[0] = W1_F1C_READ_EEPROM; 113 + wrbuf[1] = addr & 0xff; 114 + wrbuf[2] = addr >> 8; 115 + 116 + w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); 117 + return w1_read_block(sl->master, data, len); 118 + } 119 + 120 + static ssize_t w1_f1C_read_bin(struct file *filp, struct kobject *kobj, 121 + struct bin_attribute *bin_attr, 122 + char *buf, loff_t off, size_t count) 123 + { 124 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 125 + struct w1_f1C_data *data = sl->family_data; 126 + int i, min_page, max_page; 127 + 128 + count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE); 129 + if (count == 0) 130 + return 0; 131 + 132 + mutex_lock(&sl->master->mutex); 133 + 134 + if (w1_enable_crccheck) { 135 + min_page = (off >> W1_PAGE_BITS); 136 + max_page = (off + count - 1) >> W1_PAGE_BITS; 137 + for (i = min_page; i <= max_page; i++) { 138 + if (w1_f1C_refresh_block(sl, data, i)) { 139 + count = -EIO; 140 + goto out_up; 141 + } 142 + } 143 + memcpy(buf, &data->memory[off], count); 144 + } else { 145 + count = w1_f1C_read(sl, off, count, buf); 146 + } 147 + 148 + out_up: 149 + mutex_unlock(&sl->master->mutex); 150 + 151 + return count; 152 + } 153 + 154 + /** 155 + * Writes to the scratchpad and reads it back for verification. 156 + * Then copies the scratchpad to EEPROM. 157 + * The data must be on one page. 158 + * The master must be locked. 159 + * 160 + * @param sl The slave structure 161 + * @param addr Address for the write 162 + * @param len length must be <= (W1_PAGE_SIZE - (addr & W1_PAGE_MASK)) 163 + * @param data The data to write 164 + * @return 0=Success -1=failure 165 + */ 166 + static int w1_f1C_write(struct w1_slave *sl, int addr, int len, const u8 *data) 167 + { 168 + u8 wrbuf[4]; 169 + u8 rdbuf[W1_PAGE_SIZE + 3]; 170 + u8 es = (addr + len - 1) & 0x1f; 171 + unsigned int tm = 10; 172 + int i; 173 + struct w1_f1C_data *f1C = sl->family_data; 174 + 175 + /* Write the data to the scratchpad */ 176 + if (w1_reset_select_slave(sl)) 177 + return -1; 178 + 179 + wrbuf[0] = W1_F1C_WRITE_SCRATCH; 180 + wrbuf[1] = addr & 0xff; 181 + wrbuf[2] = addr >> 8; 182 + 183 + w1_write_block(sl->master, wrbuf, 3); 184 + w1_write_block(sl->master, data, len); 185 + 186 + /* Read the scratchpad and verify */ 187 + if (w1_reset_select_slave(sl)) 188 + return -1; 189 + 190 + w1_write_8(sl->master, W1_F1C_READ_SCRATCH); 191 + w1_read_block(sl->master, rdbuf, len + 3); 192 + 193 + /* Compare what was read against the data written */ 194 + if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) || 195 + (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0)) 196 + return -1; 197 + 198 + /* Copy the scratchpad to EEPROM */ 199 + if (w1_reset_select_slave(sl)) 200 + return -1; 201 + 202 + wrbuf[0] = W1_F1C_COPY_SCRATCH; 203 + wrbuf[3] = es; 204 + 205 + for (i = 0; i < sizeof(wrbuf); ++i) { 206 + /* issue 10ms strong pullup (or delay) on the last byte 207 + for writing the data from the scratchpad to EEPROM */ 208 + if (w1_strong_pullup && i == sizeof(wrbuf)-1) 209 + w1_next_pullup(sl->master, tm); 210 + 211 + w1_write_8(sl->master, wrbuf[i]); 212 + } 213 + 214 + if (!w1_strong_pullup) 215 + msleep(tm); 216 + 217 + if (w1_enable_crccheck) { 218 + /* invalidate cached data */ 219 + f1C->validcrc &= ~(1 << (addr >> W1_PAGE_BITS)); 220 + } 221 + 222 + /* Reset the bus to wake up the EEPROM (this may not be needed) */ 223 + w1_reset_bus(sl->master); 224 + 225 + return 0; 226 + } 227 + 228 + static ssize_t w1_f1C_write_bin(struct file *filp, struct kobject *kobj, 229 + struct bin_attribute *bin_attr, 230 + char *buf, loff_t off, size_t count) 231 + 232 + { 233 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 234 + int addr, len, idx; 235 + 236 + count = w1_f1C_fix_count(off, count, W1_EEPROM_SIZE); 237 + if (count == 0) 238 + return 0; 239 + 240 + if (w1_enable_crccheck) { 241 + /* can only write full blocks in cached mode */ 242 + if ((off & W1_PAGE_MASK) || (count & W1_PAGE_MASK)) { 243 + dev_err(&sl->dev, "invalid offset/count off=%d cnt=%zd\n", 244 + (int)off, count); 245 + return -EINVAL; 246 + } 247 + 248 + /* make sure the block CRCs are valid */ 249 + for (idx = 0; idx < count; idx += W1_PAGE_SIZE) { 250 + if (crc16(CRC16_INIT, &buf[idx], W1_PAGE_SIZE) 251 + != CRC16_VALID) { 252 + dev_err(&sl->dev, "bad CRC at offset %d\n", 253 + (int)off); 254 + return -EINVAL; 255 + } 256 + } 257 + } 258 + 259 + mutex_lock(&sl->master->mutex); 260 + 261 + /* Can only write data to one page at a time */ 262 + idx = 0; 263 + while (idx < count) { 264 + addr = off + idx; 265 + len = W1_PAGE_SIZE - (addr & W1_PAGE_MASK); 266 + if (len > (count - idx)) 267 + len = count - idx; 268 + 269 + if (w1_f1C_write(sl, addr, len, &buf[idx]) < 0) { 270 + count = -EIO; 271 + goto out_up; 272 + } 273 + idx += len; 274 + } 275 + 276 + out_up: 277 + mutex_unlock(&sl->master->mutex); 278 + 279 + return count; 280 + } 281 + 282 + static ssize_t w1_f1C_read_pio(struct file *filp, struct kobject *kobj, 283 + struct bin_attribute *bin_attr, 284 + char *buf, loff_t off, size_t count) 285 + 286 + { 287 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 288 + int ret; 289 + 290 + /* check arguments */ 291 + if (off != 0 || count != 1 || buf == NULL) 292 + return -EINVAL; 293 + 294 + mutex_lock(&sl->master->mutex); 295 + ret = w1_f1C_read(sl, W1_1C_REG_LOGIC_STATE, count, buf); 296 + mutex_unlock(&sl->master->mutex); 297 + 298 + return ret; 299 + } 300 + 301 + static ssize_t w1_f1C_write_pio(struct file *filp, struct kobject *kobj, 302 + struct bin_attribute *bin_attr, 303 + char *buf, loff_t off, size_t count) 304 + 305 + { 306 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 307 + u8 wrbuf[3]; 308 + u8 ack; 309 + 310 + /* check arguments */ 311 + if (off != 0 || count != 1 || buf == NULL) 312 + return -EINVAL; 313 + 314 + mutex_lock(&sl->master->mutex); 315 + 316 + /* Write the PIO data */ 317 + if (w1_reset_select_slave(sl)) { 318 + mutex_unlock(&sl->master->mutex); 319 + return -1; 320 + } 321 + 322 + /* set bit 7..2 to value '1' */ 323 + *buf = *buf | 0xFC; 324 + 325 + wrbuf[0] = W1_F1C_ACCESS_WRITE; 326 + wrbuf[1] = *buf; 327 + wrbuf[2] = ~(*buf); 328 + w1_write_block(sl->master, wrbuf, 3); 329 + 330 + w1_read_block(sl->master, &ack, sizeof(ack)); 331 + 332 + mutex_unlock(&sl->master->mutex); 333 + 334 + /* check for acknowledgement */ 335 + if (ack != 0xAA) 336 + return -EIO; 337 + 338 + return count; 339 + } 340 + 341 + static ssize_t w1_f1C_show_crccheck(struct device *dev, 342 + struct device_attribute *attr, char *buf) 343 + { 344 + if (put_user(w1_enable_crccheck + 0x30, buf)) 345 + return -EFAULT; 346 + 347 + return sizeof(w1_enable_crccheck); 348 + } 349 + 350 + static ssize_t w1_f1C_store_crccheck(struct device *dev, 351 + struct device_attribute *attr, 352 + const char *buf, size_t count) 353 + { 354 + char val; 355 + 356 + if (count != 1 || !buf) 357 + return -EINVAL; 358 + 359 + if (get_user(val, buf)) 360 + return -EFAULT; 361 + 362 + /* convert to decimal */ 363 + val = val - 0x30; 364 + if (val != 0 && val != 1) 365 + return -EINVAL; 366 + 367 + /* set the new value */ 368 + w1_enable_crccheck = val; 369 + 370 + return sizeof(w1_enable_crccheck); 371 + } 372 + 373 + #define NB_SYSFS_BIN_FILES 2 374 + static struct bin_attribute w1_f1C_bin_attr[NB_SYSFS_BIN_FILES] = { 375 + { 376 + .attr = { 377 + .name = "eeprom", 378 + .mode = S_IRUGO | S_IWUSR, 379 + }, 380 + .size = W1_EEPROM_SIZE, 381 + .read = w1_f1C_read_bin, 382 + .write = w1_f1C_write_bin, 383 + }, 384 + { 385 + .attr = { 386 + .name = "pio", 387 + .mode = S_IRUGO | S_IWUSR, 388 + }, 389 + .size = 1, 390 + .read = w1_f1C_read_pio, 391 + .write = w1_f1C_write_pio, 392 + } 393 + }; 394 + 395 + static DEVICE_ATTR(crccheck, S_IWUSR | S_IRUGO, 396 + w1_f1C_show_crccheck, w1_f1C_store_crccheck); 397 + 398 + static int w1_f1C_add_slave(struct w1_slave *sl) 399 + { 400 + int err = 0; 401 + int i; 402 + struct w1_f1C_data *data = NULL; 403 + 404 + if (w1_enable_crccheck) { 405 + data = kzalloc(sizeof(struct w1_f1C_data), GFP_KERNEL); 406 + if (!data) 407 + return -ENOMEM; 408 + sl->family_data = data; 409 + } 410 + 411 + /* create binary sysfs attributes */ 412 + for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i) 413 + err = sysfs_create_bin_file( 414 + &sl->dev.kobj, &(w1_f1C_bin_attr[i])); 415 + 416 + if (!err) { 417 + /* create device attributes */ 418 + err = device_create_file(&sl->dev, &dev_attr_crccheck); 419 + } 420 + 421 + if (err) { 422 + /* remove binary sysfs attributes */ 423 + for (i = 0; i < NB_SYSFS_BIN_FILES; ++i) 424 + sysfs_remove_bin_file( 425 + &sl->dev.kobj, &(w1_f1C_bin_attr[i])); 426 + 427 + kfree(data); 428 + } 429 + 430 + return err; 431 + } 432 + 433 + static void w1_f1C_remove_slave(struct w1_slave *sl) 434 + { 435 + int i; 436 + 437 + kfree(sl->family_data); 438 + sl->family_data = NULL; 439 + 440 + /* remove device attributes */ 441 + device_remove_file(&sl->dev, &dev_attr_crccheck); 442 + 443 + /* remove binary sysfs attributes */ 444 + for (i = 0; i < NB_SYSFS_BIN_FILES; ++i) 445 + sysfs_remove_bin_file(&sl->dev.kobj, &(w1_f1C_bin_attr[i])); 446 + } 447 + 448 + static struct w1_family_ops w1_f1C_fops = { 449 + .add_slave = w1_f1C_add_slave, 450 + .remove_slave = w1_f1C_remove_slave, 451 + }; 452 + 453 + static struct w1_family w1_family_1C = { 454 + .fid = W1_FAMILY_DS28E04, 455 + .fops = &w1_f1C_fops, 456 + }; 457 + 458 + static int __init w1_f1C_init(void) 459 + { 460 + return w1_register_family(&w1_family_1C); 461 + } 462 + 463 + static void __exit w1_f1C_fini(void) 464 + { 465 + w1_unregister_family(&w1_family_1C); 466 + } 467 + 468 + module_init(w1_f1C_init); 469 + module_exit(w1_f1C_fini);
+1
drivers/w1/w1_family.h
··· 30 30 #define W1_FAMILY_SMEM_01 0x01 31 31 #define W1_FAMILY_SMEM_81 0x81 32 32 #define W1_THERM_DS18S20 0x10 33 + #define W1_FAMILY_DS28E04 0x1C 33 34 #define W1_COUNTER_DS2423 0x1D 34 35 #define W1_THERM_DS1822 0x22 35 36 #define W1_EEPROM_DS2433 0x23