1 // SPDX-License-Identifier: GPL-2.0-only
3 * w1_ds2805 - w1 family 0d (DS28E05) driver
5 * Copyright (c) 2016 Andrew Worsley amworsley@gmail.com
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/moduleparam.h>
11 #include <linux/device.h>
12 #include <linux/types.h>
13 #include <linux/delay.h>
17 #define W1_EEPROM_DS2805 0x0D
19 #define W1_F0D_EEPROM_SIZE 128
20 #define W1_F0D_PAGE_BITS 3
21 #define W1_F0D_PAGE_SIZE (1<<W1_F0D_PAGE_BITS)
22 #define W1_F0D_PAGE_MASK 0x0F
24 #define W1_F0D_SCRATCH_BITS 1
25 #define W1_F0D_SCRATCH_SIZE (1<<W1_F0D_SCRATCH_BITS)
26 #define W1_F0D_SCRATCH_MASK (W1_F0D_SCRATCH_SIZE-1)
28 #define W1_F0D_READ_EEPROM 0xF0
29 #define W1_F0D_WRITE_EEPROM 0x55
30 #define W1_F0D_RELEASE 0xFF
32 #define W1_F0D_CS_OK 0xAA /* Chip Status Ok */
34 #define W1_F0D_TPROG_MS 16
36 #define W1_F0D_READ_RETRIES 10
37 #define W1_F0D_READ_MAXLEN W1_F0D_EEPROM_SIZE
40 * Check the file size bounds and adjusts count as needed.
41 * This would not be needed if the file size didn't reset to 0 after a write.
43 static inline size_t w1_f0d_fix_count(loff_t off
, size_t count
, size_t size
)
48 if ((off
+ count
) > size
)
55 * Read a block from W1 ROM two times and compares the results.
56 * If they are equal they are returned, otherwise the read
57 * is repeated W1_F0D_READ_RETRIES times.
59 * count must not exceed W1_F0D_READ_MAXLEN.
61 static int w1_f0d_readblock(struct w1_slave
*sl
, int off
, int count
, char *buf
)
64 u8 cmp
[W1_F0D_READ_MAXLEN
];
65 int tries
= W1_F0D_READ_RETRIES
;
68 wrbuf
[0] = W1_F0D_READ_EEPROM
;
69 wrbuf
[1] = off
& 0x7f;
72 if (w1_reset_select_slave(sl
))
75 w1_write_block(sl
->master
, wrbuf
, sizeof(wrbuf
));
76 w1_read_block(sl
->master
, buf
, count
);
78 if (w1_reset_select_slave(sl
))
81 w1_write_block(sl
->master
, wrbuf
, sizeof(wrbuf
));
82 w1_read_block(sl
->master
, cmp
, count
);
84 if (!memcmp(cmp
, buf
, count
))
88 dev_err(&sl
->dev
, "proof reading failed %d times\n",
94 static ssize_t
w1_f0d_read_bin(struct file
*filp
, struct kobject
*kobj
,
95 struct bin_attribute
*bin_attr
,
96 char *buf
, loff_t off
, size_t count
)
98 struct w1_slave
*sl
= kobj_to_w1_slave(kobj
);
101 count
= w1_f0d_fix_count(off
, count
, W1_F0D_EEPROM_SIZE
);
105 mutex_lock(&sl
->master
->mutex
);
107 /* read directly from the EEPROM in chunks of W1_F0D_READ_MAXLEN */
111 if (todo
>= W1_F0D_READ_MAXLEN
)
112 block_read
= W1_F0D_READ_MAXLEN
;
116 if (w1_f0d_readblock(sl
, off
, block_read
, buf
) < 0) {
121 todo
-= W1_F0D_READ_MAXLEN
;
122 buf
+= W1_F0D_READ_MAXLEN
;
123 off
+= W1_F0D_READ_MAXLEN
;
126 mutex_unlock(&sl
->master
->mutex
);
132 * Writes to the scratchpad and reads it back for verification.
133 * Then copies the scratchpad to EEPROM.
134 * The data must be aligned at W1_F0D_SCRATCH_SIZE bytes and
135 * must be W1_F0D_SCRATCH_SIZE bytes long.
136 * The master must be locked.
138 * @param sl The slave structure
139 * @param addr Address for the write
140 * @param len length must be <= (W1_F0D_PAGE_SIZE - (addr & W1_F0D_PAGE_MASK))
141 * @param data The data to write
142 * @return 0=Success -1=failure
144 static int w1_f0d_write(struct w1_slave
*sl
, int addr
, int len
, const u8
*data
)
146 int tries
= W1_F0D_READ_RETRIES
;
148 u8 rdbuf
[W1_F0D_SCRATCH_SIZE
];
151 if ((addr
& 1) || (len
!= 2)) {
152 dev_err(&sl
->dev
, "%s: bad addr/len - addr=%#x len=%d\n",
153 __func__
, addr
, len
);
159 /* Write the data to the scratchpad */
160 if (w1_reset_select_slave(sl
))
163 wrbuf
[0] = W1_F0D_WRITE_EEPROM
;
164 wrbuf
[1] = addr
& 0xff;
165 wrbuf
[2] = 0xff; /* ?? from Example */
167 w1_write_block(sl
->master
, wrbuf
, sizeof(wrbuf
));
168 w1_write_block(sl
->master
, data
, len
);
170 w1_read_block(sl
->master
, rdbuf
, sizeof(rdbuf
));
171 /* Compare what was read against the data written */
172 if ((rdbuf
[0] != data
[0]) || (rdbuf
[1] != data
[1])) {
178 "could not write to eeprom, scratchpad compare failed %d times\n",
179 W1_F0D_READ_RETRIES
);
180 pr_info("%s: rdbuf = %#x %#x data = %#x %#x\n",
181 __func__
, rdbuf
[0], rdbuf
[1], data
[0], data
[1]);
186 /* Trigger write out to EEPROM */
187 w1_write_8(sl
->master
, W1_F0D_RELEASE
);
189 /* Sleep for tprog ms to wait for the write to complete */
190 msleep(W1_F0D_TPROG_MS
);
192 /* Check CS (Command Status) == 0xAA ? */
193 cs
= w1_read_8(sl
->master
);
194 if (cs
!= W1_F0D_CS_OK
) {
195 dev_err(&sl
->dev
, "save to eeprom failed = CS=%#x\n", cs
);
202 static ssize_t
w1_f0d_write_bin(struct file
*filp
, struct kobject
*kobj
,
203 struct bin_attribute
*bin_attr
,
204 char *buf
, loff_t off
, size_t count
)
206 struct w1_slave
*sl
= kobj_to_w1_slave(kobj
);
210 count
= w1_f0d_fix_count(off
, count
, W1_F0D_EEPROM_SIZE
);
214 mutex_lock(&sl
->master
->mutex
);
216 /* Can only write data in blocks of the size of the scratchpad */
221 /* if len too short or addr not aligned */
222 if (len
< W1_F0D_SCRATCH_SIZE
|| addr
& W1_F0D_SCRATCH_MASK
) {
223 char tmp
[W1_F0D_SCRATCH_SIZE
];
225 /* read the block and update the parts to be written */
226 if (w1_f0d_readblock(sl
, addr
& ~W1_F0D_SCRATCH_MASK
,
227 W1_F0D_SCRATCH_SIZE
, tmp
)) {
232 /* copy at most to the boundary of the PAGE or len */
233 copy
= W1_F0D_SCRATCH_SIZE
-
234 (addr
& W1_F0D_SCRATCH_MASK
);
239 memcpy(&tmp
[addr
& W1_F0D_SCRATCH_MASK
], buf
, copy
);
240 if (w1_f0d_write(sl
, addr
& ~W1_F0D_SCRATCH_MASK
,
241 W1_F0D_SCRATCH_SIZE
, tmp
) < 0) {
247 copy
= W1_F0D_SCRATCH_SIZE
;
248 if (w1_f0d_write(sl
, addr
, copy
, buf
) < 0) {
259 mutex_unlock(&sl
->master
->mutex
);
264 static struct bin_attribute w1_f0d_bin_attr
= {
267 .mode
= S_IRUGO
| S_IWUSR
,
269 .size
= W1_F0D_EEPROM_SIZE
,
270 .read
= w1_f0d_read_bin
,
271 .write
= w1_f0d_write_bin
,
274 static int w1_f0d_add_slave(struct w1_slave
*sl
)
276 return sysfs_create_bin_file(&sl
->dev
.kobj
, &w1_f0d_bin_attr
);
279 static void w1_f0d_remove_slave(struct w1_slave
*sl
)
281 sysfs_remove_bin_file(&sl
->dev
.kobj
, &w1_f0d_bin_attr
);
284 static const struct w1_family_ops w1_f0d_fops
= {
285 .add_slave
= w1_f0d_add_slave
,
286 .remove_slave
= w1_f0d_remove_slave
,
289 static struct w1_family w1_family_0d
= {
290 .fid
= W1_EEPROM_DS2805
,
291 .fops
= &w1_f0d_fops
,
294 static int __init
w1_f0d_init(void)
296 pr_info("%s()\n", __func__
);
297 return w1_register_family(&w1_family_0d
);
300 static void __exit
w1_f0d_fini(void)
302 pr_info("%s()\n", __func__
);
303 w1_unregister_family(&w1_family_0d
);
306 module_init(w1_f0d_init
);
307 module_exit(w1_f0d_fini
);
309 MODULE_LICENSE("GPL");
310 MODULE_AUTHOR("Andrew Worsley amworsley@gmail.com");
311 MODULE_DESCRIPTION("w1 family 0d driver for DS2805, 1kb EEPROM");