Commit | Line | Data |
---|---|---|
40b0b3f8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
89610274 JFD |
2 | /* |
3 | * w1_ds2408.c - w1 family 29 (DS2408) driver | |
4 | * | |
5 | * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com> | |
89610274 JFD |
6 | */ |
7 | ||
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/moduleparam.h> | |
11 | #include <linux/device.h> | |
12 | #include <linux/types.h> | |
13 | #include <linux/delay.h> | |
14 | #include <linux/slab.h> | |
15 | ||
de0d6dbd AD |
16 | #include <linux/w1.h> |
17 | ||
18 | #define W1_FAMILY_DS2408 0x29 | |
89610274 | 19 | |
89610274 JFD |
20 | #define W1_F29_RETRIES 3 |
21 | ||
22 | #define W1_F29_REG_LOGIG_STATE 0x88 /* R */ | |
23 | #define W1_F29_REG_OUTPUT_LATCH_STATE 0x89 /* R */ | |
24 | #define W1_F29_REG_ACTIVITY_LATCH_STATE 0x8A /* R */ | |
25 | #define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */ | |
26 | #define W1_F29_REG_COND_SEARCH_POL_SELECT 0x8C /* RW */ | |
27 | #define W1_F29_REG_CONTROL_AND_STATUS 0x8D /* RW */ | |
28 | ||
29 | #define W1_F29_FUNC_READ_PIO_REGS 0xF0 | |
30 | #define W1_F29_FUNC_CHANN_ACCESS_READ 0xF5 | |
31 | #define W1_F29_FUNC_CHANN_ACCESS_WRITE 0x5A | |
32 | /* also used to write the control/status reg (0x8D): */ | |
33 | #define W1_F29_FUNC_WRITE_COND_SEARCH_REG 0xCC | |
34 | #define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3 | |
35 | ||
36 | #define W1_F29_SUCCESS_CONFIRM_BYTE 0xAA | |
37 | ||
38 | static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf) | |
39 | { | |
40 | u8 wrbuf[3]; | |
41 | dev_dbg(&sl->dev, | |
42 | "Reading with slave: %p, reg addr: %0#4x, buff addr: %p", | |
43 | sl, (unsigned int)address, buf); | |
44 | ||
45 | if (!buf) | |
46 | return -EINVAL; | |
47 | ||
b02f8bed | 48 | mutex_lock(&sl->master->bus_mutex); |
89610274 JFD |
49 | dev_dbg(&sl->dev, "mutex locked"); |
50 | ||
51 | if (w1_reset_select_slave(sl)) { | |
b02f8bed | 52 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
53 | return -EIO; |
54 | } | |
55 | ||
56 | wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS; | |
57 | wrbuf[1] = address; | |
58 | wrbuf[2] = 0; | |
59 | w1_write_block(sl->master, wrbuf, 3); | |
60 | *buf = w1_read_8(sl->master); | |
61 | ||
b02f8bed | 62 | mutex_unlock(&sl->master->bus_mutex); |
89610274 JFD |
63 | dev_dbg(&sl->dev, "mutex unlocked"); |
64 | return 1; | |
65 | } | |
66 | ||
32ea4175 GKH |
67 | static ssize_t state_read(struct file *filp, struct kobject *kobj, |
68 | struct bin_attribute *bin_attr, char *buf, loff_t off, | |
69 | size_t count) | |
89610274 JFD |
70 | { |
71 | dev_dbg(&kobj_to_w1_slave(kobj)->dev, | |
72 | "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", | |
73 | bin_attr->attr.name, kobj, (unsigned int)off, count, buf); | |
74 | if (count != 1 || off != 0) | |
75 | return -EFAULT; | |
76 | return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf); | |
77 | } | |
78 | ||
32ea4175 GKH |
79 | static ssize_t output_read(struct file *filp, struct kobject *kobj, |
80 | struct bin_attribute *bin_attr, char *buf, | |
81 | loff_t off, size_t count) | |
89610274 JFD |
82 | { |
83 | dev_dbg(&kobj_to_w1_slave(kobj)->dev, | |
84 | "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", | |
85 | bin_attr->attr.name, kobj, (unsigned int)off, count, buf); | |
86 | if (count != 1 || off != 0) | |
87 | return -EFAULT; | |
88 | return _read_reg(kobj_to_w1_slave(kobj), | |
89 | W1_F29_REG_OUTPUT_LATCH_STATE, buf); | |
90 | } | |
91 | ||
32ea4175 GKH |
92 | static ssize_t activity_read(struct file *filp, struct kobject *kobj, |
93 | struct bin_attribute *bin_attr, char *buf, | |
94 | loff_t off, size_t count) | |
89610274 JFD |
95 | { |
96 | dev_dbg(&kobj_to_w1_slave(kobj)->dev, | |
97 | "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", | |
98 | bin_attr->attr.name, kobj, (unsigned int)off, count, buf); | |
99 | if (count != 1 || off != 0) | |
100 | return -EFAULT; | |
101 | return _read_reg(kobj_to_w1_slave(kobj), | |
102 | W1_F29_REG_ACTIVITY_LATCH_STATE, buf); | |
103 | } | |
104 | ||
32ea4175 GKH |
105 | static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj, |
106 | struct bin_attribute *bin_attr, char *buf, | |
107 | loff_t off, size_t count) | |
89610274 JFD |
108 | { |
109 | dev_dbg(&kobj_to_w1_slave(kobj)->dev, | |
110 | "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", | |
111 | bin_attr->attr.name, kobj, (unsigned int)off, count, buf); | |
112 | if (count != 1 || off != 0) | |
113 | return -EFAULT; | |
114 | return _read_reg(kobj_to_w1_slave(kobj), | |
115 | W1_F29_REG_COND_SEARCH_SELECT_MASK, buf); | |
116 | } | |
117 | ||
32ea4175 GKH |
118 | static ssize_t cond_search_polarity_read(struct file *filp, |
119 | struct kobject *kobj, | |
120 | struct bin_attribute *bin_attr, | |
121 | char *buf, loff_t off, size_t count) | |
89610274 JFD |
122 | { |
123 | if (count != 1 || off != 0) | |
124 | return -EFAULT; | |
125 | return _read_reg(kobj_to_w1_slave(kobj), | |
126 | W1_F29_REG_COND_SEARCH_POL_SELECT, buf); | |
127 | } | |
128 | ||
32ea4175 GKH |
129 | static ssize_t status_control_read(struct file *filp, struct kobject *kobj, |
130 | struct bin_attribute *bin_attr, char *buf, | |
131 | loff_t off, size_t count) | |
89610274 JFD |
132 | { |
133 | if (count != 1 || off != 0) | |
134 | return -EFAULT; | |
135 | return _read_reg(kobj_to_w1_slave(kobj), | |
136 | W1_F29_REG_CONTROL_AND_STATUS, buf); | |
137 | } | |
138 | ||
6660a04f | 139 | #ifdef CONFIG_W1_SLAVE_DS2408_READBACK |
49695ac4 JFD |
140 | static bool optional_read_back_valid(struct w1_slave *sl, u8 expected) |
141 | { | |
142 | u8 w1_buf[3]; | |
143 | ||
144 | if (w1_reset_resume_command(sl->master)) | |
145 | return false; | |
146 | ||
147 | w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS; | |
148 | w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE; | |
149 | w1_buf[2] = 0; | |
150 | ||
151 | w1_write_block(sl->master, w1_buf, 3); | |
152 | ||
153 | return (w1_read_8(sl->master) == expected); | |
154 | } | |
155 | #else | |
156 | static bool optional_read_back_valid(struct w1_slave *sl, u8 expected) | |
157 | { | |
158 | return true; | |
159 | } | |
160 | #endif | |
161 | ||
32ea4175 GKH |
162 | static ssize_t output_write(struct file *filp, struct kobject *kobj, |
163 | struct bin_attribute *bin_attr, char *buf, | |
164 | loff_t off, size_t count) | |
89610274 JFD |
165 | { |
166 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | |
167 | u8 w1_buf[3]; | |
89610274 | 168 | unsigned int retries = W1_F29_RETRIES; |
49695ac4 | 169 | ssize_t bytes_written = -EIO; |
89610274 JFD |
170 | |
171 | if (count != 1 || off != 0) | |
172 | return -EFAULT; | |
173 | ||
174 | dev_dbg(&sl->dev, "locking mutex for write_output"); | |
b02f8bed | 175 | mutex_lock(&sl->master->bus_mutex); |
89610274 JFD |
176 | dev_dbg(&sl->dev, "mutex locked"); |
177 | ||
178 | if (w1_reset_select_slave(sl)) | |
49695ac4 | 179 | goto out; |
89610274 | 180 | |
49695ac4 | 181 | do { |
89610274 JFD |
182 | w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE; |
183 | w1_buf[1] = *buf; | |
184 | w1_buf[2] = ~(*buf); | |
89610274 | 185 | |
49695ac4 | 186 | w1_write_block(sl->master, w1_buf, 3); |
aceca285 | 187 | |
49695ac4 JFD |
188 | if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE && |
189 | optional_read_back_valid(sl, *buf)) { | |
190 | bytes_written = 1; | |
191 | goto out; | |
aceca285 JFD |
192 | } |
193 | ||
89610274 | 194 | if (w1_reset_resume_command(sl->master)) |
49695ac4 JFD |
195 | goto out; /* unrecoverable error */ |
196 | /* try again, the slave is ready for a command */ | |
197 | } while (--retries); | |
89610274 | 198 | |
49695ac4 | 199 | out: |
b02f8bed | 200 | mutex_unlock(&sl->master->bus_mutex); |
89610274 | 201 | |
49695ac4 JFD |
202 | dev_dbg(&sl->dev, "%s, mutex unlocked retries:%d\n", |
203 | (bytes_written > 0) ? "succeeded" : "error", retries); | |
204 | ||
205 | return bytes_written; | |
89610274 JFD |
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)); |