]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ow/ow_temp.c
Remove redundant hw sysctl declaration. gcc CI complains, but clang doesn't.
[FreeBSD/FreeBSD.git] / sys / dev / ow / ow_temp.c
1 /*-
2  * Copyright (c) 2015 M. Warner Losh <imp@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33
34 #include <sys/bus.h>
35 #include <sys/errno.h>
36 #include <sys/libkern.h>
37 #include <sys/kthread.h>
38 #include <sys/malloc.h>
39 #include <sys/module.h>
40 #include <sys/mutex.h>
41 #include <sys/proc.h>
42 #include <sys/sysctl.h>
43
44 #include <dev/ow/ow.h>
45 #include <dev/ow/own.h>
46
47 #define OWT_DS1820      0x10            /* Also 18S20 */
48 #define OWT_DS1822      0x22            /* Very close to 18B20 */
49 #define OWT_DS18B20     0x28            /* Also MAX31820 */
50 #define OWT_DS1825      0x3B            /* Just like 18B20 with address bits */
51
52 #define CONVERT_T               0x44
53 #define COPY_SCRATCHPAD         0x48
54 #define WRITE_SCRATCHPAD        0x4e
55 #define READ_POWER_SUPPLY       0xb4
56 #define RECALL_EE               0xb8
57 #define READ_SCRATCHPAD         0xbe
58
59
60 #define OW_TEMP_DONE            0x01
61 #define OW_TEMP_RUNNING         0x02
62
63 struct ow_temp_softc
64 {
65         device_t        dev;
66         int             type;
67         int             temp;
68         int             flags;
69         int             bad_crc;
70         int             bad_reads;
71         int             reading_interval;
72         int             parasite;
73         struct mtx      temp_lock;
74         struct proc     *event_thread;
75 };
76
77 static int
78 ow_temp_probe(device_t dev)
79 {
80
81         switch (ow_get_family(dev)) {
82         case OWT_DS1820:
83                 device_set_desc(dev, "One Wire Temperature");
84                 return BUS_PROBE_DEFAULT;
85         case OWT_DS1822:
86         case OWT_DS1825:
87         case OWT_DS18B20:
88                 device_set_desc(dev, "Advanced One Wire Temperature");
89                 return BUS_PROBE_DEFAULT;
90         default:
91                 return ENXIO;
92         }
93 }
94
95 static int
96 ow_temp_read_scratchpad(device_t dev, uint8_t *scratch, int len)
97 {
98         struct ow_cmd cmd;
99         
100         own_self_command(dev, &cmd, READ_SCRATCHPAD);
101         cmd.xpt_read_len = len;
102         own_command_wait(dev, &cmd);
103         memcpy(scratch, cmd.xpt_read, len);
104
105         return 0;
106 }
107
108 static int
109 ow_temp_convert_t(device_t dev)
110 {
111         struct ow_cmd cmd;
112
113         own_self_command(dev, &cmd, CONVERT_T);
114         own_command_wait(dev, &cmd);
115
116         return 0;
117 }
118
119
120 static int
121 ow_temp_read_power_supply(device_t dev, int *parasite)
122 {
123         struct ow_cmd cmd;
124
125         own_self_command(dev, &cmd, READ_POWER_SUPPLY);
126         cmd.flags |= OW_FLAG_READ_BIT;
127         cmd.xpt_read_len = 1;
128         own_command_wait(dev, &cmd);
129         *parasite = !cmd.xpt_read[0];   /* parasites pull bus low */
130
131         return 0;
132 }
133
134 static void
135 ow_temp_event_thread(void *arg)
136 {
137         struct ow_temp_softc *sc;
138         uint8_t scratch[8 + 1];
139         uint8_t crc;
140         int retries, rv, tmp;
141
142         sc = arg;
143         pause("owtstart", device_get_unit(sc->dev) * hz / 100); // 10ms stagger
144         mtx_lock(&sc->temp_lock);
145         sc->flags |= OW_TEMP_RUNNING;
146         mtx_unlock(&sc->temp_lock);
147         ow_temp_read_power_supply(sc->dev, &sc->parasite);
148         if (sc->parasite)
149                 device_printf(sc->dev, "Running in parasitic mode unsupported\n");
150         mtx_lock(&sc->temp_lock);
151         while ((sc->flags & OW_TEMP_DONE) == 0) {
152                 mtx_unlock(&sc->temp_lock);
153                 ow_temp_convert_t(sc->dev);
154                 mtx_lock(&sc->temp_lock);
155                 msleep(sc, &sc->temp_lock, 0, "owtcvt", hz);
156                 if (sc->flags & OW_TEMP_DONE)
157                         break;
158                 mtx_unlock(&sc->temp_lock);
159                 for (retries = 5; retries > 0; retries--) {
160                         rv = ow_temp_read_scratchpad(sc->dev, scratch, sizeof(scratch));
161                         if (rv == 0) {
162                                 crc = own_crc(sc->dev, scratch, sizeof(scratch) - 1);
163                                 if (crc == scratch[8]) {
164                                         if (sc->type == OWT_DS1820) {
165                                                 if (scratch[7]) {
166                                                         /*
167                                                          * Formula from DS18S20 datasheet, page 6
168                                                          * DS18S20 datasheet says count_per_c is 16, DS1820 does not
169                                                          */
170                                                         tmp = (int16_t)((scratch[0] & 0xfe) |
171                                                             (scratch[1] << 8)) << 3;
172                                                         tmp += 16 - scratch[6] - 4; /* count_per_c == 16 */
173                                                 } else
174                                                         tmp = (int16_t)(scratch[0] | (scratch[1] << 8)) << 3;
175                                         } else
176                                                 tmp = (int16_t)(scratch[0] | (scratch[1] << 8));
177                                         sc->temp = tmp * 1000 / 16 + 273150;
178                                         break;
179                                 }
180                                 sc->bad_crc++;
181                         } else
182                                 sc->bad_reads++;
183                 }
184                 mtx_lock(&sc->temp_lock);
185                 msleep(sc, &sc->temp_lock, 0, "owtcvt", sc->reading_interval);
186         }
187         sc->flags &= ~OW_TEMP_RUNNING;
188         mtx_unlock(&sc->temp_lock);
189         kproc_exit(0);
190 }
191
192 static int
193 ow_temp_attach(device_t dev)
194 {
195         struct ow_temp_softc *sc;
196
197         sc = device_get_softc(dev);
198         sc->dev = dev;
199         sc->type = ow_get_family(dev);
200         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
201             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
202             OID_AUTO, "temperature", CTLFLAG_RD | CTLTYPE_INT,
203             &sc->temp, 0, sysctl_handle_int,
204             "IK3", "Current Temperature");
205         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
206             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
207             OID_AUTO, "badcrc", CTLFLAG_RD,
208             &sc->bad_crc, 0,
209             "Number of Bad CRC on reading scratchpad");
210         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
211             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
212             OID_AUTO, "badread", CTLFLAG_RD,
213             &sc->bad_reads, 0,
214             "Number of errors on reading scratchpad");
215         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
216             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
217             OID_AUTO, "reading_interval", CTLFLAG_RW,
218             &sc->reading_interval, 0,
219             "ticks between reads");
220         SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
221             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
222             OID_AUTO, "parasite", CTLFLAG_RW,
223             &sc->parasite, 0,
224             "In Parasite mode");
225         /*
226          * Just do this for unit 0 to avoid locking
227          * the ow bus until that code can be put
228          * into place.
229          */
230         sc->temp = -1;
231         sc->reading_interval = 10 * hz;
232         mtx_init(&sc->temp_lock, "lock for doing temperature", NULL, MTX_DEF);
233         /* Start the thread */
234         if (kproc_create(ow_temp_event_thread, sc, &sc->event_thread, 0, 0,
235             "%s event thread", device_get_nameunit(dev))) {
236                 device_printf(dev, "unable to create event thread.\n");
237                 panic("ow_temp_attach, can't create thread");
238         }
239
240         return 0;
241 }
242
243 static int
244 ow_temp_detach(device_t dev)
245 {
246         struct ow_temp_softc *sc;
247
248         sc = device_get_softc(dev);
249
250         /*
251          * Wait for the thread to die.  kproc_exit will do a wakeup
252          * on the event thread's struct thread * so that we know it is
253          * safe to proceed.  IF the thread is running, set the please
254          * die flag and wait for it to comply.  Since the wakeup on
255          * the event thread happens only in kproc_exit, we don't
256          * need to loop here.
257          */
258         mtx_lock(&sc->temp_lock);
259         sc->flags |= OW_TEMP_DONE;
260         while (sc->flags & OW_TEMP_RUNNING) {
261                 wakeup(sc);
262                 msleep(sc->event_thread, &sc->temp_lock, PWAIT, "owtun", 0);
263         }
264         mtx_destroy(&sc->temp_lock);
265         
266         return 0;
267 }
268
269 devclass_t ow_temp_devclass;
270
271 static device_method_t ow_temp_methods[] = {
272         /* Device interface */
273         DEVMETHOD(device_probe,         ow_temp_probe),
274         DEVMETHOD(device_attach,        ow_temp_attach),
275         DEVMETHOD(device_detach,        ow_temp_detach),
276
277         { 0, 0 }
278 };
279
280 static driver_t ow_temp_driver = {
281         "ow_temp",
282         ow_temp_methods,
283         sizeof(struct ow_temp_softc),
284 };
285
286 DRIVER_MODULE(ow_temp, ow, ow_temp_driver, ow_temp_devclass, 0, 0);
287 MODULE_DEPEND(ow_temp, ow, 1, 1, 1);