]>
Commit | Line | Data |
---|---|---|
89610274 JFD |
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 | ||
de0d6dbd AD |
18 | #include <linux/w1.h> |
19 | ||
20 | #define W1_FAMILY_DS2408 0x29 | |
89610274 | 21 | |
89610274 JFD |
22 | #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 | ||
40 | static 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 | ||
b02f8bed | 50 | mutex_lock(&sl->master->bus_mutex); |
89610274 JFD |
51 | dev_dbg(&sl->dev, "mutex locked"); |
52 | ||
53 | if (w1_reset_select_slave(sl)) { | |
b02f8bed | 54 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
55 | 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 | ||
b02f8bed | 64 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
65 | dev_dbg(&sl->dev, "mutex unlocked"); |
66 | return 1; | |
67 | } | |
68 | ||
32ea4175 GKH |
69 | static 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) | |
89610274 JFD |
72 | { |
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 | ||
32ea4175 GKH |
81 | static 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) | |
89610274 JFD |
84 | { |
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 | ||
32ea4175 GKH |
94 | static 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) | |
89610274 JFD |
97 | { |
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 | ||
32ea4175 GKH |
107 | static 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) | |
89610274 JFD |
110 | { |
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 | ||
32ea4175 GKH |
120 | static 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) | |
89610274 JFD |
124 | { |
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 | ||
32ea4175 GKH |
131 | static 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) | |
89610274 JFD |
134 | { |
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 | ||
32ea4175 GKH |
141 | static 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) | |
89610274 JFD |
144 | { |
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"); | |
b02f8bed | 154 | mutex_lock(&sl->master->bus_mutex); |
89610274 JFD |
155 | 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); | |
aceca285 JFD |
167 | |
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 | |
89610274 JFD |
176 | /* 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 | ||
89610274 JFD |
184 | /* 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 */ | |
aceca285 JFD |
191 | if (w1_read_8(sl->master) == *buf) |
192 | #endif | |
193 | { | |
89610274 | 194 | /* success! */ |
b02f8bed | 195 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
196 | dev_dbg(&sl->dev, |
197 | "mutex unlocked, retries:%d", retries); | |
198 | return 1; | |
199 | } | |
200 | } | |
201 | error: | |
b02f8bed | 202 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
203 | 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 | */ | |
32ea4175 GKH |
212 | static 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) | |
89610274 JFD |
215 | { |
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 | ||
b02f8bed | 222 | mutex_lock(&sl->master->bus_mutex); |
89610274 JFD |
223 | |
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) { | |
b02f8bed | 230 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
231 | return 1; |
232 | } | |
233 | if (w1_reset_resume_command(sl->master)) | |
234 | goto error; | |
235 | } | |
236 | ||
237 | error: | |
b02f8bed | 238 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
239 | return -EIO; |
240 | } | |
241 | ||
32ea4175 GKH |
242 | static 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) | |
89610274 JFD |
245 | { |
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 | ||
b02f8bed | 253 | mutex_lock(&sl->master->bus_mutex); |
89610274 JFD |
254 | |
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! */ | |
b02f8bed | 275 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
276 | return 1; |
277 | } | |
278 | } | |
279 | error: | |
b02f8bed | 280 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
281 | |
282 | return -EIO; | |
283 | } | |
284 | ||
d5528773 JFD |
285 | /* |
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 | */ | |
291 | static 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)); | |
296 | ||
297 | memcpy(&magic[1], &rn, 8); | |
298 | magic[9] = 0x3C; | |
299 | ||
300 | mutex_lock(&sl->master->bus_mutex); | |
89610274 | 301 | |
d5528773 JFD |
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); | |
308 | out: | |
309 | mutex_unlock(&sl->master->bus_mutex); | |
310 | return res; | |
311 | } | |
89610274 | 312 | |
32ea4175 GKH |
313 | static BIN_ATTR_RO(state, 1); |
314 | static BIN_ATTR_RW(output, 1); | |
315 | static BIN_ATTR_RW(activity, 1); | |
316 | static BIN_ATTR_RO(cond_search_mask, 1); | |
317 | static BIN_ATTR_RO(cond_search_polarity, 1); | |
318 | static BIN_ATTR_RW(status_control, 1); | |
319 | ||
320 | static 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, | |
89610274 JFD |
328 | }; |
329 | ||
32ea4175 GKH |
330 | static const struct attribute_group w1_f29_group = { |
331 | .bin_attrs = w1_f29_bin_attrs, | |
332 | }; | |
89610274 | 333 | |
32ea4175 GKH |
334 | static const struct attribute_group *w1_f29_groups[] = { |
335 | &w1_f29_group, | |
336 | NULL, | |
337 | }; | |
89610274 JFD |
338 | |
339 | static struct w1_family_ops w1_f29_fops = { | |
32ea4175 GKH |
340 | .add_slave = w1_f29_disable_test_mode, |
341 | .groups = w1_f29_groups, | |
89610274 JFD |
342 | }; |
343 | ||
344 | static struct w1_family w1_family_29 = { | |
345 | .fid = W1_FAMILY_DS2408, | |
346 | .fops = &w1_f29_fops, | |
347 | }; | |
939fc832 | 348 | module_w1_family(w1_family_29); |
50fa2951 AD |
349 | |
350 | MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>"); | |
351 | MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO"); | |
352 | MODULE_LICENSE("GPL"); | |
353 | MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408)); |