linux/drivers/pps/clients/pps_parport.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * pps_parport.c -- kernel parallel port PPS client
   4 *
   5 * Copyright (C) 2009   Alexander Gordeev <lasaine@lvk.cs.msu.su>
   6 */
   7
   8
   9/*
  10 * TODO:
  11 * implement echo over SEL pin
  12 */
  13
  14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/init.h>
  19#include <linux/irqnr.h>
  20#include <linux/time.h>
  21#include <linux/slab.h>
  22#include <linux/parport.h>
  23#include <linux/pps_kernel.h>
  24
  25/* module parameters */
  26
  27#define CLEAR_WAIT_MAX          100
  28#define CLEAR_WAIT_MAX_ERRORS   5
  29
  30static unsigned int clear_wait = 100;
  31MODULE_PARM_DESC(clear_wait,
  32        "Maximum number of port reads when polling for signal clear,"
  33        " zero turns clear edge capture off entirely");
  34module_param(clear_wait, uint, 0);
  35
  36static DEFINE_IDA(pps_client_index);
  37
  38/* internal per port structure */
  39struct pps_client_pp {
  40        struct pardevice *pardev;       /* parport device */
  41        struct pps_device *pps;         /* PPS device */
  42        unsigned int cw;                /* port clear timeout */
  43        unsigned int cw_err;            /* number of timeouts */
  44        int index;                      /* device number */
  45};
  46
  47static inline int signal_is_set(struct parport *port)
  48{
  49        return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0;
  50}
  51
  52/* parport interrupt handler */
  53static void parport_irq(void *handle)
  54{
  55        struct pps_event_time ts_assert, ts_clear;
  56        struct pps_client_pp *dev = handle;
  57        struct parport *port = dev->pardev->port;
  58        unsigned int i;
  59        unsigned long flags;
  60
  61        /* first of all we get the time stamp... */
  62        pps_get_ts(&ts_assert);
  63
  64        if (dev->cw == 0)
  65                /* clear edge capture disabled */
  66                goto out_assert;
  67
  68        /* try capture the clear edge */
  69
  70        /* We have to disable interrupts here. The idea is to prevent
  71         * other interrupts on the same processor to introduce random
  72         * lags while polling the port. Reading from IO port is known
  73         * to take approximately 1us while other interrupt handlers can
  74         * take much more potentially.
  75         *
  76         * Interrupts won't be disabled for a long time because the
  77         * number of polls is limited by clear_wait parameter which is
  78         * kept rather low. So it should never be an issue.
  79         */
  80        local_irq_save(flags);
  81        /* check the signal (no signal means the pulse is lost this time) */
  82        if (!signal_is_set(port)) {
  83                local_irq_restore(flags);
  84                dev_err(dev->pps->dev, "lost the signal\n");
  85                goto out_assert;
  86        }
  87
  88        /* poll the port until the signal is unset */
  89        for (i = dev->cw; i; i--)
  90                if (!signal_is_set(port)) {
  91                        pps_get_ts(&ts_clear);
  92                        local_irq_restore(flags);
  93                        dev->cw_err = 0;
  94                        goto out_both;
  95                }
  96        local_irq_restore(flags);
  97
  98        /* timeout */
  99        dev->cw_err++;
 100        if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
 101                dev_err(dev->pps->dev, "disabled clear edge capture after %d"
 102                                " timeouts\n", dev->cw_err);
 103                dev->cw = 0;
 104                dev->cw_err = 0;
 105        }
 106
 107out_assert:
 108        /* fire assert event */
 109        pps_event(dev->pps, &ts_assert,
 110                        PPS_CAPTUREASSERT, NULL);
 111        return;
 112
 113out_both:
 114        /* fire assert event */
 115        pps_event(dev->pps, &ts_assert,
 116                        PPS_CAPTUREASSERT, NULL);
 117        /* fire clear event */
 118        pps_event(dev->pps, &ts_clear,
 119                        PPS_CAPTURECLEAR, NULL);
 120        return;
 121}
 122
 123static void parport_attach(struct parport *port)
 124{
 125        struct pardev_cb pps_client_cb;
 126        int index;
 127        struct pps_client_pp *device;
 128        struct pps_source_info info = {
 129                .name           = KBUILD_MODNAME,
 130                .path           = "",
 131                .mode           = PPS_CAPTUREBOTH | \
 132                                  PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
 133                                  PPS_ECHOASSERT | PPS_ECHOCLEAR | \
 134                                  PPS_CANWAIT | PPS_TSFMT_TSPEC,
 135                .owner          = THIS_MODULE,
 136                .dev            = NULL
 137        };
 138
 139        if (clear_wait > CLEAR_WAIT_MAX) {
 140                pr_err("clear_wait value should be not greater then %d\n",
 141                       CLEAR_WAIT_MAX);
 142                return;
 143        }
 144
 145        device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL);
 146        if (!device) {
 147                pr_err("memory allocation failed, not attaching\n");
 148                return;
 149        }
 150
 151        index = ida_simple_get(&pps_client_index, 0, 0, GFP_KERNEL);
 152        memset(&pps_client_cb, 0, sizeof(pps_client_cb));
 153        pps_client_cb.private = device;
 154        pps_client_cb.irq_func = parport_irq;
 155        pps_client_cb.flags = PARPORT_FLAG_EXCL;
 156        device->pardev = parport_register_dev_model(port,
 157                                                    KBUILD_MODNAME,
 158                                                    &pps_client_cb,
 159                                                    index);
 160        if (!device->pardev) {
 161                pr_err("couldn't register with %s\n", port->name);
 162                goto err_free;
 163        }
 164
 165        if (parport_claim_or_block(device->pardev) < 0) {
 166                pr_err("couldn't claim %s\n", port->name);
 167                goto err_unregister_dev;
 168        }
 169
 170        device->pps = pps_register_source(&info,
 171                        PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
 172        if (IS_ERR(device->pps)) {
 173                pr_err("couldn't register PPS source\n");
 174                goto err_release_dev;
 175        }
 176
 177        device->cw = clear_wait;
 178
 179        port->ops->enable_irq(port);
 180        device->index = index;
 181
 182        pr_info("attached to %s\n", port->name);
 183
 184        return;
 185
 186err_release_dev:
 187        parport_release(device->pardev);
 188err_unregister_dev:
 189        parport_unregister_device(device->pardev);
 190err_free:
 191        ida_simple_remove(&pps_client_index, index);
 192        kfree(device);
 193}
 194
 195static void parport_detach(struct parport *port)
 196{
 197        struct pardevice *pardev = port->cad;
 198        struct pps_client_pp *device;
 199
 200        /* FIXME: oooh, this is ugly! */
 201        if (!pardev || strcmp(pardev->name, KBUILD_MODNAME))
 202                /* not our port */
 203                return;
 204
 205        device = pardev->private;
 206
 207        port->ops->disable_irq(port);
 208        pps_unregister_source(device->pps);
 209        parport_release(pardev);
 210        parport_unregister_device(pardev);
 211        ida_simple_remove(&pps_client_index, device->index);
 212        kfree(device);
 213}
 214
 215static struct parport_driver pps_parport_driver = {
 216        .name = KBUILD_MODNAME,
 217        .match_port = parport_attach,
 218        .detach = parport_detach,
 219        .devmodel = true,
 220};
 221module_parport_driver(pps_parport_driver);
 222
 223MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
 224MODULE_DESCRIPTION("parallel port PPS client");
 225MODULE_LICENSE("GPL");
 226