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