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

w1: new driver. DS2431 chip

[akpm@linux-foundation.org: minor fixlets and cleanups]
Signed-off-by: Bernhard Weirich <bernhard.weirich@riedel.net>
Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Cc: Ben Gardner <bgardner@wabtec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Bernhard Weirich and committed by
Linus Torvalds
d8273674 ade6d810

+313
+312
drivers/w1/slaves/w1_ds2431.c
··· 1 + /* 2 + * w1_ds2431.c - w1 family 2d (DS2431) driver 3 + * 4 + * Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net> 5 + * 6 + * Heavily inspired by w1_DS2433 driver from Ben Gardner <bgardner@wabtec.com> 7 + * 8 + * This source code is licensed under the GNU General Public License, 9 + * Version 2. See the file COPYING for more details. 10 + */ 11 + 12 + #include <linux/kernel.h> 13 + #include <linux/module.h> 14 + #include <linux/moduleparam.h> 15 + #include <linux/device.h> 16 + #include <linux/types.h> 17 + #include <linux/delay.h> 18 + 19 + #include "../w1.h" 20 + #include "../w1_int.h" 21 + #include "../w1_family.h" 22 + 23 + #define W1_F2D_EEPROM_SIZE 128 24 + #define W1_F2D_PAGE_COUNT 4 25 + #define W1_F2D_PAGE_BITS 5 26 + #define W1_F2D_PAGE_SIZE (1<<W1_F2D_PAGE_BITS) 27 + #define W1_F2D_PAGE_MASK 0x1F 28 + 29 + #define W1_F2D_SCRATCH_BITS 3 30 + #define W1_F2D_SCRATCH_SIZE (1<<W1_F2D_SCRATCH_BITS) 31 + #define W1_F2D_SCRATCH_MASK (W1_F2D_SCRATCH_SIZE-1) 32 + 33 + #define W1_F2D_READ_EEPROM 0xF0 34 + #define W1_F2D_WRITE_SCRATCH 0x0F 35 + #define W1_F2D_READ_SCRATCH 0xAA 36 + #define W1_F2D_COPY_SCRATCH 0x55 37 + 38 + 39 + #define W1_F2D_TPROG_MS 11 40 + 41 + #define W1_F2D_READ_RETRIES 10 42 + #define W1_F2D_READ_MAXLEN 8 43 + 44 + /* 45 + * Check the file size bounds and adjusts count as needed. 46 + * This would not be needed if the file size didn't reset to 0 after a write. 47 + */ 48 + static inline size_t w1_f2d_fix_count(loff_t off, size_t count, size_t size) 49 + { 50 + if (off > size) 51 + return 0; 52 + 53 + if ((off + count) > size) 54 + return size - off; 55 + 56 + return count; 57 + } 58 + 59 + /* 60 + * Read a block from W1 ROM two times and compares the results. 61 + * If they are equal they are returned, otherwise the read 62 + * is repeated W1_F2D_READ_RETRIES times. 63 + * 64 + * count must not exceed W1_F2D_READ_MAXLEN. 65 + */ 66 + static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf) 67 + { 68 + u8 wrbuf[3]; 69 + u8 cmp[W1_F2D_READ_MAXLEN]; 70 + int tries = W1_F2D_READ_RETRIES; 71 + 72 + do { 73 + wrbuf[0] = W1_F2D_READ_EEPROM; 74 + wrbuf[1] = off & 0xff; 75 + wrbuf[2] = off >> 8; 76 + 77 + if (w1_reset_select_slave(sl)) 78 + return -1; 79 + 80 + w1_write_block(sl->master, wrbuf, 3); 81 + w1_read_block(sl->master, buf, count); 82 + 83 + if (w1_reset_select_slave(sl)) 84 + return -1; 85 + 86 + w1_write_block(sl->master, wrbuf, 3); 87 + w1_read_block(sl->master, cmp, count); 88 + 89 + if (!memcmp(cmp, buf, count)) 90 + return 0; 91 + } while (--tries); 92 + 93 + dev_err(&sl->dev, "proof reading failed %d times\n", 94 + W1_F2D_READ_RETRIES); 95 + 96 + return -1; 97 + } 98 + 99 + static ssize_t w1_f2d_read_bin(struct kobject *kobj, 100 + struct bin_attribute *bin_attr, 101 + char *buf, loff_t off, size_t count) 102 + { 103 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 104 + int todo = count; 105 + 106 + count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE); 107 + if (count == 0) 108 + return 0; 109 + 110 + mutex_lock(&sl->master->mutex); 111 + 112 + /* read directly from the EEPROM in chunks of W1_F2D_READ_MAXLEN */ 113 + while (todo > 0) { 114 + int block_read; 115 + 116 + if (todo >= W1_F2D_READ_MAXLEN) 117 + block_read = W1_F2D_READ_MAXLEN; 118 + else 119 + block_read = todo; 120 + 121 + if (w1_f2d_readblock(sl, off, block_read, buf) < 0) 122 + count = -EIO; 123 + 124 + todo -= W1_F2D_READ_MAXLEN; 125 + buf += W1_F2D_READ_MAXLEN; 126 + off += W1_F2D_READ_MAXLEN; 127 + } 128 + 129 + mutex_unlock(&sl->master->mutex); 130 + 131 + return count; 132 + } 133 + 134 + /* 135 + * Writes to the scratchpad and reads it back for verification. 136 + * Then copies the scratchpad to EEPROM. 137 + * The data must be aligned at W1_F2D_SCRATCH_SIZE bytes and 138 + * must be W1_F2D_SCRATCH_SIZE bytes long. 139 + * The master must be locked. 140 + * 141 + * @param sl The slave structure 142 + * @param addr Address for the write 143 + * @param len length must be <= (W1_F2D_PAGE_SIZE - (addr & W1_F2D_PAGE_MASK)) 144 + * @param data The data to write 145 + * @return 0=Success -1=failure 146 + */ 147 + static int w1_f2d_write(struct w1_slave *sl, int addr, int len, const u8 *data) 148 + { 149 + int tries = W1_F2D_READ_RETRIES; 150 + u8 wrbuf[4]; 151 + u8 rdbuf[W1_F2D_SCRATCH_SIZE + 3]; 152 + u8 es = (addr + len - 1) % W1_F2D_SCRATCH_SIZE; 153 + 154 + retry: 155 + 156 + /* Write the data to the scratchpad */ 157 + if (w1_reset_select_slave(sl)) 158 + return -1; 159 + 160 + wrbuf[0] = W1_F2D_WRITE_SCRATCH; 161 + wrbuf[1] = addr & 0xff; 162 + wrbuf[2] = addr >> 8; 163 + 164 + w1_write_block(sl->master, wrbuf, 3); 165 + w1_write_block(sl->master, data, len); 166 + 167 + /* Read the scratchpad and verify */ 168 + if (w1_reset_select_slave(sl)) 169 + return -1; 170 + 171 + w1_write_8(sl->master, W1_F2D_READ_SCRATCH); 172 + w1_read_block(sl->master, rdbuf, len + 3); 173 + 174 + /* Compare what was read against the data written */ 175 + if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) || 176 + (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0)) { 177 + 178 + if (--tries) 179 + goto retry; 180 + 181 + dev_err(&sl->dev, 182 + "could not write to eeprom, scratchpad compare failed %d times\n", 183 + W1_F2D_READ_RETRIES); 184 + 185 + return -1; 186 + } 187 + 188 + /* Copy the scratchpad to EEPROM */ 189 + if (w1_reset_select_slave(sl)) 190 + return -1; 191 + 192 + wrbuf[0] = W1_F2D_COPY_SCRATCH; 193 + wrbuf[3] = es; 194 + w1_write_block(sl->master, wrbuf, 4); 195 + 196 + /* Sleep for tprog ms to wait for the write to complete */ 197 + msleep(W1_F2D_TPROG_MS); 198 + 199 + /* Reset the bus to wake up the EEPROM */ 200 + w1_reset_bus(sl->master); 201 + 202 + return 0; 203 + } 204 + 205 + static ssize_t w1_f2d_write_bin(struct kobject *kobj, 206 + struct bin_attribute *bin_attr, 207 + char *buf, loff_t off, size_t count) 208 + { 209 + struct w1_slave *sl = kobj_to_w1_slave(kobj); 210 + int addr, len; 211 + int copy; 212 + 213 + count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE); 214 + if (count == 0) 215 + return 0; 216 + 217 + mutex_lock(&sl->master->mutex); 218 + 219 + /* Can only write data in blocks of the size of the scratchpad */ 220 + addr = off; 221 + len = count; 222 + while (len > 0) { 223 + 224 + /* if len too short or addr not aligned */ 225 + if (len < W1_F2D_SCRATCH_SIZE || addr & W1_F2D_SCRATCH_MASK) { 226 + char tmp[W1_F2D_SCRATCH_SIZE]; 227 + 228 + /* read the block and update the parts to be written */ 229 + if (w1_f2d_readblock(sl, addr & ~W1_F2D_SCRATCH_MASK, 230 + W1_F2D_SCRATCH_SIZE, tmp)) { 231 + count = -EIO; 232 + goto out_up; 233 + } 234 + 235 + /* copy at most to the boundary of the PAGE or len */ 236 + copy = W1_F2D_SCRATCH_SIZE - 237 + (addr & W1_F2D_SCRATCH_MASK); 238 + 239 + if (copy > len) 240 + copy = len; 241 + 242 + memcpy(&tmp[addr & W1_F2D_SCRATCH_MASK], buf, copy); 243 + if (w1_f2d_write(sl, addr & ~W1_F2D_SCRATCH_MASK, 244 + W1_F2D_SCRATCH_SIZE, tmp) < 0) { 245 + count = -EIO; 246 + goto out_up; 247 + } 248 + } else { 249 + 250 + copy = W1_F2D_SCRATCH_SIZE; 251 + if (w1_f2d_write(sl, addr, copy, buf) < 0) { 252 + count = -EIO; 253 + goto out_up; 254 + } 255 + } 256 + buf += copy; 257 + addr += copy; 258 + len -= copy; 259 + } 260 + 261 + out_up: 262 + mutex_unlock(&sl->master->mutex); 263 + 264 + return count; 265 + } 266 + 267 + static struct bin_attribute w1_f2d_bin_attr = { 268 + .attr = { 269 + .name = "eeprom", 270 + .mode = S_IRUGO | S_IWUSR, 271 + }, 272 + .size = W1_F2D_EEPROM_SIZE, 273 + .read = w1_f2d_read_bin, 274 + .write = w1_f2d_write_bin, 275 + }; 276 + 277 + static int w1_f2d_add_slave(struct w1_slave *sl) 278 + { 279 + return sysfs_create_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr); 280 + } 281 + 282 + static void w1_f2d_remove_slave(struct w1_slave *sl) 283 + { 284 + sysfs_remove_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr); 285 + } 286 + 287 + static struct w1_family_ops w1_f2d_fops = { 288 + .add_slave = w1_f2d_add_slave, 289 + .remove_slave = w1_f2d_remove_slave, 290 + }; 291 + 292 + static struct w1_family w1_family_2d = { 293 + .fid = W1_EEPROM_DS2431, 294 + .fops = &w1_f2d_fops, 295 + }; 296 + 297 + static int __init w1_f2d_init(void) 298 + { 299 + return w1_register_family(&w1_family_2d); 300 + } 301 + 302 + static void __exit w1_f2d_fini(void) 303 + { 304 + w1_unregister_family(&w1_family_2d); 305 + } 306 + 307 + module_init(w1_f2d_init); 308 + module_exit(w1_f2d_fini); 309 + 310 + MODULE_LICENSE("GPL"); 311 + MODULE_AUTHOR("Bernhard Weirich <bernhard.weirich@riedel.net>"); 312 + MODULE_DESCRIPTION("w1 family 2d driver for DS2431, 1kb EEPROM");
+1
drivers/w1/w1_family.h
··· 33 33 #define W1_THERM_DS1822 0x22 34 34 #define W1_EEPROM_DS2433 0x23 35 35 #define W1_THERM_DS18B20 0x28 36 + #define W1_EEPROM_DS2431 0x2D 36 37 #define W1_FAMILY_DS2760 0x30 37 38 38 39 #define MAXNAMELEN 32