1 /* 2 * w1_ds2805 - w1 family 0d (DS28E05) driver 3 * 4 * Copyright (c) 2016 Andrew Worsley amworsley@gmail.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 17 #include <linux/w1.h> 18 19 #define W1_EEPROM_DS2805 0x0D 20 21 #define W1_F0D_EEPROM_SIZE 128 22 #define W1_F0D_PAGE_BITS 3 23 #define W1_F0D_PAGE_SIZE (1<<W1_F0D_PAGE_BITS) 24 #define W1_F0D_PAGE_MASK 0x0F 25 26 #define W1_F0D_SCRATCH_BITS 1 27 #define W1_F0D_SCRATCH_SIZE (1<<W1_F0D_SCRATCH_BITS) 28 #define W1_F0D_SCRATCH_MASK (W1_F0D_SCRATCH_SIZE-1) 29 30 #define W1_F0D_READ_EEPROM 0xF0 31 #define W1_F0D_WRITE_EEPROM 0x55 32 #define W1_F0D_RELEASE 0xFF 33 34 #define W1_F0D_CS_OK 0xAA /* Chip Status Ok */ 35 36 #define W1_F0D_TPROG_MS 16 37 38 #define W1_F0D_READ_RETRIES 10 39 #define W1_F0D_READ_MAXLEN W1_F0D_EEPROM_SIZE 40 41 /* 42 * Check the file size bounds and adjusts count as needed. 43 * This would not be needed if the file size didn't reset to 0 after a write. 44 */ 45 static inline size_t w1_f0d_fix_count(loff_t off, size_t count, size_t size) 46 { 47 if (off > size) 48 return 0; 49 50 if ((off + count) > size) 51 return size - off; 52 53 return count; 54 } 55 56 /* 57 * Read a block from W1 ROM two times and compares the results. 58 * If they are equal they are returned, otherwise the read 59 * is repeated W1_F0D_READ_RETRIES times. 60 * 61 * count must not exceed W1_F0D_READ_MAXLEN. 62 */ 63 static int w1_f0d_readblock(struct w1_slave *sl, int off, int count, char *buf) 64 { 65 u8 wrbuf[3]; 66 u8 cmp[W1_F0D_READ_MAXLEN]; 67 int tries = W1_F0D_READ_RETRIES; 68 69 do { 70 wrbuf[0] = W1_F0D_READ_EEPROM; 71 wrbuf[1] = off & 0x7f; 72 wrbuf[2] = 0; 73 74 if (w1_reset_select_slave(sl)) 75 return -1; 76 77 w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); 78 w1_read_block(sl->master, buf, count); 79 80 if (w1_reset_select_slave(sl)) 81 return -1; 82 83 w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); 84 w1_read_block(sl->master, cmp, count); 85 86 if (!memcmp(cmp, buf, count)) 87 return 0; 88 } while (--tries); 89 90 dev_err(&sl->dev, "proof reading failed %d times\n", 91 W1_F0D_READ_RETRIES); 92 93 return -1; 94 } 95 96 static ssize_t w1_f0d_read_bin(struct file *filp, struct kobject *kobj, 97 struct bin_attribute *bin_attr, 98 char *buf, loff_t off, size_t count) 99 { 100 struct w1_slave *sl = kobj_to_w1_slave(kobj); 101 int todo = count; 102 103 count = w1_f0d_fix_count(off, count, W1_F0D_EEPROM_SIZE); 104 if (count == 0) 105 return 0; 106 107 mutex_lock(&sl->master->mutex); 108 109 /* read directly from the EEPROM in chunks of W1_F0D_READ_MAXLEN */ 110 while (todo > 0) { 111 int block_read; 112 113 if (todo >= W1_F0D_READ_MAXLEN) 114 block_read = W1_F0D_READ_MAXLEN; 115 else 116 block_read = todo; 117 118 if (w1_f0d_readblock(sl, off, block_read, buf) < 0) { 119 count = -EIO; 120 break; 121 } 122 123 todo -= W1_F0D_READ_MAXLEN; 124 buf += W1_F0D_READ_MAXLEN; 125 off += W1_F0D_READ_MAXLEN; 126 } 127 128 mutex_unlock(&sl->master->mutex); 129 130 return count; 131 } 132 133 /* 134 * Writes to the scratchpad and reads it back for verification. 135 * Then copies the scratchpad to EEPROM. 136 * The data must be aligned at W1_F0D_SCRATCH_SIZE bytes and 137 * must be W1_F0D_SCRATCH_SIZE bytes long. 138 * The master must be locked. 139 * 140 * @param sl The slave structure 141 * @param addr Address for the write 142 * @param len length must be <= (W1_F0D_PAGE_SIZE - (addr & W1_F0D_PAGE_MASK)) 143 * @param data The data to write 144 * @return 0=Success -1=failure 145 */ 146 static int w1_f0d_write(struct w1_slave *sl, int addr, int len, const u8 *data) 147 { 148 int tries = W1_F0D_READ_RETRIES; 149 u8 wrbuf[3]; 150 u8 rdbuf[W1_F0D_SCRATCH_SIZE]; 151 u8 cs; 152 153 if ((addr & 1) || (len != 2)) { 154 dev_err(&sl->dev, "%s: bad addr/len - addr=%#x len=%d\n", 155 __func__, addr, len); 156 return -1; 157 } 158 159 retry: 160 161 /* Write the data to the scratchpad */ 162 if (w1_reset_select_slave(sl)) 163 return -1; 164 165 wrbuf[0] = W1_F0D_WRITE_EEPROM; 166 wrbuf[1] = addr & 0xff; 167 wrbuf[2] = 0xff; /* ?? from Example */ 168 169 w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); 170 w1_write_block(sl->master, data, len); 171 172 w1_read_block(sl->master, rdbuf, sizeof(rdbuf)); 173 /* Compare what was read against the data written */ 174 if ((rdbuf[0] != data[0]) || (rdbuf[1] != data[1])) { 175 176 if (--tries) 177 goto retry; 178 179 dev_err(&sl->dev, 180 "could not write to eeprom, scratchpad compare failed %d times\n", 181 W1_F0D_READ_RETRIES); 182 pr_info("%s: rdbuf = %#x %#x data = %#x %#x\n", 183 __func__, rdbuf[0], rdbuf[1], data[0], data[1]); 184 185 return -1; 186 } 187 188 /* Trigger write out to EEPROM */ 189 w1_write_8(sl->master, W1_F0D_RELEASE); 190 191 /* Sleep for tprog ms to wait for the write to complete */ 192 msleep(W1_F0D_TPROG_MS); 193 194 /* Check CS (Command Status) == 0xAA ? */ 195 cs = w1_read_8(sl->master); 196 if (cs != W1_F0D_CS_OK) { 197 dev_err(&sl->dev, "save to eeprom failed = CS=%#x\n", cs); 198 return -1; 199 } 200 201 return 0; 202 } 203 204 static ssize_t w1_f0d_write_bin(struct file *filp, struct kobject *kobj, 205 struct bin_attribute *bin_attr, 206 char *buf, loff_t off, size_t count) 207 { 208 struct w1_slave *sl = kobj_to_w1_slave(kobj); 209 int addr, len; 210 int copy; 211 212 count = w1_f0d_fix_count(off, count, W1_F0D_EEPROM_SIZE); 213 if (count == 0) 214 return 0; 215 216 mutex_lock(&sl->master->mutex); 217 218 /* Can only write data in blocks of the size of the scratchpad */ 219 addr = off; 220 len = count; 221 while (len > 0) { 222 223 /* if len too short or addr not aligned */ 224 if (len < W1_F0D_SCRATCH_SIZE || addr & W1_F0D_SCRATCH_MASK) { 225 char tmp[W1_F0D_SCRATCH_SIZE]; 226 227 /* read the block and update the parts to be written */ 228 if (w1_f0d_readblock(sl, addr & ~W1_F0D_SCRATCH_MASK, 229 W1_F0D_SCRATCH_SIZE, tmp)) { 230 count = -EIO; 231 goto out_up; 232 } 233 234 /* copy at most to the boundary of the PAGE or len */ 235 copy = W1_F0D_SCRATCH_SIZE - 236 (addr & W1_F0D_SCRATCH_MASK); 237 238 if (copy > len) 239 copy = len; 240 241 memcpy(&tmp[addr & W1_F0D_SCRATCH_MASK], buf, copy); 242 if (w1_f0d_write(sl, addr & ~W1_F0D_SCRATCH_MASK, 243 W1_F0D_SCRATCH_SIZE, tmp) < 0) { 244 count = -EIO; 245 goto out_up; 246 } 247 } else { 248 249 copy = W1_F0D_SCRATCH_SIZE; 250 if (w1_f0d_write(sl, addr, copy, buf) < 0) { 251 count = -EIO; 252 goto out_up; 253 } 254 } 255 buf += copy; 256 addr += copy; 257 len -= copy; 258 } 259 260 out_up: 261 mutex_unlock(&sl->master->mutex); 262 263 return count; 264 } 265 266 static struct bin_attribute w1_f0d_bin_attr = { 267 .attr = { 268 .name = "eeprom", 269 .mode = S_IRUGO | S_IWUSR, 270 }, 271 .size = W1_F0D_EEPROM_SIZE, 272 .read = w1_f0d_read_bin, 273 .write = w1_f0d_write_bin, 274 }; 275 276 static int w1_f0d_add_slave(struct w1_slave *sl) 277 { 278 return sysfs_create_bin_file(&sl->dev.kobj, &w1_f0d_bin_attr); 279 } 280 281 static void w1_f0d_remove_slave(struct w1_slave *sl) 282 { 283 sysfs_remove_bin_file(&sl->dev.kobj, &w1_f0d_bin_attr); 284 } 285 286 static struct w1_family_ops w1_f0d_fops = { 287 .add_slave = w1_f0d_add_slave, 288 .remove_slave = w1_f0d_remove_slave, 289 }; 290 291 static struct w1_family w1_family_2d = { 292 .fid = W1_EEPROM_DS2805, 293 .fops = &w1_f0d_fops, 294 }; 295 296 static int __init w1_f0d_init(void) 297 { 298 pr_info("%s()\n", __func__); 299 return w1_register_family(&w1_family_2d); 300 } 301 302 static void __exit w1_f0d_fini(void) 303 { 304 pr_info("%s()\n", __func__); 305 w1_unregister_family(&w1_family_2d); 306 } 307 308 module_init(w1_f0d_init); 309 module_exit(w1_f0d_fini); 310 311 MODULE_LICENSE("GPL"); 312 MODULE_AUTHOR("Andrew Worsley amworsley@gmail.com"); 313 MODULE_DESCRIPTION("w1 family 0d driver for DS2805, 1kb EEPROM"); 314