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"); 313