blob: b535d5ec35b6a90b6f6c677bbf630c7a55d7ef1c [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
Andrew F. Davisde0d6db2017-06-05 08:52:08 -050018#include <linux/w1.h>
19
20#define W1_FAMILY_DS2408 0x29
Jean-François Dagenais89610272011-05-26 16:26:02 -070021
Jean-François Dagenais89610272011-05-26 16:26:02 -070022#define W1_F29_RETRIES 3
23
24#define W1_F29_REG_LOGIG_STATE 0x88 /* R */
25#define W1_F29_REG_OUTPUT_LATCH_STATE 0x89 /* R */
26#define W1_F29_REG_ACTIVITY_LATCH_STATE 0x8A /* R */
27#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
28#define W1_F29_REG_COND_SEARCH_POL_SELECT 0x8C /* RW */
29#define W1_F29_REG_CONTROL_AND_STATUS 0x8D /* RW */
30
31#define W1_F29_FUNC_READ_PIO_REGS 0xF0
32#define W1_F29_FUNC_CHANN_ACCESS_READ 0xF5
33#define W1_F29_FUNC_CHANN_ACCESS_WRITE 0x5A
34/* also used to write the control/status reg (0x8D): */
35#define W1_F29_FUNC_WRITE_COND_SEARCH_REG 0xCC
36#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
37
38#define W1_F29_SUCCESS_CONFIRM_BYTE 0xAA
39
40static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
41{
42 u8 wrbuf[3];
43 dev_dbg(&sl->dev,
44 "Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
45 sl, (unsigned int)address, buf);
46
47 if (!buf)
48 return -EINVAL;
49
NeilBrownb02f8be2012-05-18 15:59:52 +100050 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -070051 dev_dbg(&sl->dev, "mutex locked");
52
53 if (w1_reset_select_slave(sl)) {
NeilBrownb02f8be2012-05-18 15:59:52 +100054 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -070055 return -EIO;
56 }
57
58 wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
59 wrbuf[1] = address;
60 wrbuf[2] = 0;
61 w1_write_block(sl->master, wrbuf, 3);
62 *buf = w1_read_8(sl->master);
63
NeilBrownb02f8be2012-05-18 15:59:52 +100064 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -070065 dev_dbg(&sl->dev, "mutex unlocked");
66 return 1;
67}
68
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -070069static ssize_t state_read(struct file *filp, struct kobject *kobj,
70 struct bin_attribute *bin_attr, char *buf, loff_t off,
71 size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -070072{
73 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
74 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
75 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
76 if (count != 1 || off != 0)
77 return -EFAULT;
78 return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf);
79}
80
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -070081static ssize_t output_read(struct file *filp, struct kobject *kobj,
82 struct bin_attribute *bin_attr, char *buf,
83 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -070084{
85 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
86 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
87 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
88 if (count != 1 || off != 0)
89 return -EFAULT;
90 return _read_reg(kobj_to_w1_slave(kobj),
91 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
92}
93
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -070094static ssize_t activity_read(struct file *filp, struct kobject *kobj,
95 struct bin_attribute *bin_attr, char *buf,
96 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -070097{
98 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
99 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
100 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
101 if (count != 1 || off != 0)
102 return -EFAULT;
103 return _read_reg(kobj_to_w1_slave(kobj),
104 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
105}
106
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700107static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj,
108 struct bin_attribute *bin_attr, char *buf,
109 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700110{
111 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
112 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
113 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
114 if (count != 1 || off != 0)
115 return -EFAULT;
116 return _read_reg(kobj_to_w1_slave(kobj),
117 W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
118}
119
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700120static ssize_t cond_search_polarity_read(struct file *filp,
121 struct kobject *kobj,
122 struct bin_attribute *bin_attr,
123 char *buf, loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700124{
125 if (count != 1 || off != 0)
126 return -EFAULT;
127 return _read_reg(kobj_to_w1_slave(kobj),
128 W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
129}
130
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700131static ssize_t status_control_read(struct file *filp, struct kobject *kobj,
132 struct bin_attribute *bin_attr, char *buf,
133 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700134{
135 if (count != 1 || off != 0)
136 return -EFAULT;
137 return _read_reg(kobj_to_w1_slave(kobj),
138 W1_F29_REG_CONTROL_AND_STATUS, buf);
139}
140
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700141static ssize_t output_write(struct file *filp, struct kobject *kobj,
142 struct bin_attribute *bin_attr, char *buf,
143 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700144{
145 struct w1_slave *sl = kobj_to_w1_slave(kobj);
146 u8 w1_buf[3];
147 u8 readBack;
148 unsigned int retries = W1_F29_RETRIES;
149
150 if (count != 1 || off != 0)
151 return -EFAULT;
152
153 dev_dbg(&sl->dev, "locking mutex for write_output");
NeilBrownb02f8be2012-05-18 15:59:52 +1000154 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700155 dev_dbg(&sl->dev, "mutex locked");
156
157 if (w1_reset_select_slave(sl))
158 goto error;
159
160 while (retries--) {
161 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
162 w1_buf[1] = *buf;
163 w1_buf[2] = ~(*buf);
164 w1_write_block(sl->master, w1_buf, 3);
165
166 readBack = w1_read_8(sl->master);
Jean-Francois Dagenaisaceca282013-03-15 14:20:25 -0400167
168 if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) {
169 if (w1_reset_resume_command(sl->master))
170 goto error;
171 /* try again, the slave is ready for a command */
172 continue;
173 }
174
175#ifdef CONFIG_W1_SLAVE_DS2408_READBACK
Jean-François Dagenais89610272011-05-26 16:26:02 -0700176 /* here the master could read another byte which
177 would be the PIO reg (the actual pin logic state)
178 since in this driver we don't know which pins are
179 in and outs, there's no value to read the state and
180 compare. with (*buf) so end this command abruptly: */
181 if (w1_reset_resume_command(sl->master))
182 goto error;
183
Jean-François Dagenais89610272011-05-26 16:26:02 -0700184 /* go read back the output latches */
185 /* (the direct effect of the write above) */
186 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
187 w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
188 w1_buf[2] = 0;
189 w1_write_block(sl->master, w1_buf, 3);
190 /* read the result of the READ_PIO_REGS command */
Jean-Francois Dagenaisaceca282013-03-15 14:20:25 -0400191 if (w1_read_8(sl->master) == *buf)
192#endif
193 {
Jean-François Dagenais89610272011-05-26 16:26:02 -0700194 /* success! */
NeilBrownb02f8be2012-05-18 15:59:52 +1000195 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700196 dev_dbg(&sl->dev,
197 "mutex unlocked, retries:%d", retries);
198 return 1;
199 }
200 }
201error:
NeilBrownb02f8be2012-05-18 15:59:52 +1000202 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700203 dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
204
205 return -EIO;
206}
207
208
209/**
210 * Writing to the activity file resets the activity latches.
211 */
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700212static ssize_t activity_write(struct file *filp, struct kobject *kobj,
213 struct bin_attribute *bin_attr, char *buf,
214 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700215{
216 struct w1_slave *sl = kobj_to_w1_slave(kobj);
217 unsigned int retries = W1_F29_RETRIES;
218
219 if (count != 1 || off != 0)
220 return -EFAULT;
221
NeilBrownb02f8be2012-05-18 15:59:52 +1000222 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700223
224 if (w1_reset_select_slave(sl))
225 goto error;
226
227 while (retries--) {
228 w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
229 if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
NeilBrownb02f8be2012-05-18 15:59:52 +1000230 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700231 return 1;
232 }
233 if (w1_reset_resume_command(sl->master))
234 goto error;
235 }
236
237error:
NeilBrownb02f8be2012-05-18 15:59:52 +1000238 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700239 return -EIO;
240}
241
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700242static ssize_t status_control_write(struct file *filp, struct kobject *kobj,
243 struct bin_attribute *bin_attr, char *buf,
244 loff_t off, size_t count)
Jean-François Dagenais89610272011-05-26 16:26:02 -0700245{
246 struct w1_slave *sl = kobj_to_w1_slave(kobj);
247 u8 w1_buf[4];
248 unsigned int retries = W1_F29_RETRIES;
249
250 if (count != 1 || off != 0)
251 return -EFAULT;
252
NeilBrownb02f8be2012-05-18 15:59:52 +1000253 mutex_lock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700254
255 if (w1_reset_select_slave(sl))
256 goto error;
257
258 while (retries--) {
259 w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
260 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
261 w1_buf[2] = 0;
262 w1_buf[3] = *buf;
263
264 w1_write_block(sl->master, w1_buf, 4);
265 if (w1_reset_resume_command(sl->master))
266 goto error;
267
268 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
269 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
270 w1_buf[2] = 0;
271
272 w1_write_block(sl->master, w1_buf, 3);
273 if (w1_read_8(sl->master) == *buf) {
274 /* success! */
NeilBrownb02f8be2012-05-18 15:59:52 +1000275 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700276 return 1;
277 }
278 }
279error:
NeilBrownb02f8be2012-05-18 15:59:52 +1000280 mutex_unlock(&sl->master->bus_mutex);
Jean-François Dagenais89610272011-05-26 16:26:02 -0700281
282 return -EIO;
283}
284
Jean-Francois Dagenaisd5528772013-07-03 15:09:15 -0700285/*
286 * This is a special sequence we must do to ensure the P0 output is not stuck
287 * in test mode. This is described in rev 2 of the ds2408's datasheet
288 * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under
289 * "APPLICATION INFORMATION/Power-up timing".
290 */
291static int w1_f29_disable_test_mode(struct w1_slave *sl)
292{
293 int res;
294 u8 magic[10] = {0x96, };
295 u64 rn = le64_to_cpu(*((u64*)&sl->reg_num));
Jean-François Dagenais89610272011-05-26 16:26:02 -0700296
Jean-Francois Dagenaisd5528772013-07-03 15:09:15 -0700297 memcpy(&magic[1], &rn, 8);
298 magic[9] = 0x3C;
299
300 mutex_lock(&sl->master->bus_mutex);
301
302 res = w1_reset_bus(sl->master);
303 if (res)
304 goto out;
305 w1_write_block(sl->master, magic, ARRAY_SIZE(magic));
306
307 res = w1_reset_bus(sl->master);
308out:
309 mutex_unlock(&sl->master->bus_mutex);
310 return res;
311}
Jean-François Dagenais89610272011-05-26 16:26:02 -0700312
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700313static BIN_ATTR_RO(state, 1);
314static BIN_ATTR_RW(output, 1);
315static BIN_ATTR_RW(activity, 1);
316static BIN_ATTR_RO(cond_search_mask, 1);
317static BIN_ATTR_RO(cond_search_polarity, 1);
318static BIN_ATTR_RW(status_control, 1);
319
320static struct bin_attribute *w1_f29_bin_attrs[] = {
321 &bin_attr_state,
322 &bin_attr_output,
323 &bin_attr_activity,
324 &bin_attr_cond_search_mask,
325 &bin_attr_cond_search_polarity,
326 &bin_attr_status_control,
327 NULL,
Jean-François Dagenais89610272011-05-26 16:26:02 -0700328};
329
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700330static const struct attribute_group w1_f29_group = {
331 .bin_attrs = w1_f29_bin_attrs,
332};
Jean-François Dagenais89610272011-05-26 16:26:02 -0700333
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700334static const struct attribute_group *w1_f29_groups[] = {
335 &w1_f29_group,
336 NULL,
337};
Jean-François Dagenais89610272011-05-26 16:26:02 -0700338
339static struct w1_family_ops w1_f29_fops = {
Greg Kroah-Hartman32ea4172013-08-21 15:44:57 -0700340 .add_slave = w1_f29_disable_test_mode,
341 .groups = w1_f29_groups,
Jean-François Dagenais89610272011-05-26 16:26:02 -0700342};
343
344static struct w1_family w1_family_29 = {
345 .fid = W1_FAMILY_DS2408,
346 .fops = &w1_f29_fops,
347};
Andrew F. Davis939fc832016-08-02 14:07:09 -0700348module_w1_family(w1_family_29);
Andrew F. Davis50fa2952017-05-16 15:02:12 -0500349
350MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
351MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO");
352MODULE_LICENSE("GPL");
353MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408));