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