net: ethernet: ti: netcp_core: return error while dma channel open issue
[linux-2.6-microblaze.git] / drivers / w1 / slaves / w1_ds2405.c
1 /*
2  *      w1_ds2405.c
3  *
4  * Copyright (c) 2017 Maciej S. Szmigiero <mail@maciej.szmigiero.name>
5  * Based on w1_therm.c copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
6  *
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the therms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 #include <linux/device.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/moduleparam.h>
23 #include <linux/mutex.h>
24 #include <linux/string.h>
25 #include <linux/types.h>
26
27 #include "../w1.h"
28 #include "../w1_family.h"
29
30 MODULE_LICENSE("GPL");
31 MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>");
32 MODULE_DESCRIPTION("Driver for 1-wire Dallas DS2405 PIO.");
33 MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2405));
34
35 static int w1_ds2405_select(struct w1_slave *sl, bool only_active)
36 {
37         struct w1_master *dev = sl->master;
38
39         u64 dev_addr = le64_to_cpu(*(u64 *)&sl->reg_num);
40         unsigned int bit_ctr;
41
42         if (w1_reset_bus(dev) != 0)
43                 return 0;
44
45         /*
46          * We cannot use a normal Match ROM command
47          * since doing so would toggle PIO state
48          */
49         w1_write_8(dev, only_active ? W1_ALARM_SEARCH : W1_SEARCH);
50
51         for (bit_ctr = 0; bit_ctr < 64; bit_ctr++) {
52                 int bit2send = !!(dev_addr & BIT(bit_ctr));
53                 u8 ret;
54
55                 ret = w1_triplet(dev, bit2send);
56
57                 if ((ret & (BIT(0) | BIT(1))) ==
58                     (BIT(0) | BIT(1))) /* no devices found */
59                         return 0;
60
61                 if (!!(ret & BIT(2)) != bit2send)
62                         /* wrong direction taken - no such device */
63                         return 0;
64         }
65
66         return 1;
67 }
68
69 static int w1_ds2405_read_pio(struct w1_slave *sl)
70 {
71         if (w1_ds2405_select(sl, true))
72                 return 0; /* "active" means PIO is low */
73
74         if (w1_ds2405_select(sl, false))
75                 return 1;
76
77         return -ENODEV;
78 }
79
80 static ssize_t state_show(struct device *device,
81                           struct device_attribute *attr, char *buf)
82 {
83         struct w1_slave *sl = dev_to_w1_slave(device);
84         struct w1_master *dev = sl->master;
85
86         int ret;
87         ssize_t f_retval;
88         u8 state;
89
90         ret = mutex_lock_interruptible(&dev->bus_mutex);
91         if (ret)
92                 return ret;
93
94         if (!w1_ds2405_select(sl, false)) {
95                 f_retval = -ENODEV;
96                 goto out_unlock;
97         }
98
99         state = w1_read_8(dev);
100         if (state != 0 &&
101             state != 0xff) {
102                 dev_err(device, "non-consistent state %x\n", state);
103                 f_retval = -EIO;
104                 goto out_unlock;
105         }
106
107         *buf = state ? '1' : '0';
108         f_retval = 1;
109
110 out_unlock:
111         w1_reset_bus(dev);
112         mutex_unlock(&dev->bus_mutex);
113
114         return f_retval;
115 }
116
117 static ssize_t output_show(struct device *device,
118                            struct device_attribute *attr, char *buf)
119 {
120         struct w1_slave *sl = dev_to_w1_slave(device);
121         struct w1_master *dev = sl->master;
122
123         int ret;
124         ssize_t f_retval;
125
126         ret = mutex_lock_interruptible(&dev->bus_mutex);
127         if (ret)
128                 return ret;
129
130         ret = w1_ds2405_read_pio(sl);
131         if (ret < 0) {
132                 f_retval = ret;
133                 goto out_unlock;
134         }
135
136         *buf = ret ? '1' : '0';
137         f_retval = 1;
138
139 out_unlock:
140         w1_reset_bus(dev);
141         mutex_unlock(&dev->bus_mutex);
142
143         return f_retval;
144 }
145
146 static ssize_t output_store(struct device *device,
147                             struct device_attribute *attr,
148                             const char *buf, size_t count)
149 {
150         struct w1_slave *sl = dev_to_w1_slave(device);
151         struct w1_master *dev = sl->master;
152
153         int ret, current_pio;
154         unsigned int val;
155         ssize_t f_retval;
156
157         if (count < 1)
158                 return -EINVAL;
159
160         if (sscanf(buf, " %u%n", &val, &ret) < 1)
161                 return -EINVAL;
162
163         if (val != 0 && val != 1)
164                 return -EINVAL;
165
166         f_retval = ret;
167
168         ret = mutex_lock_interruptible(&dev->bus_mutex);
169         if (ret)
170                 return ret;
171
172         current_pio = w1_ds2405_read_pio(sl);
173         if (current_pio < 0) {
174                 f_retval = current_pio;
175                 goto out_unlock;
176         }
177
178         if (current_pio == val)
179                 goto out_unlock;
180
181         if (w1_reset_bus(dev) != 0) {
182                 f_retval = -ENODEV;
183                 goto out_unlock;
184         }
185
186         /*
187          * can't use w1_reset_select_slave() here since it uses Skip ROM if
188          * there is only one device on bus
189          */
190         do {
191                 u64 dev_addr = le64_to_cpu(*(u64 *)&sl->reg_num);
192                 u8 cmd[9];
193
194                 cmd[0] = W1_MATCH_ROM;
195                 memcpy(&cmd[1], &dev_addr, sizeof(dev_addr));
196
197                 w1_write_block(dev, cmd, sizeof(cmd));
198         } while (0);
199
200 out_unlock:
201         w1_reset_bus(dev);
202         mutex_unlock(&dev->bus_mutex);
203
204         return f_retval;
205 }
206
207 static DEVICE_ATTR_RO(state);
208 static DEVICE_ATTR_RW(output);
209
210 static struct attribute *w1_ds2405_attrs[] = {
211         &dev_attr_state.attr,
212         &dev_attr_output.attr,
213         NULL
214 };
215
216 ATTRIBUTE_GROUPS(w1_ds2405);
217
218 static struct w1_family_ops w1_ds2405_fops = {
219         .groups = w1_ds2405_groups
220 };
221
222 static struct w1_family w1_family_ds2405 = {
223         .fid = W1_FAMILY_DS2405,
224         .fops = &w1_ds2405_fops
225 };
226
227 module_w1_family(w1_family_ds2405);