[LinuxPPS] [PATCH 1/1] pps: pps_parport pps-echo implementation
Tom Burkart
tom at aussec.com
Fri May 3 06:37:06 CEST 2019
This patch implements the pps echo functionality for pps_parport, that
sysfs claims is available already.
Configuration is via module parameters. Any one of the four control
lines may be used as the ECHO output.
Signed-off-by: Tom Burkart <tom at aussec.com>
---
drivers/pps/clients/pps_parport.c | 101 +++++++++++++++++++++++++++++++++++---
1 file changed, 93 insertions(+), 8 deletions(-)
diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
index 7226e39aae83..28f42e292901 100644
--- a/drivers/pps/clients/pps_parport.c
+++ b/drivers/pps/clients/pps_parport.c
@@ -20,11 +20,6 @@
*/
-/*
- * TODO:
- * implement echo over SEL pin
- */
-
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
@@ -35,6 +30,8 @@
#include <linux/slab.h>
#include <linux/parport.h>
#include <linux/pps_kernel.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#define DRVDESC "parallel port PPS client"
@@ -49,15 +46,33 @@ MODULE_PARM_DESC(clear_wait,
" zero turns clear edge capture off entirely");
module_param(clear_wait, uint, 0);
+static unsigned int echo_active_ms = 0;
+MODULE_PARM_DESC(echo_active_ms,
+ "Active part of the echo pulse in ms, zero to disable (default)");
+module_param(echo_active_ms, uint, 0);
+static unsigned int invert_pps_echo = 0;
+MODULE_PARM_DESC(invert_pps_echo,
+ "Invert the PPS echo pulse, zero no inversion");
+module_param(invert_pps_echo, uint, 0);
+static unsigned int echo_pin = 1;
+MODULE_PARM_DESC(echo_pin,
+ "Pin number of echo pin to use: "
+ "1: STROBE (default), 14: LINEFEED, 16: RESET, 17: SELECT");
+module_param(echo_pin, uint, 0);
+
static DEFINE_IDA(pps_client_index);
/* internal per port structure */
struct pps_client_pp {
struct pardevice *pardev; /* parport device */
struct pps_device *pps; /* PPS device */
+ struct timer_list echo_timer; /* timer for resetting echo active edge */
+ unsigned long echo_timeout; /* timer timeout value in jiffies */
unsigned int cw; /* port clear timeout */
unsigned int cw_err; /* number of timeouts */
int index; /* device number */
+ unsigned int invert_pps_echo; /* local copy of module parameters */
+ unsigned char echo_pin;
};
static inline int signal_is_set(struct parport *port)
@@ -123,19 +138,55 @@ static void parport_irq(void *handle)
out_assert:
/* fire assert event */
pps_event(dev->pps, &ts_assert,
- PPS_CAPTUREASSERT, NULL);
+ PPS_CAPTUREASSERT, handle);
return;
out_both:
/* fire assert event */
pps_event(dev->pps, &ts_assert,
- PPS_CAPTUREASSERT, NULL);
+ PPS_CAPTUREASSERT, handle);
/* fire clear event */
pps_event(dev->pps, &ts_clear,
- PPS_CAPTURECLEAR, NULL);
+ PPS_CAPTURECLEAR, handle);
return;
}
+/* echo function (only active if echo_active_ms is non-zero) */
+static void parport_echo(struct pps_device *pps, int event, void *handle)
+{
+ struct pps_client_pp *device = handle;
+ struct parport *port = device->pardev->port;
+
+ switch (event) {
+ case PPS_CAPTUREASSERT:
+ if (pps->params.mode & PPS_ECHOASSERT)
+ port->ops->write_control(port,
+ device->invert_pps_echo? device->echo_pin : 0);
+ break;
+
+ case PPS_CAPTURECLEAR:
+ if (pps->params.mode & PPS_ECHOCLEAR)
+ port->ops->write_control(port,
+ device->invert_pps_echo? device->echo_pin : 0);
+ break;
+ }
+ /* fire the timer */
+ if (pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) {
+ device->echo_timer.expires = jiffies + device->echo_timeout;
+ add_timer(&device->echo_timer);
+ }
+}
+
+/* Timer callback to reset the echo pin to the inactive state */
+static void parport_echo_timer_callback(struct timer_list *t)
+{
+ const struct pps_client_pp *device = from_timer(device, t, echo_timer);
+ struct parport *port = device->pardev->port;
+
+ port->ops->write_control(port,
+ device->invert_pps_echo? 0 : device->echo_pin);
+}
+
static void parport_attach(struct parport *port)
{
struct pardev_cb pps_client_cb;
@@ -158,6 +209,34 @@ static void parport_attach(struct parport *port)
return;
}
+ if (echo_active_ms > 999 ) {
+ pr_err("PPS ECHO active edge too long: %ums\n", echo_active_ms);
+ return;
+ }
+ if (echo_active_ms) {
+ switch (echo_pin) {
+ case 1:
+ device->echo_pin = PARPORT_CONTROL_STROBE;
+ break;
+ case 14:
+ device->echo_pin = PARPORT_CONTROL_AUTOFD;
+ break;
+ case 16:
+ device->echo_pin = PARPORT_CONTROL_INIT;
+ break;
+ case 17:
+ device->echo_pin = PARPORT_CONTROL_SELECT;
+ break;
+ default:
+ pr_err("Bad ECHO pin number: %u", echo_pin);
+ return;
+ }
+ device->invert_pps_echo = invert_pps_echo;
+ device->pps->info.echo = parport_echo;
+ device->echo_timeout = msecs_to_jiffies(echo_active_ms);
+ timer_setup(&device->echo_timer, parport_echo_timer_callback, 0);
+ }
+
index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
memset(&pps_client_cb, 0, sizeof(pps_client_cb));
pps_client_cb.private = device;
@@ -214,6 +293,12 @@ static void parport_detach(struct parport *port)
device = pardev->private;
+ if (device->pps->info.echo) {
+ del_timer_sync(&device->echo_timer);
+ /* reset echo pin in any case */
+ port->ops->write_control(port,
+ device->invert_pps_echo? 0 : device->echo_pin);
+ }
port->ops->disable_irq(port);
pps_unregister_source(device->pps);
parport_release(pardev);
--
2.12.3
More information about the discussions
mailing list