]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/w1/slaves/w1_ds2408.c
w1: Add subsystem kernel public interface
[mirror_ubuntu-artful-kernel.git] / drivers / w1 / slaves / w1_ds2408.c
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
18 #include <linux/w1.h>
19
20 #define W1_FAMILY_DS2408 0x29
21
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
50 mutex_lock(&sl->master->bus_mutex);
51 dev_dbg(&sl->dev, "mutex locked");
52
53 if (w1_reset_select_slave(sl)) {
54 mutex_unlock(&sl->master->bus_mutex);
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
64 mutex_unlock(&sl->master->bus_mutex);
65 dev_dbg(&sl->dev, "mutex unlocked");
66 return 1;
67 }
68
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)
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
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)
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
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)
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
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)
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
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)
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
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)
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
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)
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");
154 mutex_lock(&sl->master->bus_mutex);
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);
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
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
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 */
191 if (w1_read_8(sl->master) == *buf)
192 #endif
193 {
194 /* success! */
195 mutex_unlock(&sl->master->bus_mutex);
196 dev_dbg(&sl->dev,
197 "mutex unlocked, retries:%d", retries);
198 return 1;
199 }
200 }
201 error:
202 mutex_unlock(&sl->master->bus_mutex);
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 */
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)
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
222 mutex_lock(&sl->master->bus_mutex);
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) {
230 mutex_unlock(&sl->master->bus_mutex);
231 return 1;
232 }
233 if (w1_reset_resume_command(sl->master))
234 goto error;
235 }
236
237 error:
238 mutex_unlock(&sl->master->bus_mutex);
239 return -EIO;
240 }
241
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)
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
253 mutex_lock(&sl->master->bus_mutex);
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! */
275 mutex_unlock(&sl->master->bus_mutex);
276 return 1;
277 }
278 }
279 error:
280 mutex_unlock(&sl->master->bus_mutex);
281
282 return -EIO;
283 }
284
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);
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);
308 out:
309 mutex_unlock(&sl->master->bus_mutex);
310 return res;
311 }
312
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,
328 };
329
330 static const struct attribute_group w1_f29_group = {
331 .bin_attrs = w1_f29_bin_attrs,
332 };
333
334 static const struct attribute_group *w1_f29_groups[] = {
335 &w1_f29_group,
336 NULL,
337 };
338
339 static struct w1_family_ops w1_f29_fops = {
340 .add_slave = w1_f29_disable_test_mode,
341 .groups = w1_f29_groups,
342 };
343
344 static struct w1_family w1_family_29 = {
345 .fid = W1_FAMILY_DS2408,
346 .fops = &w1_f29_fops,
347 };
348 module_w1_family(w1_family_29);
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));