xref: /openbmc/linux/drivers/w1/slaves/w1_ds2805.c (revision 98ddec80)
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