blob: aec5958e66e9c585304a3c52f164533fbbf329f3 [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
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -070075static ssize_t state_read(struct file *filp, struct kobject *kobj,
76 struct bin_attribute *bin_attr, char *buf, loff_t off,
77 size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -070078{
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
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -070087static ssize_t output_read(struct file *filp, struct kobject *kobj,
88 struct bin_attribute *bin_attr, char *buf,
89 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -070090{
91 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
92 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
93 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
94 if (count != 1 || off != 0)
95 return -EFAULT;
96 return _read_reg(kobj_to_w1_slave(kobj),
97 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
98}
99
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700100static ssize_t activity_read(struct file *filp, struct kobject *kobj,
101 struct bin_attribute *bin_attr, char *buf,
102 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700103{
104 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
105 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
106 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
107 if (count != 1 || off != 0)
108 return -EFAULT;
109 return _read_reg(kobj_to_w1_slave(kobj),
110 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
111}
112
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700113static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
114 struct bin_attribute *bin_attr, char *buf,
115 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700116{
117 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
118 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
119 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
120 if (count != 1 || off != 0)
121 return -EFAULT;
122 return _read_reg(kobj_to_w1_slave(kobj),
123 W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
124}
125
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700126static ssize_t cond_search_polarity_read(struct file *filp,
127 struct kobject *kobj,
128 struct bin_attribute *bin_attr,
129 char *buf, loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700130{
131 if (count != 1 || off != 0)
132 return -EFAULT;
133 return _read_reg(kobj_to_w1_slave(kobj),
134 W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
135}
136
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700137static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
138 struct bin_attribute *bin_attr, char *buf,
139 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700140{
141 if (count != 1 || off != 0)
142 return -EFAULT;
143 return _read_reg(kobj_to_w1_slave(kobj),
144 W1_F29_REG_CONTROL_AND_STATUS, buf);
145}
146
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700147static ssize_t output_write(struct file *filp, struct kobject *kobj,
148 struct bin_attribute *bin_attr, char *buf,
149 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700150{
151 struct w1_slave *sl = kobj_to_w1_slave(kobj);
152 u8 w1_buf[3];
153 u8 readBack;
154 unsigned int retries = W1_F29_RETRIES;
155
156 if (count != 1 || off != 0)
157 return -EFAULT;
158
159 dev_dbg(&sl->dev, "locking mutex for write_output");
NeilBrownb02f8be2012-05-18 15:59:52 +1000160 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700161 dev_dbg(&sl->dev, "mutex locked");
162
163 if (w1_reset_select_slave(sl))
164 goto error;
165
166 while (retries--) {
167 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
168 w1_buf[1] = *buf;
169 w1_buf[2] = ~(*buf);
170 w1_write_block(sl->master, w1_buf, 3);
171
172 readBack = w1_read_8(sl->master);
Jean-Francois Dagenaisaceca282013-03-15 14:20:25 -0400173
174 if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
175 if (w1_reset_resume_command(sl->master))
176 goto error;
177 /* try again, the slave is ready for a command */
178 continue;
179 }
180
181#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
Jean-François Dagenais89610272011-05-26 16:26:02 -0700182 /* here the master could read another byte which
183 would be the PIO reg (the actual pin logic state)
184 since in this driver we don't know which pins are
185 in and outs, there's no value to read the state and
186 compare. with (*buf) so end this command abruptly: */
187 if (w1_reset_resume_command(sl->master))
188 goto error;
189
Jean-François Dagenais89610272011-05-26 16:26:02 -0700190 /* go read back the output latches */
191 /* (the direct effect of the write above) */
192 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
193 w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
194 w1_buf[2] = 0;
195 w1_write_block(sl->master, w1_buf, 3);
196 /* read the result of the READ_PIO_REGS command */
Jean-Francois Dagenaisaceca282013-03-15 14:20:25 -0400197 if (w1_read_8(sl->master) == *buf)
198#endif
199 {
Jean-François Dagenais89610272011-05-26 16:26:02 -0700200 /* success! */
NeilBrownb02f8be2012-05-18 15:59:52 +1000201 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700202 dev_dbg(&sl->dev,
203 "mutex unlocked, retries:%d", retries);
204 return 1;
205 }
206 }
207error:
NeilBrownb02f8be2012-05-18 15:59:52 +1000208 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700209 dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
210
211 return -EIO;
212}
213
214
215/**
216 * Writing to the activity file resets the activity latches.
217 */
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700218static ssize_t activity_write(struct file *filp, struct kobject *kobj,
219 struct bin_attribute *bin_attr, char *buf,
220 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700221{
222 struct w1_slave *sl = kobj_to_w1_slave(kobj);
223 unsigned int retries = W1_F29_RETRIES;
224
225 if (count != 1 || off != 0)
226 return -EFAULT;
227
NeilBrownb02f8be2012-05-18 15:59:52 +1000228 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700229
230 if (w1_reset_select_slave(sl))
231 goto error;
232
233 while (retries--) {
234 w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
235 if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
NeilBrownb02f8be2012-05-18 15:59:52 +1000236 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700237 return 1;
238 }
239 if (w1_reset_resume_command(sl->master))
240 goto error;
241 }
242
243error:
NeilBrownb02f8be2012-05-18 15:59:52 +1000244 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700245 return -EIO;
246}
247
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700248static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
249 struct bin_attribute *bin_attr, char *buf,
250 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700251{
252 struct w1_slave *sl = kobj_to_w1_slave(kobj);
253 u8 w1_buf[4];
254 unsigned int retries = W1_F29_RETRIES;
255
256 if (count != 1 || off != 0)
257 return -EFAULT;
258
NeilBrownb02f8be2012-05-18 15:59:52 +1000259 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700260
261 if (w1_reset_select_slave(sl))
262 goto error;
263
264 while (retries--) {
265 w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
266 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
267 w1_buf[2] = 0;
268 w1_buf[3] = *buf;
269
270 w1_write_block(sl->master, w1_buf, 4);
271 if (w1_reset_resume_command(sl->master))
272 goto error;
273
274 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
275 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
276 w1_buf[2] = 0;
277
278 w1_write_block(sl->master, w1_buf, 3);
279 if (w1_read_8(sl->master) == *buf) {
280 /* success! */
NeilBrownb02f8be2012-05-18 15:59:52 +1000281 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700282 return 1;
283 }
284 }
285error:
NeilBrownb02f8be2012-05-18 15:59:52 +1000286 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700287
288 return -EIO;
289}
290
Jean-Francois Dagenaisd5528772013-07-03 15:09:15 -0700291/*
292 * This is a special sequence we must do to ensure the P0 output is not stuck
293 * in test mode. This is described in rev 2 of the ds2408's datasheet
294 * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
295 * "APPLICATION INFORMATION/Power-up timing".
296 */
297static int w1_f29_disable_test_mode(struct w1_slave *sl)
298{
299 int res;
300 u8 magic[10] = {0x96, };
301 u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
Jean-François Dagenais89610272011-05-26 16:26:02 -0700302
Jean-Francois Dagenaisd5528772013-07-03 15:09:15 -0700303 memcpy(&magic[1], &rn, 8);
304 magic[9] = 0x3C;
305
306 mutex_lock(&sl->master->bus_mutex);
307
308 res = w1_reset_bus(sl->master);
309 if (res)
310 goto out;
311 w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
312
313 res = w1_reset_bus(sl->master);
314out:
315 mutex_unlock(&sl->master->bus_mutex);
316 return res;
317}
Jean-François Dagenais89610272011-05-26 16:26:02 -0700318
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700319static BIN_ATTR_RO(state, 1);
320static BIN_ATTR_RW(output, 1);
321static BIN_ATTR_RW(activity, 1);
322static BIN_ATTR_RO(cond_search_mask, 1);
323static BIN_ATTR_RO(cond_search_polarity, 1);
324static BIN_ATTR_RW(status_control, 1);
325
326static struct bin_attribute *w1_f29_bin_attrs[] = {
327 &bin_attr_state,
328 &bin_attr_output,
329 &bin_attr_activity,
330 &bin_attr_cond_search_mask,
331 &bin_attr_cond_search_polarity,
332 &bin_attr_status_control,
333 NULL,
Jean-François Dagenais89610272011-05-26 16:26:02 -0700334};
335
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700336static const struct attribute_group w1_f29_group = {
337 .bin_attrs = w1_f29_bin_attrs,
338};
Jean-François Dagenais89610272011-05-26 16:26:02 -0700339
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700340static const struct attribute_group *w1_f29_groups[] = {
341 &w1_f29_group,
342 NULL,
343};
Jean-François Dagenais89610272011-05-26 16:26:02 -0700344
345static struct w1_family_ops w1_f29_fops = {
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700346 .add_slave = w1_f29_disable_test_mode,
347 .groups = w1_f29_groups,
Jean-François Dagenais89610272011-05-26 16:26:02 -0700348};
349
350static struct w1_family w1_family_29 = {
351 .fid = W1_FAMILY_DS2408,
352 .fops = &w1_f29_fops,
353};
Andrew F. Davis939fc832016-08-02 14:07:09 -0700354module_w1_family(w1_family_29);