1 /* $OpenBSD: mbg.c,v 1.37 2024/05/24 06:02:58 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/param.h>
20 #include <sys/device.h>
21 #include <sys/timeout.h>
22 #include <sys/systm.h>
23 #include <sys/sensors.h>
24 #include <sys/time.h>
25
26 #include <machine/bus.h>
27
28 #include <dev/pci/pcivar.h>
29 #include <dev/pci/pcireg.h>
30 #include <dev/pci/pcidevs.h>
31
32 struct mbg_softc {
33 struct device sc_dev;
34 bus_space_tag_t sc_iot;
35 bus_space_handle_t sc_ioh;
36
37 /*
38 * I/O region used by the AMCC S5920 found on the PCI509 card
39 * used to access the data.
40 */
41 bus_space_tag_t sc_iot_s5920;
42 bus_space_handle_t sc_ioh_s5920;
43
44 struct ksensor sc_timedelta;
45 struct ksensor sc_signal;
46 struct ksensordev sc_sensordev;
47 struct timeout sc_timeout; /* invalidate sensor */
48 int sc_trust; /* trust time in seconds */
49
50 int (*sc_read)(struct mbg_softc *, int cmd,
51 char *buf, size_t len,
52 struct timespec *tstamp);
53 };
54
55 struct mbg_time {
56 u_int8_t hundreds;
57 u_int8_t sec;
58 u_int8_t min;
59 u_int8_t hour;
60 u_int8_t mday;
61 u_int8_t wday; /* 1 (monday) - 7 (sunday) */
62 u_int8_t mon;
63 u_int8_t year; /* 0 - 99 */
64 u_int8_t status;
65 u_int8_t signal;
66 int8_t utc_off;
67 };
68
69 struct mbg_time_hr {
70 u_int32_t sec; /* always UTC */
71 u_int32_t frac; /* fractions of second */
72 int32_t utc_off; /* informal only, in seconds */
73 u_int16_t status;
74 u_int8_t signal;
75 };
76
77 /* mbg_time.status bits */
78 #define MBG_FREERUN 0x01 /* clock running on xtal */
79 #define MBG_DST_ENA 0x02 /* DST enabled */
80 #define MBG_SYNC 0x04 /* clock synced at least once */
81 #define MBG_DST_CHG 0x08 /* DST change announcement */
82 #define MBG_UTC 0x10 /* special UTC firmware is installed */
83 #define MBG_LEAP 0x20 /* announcement of a leap second */
84 #define MBG_IFTM 0x40 /* current time was set from host */
85 #define MBG_INVALID 0x80 /* time invalid, batt. was disconn. */
86
87 /* AMCC S5920 registers */
88 #define AMCC_DATA 0x00 /* data register, on 2nd IO region */
89 #define AMCC_OMB 0x0c /* outgoing mailbox */
90 #define AMCC_IMB 0x1c /* incoming mailbox */
91
92 /* AMCC S5933 registers */
93 #define AMCC_OMB1 0x00 /* outgoing mailbox 1 */
94 #define AMCC_IMB4 0x1c /* incoming mailbox 4 */
95 #define AMCC_FIFO 0x20 /* FIFO register */
96 #define AMCC_INTCSR 0x38 /* interrupt control/status register */
97 #define AMCC_MCSR 0x3c /* master control/status register */
98
99 /* ASIC registers */
100 #define ASIC_CFG 0x00
101 #define ASIC_FEATURES 0x08 /* r/o */
102 #define ASIC_STATUS 0x10
103 #define ASIC_CTLSTATUS 0x14
104 #define ASIC_DATA 0x18
105 #define ASIC_RES1 0x1c
106 #define ASIC_ADDON 0x20
107
108 /* commands */
109 #define MBG_GET_TIME 0x00
110 #define MBG_GET_SYNC_TIME 0x02
111 #define MBG_GET_TIME_HR 0x03
112 #define MBG_SET_TIME 0x10
113 #define MBG_GET_TZCODE 0x32
114 #define MBG_SET_TZCODE 0x33
115 #define MBG_GET_FW_ID_1 0x40
116 #define MBG_GET_FW_ID_2 0x41
117 #define MBG_GET_SERNUM 0x42
118
119 /* timezone codes (for MBG_{GET|SET}_TZCODE) */
120 #define MBG_TZCODE_CET_CEST 0x00
121 #define MBG_TZCODE_CET 0x01
122 #define MBG_TZCODE_UTC 0x02
123 #define MBG_TZCODE_EET_EEST 0x03
124
125 /* misc. constants */
126 #define MBG_FIFO_LEN 16
127 #define MBG_ID_LEN (2 * MBG_FIFO_LEN + 1)
128 #define MBG_BUSY 0x01
129 #define MBG_SIG_BIAS 55
130 #define MBG_SIG_MAX 68
131 #define NSECPERSEC 1000000000LL /* nanoseconds per second */
132 #define HRDIVISOR 0x100000000LL /* for hi-res timestamp */
133
134 int mbg_probe(struct device *, void *, void *);
135 void mbg_attach(struct device *, struct device *, void *);
136 void mbg_task(void *);
137 void mbg_task_hr(void *);
138 void mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp,
139 int64_t timedelta, u_int8_t rsignal, u_int16_t status);
140 int mbg_read_amcc_s5920(struct mbg_softc *, int cmd, char *buf, size_t len,
141 struct timespec *tstamp);
142 int mbg_read_amcc_s5933(struct mbg_softc *, int cmd, char *buf, size_t len,
143 struct timespec *tstamp);
144 int mbg_read_asic(struct mbg_softc *, int cmd, char *buf, size_t len,
145 struct timespec *tstamp);
146 void mbg_timeout(void *);
147
148 const struct cfattach mbg_ca = {
149 sizeof(struct mbg_softc), mbg_probe, mbg_attach
150 };
151
152 struct cfdriver mbg_cd = {
153 NULL, "mbg", DV_DULL
154 };
155
156 const struct pci_matchid mbg_devices[] = {
157 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_GPS170PCI },
158 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI32 },
159 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI509 },
160 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI510 },
161 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI511 },
162 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PEX511 },
163 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PZF180PEX }
164 };
165
166 int
mbg_probe(struct device * parent,void * match,void * aux)167 mbg_probe(struct device *parent, void *match, void *aux)
168 {
169 return pci_matchbyid((struct pci_attach_args *)aux, mbg_devices,
170 nitems(mbg_devices));
171 }
172
173 void
mbg_attach(struct device * parent,struct device * self,void * aux)174 mbg_attach(struct device *parent, struct device *self, void *aux)
175 {
176 struct mbg_softc *sc = (struct mbg_softc *)self;
177 struct pci_attach_args *pa = (struct pci_attach_args *)aux;
178 struct mbg_time tframe;
179 pcireg_t memtype;
180 bus_size_t iosize, iosize2;
181 int bar = PCI_MAPREG_START, signal, t_trust;
182 const char *desc;
183 #ifdef MBG_DEBUG
184 char fw_id[MBG_ID_LEN];
185 #endif
186
187 timeout_set(&sc->sc_timeout, mbg_timeout, sc);
188
189 /* for the PEX511 use BAR2 instead of BAR0*/
190 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MEINBERG_PEX511)
191 bar += 0x08;
192
193 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar);
194 if (pci_mapreg_map(pa, bar, memtype, 0, &sc->sc_iot,
195 &sc->sc_ioh, NULL, &iosize, 0)) {
196 printf(": PCI %s region not found\n",
197 memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
198 return;
199 }
200
201 if ((desc = pci_findproduct(pa->pa_id)) == NULL)
202 desc = "Radio clock";
203 strlcpy(sc->sc_timedelta.desc, desc, sizeof(sc->sc_timedelta.desc));
204
205 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
206 sizeof(sc->sc_sensordev.xname));
207
208 sc->sc_timedelta.type = SENSOR_TIMEDELTA;
209 sc->sc_timedelta.status = SENSOR_S_UNKNOWN;
210 sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta);
211
212 sc->sc_signal.type = SENSOR_PERCENT;
213 sc->sc_signal.status = SENSOR_S_UNKNOWN;
214 strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc));
215 sensor_attach(&sc->sc_sensordev, &sc->sc_signal);
216
217 t_trust = 12 * 60 * 60; /* twelve hours */
218
219 switch (PCI_PRODUCT(pa->pa_id)) {
220 case PCI_PRODUCT_MEINBERG_PCI32:
221 sc->sc_read = mbg_read_amcc_s5933;
222 sensor_task_register(sc, mbg_task, 10);
223 break;
224 case PCI_PRODUCT_MEINBERG_PCI509:
225 /*
226 * map the second I/O region needed in addition to the first
227 * to get at the actual data.
228 */
229 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag,
230 PCI_MAPREG_START + 0x04);
231 if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04, memtype, 0,
232 &sc->sc_iot_s5920, &sc->sc_ioh_s5920, NULL, &iosize2, 0)) {
233 printf(": PCI2 %s region not found\n",
234 memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory");
235
236 /* unmap first mapped region as well if we fail */
237 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
238 return;
239 }
240 sc->sc_read = mbg_read_amcc_s5920;
241 sensor_task_register(sc, mbg_task, 10);
242 break;
243 case PCI_PRODUCT_MEINBERG_PCI510:
244 case PCI_PRODUCT_MEINBERG_PCI511:
245 case PCI_PRODUCT_MEINBERG_PEX511:
246 sc->sc_read = mbg_read_asic;
247 sensor_task_register(sc, mbg_task, 10);
248 break;
249 case PCI_PRODUCT_MEINBERG_GPS170PCI:
250 case PCI_PRODUCT_MEINBERG_PZF180PEX:
251 t_trust = 4 * 24 * 60 * 60; /* four days */
252 sc->sc_read = mbg_read_asic;
253 sensor_task_register(sc, mbg_task_hr, 1);
254 break;
255 default:
256 /* this can not normally happen, but then there is murphy */
257 panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id));
258 break;
259 }
260
261 sc->sc_trust = t_trust;
262
263 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe,
264 sizeof(struct mbg_time), NULL)) {
265 printf(": unknown status");
266 sc->sc_signal.status = SENSOR_S_CRIT;
267 } else {
268 sc->sc_signal.status = SENSOR_S_OK;
269 signal = tframe.signal - MBG_SIG_BIAS;
270 if (signal < 0)
271 signal = 0;
272 else if (signal > MBG_SIG_MAX)
273 signal = MBG_SIG_MAX;
274 sc->sc_signal.value = signal;
275
276 if (tframe.status & MBG_SYNC)
277 printf(": synchronized");
278 else
279 printf(": not synchronized");
280 if (tframe.status & MBG_FREERUN) {
281 sc->sc_signal.status = SENSOR_S_WARN;
282 printf(", free running");
283 }
284 if (tframe.status & MBG_IFTM)
285 printf(", time set from host");
286 }
287 #ifdef MBG_DEBUG
288 if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) ||
289 sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN,
290 NULL))
291 printf(", firmware unknown");
292 else {
293 fw_id[MBG_ID_LEN - 1] = '\0';
294 printf(", firmware %s", fw_id);
295 }
296 #endif
297 printf("\n");
298 sensordev_install(&sc->sc_sensordev);
299 timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
300 }
301
302 /*
303 * mbg_task() reads a timestamp from cards that to not provide a high
304 * resolution timestamp. The precision is limited to 1/100 sec.
305 */
306 void
mbg_task(void * arg)307 mbg_task(void *arg)
308 {
309 struct mbg_softc *sc = (struct mbg_softc *)arg;
310 struct mbg_time tframe;
311 struct clock_ymdhms ymdhms;
312 struct timespec tstamp;
313 int64_t timedelta;
314 time_t trecv;
315
316 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe),
317 &tstamp)) {
318 sc->sc_signal.status = SENSOR_S_CRIT;
319 return;
320 }
321 if (tframe.status & MBG_INVALID) {
322 sc->sc_signal.status = SENSOR_S_CRIT;
323 return;
324 }
325 ymdhms.dt_year = tframe.year + 2000;
326 ymdhms.dt_mon = tframe.mon;
327 ymdhms.dt_day = tframe.mday;
328 ymdhms.dt_hour = tframe.hour;
329 ymdhms.dt_min = tframe.min;
330 ymdhms.dt_sec = tframe.sec;
331 trecv = clock_ymdhms_to_secs(&ymdhms) - tframe.utc_off * 3600;
332
333 timedelta = (int64_t)((tstamp.tv_sec - trecv) * 100
334 - tframe.hundreds) * 10000000LL + tstamp.tv_nsec;
335
336 mbg_update_sensor(sc, &tstamp, timedelta, tframe.signal,
337 (u_int16_t)tframe.status);
338 }
339
340 /*
341 * mbg_task_hr() reads a timestamp from cards that do provide a high
342 * resolution timestamp.
343 */
344 void
mbg_task_hr(void * arg)345 mbg_task_hr(void *arg)
346 {
347 struct mbg_softc *sc = (struct mbg_softc *)arg;
348 struct mbg_time_hr tframe;
349 struct timespec tstamp;
350 int64_t tlocal, trecv;
351
352 if (sc->sc_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe),
353 &tstamp)) {
354 sc->sc_signal.status = SENSOR_S_CRIT;
355 return;
356 }
357 if (tframe.status & MBG_INVALID) {
358 sc->sc_signal.status = SENSOR_S_CRIT;
359 return;
360 }
361
362 tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec;
363 trecv = letoh32(tframe.sec) * NSECPERSEC +
364 (letoh32(tframe.frac) * NSECPERSEC >> 32);
365
366 mbg_update_sensor(sc, &tstamp, tlocal - trecv, tframe.signal,
367 letoh16(tframe.status));
368 }
369
370 /* update the sensor value, common to all cards */
371 void
mbg_update_sensor(struct mbg_softc * sc,struct timespec * tstamp,int64_t timedelta,u_int8_t rsignal,u_int16_t status)372 mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp,
373 int64_t timedelta, u_int8_t rsignal, u_int16_t status)
374 {
375 int signal;
376
377 sc->sc_timedelta.value = timedelta;
378 sc->sc_timedelta.tv.tv_sec = tstamp->tv_sec;
379 sc->sc_timedelta.tv.tv_usec = tstamp->tv_nsec / 1000;
380
381 signal = rsignal - MBG_SIG_BIAS;
382 if (signal < 0)
383 signal = 0;
384 else if (signal > MBG_SIG_MAX)
385 signal = MBG_SIG_MAX;
386
387 sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX;
388 sc->sc_signal.status = status & MBG_FREERUN ?
389 SENSOR_S_WARN : SENSOR_S_OK;
390 sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec;
391 sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec;
392 if (!(status & MBG_FREERUN)) {
393 sc->sc_timedelta.status = SENSOR_S_OK;
394 timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
395 }
396 }
397
398 /*
399 * send a command and read back results to an AMCC S5920 based card
400 * (e.g. the PCI509 DCF77 radio clock)
401 */
402 int
mbg_read_amcc_s5920(struct mbg_softc * sc,int cmd,char * buf,size_t len,struct timespec * tstamp)403 mbg_read_amcc_s5920(struct mbg_softc *sc, int cmd, char *buf, size_t len,
404 struct timespec *tstamp)
405 {
406 long timer, tmax;
407 size_t quot, rem;
408 u_int32_t ul;
409 int n;
410 u_int8_t status;
411
412 quot = len / 4;
413 rem = len % 4;
414
415 /* write the command, optionally taking a timestamp */
416 if (tstamp)
417 nanotime(tstamp);
418 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB, cmd);
419
420 /* wait for the BUSY flag to go low (approx 70 us on i386) */
421 timer = 0;
422 tmax = cold ? 50 : 10;
423 do {
424 if (cold)
425 delay(20);
426 else
427 tsleep_nsec(tstamp, 0, "mbg", MSEC_TO_NSEC(1));
428 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
429 AMCC_IMB4 + 3);
430 } while ((status & MBG_BUSY) && timer++ < tmax);
431
432 if (status & MBG_BUSY)
433 return -1;
434
435 /* read data from the device */
436 if (len) {
437 for (n = 0; n < quot; n++) {
438 *(u_int32_t *)buf = bus_space_read_4(sc->sc_iot_s5920,
439 sc->sc_ioh_s5920, AMCC_DATA);
440 buf += sizeof(u_int32_t);
441 }
442 if (rem) {
443 ul = bus_space_read_4(sc->sc_iot_s5920,
444 sc->sc_ioh_s5920, AMCC_DATA);
445 for (n = 0; n < rem; n++)
446 *buf++ = *((char *)&ul + n);
447 }
448 } else
449 bus_space_read_4(sc->sc_iot_s5920, sc->sc_ioh_s5920, AMCC_DATA);
450 return 0;
451 }
452
453 /*
454 * send a command and read back results to an AMCC S5933 based card
455 * (e.g. the PCI32 DCF77 radio clock)
456 */
457 int
mbg_read_amcc_s5933(struct mbg_softc * sc,int cmd,char * buf,size_t len,struct timespec * tstamp)458 mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len,
459 struct timespec *tstamp)
460 {
461 long timer, tmax;
462 size_t n;
463 u_int8_t status;
464
465 /* reset inbound mailbox and clear FIFO status */
466 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_MCSR + 3, 0x0c);
467
468 /* set FIFO */
469 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_INTCSR + 3, 0x3c);
470
471 /* write the command, optionally taking a timestamp */
472 if (tstamp)
473 nanotime(tstamp);
474 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB1, cmd);
475
476 /* wait for the BUSY flag to go low (approx 70 us on i386) */
477 timer = 0;
478 tmax = cold ? 50 : 10;
479 do {
480 if (cold)
481 delay(20);
482 else
483 tsleep_nsec(tstamp, 0, "mbg", MSEC_TO_NSEC(1));
484 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
485 AMCC_IMB4 + 3);
486 } while ((status & MBG_BUSY) && timer++ < tmax);
487
488 if (status & MBG_BUSY)
489 return -1;
490
491 /* read data from the device FIFO */
492 for (n = 0; n < len; n++) {
493 if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, AMCC_MCSR)
494 & 0x20) {
495 return -1;
496 }
497 buf[n] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
498 AMCC_FIFO + (n % 4));
499 }
500 return 0;
501 }
502
503 /*
504 * send a command and read back results to an ASIC based card
505 * (e.g. the PCI511 DCF77 radio clock)
506 */
507 int
mbg_read_asic(struct mbg_softc * sc,int cmd,char * buf,size_t len,struct timespec * tstamp)508 mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len,
509 struct timespec *tstamp)
510 {
511 long timer, tmax;
512 size_t n;
513 u_int32_t data;
514 u_int16_t port;
515 char *p = buf;
516 u_int8_t status;
517 int s;
518
519 /* write the command, optionally taking a timestamp */
520 if (tstamp) {
521 s = splhigh();
522 nanotime(tstamp);
523 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
524 splx(s);
525 } else
526 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd);
527
528 /* wait for the BUSY flag to go low */
529 timer = 0;
530 tmax = cold ? 50 : 10;
531 do {
532 if (cold)
533 delay(20);
534 else
535 tsleep_nsec(tstamp, 0, "mbg", MSEC_TO_NSEC(1));
536 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS);
537 } while ((status & MBG_BUSY) && timer++ < tmax);
538
539 if (status & MBG_BUSY)
540 return -1;
541
542 /* read data from the device FIFO */
543 port = ASIC_ADDON;
544 for (n = 0; n < len / 4; n++) {
545 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
546 *(u_int32_t *)p = data;
547 p += sizeof(data);
548 port += sizeof(data);
549 }
550
551 if (len % 4) {
552 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port);
553 for (n = 0; n < len % 4; n++) {
554 *p++ = data & 0xff;
555 data >>= 8;
556 }
557 }
558 return 0;
559 }
560
561 /*
562 * degrade the sensor state if we are freerunning for more than
563 * sc->sc_trust seconds.
564 */
565 void
mbg_timeout(void * xsc)566 mbg_timeout(void *xsc)
567 {
568 struct mbg_softc *sc = xsc;
569
570 if (sc->sc_timedelta.status == SENSOR_S_OK) {
571 sc->sc_timedelta.status = SENSOR_S_WARN;
572 /*
573 * further degrade in sc->sc_trust seconds if no new valid
574 * time data can be read from the device.
575 */
576 timeout_add_sec(&sc->sc_timeout, sc->sc_trust);
577 } else
578 sc->sc_timedelta.status = SENSOR_S_CRIT;
579 }
580