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 */ 48static 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 */ 66static 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 99static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, 100 struct bin_attribute *bin_attr, char *buf, 101 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->bus_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->bus_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 */ 147static 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 154retry: 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 205static ssize_t eeprom_write(struct file *filp, struct kobject *kobj, 206 struct bin_attribute *bin_attr, char *buf, 207 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->bus_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 261out_up: 262 mutex_unlock(&sl->master->bus_mutex); 263 264 return count; 265} 266 267static BIN_ATTR_RW(eeprom, W1_F2D_EEPROM_SIZE); 268 269static struct bin_attribute *w1_f2d_bin_attrs[] = { 270 &bin_attr_eeprom, 271 NULL, 272}; 273 274static const struct attribute_group w1_f2d_group = { 275 .bin_attrs = w1_f2d_bin_attrs, 276}; 277 278static const struct attribute_group *w1_f2d_groups[] = { 279 &w1_f2d_group, 280 NULL, 281}; 282 283static struct w1_family_ops w1_f2d_fops = { 284 .groups = w1_f2d_groups, 285}; 286 287static struct w1_family w1_family_2d = { 288 .fid = W1_EEPROM_DS2431, 289 .fops = &w1_f2d_fops, 290}; 291 292static int __init w1_f2d_init(void) 293{ 294 return w1_register_family(&w1_family_2d); 295} 296 297static void __exit w1_f2d_fini(void) 298{ 299 w1_unregister_family(&w1_family_2d); 300} 301 302module_init(w1_f2d_init); 303module_exit(w1_f2d_fini); 304 305MODULE_LICENSE("GPL"); 306MODULE_AUTHOR("Bernhard Weirich <bernhard.weirich@riedel.net>"); 307MODULE_DESCRIPTION("w1 family 2d driver for DS2431, 1kb EEPROM"); 308MODULE_ALIAS("w1-family-" __stringify(W1_EEPROM_DS2431)); 309