root/drivers/w1/slaves/w1_ds2431.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. w1_f2d_fix_count
  2. w1_f2d_readblock
  3. eeprom_read
  4. w1_f2d_write
  5. eeprom_write

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

/* [<][>][^][v][top][bottom][index][help] */