pps: simplify conditions a bit
[firefly-linux-kernel-4.4.55.git] / drivers / pps / kapi.c
1 /*
2  * kernel API
3  *
4  *
5  * Copyright (C) 2005-2009   Rodolfo Giometti <giometti@linux.it>
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/sched.h>
28 #include <linux/time.h>
29 #include <linux/spinlock.h>
30 #include <linux/fs.h>
31 #include <linux/pps_kernel.h>
32 #include <linux/slab.h>
33
34 /*
35  * Local functions
36  */
37
38 static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
39 {
40         ts->nsec += offset->nsec;
41         while (ts->nsec >= NSEC_PER_SEC) {
42                 ts->nsec -= NSEC_PER_SEC;
43                 ts->sec++;
44         }
45         while (ts->nsec < 0) {
46                 ts->nsec += NSEC_PER_SEC;
47                 ts->sec--;
48         }
49         ts->sec += offset->sec;
50 }
51
52 /*
53  * Exported functions
54  */
55
56 /* pps_register_source - add a PPS source in the system
57  * @info: the PPS info struct
58  * @default_params: the default PPS parameters of the new source
59  *
60  * This function is used to add a new PPS source in the system. The new
61  * source is described by info's fields and it will have, as default PPS
62  * parameters, the ones specified into default_params.
63  *
64  * The function returns, in case of success, the PPS device. Otherwise NULL.
65  */
66
67 struct pps_device *pps_register_source(struct pps_source_info *info,
68                 int default_params)
69 {
70         struct pps_device *pps;
71         int err;
72
73         /* Sanity checks */
74         if ((info->mode & default_params) != default_params) {
75                 pr_err("%s: unsupported default parameters\n",
76                                         info->name);
77                 err = -EINVAL;
78                 goto pps_register_source_exit;
79         }
80         if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
81                         info->echo == NULL) {
82                 pr_err("%s: echo function is not defined\n",
83                                         info->name);
84                 err = -EINVAL;
85                 goto pps_register_source_exit;
86         }
87         if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
88                 pr_err("%s: unspecified time format\n",
89                                         info->name);
90                 err = -EINVAL;
91                 goto pps_register_source_exit;
92         }
93
94         /* Allocate memory for the new PPS source struct */
95         pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
96         if (pps == NULL) {
97                 err = -ENOMEM;
98                 goto pps_register_source_exit;
99         }
100
101         /* These initializations must be done before calling idr_get_new()
102          * in order to avoid reces into pps_event().
103          */
104         pps->params.api_version = PPS_API_VERS;
105         pps->params.mode = default_params;
106         pps->info = *info;
107
108         init_waitqueue_head(&pps->queue);
109         spin_lock_init(&pps->lock);
110
111         /* Create the char device */
112         err = pps_register_cdev(pps);
113         if (err < 0) {
114                 pr_err("%s: unable to create char device\n",
115                                         info->name);
116                 goto kfree_pps;
117         }
118
119         dev_info(pps->dev, "new PPS source %s\n", info->name);
120
121         return pps;
122
123 kfree_pps:
124         kfree(pps);
125
126 pps_register_source_exit:
127         pr_err("%s: unable to register source\n", info->name);
128
129         return NULL;
130 }
131 EXPORT_SYMBOL(pps_register_source);
132
133 /* pps_unregister_source - remove a PPS source from the system
134  * @pps: the PPS source
135  *
136  * This function is used to remove a previously registered PPS source from
137  * the system.
138  */
139
140 void pps_unregister_source(struct pps_device *pps)
141 {
142         pps_unregister_cdev(pps);
143
144         /* don't have to kfree(pps) here because it will be done on
145          * device destruction */
146 }
147 EXPORT_SYMBOL(pps_unregister_source);
148
149 /* pps_event - register a PPS event into the system
150  * @pps: the PPS device
151  * @ts: the event timestamp
152  * @event: the event type
153  * @data: userdef pointer
154  *
155  * This function is used by each PPS client in order to register a new
156  * PPS event into the system (it's usually called inside an IRQ handler).
157  *
158  * If an echo function is associated with the PPS device it will be called
159  * as:
160  *      pps->info.echo(pps, event, data);
161  */
162 void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
163                 void *data)
164 {
165         unsigned long flags;
166         int captured = 0;
167         struct pps_ktime ts_real;
168
169         /* check event type */
170         BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
171
172         dev_dbg(pps->dev, "PPS event at %ld.%09ld\n",
173                         ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
174
175         timespec_to_pps_ktime(&ts_real, ts->ts_real);
176
177         spin_lock_irqsave(&pps->lock, flags);
178
179         /* Must call the echo function? */
180         if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
181                 pps->info.echo(pps, event, data);
182
183         /* Check the event */
184         pps->current_mode = pps->params.mode;
185         if (event & pps->params.mode & PPS_CAPTUREASSERT) {
186                 /* We have to add an offset? */
187                 if (pps->params.mode & PPS_OFFSETASSERT)
188                         pps_add_offset(&ts_real,
189                                         &pps->params.assert_off_tu);
190
191                 /* Save the time stamp */
192                 pps->assert_tu = ts_real;
193                 pps->assert_sequence++;
194                 dev_dbg(pps->dev, "capture assert seq #%u\n",
195                         pps->assert_sequence);
196
197                 captured = ~0;
198         }
199         if (event & pps->params.mode & PPS_CAPTURECLEAR) {
200                 /* We have to add an offset? */
201                 if (pps->params.mode & PPS_OFFSETCLEAR)
202                         pps_add_offset(&ts_real,
203                                         &pps->params.clear_off_tu);
204
205                 /* Save the time stamp */
206                 pps->clear_tu = ts_real;
207                 pps->clear_sequence++;
208                 dev_dbg(pps->dev, "capture clear seq #%u\n",
209                         pps->clear_sequence);
210
211                 captured = ~0;
212         }
213
214         /* Wake up if captured something */
215         if (captured) {
216                 pps->last_ev++;
217                 wake_up_interruptible_all(&pps->queue);
218
219                 kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
220         }
221
222         spin_unlock_irqrestore(&pps->lock, flags);
223 }
224 EXPORT_SYMBOL(pps_event);