xref: /openbsd-src/sys/dev/gpio/gpiodcf.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: gpiodcf.c,v 1.1 2008/11/28 17:42:43 mbalmer Exp $ */
2 
3 /*
4  * Copyright (c) 2008 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/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/conf.h>
23 #include <sys/file.h>
24 #include <sys/select.h>
25 #include <sys/proc.h>
26 #include <sys/vnode.h>
27 #include <sys/device.h>
28 #include <sys/poll.h>
29 #include <sys/time.h>
30 #include <sys/sensors.h>
31 #include <sys/gpio.h>
32 
33 #include <dev/gpio/gpiovar.h>
34 
35 #ifdef GPIODCF_DEBUG
36 #define DPRINTFN(n, x)	do { if (gpiodcfdebug > (n)) printf x; } while (0)
37 int gpiodcfdebug = 0;
38 #else
39 #define DPRINTFN(n, x)
40 #endif
41 #define DPRINTF(x)	DPRINTFN(0, x)
42 
43 #define DPERIOD1	((long) 5 * 60)		/* degrade OK -> WARN */
44 #define DPERIOD2	((long) 15 * 60)	/* degrade WARN -> CRIT */
45 
46 /* max. skew of received time diff vs. measured time diff in percent. */
47 #define MAX_SKEW	5
48 
49 #define CLOCK_DCF77	0
50 #define CLOCK_HBG	1
51 
52 #define GPIODCF_NPINS		1
53 #define	GPIODCF_PIN_DATA	0
54 
55 static const char	*clockname[2] = {
56 	"DCF77",
57 	"HBG" };
58 
59 struct gpiodcf_softc {
60 	struct device		sc_dev;		/* base device */
61 	void			*sc_gpio;
62 	struct gpio_pinmap	sc_map;
63 	int			__map[GPIODCF_NPINS];
64 	u_char			sc_dying;	/* disconnecting */
65 	int			sc_data;
66 
67 	struct timeout		sc_to;
68 
69 	struct timeout		sc_bv_to;	/* bit-value detect */
70 	struct timeout		sc_db_to;	/* debounce */
71 	struct timeout		sc_mg_to;	/* minute-gap detect */
72 	struct timeout		sc_sl_to;	/* signal-loss detect */
73 	struct timeout		sc_it_to;	/* invalidate time */
74 	struct timeout		sc_ct_to;	/* detect clock type */
75 
76 	int			sc_detect_ct;	/* != 0: autodetect type */
77 	int			sc_clocktype;	/* DCF77 or HBG */
78 	int			sc_sync;	/* 1 during sync */
79 	u_int64_t		sc_mask;	/* 64 bit mask */
80 	u_int64_t		sc_tbits;	/* Time bits */
81 	int			sc_minute;
82 	int			sc_level;
83 	time_t			sc_last_mg;
84 	time_t			sc_current;	/* current time */
85 	time_t			sc_next;	/* time to become valid next */
86 	time_t			sc_last;
87 	int			sc_nrecv;	/* consecutive valid times */
88 	struct timeval		sc_last_tv;	/* uptime of last valid time */
89 	struct ksensor		sc_sensor;
90 #ifdef GPIODCF_DEBUG
91 	struct ksensor		sc_skew;	/* recv vs local skew */
92 #endif
93 	struct ksensordev	sc_sensordev;
94 };
95 
96 /*
97  * timeouts being used in hz:
98  * t_bv		bit value detection (150ms)
99  * t_ct		detect clocktype (250ms)
100  * t_sync	sync (950ms)
101  * t_mg		minute gap detection (1500ms)
102  * t_mgsync	resync after a minute gap (450ms)
103  * t_sl		detect signal loss (3sec)
104  * t_wait	wait (5sec)
105  * t_warn	degrade sensor status to warning (5min)
106  * t_crit	degrade sensor status to critical (15min)
107  */
108 static int t_bv, t_ct, t_sync, t_mg, t_sl, t_mgsync, t_wait, t_warn, t_crit;
109 
110 void	gpiodcf_intr(void *);
111 void	gpiodcf_probe(void *);
112 void	gpiodcf_bv_probe(void *);
113 void	gpiodcf_mg_probe(void *);
114 void	gpiodcf_sl_probe(void *);
115 void	gpiodcf_ct_probe(void *);
116 void	gpiodcf_invalidate(void *);
117 
118 int gpiodcf_match(struct device *, void *, void *);
119 void gpiodcf_attach(struct device *, struct device *, void *);
120 int gpiodcf_detach(struct device *, int);
121 int gpiodcf_activate(struct device *, enum devact);
122 
123 int gpiodcf_signal(struct gpiodcf_softc *);
124 
125 struct cfdriver gpiodcf_cd = {
126 	NULL, "gpiodcf", DV_DULL
127 };
128 
129 const struct cfattach gpiodcf_ca = {
130 	sizeof(struct gpiodcf_softc),
131 	gpiodcf_match,
132 	gpiodcf_attach,
133 	gpiodcf_detach,
134 	gpiodcf_activate
135 };
136 
137 int
138 gpiodcf_match(struct device *parent, void *match, void *aux)
139 {
140 	struct cfdata *cf = match;
141 	struct gpio_attach_args *ga = aux;
142 
143 	if (ga->ga_offset == -1)
144 		return 0;
145 
146 	return (strcmp(cf->cf_driver->cd_name, "gpiodcf") == 0);
147 }
148 
149 void
150 gpiodcf_attach(struct device *parent, struct device *self, void *aux)
151 {
152 	struct gpiodcf_softc		*sc = (struct gpiodcf_softc *)self;
153 	struct gpio_attach_args		*ga = aux;
154 	struct timeval			 t;
155 	int				 caps;
156 
157 	if (gpio_npins(ga->ga_mask) != GPIODCF_NPINS) {
158 		printf(": invalid pin mask\n");
159 		return;
160 	}
161 	sc->sc_gpio = ga->ga_gpio;
162 	sc->sc_map.pm_map = sc->__map;
163 	if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
164 	    &sc->sc_map)) {
165 		printf(": can't map pins\n");
166 		return;
167 	}
168 
169 	caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA);
170 	if (!(caps & GPIO_PIN_INPUT)) {
171 		printf(": data pin is unable to receive input\n");
172 		goto fishy;
173 	}
174 	printf(": DATA[%d]", sc->sc_map.pm_map[GPIODCF_PIN_DATA]);
175 	sc->sc_data = GPIO_PIN_INPUT;
176 	gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA, sc->sc_data);
177 	printf("\n");
178 
179 	sc->sc_detect_ct = 1;
180 	strlcpy(sc->sc_sensor.desc, "Unknown",
181 	    sizeof(sc->sc_sensor.desc));
182 
183 	timeout_set(&sc->sc_to, gpiodcf_probe, sc);
184 	timeout_set(&sc->sc_bv_to, gpiodcf_bv_probe, sc);
185 	timeout_set(&sc->sc_mg_to, gpiodcf_mg_probe, sc);
186 	timeout_set(&sc->sc_sl_to, gpiodcf_sl_probe, sc);
187 	timeout_set(&sc->sc_it_to, gpiodcf_invalidate, sc);
188 	timeout_set(&sc->sc_ct_to, gpiodcf_ct_probe, sc);
189 
190 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
191 	    sizeof(sc->sc_sensordev.xname));
192 
193 	sc->sc_sensor.type = SENSOR_TIMEDELTA;
194 	sc->sc_sensor.status = SENSOR_S_UNKNOWN;
195 	sc->sc_sensor.value = 0LL;
196 	sc->sc_sensor.flags = 0;
197 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
198 
199 #ifdef GPIODCF_DEBUG
200 	sc->sc_skew.type = SENSOR_TIMEDELTA;
201 	sc->sc_skew.status = SENSOR_S_UNKNOWN;
202 	sc->sc_skew.value = 0LL;
203 	sc->sc_skew.flags = 0;
204 	strlcpy(sc->sc_skew.desc, "local clock skew",
205 	    sizeof(sc->sc_skew.desc));
206 	sensor_attach(&sc->sc_sensordev, &sc->sc_skew);
207 #endif
208 	sensordev_install(&sc->sc_sensordev);
209 
210 	sc->sc_clocktype = -1;
211 	sc->sc_level = 0;
212 	sc->sc_minute = 0;
213 	sc->sc_last_mg = 0L;
214 
215 	sc->sc_sync = 1;
216 
217 	sc->sc_current = 0L;
218 	sc->sc_next = 0L;
219 	sc->sc_nrecv = 0;
220 	sc->sc_last = 0L;
221 	sc->sc_last_tv.tv_sec = 0L;
222 
223 	/* convert timevals to hz */
224 	t.tv_sec = 0L;
225 	t.tv_usec = 150000L;
226 	t_bv = tvtohz(&t);
227 
228 	t.tv_usec = 450000L;
229 	t_mgsync = tvtohz(&t);
230 
231 	t.tv_usec = 950000L;
232 	t_sync = tvtohz(&t);
233 
234 	t.tv_sec = 1L;
235 	t.tv_usec = 500000L;
236 	t_mg = tvtohz(&t);
237 
238 	t.tv_sec = 3L;
239 	t.tv_usec = 0L;
240 	t_sl = tvtohz(&t);
241 
242 	t.tv_sec = 5L;
243 	t_wait = tvtohz(&t);
244 
245 	t.tv_sec = DPERIOD1;
246 	t_warn = tvtohz(&t);
247 
248 	t.tv_sec = DPERIOD2;
249 	t_crit = tvtohz(&t);
250 
251 	if (sc->sc_detect_ct) {
252 		t.tv_sec = 0L;
253 		t.tv_usec = 250000L;
254 		t_ct = tvtohz(&t);
255 	}
256 
257 	/* Give the receiver some slack to stabilize */
258 	timeout_add(&sc->sc_to, t_wait);
259 
260 	/* Detect signal loss */
261 	timeout_add(&sc->sc_sl_to, t_wait + t_sl);
262 
263 	DPRINTF(("synchronizing\n"));
264 	return;
265 
266 fishy:
267 	DPRINTF(("gpiodcf_attach failed\n"));
268 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
269 	sc->sc_dying = 1;
270 }
271 
272 int
273 gpiodcf_detach(struct device *self, int flags)
274 {
275 	struct gpiodcf_softc	*sc = (struct gpiodcf_softc *)self;
276 
277 	sc->sc_dying = 1;
278 
279 	timeout_del(&sc->sc_to);
280 	timeout_del(&sc->sc_bv_to);
281 	timeout_del(&sc->sc_mg_to);
282 	timeout_del(&sc->sc_sl_to);
283 	timeout_del(&sc->sc_it_to);
284 	timeout_del(&sc->sc_ct_to);
285 
286 	/* Unregister the clock with the kernel */
287 	sensordev_deinstall(&sc->sc_sensordev);
288 
289 	/* Finally unmap the GPIO pin */
290 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
291 
292 	return 0;
293 }
294 
295 /*
296  * return 1 during high-power-, 0 during low-power-emission
297  * If bit 0 is set, the transmitter emits at full power.
298  * During the low-power emission we decode a zero bit.
299  */
300 int
301 gpiodcf_signal(struct gpiodcf_softc *sc)
302 {
303 	return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIODCF_PIN_DATA) ==
304 	    GPIO_PIN_HIGH ? 1 : 0);
305 }
306 
307 /* gpiodcf_probe runs in a process context. */
308 void
309 gpiodcf_probe(void *xsc)
310 {
311 	struct gpiodcf_softc	*sc = xsc;
312 	struct timespec		 now;
313 	int			 data;
314 
315 	if (sc->sc_dying)
316 		return;
317 
318 	data = gpiodcf_signal(sc);
319 	if (data == -1)
320 		return;
321 
322 	if (data) {
323 		sc->sc_level = 1;
324 		timeout_add(&sc->sc_to, 1);
325 		return;
326 	}
327 
328 	if (sc->sc_level == 0)
329 		return;
330 
331 	/* the beginning of a second */
332 	sc->sc_level = 0;
333 	if (sc->sc_minute == 1) {
334 		if (sc->sc_sync) {
335 			DPRINTF(("start collecting bits\n"));
336 			sc->sc_sync = 0;
337 			if (sc->sc_sensor.status == SENSOR_S_UNKNOWN &&
338 			    sc->sc_detect_ct)
339 				sc->sc_clocktype = -1;
340 		} else {
341 			/* provide the timedelta */
342 			microtime(&sc->sc_sensor.tv);
343 			nanotime(&now);
344 			sc->sc_current = sc->sc_next;
345 			sc->sc_sensor.value = (int64_t)(now.tv_sec -
346 			    sc->sc_current) * 1000000000LL + now.tv_nsec;
347 
348 			/* set the clocktype and make sensor valid */
349 			if (sc->sc_sensor.status == SENSOR_S_UNKNOWN &&
350 			    sc->sc_detect_ct) {
351 				strlcpy(sc->sc_sensor.desc, sc->sc_clocktype ?
352 				    clockname[CLOCK_HBG] :
353 				    clockname[CLOCK_DCF77],
354 				    sizeof(sc->sc_sensor.desc));
355 			}
356 			sc->sc_sensor.status = SENSOR_S_OK;
357 
358 			/*
359 			 * if no valid time information is received
360 			 * during the next 5 minutes, the sensor state
361 			 * will be degraded to SENSOR_S_WARN
362 			 */
363 			timeout_add(&sc->sc_it_to, t_warn);
364 		}
365 		sc->sc_minute = 0;
366 	}
367 
368 	timeout_add(&sc->sc_to, t_sync);	/* resync in 950 ms */
369 
370 	/* no clock and bit detection during sync */
371 	if (!sc->sc_sync) {
372 		/* detect bit value */
373 		timeout_add(&sc->sc_bv_to, t_bv);
374 
375 		/* detect clocktype */
376 		if (sc->sc_detect_ct && sc->sc_clocktype == -1)
377 			timeout_add(&sc->sc_ct_to, t_ct);
378 	}
379 	timeout_add(&sc->sc_mg_to, t_mg);	/* detect minute gap */
380 	timeout_add(&sc->sc_sl_to, t_sl);	/* detect signal loss */
381 }
382 
383 /* detect the bit value */
384 void
385 gpiodcf_bv_probe(void *xsc)
386 {
387 	struct gpiodcf_softc	*sc = xsc;
388 	int			 data;
389 
390 	if (sc->sc_dying)
391 		return;
392 
393 	data = gpiodcf_signal(sc);
394 	if (data == -1) {
395 		DPRINTF(("bit detection failed\n"));
396 		return;
397 	}
398 
399 	DPRINTFN(1, (data ? "0" : "1"));
400 	if (!(data))
401 		sc->sc_tbits |= sc->sc_mask;
402 	sc->sc_mask <<= 1;
403 }
404 
405 /* detect the minute gap */
406 void
407 gpiodcf_mg_probe(void *xsc)
408 {
409 	struct gpiodcf_softc	*sc = xsc;
410 	struct clock_ymdhms	 ymdhm;
411 	struct timeval		 monotime;
412 	int			 tdiff_recv, tdiff_local;
413 	int			 skew;
414 	int			 minute_bits, hour_bits, day_bits;
415 	int			 month_bits, year_bits, wday;
416 	int			 p1, p2, p3;
417 	int			 p1_bit, p2_bit, p3_bit;
418 	int			 r_bit, a1_bit, a2_bit, z1_bit, z2_bit;
419 	int			 s_bit, m_bit;
420 	u_int32_t		 parity = 0x6996;
421 
422 	if (sc->sc_sync) {
423 		sc->sc_minute = 1;
424 		goto cleanbits;
425 	}
426 
427 	if (time_second - sc->sc_last_mg < 57) {
428 		DPRINTF(("\nunexpected gap, resync\n"));
429 		sc->sc_sync = sc->sc_minute = 1;
430 		goto cleanbits;
431 	}
432 
433 	/* extract bits w/o parity */
434 	m_bit = sc->sc_tbits & 1;
435 	r_bit = sc->sc_tbits >> 15 & 1;
436 	a1_bit = sc->sc_tbits >> 16 & 1;
437 	z1_bit = sc->sc_tbits >> 17 & 1;
438 	z2_bit = sc->sc_tbits >> 18 & 1;
439 	a2_bit = sc->sc_tbits >> 19 & 1;
440 	s_bit = sc->sc_tbits >> 20 & 1;
441 	p1_bit = sc->sc_tbits >> 28 & 1;
442 	p2_bit = sc->sc_tbits >> 35 & 1;
443 	p3_bit = sc->sc_tbits >> 58 & 1;
444 
445 	minute_bits = sc->sc_tbits >> 21 & 0x7f;
446 	hour_bits = sc->sc_tbits >> 29 & 0x3f;
447 	day_bits = sc->sc_tbits >> 36 & 0x3f;
448 	wday = (sc->sc_tbits >> 42) & 0x07;
449 	month_bits = sc->sc_tbits >> 45 & 0x1f;
450 	year_bits = sc->sc_tbits >> 50 & 0xff;
451 
452 	/* validate time information */
453 	p1 = (parity >> (minute_bits & 0x0f) & 1) ^
454 	    (parity >> (minute_bits >> 4) & 1);
455 
456 	p2 = (parity >> (hour_bits & 0x0f) & 1) ^
457 	    (parity >> (hour_bits >> 4) & 1);
458 
459 	p3 = (parity >> (day_bits & 0x0f) & 1) ^
460 	    (parity >> (day_bits >> 4) & 1) ^
461 	    ((parity >> wday) & 1) ^ (parity >> (month_bits & 0x0f) & 1) ^
462 	    (parity >> (month_bits >> 4) & 1) ^
463 	    (parity >> (year_bits & 0x0f) & 1) ^
464 	    (parity >> (year_bits >> 4) & 1);
465 
466 	if (m_bit == 0 && s_bit == 1 && p1 == p1_bit && p2 == p2_bit &&
467 	    p3 == p3_bit && (z1_bit ^ z2_bit)) {
468 
469 		/* Decode time */
470 		if ((ymdhm.dt_year = 2000 + FROMBCD(year_bits)) > 2037) {
471 			DPRINTF(("year out of range, resync\n"));
472 			sc->sc_sync = 1;
473 			goto cleanbits;
474 		}
475 		ymdhm.dt_min = FROMBCD(minute_bits);
476 		ymdhm.dt_hour = FROMBCD(hour_bits);
477 		ymdhm.dt_day = FROMBCD(day_bits);
478 		ymdhm.dt_mon = FROMBCD(month_bits);
479 		ymdhm.dt_sec = 0;
480 
481 		sc->sc_next = clock_ymdhms_to_secs(&ymdhm);
482 		getmicrouptime(&monotime);
483 
484 		/* convert to coordinated universal time */
485 		sc->sc_next -= z1_bit ? 7200 : 3600;
486 
487 		DPRINTF(("\n%02d.%02d.%04d %02d:%02d:00 %s",
488 		    ymdhm.dt_day, ymdhm.dt_mon, ymdhm.dt_year,
489 		    ymdhm.dt_hour, ymdhm.dt_min, z1_bit ? "CEST" : "CET"));
490 		DPRINTF((r_bit ? ", call bit" : ""));
491 		DPRINTF((a1_bit ? ", dst chg ann." : ""));
492 		DPRINTF((a2_bit ? ", leap sec ann." : ""));
493 		DPRINTF(("\n"));
494 
495 		if (sc->sc_last) {
496 			tdiff_recv = sc->sc_next - sc->sc_last;
497 			tdiff_local = monotime.tv_sec - sc->sc_last_tv.tv_sec;
498 			skew = abs(tdiff_local - tdiff_recv);
499 #ifdef GPIODCF_DEBUG
500 			if (sc->sc_skew.status == SENSOR_S_UNKNOWN)
501 				sc->sc_skew.status = SENSOR_S_CRIT;
502 			sc->sc_skew.value = skew * 1000000000LL;
503 			getmicrotime(&sc->sc_skew.tv);
504 #endif
505 			DPRINTF(("local = %d, recv = %d, skew = %d\n",
506 			    tdiff_local, tdiff_recv, skew));
507 
508 			if (skew && skew * 100LL / tdiff_local > MAX_SKEW) {
509 				DPRINTF(("skew out of tolerated range\n"));
510 				goto cleanbits;
511 			} else {
512 				if (sc->sc_nrecv < 2) {
513 					sc->sc_nrecv++;
514 					DPRINTF(("got frame %d\n",
515 					    sc->sc_nrecv));
516 				} else {
517 					DPRINTF(("data is valid\n"));
518 					sc->sc_minute = 1;
519 				}
520 			}
521 		} else {
522 			DPRINTF(("received the first frame\n"));
523 			sc->sc_nrecv = 1;
524 		}
525 
526 		/* record the time received and when it was received */
527 		sc->sc_last = sc->sc_next;
528 		sc->sc_last_tv.tv_sec = monotime.tv_sec;
529 	} else {
530 		DPRINTF(("\nparity error, resync\n"));
531 		sc->sc_sync = sc->sc_minute = 1;
532 	}
533 
534 cleanbits:
535 	timeout_add(&sc->sc_to, t_mgsync);	/* re-sync in 450 ms */
536 	sc->sc_last_mg = time_second;
537 	sc->sc_tbits = 0LL;
538 	sc->sc_mask = 1LL;
539 }
540 
541 /* detect signal loss */
542 void
543 gpiodcf_sl_probe(void *xsc)
544 {
545 	struct gpiodcf_softc *sc = xsc;
546 
547 	if (sc->sc_dying)
548 		return;
549 
550 	DPRINTF(("no signal\n"));
551 	sc->sc_sync = 1;
552 	timeout_add(&sc->sc_to, t_wait);
553 	timeout_add(&sc->sc_sl_to, t_wait + t_sl);
554 }
555 
556 /* invalidate timedelta (called in an interrupt context) */
557 void
558 gpiodcf_invalidate(void *xsc)
559 {
560 	struct gpiodcf_softc *sc = xsc;
561 
562 	if (sc->sc_dying)
563 		return;
564 
565 	if (sc->sc_sensor.status == SENSOR_S_OK) {
566 		sc->sc_sensor.status = SENSOR_S_WARN;
567 		/*
568 		 * further degrade in 15 minutes if we dont receive any new
569 		 * time information
570 		 */
571 		timeout_add(&sc->sc_it_to, t_crit);
572 	} else {
573 		sc->sc_sensor.status = SENSOR_S_CRIT;
574 		sc->sc_nrecv = 0;
575 	}
576 }
577 
578 /* detect clock type.  used for older devices only. */
579 void
580 gpiodcf_ct_probe(void *xsc)
581 {
582 	struct gpiodcf_softc	*sc = xsc;
583 	int			 data;
584 
585 	if (sc->sc_dying)
586 		return;
587 
588 	data = gpiodcf_signal(sc);
589 	if (data == -1) {
590 		DPRINTF(("clocktype detection failed\n"));
591 		return;
592 	}
593 
594 	sc->sc_clocktype = data ? 0 : 1;
595 	DPRINTF(("\nclocktype is %s\n", sc->sc_clocktype ?
596 		clockname[CLOCK_HBG] : clockname[CLOCK_DCF77]));
597 }
598 
599 int
600 gpiodcf_activate(struct device *self, enum devact act)
601 {
602 	struct gpiodcf_softc *sc = (struct gpiodcf_softc *)self;
603 
604 	switch (act) {
605 	case DVACT_ACTIVATE:
606 		break;
607 	case DVACT_DEACTIVATE:
608 		sc->sc_dying = 1;
609 		break;
610 	}
611 	return 0;
612 }
613