]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/w1/slaves/w1_ds2408.c
drivers/w1/slaves/w1_ds2408.c: add magic sequence to disable P0 test mode
[karo-tx-linux.git] / drivers / w1 / slaves / w1_ds2408.c
1 /*
2  *      w1_ds2408.c - w1 family 29 (DS2408) driver
3  *
4  * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.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 #include <linux/slab.h>
17
18 #include "../w1.h"
19 #include "../w1_int.h"
20 #include "../w1_family.h"
21
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
24 MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");
25
26
27 #define W1_F29_RETRIES          3
28
29 #define W1_F29_REG_LOGIG_STATE             0x88 /* R */
30 #define W1_F29_REG_OUTPUT_LATCH_STATE      0x89 /* R */
31 #define W1_F29_REG_ACTIVITY_LATCH_STATE    0x8A /* R */
32 #define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
33 #define W1_F29_REG_COND_SEARCH_POL_SELECT  0x8C /* RW */
34 #define W1_F29_REG_CONTROL_AND_STATUS      0x8D /* RW */
35
36 #define W1_F29_FUNC_READ_PIO_REGS          0xF0
37 #define W1_F29_FUNC_CHANN_ACCESS_READ      0xF5
38 #define W1_F29_FUNC_CHANN_ACCESS_WRITE     0x5A
39 /* also used to write the control/status reg (0x8D): */
40 #define W1_F29_FUNC_WRITE_COND_SEARCH_REG  0xCC
41 #define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
42
43 #define W1_F29_SUCCESS_CONFIRM_BYTE        0xAA
44
45 static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
46 {
47         u8 wrbuf[3];
48         dev_dbg(&sl->dev,
49                         "Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
50                         sl, (unsigned int)address, buf);
51
52         if (!buf)
53                 return -EINVAL;
54
55         mutex_lock(&sl->master->bus_mutex);
56         dev_dbg(&sl->dev, "mutex locked");
57
58         if (w1_reset_select_slave(sl)) {
59                 mutex_unlock(&sl->master->bus_mutex);
60                 return -EIO;
61         }
62
63         wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
64         wrbuf[1] = address;
65         wrbuf[2] = 0;
66         w1_write_block(sl->master, wrbuf, 3);
67         *buf = w1_read_8(sl->master);
68
69         mutex_unlock(&sl->master->bus_mutex);
70         dev_dbg(&sl->dev, "mutex unlocked");
71         return 1;
72 }
73
74 static ssize_t w1_f29_read_state(
75         struct file *filp, struct kobject *kobj,
76         struct bin_attribute *bin_attr,
77         char *buf, loff_t off, size_t count)
78 {
79         dev_dbg(&kobj_to_w1_slave(kobj)->dev,
80                 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
81                 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
82         if (count != 1 || off != 0)
83                 return -EFAULT;
84         return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
85 }
86
87 static ssize_t w1_f29_read_output(
88         struct file *filp, struct kobject *kobj,
89         struct bin_attribute *bin_attr,
90         char *buf, loff_t off, size_t count)
91 {
92         dev_dbg(&kobj_to_w1_slave(kobj)->dev,
93                 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
94                 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
95         if (count != 1 || off != 0)
96                 return -EFAULT;
97         return _read_reg(kobj_to_w1_slave(kobj),
98                                          W1_F29_REG_OUTPUT_LATCH_STATE, buf);
99 }
100
101 static ssize_t w1_f29_read_activity(
102         struct file *filp, struct kobject *kobj,
103         struct bin_attribute *bin_attr,
104         char *buf, loff_t off, size_t count)
105 {
106         dev_dbg(&kobj_to_w1_slave(kobj)->dev,
107                 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
108                 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
109         if (count != 1 || off != 0)
110                 return -EFAULT;
111         return _read_reg(kobj_to_w1_slave(kobj),
112                                          W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
113 }
114
115 static ssize_t w1_f29_read_cond_search_mask(
116         struct file *filp, struct kobject *kobj,
117         struct bin_attribute *bin_attr,
118         char *buf, loff_t off, size_t count)
119 {
120         dev_dbg(&kobj_to_w1_slave(kobj)->dev,
121                 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
122                 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
123         if (count != 1 || off != 0)
124                 return -EFAULT;
125         return _read_reg(kobj_to_w1_slave(kobj),
126                 W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
127 }
128
129 static ssize_t w1_f29_read_cond_search_polarity(
130         struct file *filp, struct kobject *kobj,
131         struct bin_attribute *bin_attr,
132         char *buf, loff_t off, size_t count)
133 {
134         if (count != 1 || off != 0)
135                 return -EFAULT;
136         return _read_reg(kobj_to_w1_slave(kobj),
137                 W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
138 }
139
140 static ssize_t w1_f29_read_status_control(
141         struct file *filp, struct kobject *kobj,
142         struct bin_attribute *bin_attr,
143         char *buf, loff_t off, size_t count)
144 {
145         if (count != 1 || off != 0)
146                 return -EFAULT;
147         return _read_reg(kobj_to_w1_slave(kobj),
148                 W1_F29_REG_CONTROL_AND_STATUS, buf);
149 }
150
151
152
153
154 static ssize_t w1_f29_write_output(
155         struct file *filp, struct kobject *kobj,
156         struct bin_attribute *bin_attr,
157         char *buf, loff_t off, size_t count)
158 {
159         struct w1_slave *sl = kobj_to_w1_slave(kobj);
160         u8 w1_buf[3];
161         u8 readBack;
162         unsigned int retries = W1_F29_RETRIES;
163
164         if (count != 1 || off != 0)
165                 return -EFAULT;
166
167         dev_dbg(&sl->dev, "locking mutex for write_output");
168         mutex_lock(&sl->master->bus_mutex);
169         dev_dbg(&sl->dev, "mutex locked");
170
171         if (w1_reset_select_slave(sl))
172                 goto error;
173
174         while (retries--) {
175                 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
176                 w1_buf[1] = *buf;
177                 w1_buf[2] = ~(*buf);
178                 w1_write_block(sl->master, w1_buf, 3);
179
180                 readBack = w1_read_8(sl->master);
181
182                 if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
183                         if (w1_reset_resume_command(sl->master))
184                                 goto error;
185                         /* try again, the slave is ready for a command */
186                         continue;
187                 }
188
189 #ifdef CONFIG_W1_SLAVE_DS2408_READBACK
190                 /* here the master could read another byte which
191                    would be the PIO reg (the actual pin logic state)
192                    since in this driver we don't know which pins are
193                    in and outs, there's no value to read the state and
194                    compare. with (*buf) so end this command abruptly: */
195                 if (w1_reset_resume_command(sl->master))
196                         goto error;
197
198                 /* go read back the output latches */
199                 /* (the direct effect of the write above) */
200                 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
201                 w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
202                 w1_buf[2] = 0;
203                 w1_write_block(sl->master, w1_buf, 3);
204                 /* read the result of the READ_PIO_REGS command */
205                 if (w1_read_8(sl->master) == *buf)
206 #endif
207                 {
208                         /* success! */
209                         mutex_unlock(&sl->master->bus_mutex);
210                         dev_dbg(&sl->dev,
211                                 "mutex unlocked, retries:%d", retries);
212                         return 1;
213                 }
214         }
215 error:
216         mutex_unlock(&sl->master->bus_mutex);
217         dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
218
219         return -EIO;
220 }
221
222
223 /**
224  * Writing to the activity file resets the activity latches.
225  */
226 static ssize_t w1_f29_write_activity(
227         struct file *filp, struct kobject *kobj,
228         struct bin_attribute *bin_attr,
229         char *buf, loff_t off, size_t count)
230 {
231         struct w1_slave *sl = kobj_to_w1_slave(kobj);
232         unsigned int retries = W1_F29_RETRIES;
233
234         if (count != 1 || off != 0)
235                 return -EFAULT;
236
237         mutex_lock(&sl->master->bus_mutex);
238
239         if (w1_reset_select_slave(sl))
240                 goto error;
241
242         while (retries--) {
243                 w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
244                 if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
245                         mutex_unlock(&sl->master->bus_mutex);
246                         return 1;
247                 }
248                 if (w1_reset_resume_command(sl->master))
249                         goto error;
250         }
251
252 error:
253         mutex_unlock(&sl->master->bus_mutex);
254         return -EIO;
255 }
256
257 static ssize_t w1_f29_write_status_control(
258         struct file *filp,
259         struct kobject *kobj,
260         struct bin_attribute *bin_attr,
261         char *buf,
262         loff_t off,
263         size_t count)
264 {
265         struct w1_slave *sl = kobj_to_w1_slave(kobj);
266         u8 w1_buf[4];
267         unsigned int retries = W1_F29_RETRIES;
268
269         if (count != 1 || off != 0)
270                 return -EFAULT;
271
272         mutex_lock(&sl->master->bus_mutex);
273
274         if (w1_reset_select_slave(sl))
275                 goto error;
276
277         while (retries--) {
278                 w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
279                 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
280                 w1_buf[2] = 0;
281                 w1_buf[3] = *buf;
282
283                 w1_write_block(sl->master, w1_buf, 4);
284                 if (w1_reset_resume_command(sl->master))
285                         goto error;
286
287                 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
288                 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
289                 w1_buf[2] = 0;
290
291                 w1_write_block(sl->master, w1_buf, 3);
292                 if (w1_read_8(sl->master) == *buf) {
293                         /* success! */
294                         mutex_unlock(&sl->master->bus_mutex);
295                         return 1;
296                 }
297         }
298 error:
299         mutex_unlock(&sl->master->bus_mutex);
300
301         return -EIO;
302 }
303
304 /**
305  * This is a special sequence we must do to ensure the P0 output is not stuck
306  * in test mode. This is described in rev 2 of the ds2408's datasheet
307  * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
308  * "APPLICATION INFORMATION/Power-up timing".
309  */
310 static int w1_f29_disable_test_mode(struct w1_slave *sl)
311 {
312         int res;
313         u8 magic[10] = {0x96, };
314         u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
315         memcpy(&magic[1], &rn, 8);
316         magic[9] = 0x3C;
317
318         mutex_lock(&sl->master->bus_mutex);
319
320         res = w1_reset_bus(sl->master);
321         if (res)
322                 goto out;
323         w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
324
325         res = w1_reset_bus(sl->master);
326 out:
327         mutex_unlock(&sl->master->bus_mutex);
328         return res;
329 }
330
331 static struct bin_attribute w1_f29_sysfs_bin_files[] = {
332         {
333                 .attr = {
334                         .name = "state",
335                         .mode = S_IRUGO,
336                 },
337                 .size = 1,
338                 .read = w1_f29_read_state,
339         },
340         {
341                 .attr = {
342                         .name = "output",
343                         .mode = S_IRUGO | S_IWUSR | S_IWGRP,
344                 },
345                 .size = 1,
346                 .read = w1_f29_read_output,
347                 .write = w1_f29_write_output,
348         },
349         {
350                 .attr = {
351                         .name = "activity",
352                         .mode = S_IRUGO,
353                 },
354                 .size = 1,
355                 .read = w1_f29_read_activity,
356                 .write = w1_f29_write_activity,
357         },
358         {
359                 .attr = {
360                         .name = "cond_search_mask",
361                         .mode = S_IRUGO,
362                 },
363                 .size = 1,
364                 .read = w1_f29_read_cond_search_mask,
365         },
366         {
367                 .attr = {
368                         .name = "cond_search_polarity",
369                         .mode = S_IRUGO,
370                 },
371                 .size = 1,
372                 .read = w1_f29_read_cond_search_polarity,
373         },
374         {
375                 .attr = {
376                         .name = "status_control",
377                         .mode = S_IRUGO | S_IWUSR | S_IWGRP,
378                 },
379                 .size = 1,
380                 .read = w1_f29_read_status_control,
381                 .write = w1_f29_write_status_control,
382         }
383 };
384
385 static int w1_f29_add_slave(struct w1_slave *sl)
386 {
387         int err = 0;
388         int i;
389
390         err = w1_f29_disable_test_mode(sl);
391         if (err)
392                 return err;
393
394         for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i)
395                 err = sysfs_create_bin_file(
396                         &sl->dev.kobj,
397                         &(w1_f29_sysfs_bin_files[i]));
398         if (err)
399                 while (--i >= 0)
400                         sysfs_remove_bin_file(&sl->dev.kobj,
401                                 &(w1_f29_sysfs_bin_files[i]));
402         return err;
403 }
404
405 static void w1_f29_remove_slave(struct w1_slave *sl)
406 {
407         int i;
408         for (i = ARRAY_SIZE(w1_f29_sysfs_bin_files) - 1; i >= 0; --i)
409                 sysfs_remove_bin_file(&sl->dev.kobj,
410                         &(w1_f29_sysfs_bin_files[i]));
411 }
412
413 static struct w1_family_ops w1_f29_fops = {
414         .add_slave      = w1_f29_add_slave,
415         .remove_slave   = w1_f29_remove_slave,
416 };
417
418 static struct w1_family w1_family_29 = {
419         .fid = W1_FAMILY_DS2408,
420         .fops = &w1_f29_fops,
421 };
422
423 static int __init w1_f29_init(void)
424 {
425         return w1_register_family(&w1_family_29);
426 }
427
428 static void __exit w1_f29_exit(void)
429 {
430         w1_unregister_family(&w1_family_29);
431 }
432
433 module_init(w1_f29_init);
434 module_exit(w1_f29_exit);