aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1
diff options
context:
space:
mode:
authorJean-François Dagenais <dagenaisj@sonatest.com>2011-05-26 19:26:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-26 20:12:38 -0400
commit89610274bd43edc68c66ff7cf58e05debd519a5e (patch)
tree67531694ae20a3e8eff21b458df3ac8485af6e74 /drivers/w1
parent67dfd54c2d83a76a5756760f7fee0c8cfac52b1c (diff)
w1: add 1-wire (w1) DS2408 8-Channel Addressable Switch support
This DS2408 w1 slave driver is not complete for all the features of the chip, but its sufficient if you use it as a simple IO expander. [randy.dunlap@oracle.com: fix w1_ds2408.c printk formats] Signed-off-by: Jean-François Dagenais <dagenaisj@sonatest.com> Cc: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Cc: Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> Cc: Matt Reimer <mreimer@vpop.net> Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/w1')
-rw-r--r--drivers/w1/slaves/Kconfig7
-rw-r--r--drivers/w1/slaves/Makefile1
-rw-r--r--drivers/w1/slaves/w1_ds2408.c402
-rw-r--r--drivers/w1/w1_family.h1
4 files changed, 411 insertions, 0 deletions
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index f0c909625bd1..cd1b72411bd4 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -16,6 +16,13 @@ config W1_SLAVE_SMEM
16 Say Y here if you want to connect 1-wire 16 Say Y here if you want to connect 1-wire
17 simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire. 17 simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
18 18
19config W1_SLAVE_DS2408
20 tristate "8-Channel Addressable Switch (IO Expander) 0x29 family support (DS2408)"
21 help
22 Say Y here if you want to use a 1-wire
23
24 DS2408 8-Channel Addressable Switch device support
25
19config W1_SLAVE_DS2423 26config W1_SLAVE_DS2423
20 tristate "Counter 1-wire device (DS2423)" 27 tristate "Counter 1-wire device (DS2423)"
21 select CRC16 28 select CRC16
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 3c76350a24f7..75e3913910bb 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -4,6 +4,7 @@
4 4
5obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o 5obj-$(CONFIG_W1_SLAVE_THERM) += w1_therm.o
6obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o 6obj-$(CONFIG_W1_SLAVE_SMEM) += w1_smem.o
7obj-$(CONFIG_W1_SLAVE_DS2408) += w1_ds2408.o
7obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o 8obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o
8obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o 9obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o
9obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o 10obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
new file mode 100644
index 000000000000..c37781899d90
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -0,0 +1,402 @@
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 "../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");
25
26
27#define W1_F29_RETRIES 3
28
29#define W1_F29_REG_LOGIG_STATE 0x88 /* R */
30#define W1_F29_REG_OUTPUT_LATCH_STATE 0x89 /* R */
31#define W1_F29_REG_ACTIVITY_LATCH_STATE 0x8A /* R */
32#define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */
33#define W1_F29_REG_COND_SEARCH_POL_SELECT 0x8C /* RW */
34#define W1_F29_REG_CONTROL_AND_STATUS 0x8D /* RW */
35
36#define W1_F29_FUNC_READ_PIO_REGS 0xF0
37#define W1_F29_FUNC_CHANN_ACCESS_READ 0xF5
38#define W1_F29_FUNC_CHANN_ACCESS_WRITE 0x5A
39/* also used to write the control/status reg (0x8D): */
40#define W1_F29_FUNC_WRITE_COND_SEARCH_REG 0xCC
41#define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3
42
43#define W1_F29_SUCCESS_CONFIRM_BYTE 0xAA
44
45static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf)
46{
47 u8 wrbuf[3];
48 dev_dbg(&sl->dev,
49 "Reading with slave: %p, reg addr: %0#4x, buff addr: %p",
50 sl, (unsigned int)address, buf);
51
52 if (!buf)
53 return -EINVAL;
54
55 mutex_lock(&sl->master->mutex);
56 dev_dbg(&sl->dev, "mutex locked");
57
58 if (w1_reset_select_slave(sl)) {
59 mutex_unlock(&sl->master->mutex);
60 return -EIO;
61 }
62
63 wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS;
64 wrbuf[1] = address;
65 wrbuf[2] = 0;
66 w1_write_block(sl->master, wrbuf, 3);
67 *buf = w1_read_8(sl->master);
68
69 mutex_unlock(&sl->master->mutex);
70 dev_dbg(&sl->dev, "mutex unlocked");
71 return 1;
72}
73
74static ssize_t w1_f29_read_state(
75 struct file *filp, struct kobject *kobj,
76 struct bin_attribute *bin_attr,
77 char *buf, loff_t off, size_t count)
78{
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
87static ssize_t w1_f29_read_output(
88 struct file *filp, struct kobject *kobj,
89 struct bin_attribute *bin_attr,
90 char *buf, loff_t off, size_t count)
91{
92 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
93 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
94 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
95 if (count != 1 || off != 0)
96 return -EFAULT;
97 return _read_reg(kobj_to_w1_slave(kobj),
98 W1_F29_REG_OUTPUT_LATCH_STATE, buf);
99}
100
101static ssize_t w1_f29_read_activity(
102 struct file *filp, struct kobject *kobj,
103 struct bin_attribute *bin_attr,
104 char *buf, loff_t off, size_t count)
105{
106 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
107 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
108 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
109 if (count != 1 || off != 0)
110 return -EFAULT;
111 return _read_reg(kobj_to_w1_slave(kobj),
112 W1_F29_REG_ACTIVITY_LATCH_STATE, buf);
113}
114
115static ssize_t w1_f29_read_cond_search_mask(
116 struct file *filp, struct kobject *kobj,
117 struct bin_attribute *bin_attr,
118 char *buf, loff_t off, size_t count)
119{
120 dev_dbg(&kobj_to_w1_slave(kobj)->dev,
121 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p",
122 bin_attr->attr.name, kobj, (unsigned int)off, count, buf);
123 if (count != 1 || off != 0)
124 return -EFAULT;
125 return _read_reg(kobj_to_w1_slave(kobj),
126 W1_F29_REG_COND_SEARCH_SELECT_MASK, buf);
127}
128
129static ssize_t w1_f29_read_cond_search_polarity(
130 struct file *filp, struct kobject *kobj,
131 struct bin_attribute *bin_attr,
132 char *buf, loff_t off, size_t count)
133{
134 if (count != 1 || off != 0)
135 return -EFAULT;
136 return _read_reg(kobj_to_w1_slave(kobj),
137 W1_F29_REG_COND_SEARCH_POL_SELECT, buf);
138}
139
140static ssize_t w1_f29_read_status_control(
141 struct file *filp, struct kobject *kobj,
142 struct bin_attribute *bin_attr,
143 char *buf, loff_t off, size_t count)
144{
145 if (count != 1 || off != 0)
146 return -EFAULT;
147 return _read_reg(kobj_to_w1_slave(kobj),
148 W1_F29_REG_CONTROL_AND_STATUS, buf);
149}
150
151
152
153
154static ssize_t w1_f29_write_output(
155 struct file *filp, struct kobject *kobj,
156 struct bin_attribute *bin_attr,
157 char *buf, loff_t off, size_t count)
158{
159 struct w1_slave *sl = kobj_to_w1_slave(kobj);
160 u8 w1_buf[3];
161 u8 readBack;
162 unsigned int retries = W1_F29_RETRIES;
163
164 if (count != 1 || off != 0)
165 return -EFAULT;
166
167 dev_dbg(&sl->dev, "locking mutex for write_output");
168 mutex_lock(&sl->master->mutex);
169 dev_dbg(&sl->dev, "mutex locked");
170
171 if (w1_reset_select_slave(sl))
172 goto error;
173
174 while (retries--) {
175 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE;
176 w1_buf[1] = *buf;
177 w1_buf[2] = ~(*buf);
178 w1_write_block(sl->master, w1_buf, 3);
179
180 readBack = w1_read_8(sl->master);
181 /* here the master could read another byte which
182 would be the PIO reg (the actual pin logic state)
183 since in this driver we don't know which pins are
184 in and outs, there's no value to read the state and
185 compare. with (*buf) so end this command abruptly: */
186 if (w1_reset_resume_command(sl->master))
187 goto error;
188
189 if (readBack != 0xAA) {
190 /* try again, the slave is ready for a command */
191 continue;
192 }
193
194 /* go read back the output latches */
195 /* (the direct effect of the write above) */
196 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
197 w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
198 w1_buf[2] = 0;
199 w1_write_block(sl->master, w1_buf, 3);
200 /* read the result of the READ_PIO_REGS command */
201 if (w1_read_8(sl->master) == *buf) {
202 /* success! */
203 mutex_unlock(&sl->master->mutex);
204 dev_dbg(&sl->dev,
205 "mutex unlocked, retries:%d", retries);
206 return 1;
207 }
208 }
209error:
210 mutex_unlock(&sl->master->mutex);
211 dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
212
213 return -EIO;
214}
215
216
217/**
218 * Writing to the activity file resets the activity latches.
219 */
220static ssize_t w1_f29_write_activity(
221 struct file *filp, struct kobject *kobj,
222 struct bin_attribute *bin_attr,
223 char *buf, loff_t off, size_t count)
224{
225 struct w1_slave *sl = kobj_to_w1_slave(kobj);
226 unsigned int retries = W1_F29_RETRIES;
227
228 if (count != 1 || off != 0)
229 return -EFAULT;
230
231 mutex_lock(&sl->master->mutex);
232
233 if (w1_reset_select_slave(sl))
234 goto error;
235
236 while (retries--) {
237 w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
238 if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
239 mutex_unlock(&sl->master->mutex);
240 return 1;
241 }
242 if (w1_reset_resume_command(sl->master))
243 goto error;
244 }
245
246error:
247 mutex_unlock(&sl->master->mutex);
248 return -EIO;
249}
250
251static ssize_t w1_f29_write_status_control(
252 struct file *filp,
253 struct kobject *kobj,
254 struct bin_attribute *bin_attr,
255 char *buf,
256 loff_t off,
257 size_t count)
258{
259 struct w1_slave *sl = kobj_to_w1_slave(kobj);
260 u8 w1_buf[4];
261 unsigned int retries = W1_F29_RETRIES;
262
263 if (count != 1 || off != 0)
264 return -EFAULT;
265
266 mutex_lock(&sl->master->mutex);
267
268 if (w1_reset_select_slave(sl))
269 goto error;
270
271 while (retries--) {
272 w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
273 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
274 w1_buf[2] = 0;
275 w1_buf[3] = *buf;
276
277 w1_write_block(sl->master, w1_buf, 4);
278 if (w1_reset_resume_command(sl->master))
279 goto error;
280
281 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
282 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
283 w1_buf[2] = 0;
284
285 w1_write_block(sl->master, w1_buf, 3);
286 if (w1_read_8(sl->master) == *buf) {
287 /* success! */
288 mutex_unlock(&sl->master->mutex);
289 return 1;
290 }
291 }
292error:
293 mutex_unlock(&sl->master->mutex);
294
295 return -EIO;
296}
297
298
299
300#define NB_SYSFS_BIN_FILES 6
301static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
302 {
303 .attr = {
304 .name = "state",
305 .mode = S_IRUGO,
306 },
307 .size = 1,
308 .read = w1_f29_read_state,
309 },
310 {
311 .attr = {
312 .name = "output",
313 .mode = S_IRUGO | S_IWUSR | S_IWGRP,
314 },
315 .size = 1,
316 .read = w1_f29_read_output,
317 .write = w1_f29_write_output,
318 },
319 {
320 .attr = {
321 .name = "activity",
322 .mode = S_IRUGO,
323 },
324 .size = 1,
325 .read = w1_f29_read_activity,
326 .write = w1_f29_write_activity,
327 },
328 {
329 .attr = {
330 .name = "cond_search_mask",
331 .mode = S_IRUGO,
332 },
333 .size = 1,
334 .read = w1_f29_read_cond_search_mask,
335 .write = 0,
336 },
337 {
338 .attr = {
339 .name = "cond_search_polarity",
340 .mode = S_IRUGO,
341 },
342 .size = 1,
343 .read = w1_f29_read_cond_search_polarity,
344 .write = 0,
345 },
346 {
347 .attr = {
348 .name = "status_control",
349 .mode = S_IRUGO | S_IWUSR | S_IWGRP,
350 },
351 .size = 1,
352 .read = w1_f29_read_status_control,
353 .write = w1_f29_write_status_control,
354 }
355};
356
357static int w1_f29_add_slave(struct w1_slave *sl)
358{
359 int err = 0;
360 int i;
361
362 for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
363 err = sysfs_create_bin_file(
364 &sl->dev.kobj,
365 &(w1_f29_sysfs_bin_files[i]));
366 if (err)
367 while (--i >= 0)
368 sysfs_remove_bin_file(&sl->dev.kobj,
369 &(w1_f29_sysfs_bin_files[i]));
370 return err;
371}
372
373static void w1_f29_remove_slave(struct w1_slave *sl)
374{
375 int i;
376 for (i = NB_SYSFS_BIN_FILES; i <= 0; --i)
377 sysfs_remove_bin_file(&sl->dev.kobj,
378 &(w1_f29_sysfs_bin_files[i]));
379}
380
381static struct w1_family_ops w1_f29_fops = {
382 .add_slave = w1_f29_add_slave,
383 .remove_slave = w1_f29_remove_slave,
384};
385
386static struct w1_family w1_family_29 = {
387 .fid = W1_FAMILY_DS2408,
388 .fops = &w1_f29_fops,
389};
390
391static int __init w1_f29_init(void)
392{
393 return w1_register_family(&w1_family_29);
394}
395
396static void __exit w1_f29_exit(void)
397{
398 w1_unregister_family(&w1_family_29);
399}
400
401module_init(w1_f29_init);
402module_exit(w1_f29_exit);
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index f3b636d7cafe..75137590c3bc 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -34,6 +34,7 @@
34#define W1_THERM_DS1822 0x22 34#define W1_THERM_DS1822 0x22
35#define W1_EEPROM_DS2433 0x23 35#define W1_EEPROM_DS2433 0x23
36#define W1_THERM_DS18B20 0x28 36#define W1_THERM_DS18B20 0x28
37#define W1_FAMILY_DS2408 0x29
37#define W1_EEPROM_DS2431 0x2D 38#define W1_EEPROM_DS2431 0x2D
38#define W1_FAMILY_DS2760 0x30 39#define W1_FAMILY_DS2760 0x30
39 40