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