void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) { struct pps_event_time evt; switch (event->type) { case PTP_CLOCK_ALARM: break; case PTP_CLOCK_EXTTS: enqueue_external_timestamp(&ptp->tsevq, event); wake_up_interruptible(&ptp->tsev_wq); break; case PTP_CLOCK_PPS: pps_get_ts(&evt); pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT, NULL); break; case PTP_CLOCK_PPSUSR: pps_event(ptp->pps_source, &event->pps_times, PTP_PPS_EVENT, NULL); break; } }
static void xrpu_poll_pps(struct timecounter *tc) { struct softc *sc = tc->tc_priv; int i, j; unsigned count1, ppscount; for (i = 0; i < XRPU_MAX_PPS; i++) { if (sc->assert[i]) { ppscount = *(sc->assert[i]) & tc->tc_counter_mask; j = 0; do { count1 = ppscount; ppscount = *(sc->assert[i]) & tc->tc_counter_mask; } while (ppscount != count1 && ++j < 5); pps_event(&sc->pps[i], tc, ppscount, PPS_CAPTUREASSERT); } if (sc->clear[i]) { j = 0; ppscount = *(sc->clear[i]) & tc->tc_counter_mask; do { count1 = ppscount; ppscount = *(sc->clear[i]) & tc->tc_counter_mask; } while (ppscount != count1 && ++j < 5); pps_event(&sc->pps[i], tc, ppscount, PPS_CAPTURECLEAR); } } }
static void uart_pps_process(struct uart_softc *sc, int ser_sig) { sbintime_t now; int is_assert, pps_sig; /* Which signal is configured as PPS? Early out if none. */ switch(sc->sc_pps_mode & UART_PPS_SIGNAL_MASK) { case UART_PPS_CTS: pps_sig = SER_CTS; break; case UART_PPS_DCD: pps_sig = SER_DCD; break; default: return; } /* Early out if there is no change in the signal configured as PPS. */ if ((ser_sig & SER_DELTA(pps_sig)) == 0) return; /* * In narrow-pulse mode we need to synthesize both capture and clear * events from a single "delta occurred" indication from the uart * hardware because the pulse width is too narrow to reliably detect * both edges. However, when the pulse width is close to our interrupt * processing latency we might intermittantly catch both edges. To * guard against generating spurious events when that happens, we use a * separate timer to ensure at least half a second elapses before we * generate another event. */ pps_capture(&sc->sc_pps); if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE) { now = getsbinuptime(); if (now > sc->sc_pps_captime + 500 * SBT_1MS) { sc->sc_pps_captime = now; pps_event(&sc->sc_pps, PPS_CAPTUREASSERT); pps_event(&sc->sc_pps, PPS_CAPTURECLEAR); } } else { is_assert = ser_sig & pps_sig; if (sc->sc_pps_mode & UART_PPS_INVERT_PULSE) is_assert = !is_assert; pps_event(&sc->sc_pps, is_assert ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); } }
void ucom_status_change(struct ucom_softc *sc) { struct tty *tp = sc->sc_tty; u_char old_msr; if (sc->sc_methods->ucom_get_status != NULL) { old_msr = sc->sc_msr; sc->sc_methods->ucom_get_status(sc->sc_parent, sc->sc_portno, &sc->sc_lsr, &sc->sc_msr); if (ISSET((sc->sc_msr ^ old_msr), UMSR_DCD)) { mutex_spin_enter(&timecounter_lock); pps_capture(&sc->sc_pps_state); pps_event(&sc->sc_pps_state, (sc->sc_msr & UMSR_DCD) ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); mutex_spin_exit(&timecounter_lock); (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msr, UMSR_DCD)); } } else { sc->sc_lsr = 0; /* Assume DCD is present, if we have no chance to check it. */ sc->sc_msr = UMSR_DCD; } }
static void elan_poll_pps(struct timecounter *tc) { static int state; int i; uint16_t u, x, y, z; register_t saveintr; /* * Grab the HW state as quickly and compactly as we can. Disable * interrupts to avoid measuring our interrupt service time on * hw with quality clock sources. */ saveintr = intr_disable(); x = *pps_ap[0]; /* state, must be first, see below */ y = *pps_ap[1]; /* timer2 */ z = *pps_ap[2]; /* timer1 */ intr_restore(saveintr); /* * Order is important here. We need to check the state of the GPIO * pin first, in order to avoid reading timer 1 right before the * state change. Technically pps_a may be zero in which case we * harmlessly read the REVID register and the contents of pps_d is * of no concern. */ i = x & pps_d; /* If state did not change or we don't have a GPIO pin, return */ if (i == state || pps_a == 0) return; state = i; /* If the state is "low", flip the echo GPIO and return. */ if (!i) { if (echo_a) mmcrptr[(echo_a ^ 0xc) / 2] = echo_d; return; } /* * Subtract timer1 from timer2 to compensate for time from the * edge until we read the counters. */ u = y - z; pps_capture(&elan_pps); elan_pps.capcount = u; pps_event(&elan_pps, PPS_CAPTUREASSERT); /* Twiddle echo bit */ if (echo_a) mmcrptr[echo_a / 2] = echo_d; }
static void pps_ktimer_event(unsigned long ptr) { struct pps_event_time ts; /* */ pps_get_ts(&ts); pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); }
static irqreturn_t pps_gpio_irq_handler(int irq, void *data) { const struct pps_gpio_device_data *info; struct pps_event_time ts; int rising_edge; /* Get the time stamp first */ pps_get_ts(&ts); info = data; rising_edge = gpio_get_value(info->pdata->gpio_pin); if ((rising_edge && !info->pdata->assert_falling_edge) || (!rising_edge && info->pdata->assert_falling_edge)) pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL); else if (info->pdata->capture_clear && ((rising_edge && info->pdata->assert_falling_edge) || (!rising_edge && !info->pdata->assert_falling_edge))) pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL); return IRQ_HANDLED; }
static void pps_ktimer_event(unsigned long ptr) { struct pps_event_time ts; /* First of all we get the time stamp... */ pps_get_ts(&ts); dev_info(pps->dev, "PPS event at %lu\n", jiffies); pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); }
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, struct pps_event_time *ts) { struct pps_device *pps = (struct pps_device *)tty->disc_data; BUG_ON(pps == NULL); /* Now do the PPS event report */ pps_event(pps, ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR, NULL); dev_dbg(pps->dev, "PPS %s at %lu\n", status ? "assert" : "clear", jiffies); }
static void am335x_dmtimer_process_pps_event(void *arg, int pending) { struct am335x_dmtimer_softc *sc; sc = arg; /* This is the task function that gets enqueued by poll_pps. Once the * time has been captured in the hw interrupt context, the remaining * (more expensive) work to process the event is done later in a * non-fast-interrupt context. * * We only support capture of the rising or falling edge, not both at * once; tell the kernel to process whichever mode is currently active. */ pps_event(&sc->pps, sc->pps.ppsparam.mode & PPS_CAPTUREBOTH); }
static void pps_ktimer_event(unsigned long ptr) { struct timespec __ts; struct pps_ktime ts; /* First of all we get the time stamp... */ getnstimeofday(&__ts); pr_info("PPS event at %lu\n", jiffies); /* ... and translate it to PPS time data struct */ ts.sec = __ts.tv_sec; ts.nsec = __ts.tv_nsec; pps_event(source, &ts, PPS_CAPTUREASSERT, NULL); mod_timer(&ktimer, jiffies + HZ); }
static void ucom_cfg_status_change(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; struct tty *tp; uint8_t new_msr; uint8_t new_lsr; uint8_t msr_delta; uint8_t lsr_delta; tp = sc->sc_tty; UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { return; } if (sc->sc_callback->ucom_cfg_get_status == NULL) { return; } /* get status */ new_msr = 0; new_lsr = 0; (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { /* TTY device closed */ return; } msr_delta = (sc->sc_msr ^ new_msr); lsr_delta = (sc->sc_lsr ^ new_lsr); sc->sc_msr = new_msr; sc->sc_lsr = new_lsr; /* * Time pulse counting support. Note that both CTS and DCD are * active-low signals. The status bit is high to indicate that * the signal on the line is low, which corresponds to a PPS * clear event. */ switch(ucom_pps_mode) { case 1: if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) && (msr_delta & SER_CTS)) { pps_capture(&sc->sc_pps); pps_event(&sc->sc_pps, (sc->sc_msr & SER_CTS) ? PPS_CAPTURECLEAR : PPS_CAPTUREASSERT); } break; case 2: if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) && (msr_delta & SER_DCD)) { pps_capture(&sc->sc_pps); pps_event(&sc->sc_pps, (sc->sc_msr & SER_DCD) ? PPS_CAPTURECLEAR : PPS_CAPTUREASSERT); } break; default: break; } if (msr_delta & SER_DCD) { int onoff = (sc->sc_msr & SER_DCD) ? 1 : 0; DPRINTF("DCD changed to %d\n", onoff); ttydisc_modem(tp, onoff); } if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) { DPRINTF("BREAK detected\n"); ttydisc_rint(tp, 0, TRE_BREAK); ttydisc_rint_done(tp); } if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) { DPRINTF("Frame error detected\n"); ttydisc_rint(tp, 0, TRE_FRAMING); ttydisc_rint_done(tp); } if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) { DPRINTF("Parity error detected\n"); ttydisc_rint(tp, 0, TRE_PARITY); ttydisc_rint_done(tp); } }
static void ucom_cfg_status_change(struct usb_proc_msg *_task) { struct ucom_cfg_task *task = (struct ucom_cfg_task *)_task; struct ucom_softc *sc = task->sc; struct tty *tp; int onoff; uint8_t new_msr; uint8_t new_lsr; uint8_t msr_delta; uint8_t lsr_delta; uint8_t pps_signal; tp = sc->sc_tty; UCOM_MTX_ASSERT(sc, MA_OWNED); if (!(sc->sc_flag & UCOM_FLAG_LL_READY)) { return; } if (sc->sc_callback->ucom_cfg_get_status == NULL) { return; } /* get status */ new_msr = 0; new_lsr = 0; (sc->sc_callback->ucom_cfg_get_status) (sc, &new_lsr, &new_msr); if (!(sc->sc_flag & UCOM_FLAG_HL_READY)) { /* TTY device closed */ return; } msr_delta = (sc->sc_msr ^ new_msr); lsr_delta = (sc->sc_lsr ^ new_lsr); sc->sc_msr = new_msr; sc->sc_lsr = new_lsr; /* * Time pulse counting support. */ switch(ucom_pps_mode & UART_PPS_SIGNAL_MASK) { case UART_PPS_CTS: pps_signal = SER_CTS; break; case UART_PPS_DCD: pps_signal = SER_DCD; break; default: pps_signal = 0; break; } if ((sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) && (msr_delta & pps_signal)) { pps_capture(&sc->sc_pps); onoff = (sc->sc_msr & pps_signal) ? 1 : 0; if (ucom_pps_mode & UART_PPS_INVERT_PULSE) onoff = !onoff; pps_event(&sc->sc_pps, onoff ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR); } if (msr_delta & SER_DCD) { onoff = (sc->sc_msr & SER_DCD) ? 1 : 0; DPRINTF("DCD changed to %d\n", onoff); ttydisc_modem(tp, onoff); } if ((lsr_delta & ULSR_BI) && (sc->sc_lsr & ULSR_BI)) { DPRINTF("BREAK detected\n"); ttydisc_rint(tp, 0, TRE_BREAK); ttydisc_rint_done(tp); } if ((lsr_delta & ULSR_FE) && (sc->sc_lsr & ULSR_FE)) { DPRINTF("Frame error detected\n"); ttydisc_rint(tp, 0, TRE_FRAMING); ttydisc_rint_done(tp); } if ((lsr_delta & ULSR_PE) && (sc->sc_lsr & ULSR_PE)) { DPRINTF("Parity error detected\n"); ttydisc_rint(tp, 0, TRE_PARITY); ttydisc_rint_done(tp); } }