root/drivers/pps/kc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pps_kc_bind
  2. pps_kc_remove
  3. pps_kc_event

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * PPS kernel consumer API
   4  *
   5  * Copyright (C) 2009-2010   Alexander Gordeev <lasaine@lvk.cs.msu.su>
   6  */
   7 
   8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/device.h>
  13 #include <linux/init.h>
  14 #include <linux/spinlock.h>
  15 #include <linux/pps_kernel.h>
  16 
  17 #include "kc.h"
  18 
  19 /*
  20  * Global variables
  21  */
  22 
  23 /* state variables to bind kernel consumer */
  24 static DEFINE_SPINLOCK(pps_kc_hardpps_lock);
  25 /* PPS API (RFC 2783): current source and mode for kernel consumer */
  26 static struct pps_device *pps_kc_hardpps_dev;   /* unique pointer to device */
  27 static int pps_kc_hardpps_mode;         /* mode bits for kernel consumer */
  28 
  29 /* pps_kc_bind - control PPS kernel consumer binding
  30  * @pps: the PPS source
  31  * @bind_args: kernel consumer bind parameters
  32  *
  33  * This function is used to bind or unbind PPS kernel consumer according to
  34  * supplied parameters. Should not be called in interrupt context.
  35  */
  36 int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
  37 {
  38         /* Check if another consumer is already bound */
  39         spin_lock_irq(&pps_kc_hardpps_lock);
  40 
  41         if (bind_args->edge == 0)
  42                 if (pps_kc_hardpps_dev == pps) {
  43                         pps_kc_hardpps_mode = 0;
  44                         pps_kc_hardpps_dev = NULL;
  45                         spin_unlock_irq(&pps_kc_hardpps_lock);
  46                         dev_info(pps->dev, "unbound kernel"
  47                                         " consumer\n");
  48                 } else {
  49                         spin_unlock_irq(&pps_kc_hardpps_lock);
  50                         dev_err(pps->dev, "selected kernel consumer"
  51                                         " is not bound\n");
  52                         return -EINVAL;
  53                 }
  54         else
  55                 if (pps_kc_hardpps_dev == NULL ||
  56                                 pps_kc_hardpps_dev == pps) {
  57                         pps_kc_hardpps_mode = bind_args->edge;
  58                         pps_kc_hardpps_dev = pps;
  59                         spin_unlock_irq(&pps_kc_hardpps_lock);
  60                         dev_info(pps->dev, "bound kernel consumer: "
  61                                 "edge=0x%x\n", bind_args->edge);
  62                 } else {
  63                         spin_unlock_irq(&pps_kc_hardpps_lock);
  64                         dev_err(pps->dev, "another kernel consumer"
  65                                         " is already bound\n");
  66                         return -EINVAL;
  67                 }
  68 
  69         return 0;
  70 }
  71 
  72 /* pps_kc_remove - unbind kernel consumer on PPS source removal
  73  * @pps: the PPS source
  74  *
  75  * This function is used to disable kernel consumer on PPS source removal
  76  * if this source was bound to PPS kernel consumer. Can be called on any
  77  * source safely. Should not be called in interrupt context.
  78  */
  79 void pps_kc_remove(struct pps_device *pps)
  80 {
  81         spin_lock_irq(&pps_kc_hardpps_lock);
  82         if (pps == pps_kc_hardpps_dev) {
  83                 pps_kc_hardpps_mode = 0;
  84                 pps_kc_hardpps_dev = NULL;
  85                 spin_unlock_irq(&pps_kc_hardpps_lock);
  86                 dev_info(pps->dev, "unbound kernel consumer"
  87                                 " on device removal\n");
  88         } else
  89                 spin_unlock_irq(&pps_kc_hardpps_lock);
  90 }
  91 
  92 /* pps_kc_event - call hardpps() on PPS event
  93  * @pps: the PPS source
  94  * @ts: PPS event timestamp
  95  * @event: PPS event edge
  96  *
  97  * This function calls hardpps() when an event from bound PPS source occurs.
  98  */
  99 void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,
 100                 int event)
 101 {
 102         unsigned long flags;
 103 
 104         /* Pass some events to kernel consumer if activated */
 105         spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
 106         if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode)
 107                 hardpps(&ts->ts_real, &ts->ts_raw);
 108         spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
 109 }

/* [<][>][^][v][top][bottom][index][help] */