1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PPS kernel consumer API
5 * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su>
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
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 */
29 /* pps_kc_bind - control PPS kernel consumer binding
30 * @pps: the PPS source
31 * @bind_args: kernel consumer bind parameters
33 * This function is used to bind or unbind PPS kernel consumer according to
34 * supplied parameters. Should not be called in interrupt context.
36 int pps_kc_bind(struct pps_device
*pps
, struct pps_bind_args
*bind_args
)
38 /* Check if another consumer is already bound */
39 spin_lock_irq(&pps_kc_hardpps_lock
);
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"
49 spin_unlock_irq(&pps_kc_hardpps_lock
);
50 dev_err(pps
->dev
, "selected kernel consumer"
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
);
63 spin_unlock_irq(&pps_kc_hardpps_lock
);
64 dev_err(pps
->dev
, "another kernel consumer"
65 " is already bound\n");
72 /* pps_kc_remove - unbind kernel consumer on PPS source removal
73 * @pps: the PPS source
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.
79 void pps_kc_remove(struct pps_device
*pps
)
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");
89 spin_unlock_irq(&pps_kc_hardpps_lock
);
92 /* pps_kc_event - call hardpps() on PPS event
93 * @pps: the PPS source
94 * @ts: PPS event timestamp
95 * @event: PPS event edge
97 * This function calls hardpps() when an event from bound PPS source occurs.
99 void pps_kc_event(struct pps_device
*pps
, struct pps_event_time
*ts
,
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
);