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