Commit | Line | Data |
---|---|---|
40b0b3f8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
94859308 SA |
2 | /* |
3 | * w1_ds2406.c - w1 family 12 (DS2406) driver | |
4 | * based on w1_ds2413.c by Mariusz Bialonczyk <manio@skyboo.net> | |
5 | * | |
6 | * Copyright (c) 2014 Scott Alfter <scott@alfter.us> | |
94859308 SA |
7 | */ |
8 | ||
9 | #include <linux/kernel.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/moduleparam.h> | |
12 | #include <linux/device.h> | |
13 | #include <linux/types.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/slab.h> | |
16 | #include <linux/crc16.h> | |
17 | ||
de0d6dbd AD |
18 | #include <linux/w1.h> |
19 | ||
20 | #define W1_FAMILY_DS2406 0x12 | |
94859308 | 21 | |
94859308 SA |
22 | #define W1_F12_FUNC_READ_STATUS 0xAA |
23 | #define W1_F12_FUNC_WRITE_STATUS 0x55 | |
24 | ||
25 | static ssize_t w1_f12_read_state( | |
26 | struct file *filp, struct kobject *kobj, | |
27 | struct bin_attribute *bin_attr, | |
28 | char *buf, loff_t off, size_t count) | |
29 | { | |
ad9c36be | 30 | u8 w1_buf[6] = {W1_F12_FUNC_READ_STATUS, 7, 0, 0, 0, 0}; |
94859308 | 31 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
ad9c36be | 32 | u16 crc = 0; |
94859308 | 33 | int i; |
ad9c36be | 34 | ssize_t rtnval = 1; |
94859308 SA |
35 | |
36 | if (off != 0) | |
37 | return 0; | |
38 | if (!buf) | |
39 | return -EINVAL; | |
40 | ||
41 | mutex_lock(&sl->master->bus_mutex); | |
42 | ||
43 | if (w1_reset_select_slave(sl)) { | |
44 | mutex_unlock(&sl->master->bus_mutex); | |
45 | return -EIO; | |
46 | } | |
47 | ||
48 | w1_write_block(sl->master, w1_buf, 3); | |
49 | w1_read_block(sl->master, w1_buf+3, 3); | |
ad9c36be KK |
50 | for (i = 0; i < 6; i++) |
51 | crc = crc16_byte(crc, w1_buf[i]); | |
52 | if (crc == 0xb001) /* good read? */ | |
53 | *buf = ((w1_buf[3]>>5)&3)|0x30; | |
94859308 | 54 | else |
ad9c36be | 55 | rtnval = -EIO; |
94859308 SA |
56 | |
57 | mutex_unlock(&sl->master->bus_mutex); | |
58 | ||
59 | return rtnval; | |
60 | } | |
61 | ||
62 | static ssize_t w1_f12_write_output( | |
63 | struct file *filp, struct kobject *kobj, | |
64 | struct bin_attribute *bin_attr, | |
65 | char *buf, loff_t off, size_t count) | |
66 | { | |
67 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | |
ad9c36be KK |
68 | u8 w1_buf[6] = {W1_F12_FUNC_WRITE_STATUS, 7, 0, 0, 0, 0}; |
69 | u16 crc = 0; | |
94859308 | 70 | int i; |
ad9c36be | 71 | ssize_t rtnval = 1; |
94859308 SA |
72 | |
73 | if (count != 1 || off != 0) | |
74 | return -EFAULT; | |
75 | ||
76 | mutex_lock(&sl->master->bus_mutex); | |
77 | ||
78 | if (w1_reset_select_slave(sl)) { | |
79 | mutex_unlock(&sl->master->bus_mutex); | |
80 | return -EIO; | |
81 | } | |
82 | ||
83 | w1_buf[3] = (((*buf)&3)<<5)|0x1F; | |
84 | w1_write_block(sl->master, w1_buf, 4); | |
85 | w1_read_block(sl->master, w1_buf+4, 2); | |
ad9c36be KK |
86 | for (i = 0; i < 6; i++) |
87 | crc = crc16_byte(crc, w1_buf[i]); | |
88 | if (crc == 0xb001) /* good read? */ | |
94859308 SA |
89 | w1_write_8(sl->master, 0xFF); |
90 | else | |
ad9c36be | 91 | rtnval = -EIO; |
94859308 SA |
92 | |
93 | mutex_unlock(&sl->master->bus_mutex); | |
94 | return rtnval; | |
95 | } | |
96 | ||
97 | #define NB_SYSFS_BIN_FILES 2 | |
98 | static struct bin_attribute w1_f12_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { | |
99 | { | |
100 | .attr = { | |
101 | .name = "state", | |
921e0f2f | 102 | .mode = 0444, |
94859308 SA |
103 | }, |
104 | .size = 1, | |
105 | .read = w1_f12_read_state, | |
106 | }, | |
107 | { | |
108 | .attr = { | |
109 | .name = "output", | |
921e0f2f | 110 | .mode = 0664, |
94859308 SA |
111 | }, |
112 | .size = 1, | |
113 | .write = w1_f12_write_output, | |
114 | } | |
115 | }; | |
116 | ||
117 | static int w1_f12_add_slave(struct w1_slave *sl) | |
118 | { | |
119 | int err = 0; | |
120 | int i; | |
121 | ||
122 | for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i) | |
123 | err = sysfs_create_bin_file( | |
124 | &sl->dev.kobj, | |
125 | &(w1_f12_sysfs_bin_files[i])); | |
126 | if (err) | |
127 | while (--i >= 0) | |
128 | sysfs_remove_bin_file(&sl->dev.kobj, | |
129 | &(w1_f12_sysfs_bin_files[i])); | |
130 | return err; | |
131 | } | |
132 | ||
133 | static void w1_f12_remove_slave(struct w1_slave *sl) | |
134 | { | |
135 | int i; | |
ad9c36be | 136 | |
94859308 SA |
137 | for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i) |
138 | sysfs_remove_bin_file(&sl->dev.kobj, | |
139 | &(w1_f12_sysfs_bin_files[i])); | |
140 | } | |
141 | ||
57de2dfc | 142 | static const struct w1_family_ops w1_f12_fops = { |
94859308 SA |
143 | .add_slave = w1_f12_add_slave, |
144 | .remove_slave = w1_f12_remove_slave, | |
145 | }; | |
146 | ||
147 | static struct w1_family w1_family_12 = { | |
148 | .fid = W1_FAMILY_DS2406, | |
149 | .fops = &w1_f12_fops, | |
150 | }; | |
939fc832 | 151 | module_w1_family(w1_family_12); |
50fa2951 AD |
152 | |
153 | MODULE_AUTHOR("Scott Alfter <scott@alfter.us>"); | |
154 | MODULE_DESCRIPTION("w1 family 12 driver for DS2406 2 Pin IO"); | |
155 | MODULE_LICENSE("GPL"); |