xref: /linux/drivers/pps/generators/pps_gen.c (revision 7a5f1cd22d47f8ca4b760b6334378ae42c1bd24b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * PPS generators core file
4  *
5  * Copyright (C) 2024 Rodolfo Giometti <giometti@enneenne.com>
6  */
7 
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <linux/time.h>
15 #include <linux/timex.h>
16 #include <linux/uaccess.h>
17 #include <linux/idr.h>
18 #include <linux/cdev.h>
19 #include <linux/poll.h>
20 #include <linux/fs.h>
21 #include <linux/pps_gen_kernel.h>
22 #include <linux/slab.h>
23 
24 /*
25  * Local variables
26  */
27 
28 static dev_t pps_gen_devt;
29 static const struct class pps_gen_class = {
30 	.name		= "pps-gen",
31 	.dev_groups	= pps_gen_groups
32 };
33 
34 static DEFINE_IDA(pps_gen_ida);
35 
36 /*
37  * Char device methods
38  */
39 
40 static __poll_t pps_gen_cdev_poll(struct file *file, poll_table *wait)
41 {
42 	struct pps_gen_device *pps_gen = file->private_data;
43 
44 	poll_wait(file, &pps_gen->queue, wait);
45 	return EPOLLIN | EPOLLRDNORM;
46 }
47 
48 static int pps_gen_cdev_fasync(int fd, struct file *file, int on)
49 {
50 	struct pps_gen_device *pps_gen = file->private_data;
51 
52 	return fasync_helper(fd, file, on, &pps_gen->async_queue);
53 }
54 
55 static long pps_gen_cdev_ioctl(struct file *file,
56 		unsigned int cmd, unsigned long arg)
57 {
58 	struct pps_gen_device *pps_gen = file->private_data;
59 	void __user *uarg = (void __user *) arg;
60 	unsigned int __user *uiuarg = (unsigned int __user *) arg;
61 	unsigned int status;
62 	int ret;
63 
64 	switch (cmd) {
65 	case PPS_GEN_SETENABLE:
66 		dev_dbg(pps_gen->dev, "PPS_GEN_SETENABLE\n");
67 
68 		ret = get_user(status, uiuarg);
69 		if (ret)
70 			return -EFAULT;
71 
72 		ret = pps_gen->info->enable(pps_gen, status);
73 		if (ret)
74 			return ret;
75 		pps_gen->enabled = status;
76 
77 		break;
78 
79 	case PPS_GEN_USESYSTEMCLOCK:
80 		dev_dbg(pps_gen->dev, "PPS_GEN_USESYSTEMCLOCK\n");
81 
82 		ret = put_user(pps_gen->info->use_system_clock, uiuarg);
83 		if (ret)
84 			return -EFAULT;
85 
86 		break;
87 
88 	case PPS_GEN_FETCHEVENT: {
89 		struct pps_gen_event info;
90 		unsigned int ev = pps_gen->last_ev;
91 
92 		dev_dbg(pps_gen->dev, "PPS_GEN_FETCHEVENT\n");
93 
94 		ret = wait_event_interruptible(pps_gen->queue,
95 				ev != pps_gen->last_ev);
96 		if (ret == -ERESTARTSYS) {
97 			dev_dbg(pps_gen->dev, "pending signal caught\n");
98 			return -EINTR;
99 		}
100 
101 		spin_lock_irq(&pps_gen->lock);
102 		info.sequence = pps_gen->sequence;
103 		info.event = pps_gen->event;
104 		spin_unlock_irq(&pps_gen->lock);
105 
106 		ret = copy_to_user(uarg, &info, sizeof(struct pps_gen_event));
107 		if (ret)
108 			return -EFAULT;
109 
110 		break;
111 	}
112 	default:
113 		return -ENOTTY;
114 	}
115 
116 	return 0;
117 }
118 
119 static int pps_gen_cdev_open(struct inode *inode, struct file *file)
120 {
121 	struct pps_gen_device *pps_gen = container_of(inode->i_cdev,
122 				struct pps_gen_device, cdev);
123 
124 	get_device(pps_gen->dev);
125 	file->private_data = pps_gen;
126 	return 0;
127 }
128 
129 static int pps_gen_cdev_release(struct inode *inode, struct file *file)
130 {
131 	struct pps_gen_device *pps_gen = file->private_data;
132 
133 	put_device(pps_gen->dev);
134 	return 0;
135 }
136 
137 /*
138  * Char device stuff
139  */
140 
141 static const struct file_operations pps_gen_cdev_fops = {
142 	.owner		= THIS_MODULE,
143 	.poll	   = pps_gen_cdev_poll,
144 	.fasync	 = pps_gen_cdev_fasync,
145 	.unlocked_ioctl	= pps_gen_cdev_ioctl,
146 	.open		= pps_gen_cdev_open,
147 	.release	= pps_gen_cdev_release,
148 };
149 
150 static void pps_gen_device_destruct(struct device *dev)
151 {
152 	struct pps_gen_device *pps_gen = dev_get_drvdata(dev);
153 
154 	cdev_del(&pps_gen->cdev);
155 
156 	pr_debug("deallocating pps-gen%d\n", pps_gen->id);
157 	ida_free(&pps_gen_ida, pps_gen->id);
158 
159 	kfree(dev);
160 	kfree(pps_gen);
161 }
162 
163 static int pps_gen_register_cdev(struct pps_gen_device *pps_gen)
164 {
165 	int err;
166 	dev_t devt;
167 
168 	err = ida_alloc_max(&pps_gen_ida, PPS_GEN_MAX_SOURCES - 1, GFP_KERNEL);
169 	if (err < 0) {
170 		if (err == -ENOSPC) {
171 			pr_err("too many PPS sources in the system\n");
172 			err = -EBUSY;
173 		}
174 		return err;
175 	}
176 	pps_gen->id = err;
177 
178 	devt = MKDEV(MAJOR(pps_gen_devt), pps_gen->id);
179 
180 	cdev_init(&pps_gen->cdev, &pps_gen_cdev_fops);
181 	pps_gen->cdev.owner = pps_gen->info->owner;
182 
183 	err = cdev_add(&pps_gen->cdev, devt, 1);
184 	if (err) {
185 		pr_err("failed to add char device %d:%d\n",
186 				MAJOR(pps_gen_devt), pps_gen->id);
187 		goto free_ida;
188 	}
189 	pps_gen->dev = device_create(&pps_gen_class, pps_gen->info->parent, devt,
190 				     pps_gen, "pps-gen%d", pps_gen->id);
191 	if (IS_ERR(pps_gen->dev)) {
192 		err = PTR_ERR(pps_gen->dev);
193 		goto del_cdev;
194 	}
195 	pps_gen->dev->release = pps_gen_device_destruct;
196 	dev_set_drvdata(pps_gen->dev, pps_gen);
197 
198 	pr_debug("generator got cdev (%d:%d)\n",
199 			MAJOR(pps_gen_devt), pps_gen->id);
200 
201 	return 0;
202 
203 del_cdev:
204 	cdev_del(&pps_gen->cdev);
205 free_ida:
206 	ida_free(&pps_gen_ida, pps_gen->id);
207 	return err;
208 }
209 
210 static void pps_gen_unregister_cdev(struct pps_gen_device *pps_gen)
211 {
212 	pr_debug("unregistering pps-gen%d\n", pps_gen->id);
213 	device_destroy(&pps_gen_class, pps_gen->dev->devt);
214 }
215 
216 /*
217  * Exported functions
218  */
219 
220 /**
221  * pps_gen_register_source() - add a PPS generator in the system
222  * @info: the PPS generator info struct
223  *
224  * This function is used to register a new PPS generator in the system.
225  * When it returns successfully the new generator is up and running, and
226  * it can be managed by the userspace.
227  *
228  * Return: the PPS generator device in case of success, and ERR_PTR(errno)
229  *	 otherwise.
230  */
231 struct pps_gen_device *pps_gen_register_source(const struct pps_gen_source_info *info)
232 {
233 	struct pps_gen_device *pps_gen;
234 	int err;
235 
236 	pps_gen = kzalloc_obj(struct pps_gen_device);
237 	if (pps_gen == NULL) {
238 		err = -ENOMEM;
239 		goto pps_gen_register_source_exit;
240 	}
241 	pps_gen->info = info;
242 	pps_gen->enabled = false;
243 
244 	init_waitqueue_head(&pps_gen->queue);
245 	spin_lock_init(&pps_gen->lock);
246 
247 	/* Create the char device */
248 	err = pps_gen_register_cdev(pps_gen);
249 	if (err < 0) {
250 		pr_err(" unable to create char device\n");
251 		goto kfree_pps_gen;
252 	}
253 
254 	return pps_gen;
255 
256 kfree_pps_gen:
257 	kfree(pps_gen);
258 
259 pps_gen_register_source_exit:
260 	pr_err("unable to register generator\n");
261 
262 	return ERR_PTR(err);
263 }
264 EXPORT_SYMBOL(pps_gen_register_source);
265 
266 /**
267  * pps_gen_unregister_source() - remove a PPS generator from the system
268  * @pps_gen: the PPS generator device to be removed
269  *
270  * This function is used to deregister a PPS generator from the system. When
271  * called, it disables the generator so no pulses are generated anymore.
272  */
273 void pps_gen_unregister_source(struct pps_gen_device *pps_gen)
274 {
275 	pps_gen_unregister_cdev(pps_gen);
276 }
277 EXPORT_SYMBOL(pps_gen_unregister_source);
278 
279 /* pps_gen_event - register a PPS generator event into the system
280  * @pps: the PPS generator device
281  * @event: the event type
282  * @data: userdef pointer
283  *
284  * This function is used by each PPS generator in order to register a new
285  * PPS event into the system (it's usually called inside an IRQ handler).
286  */
287 void pps_gen_event(struct pps_gen_device *pps_gen,
288 			unsigned int event, void *data)
289 {
290 	unsigned long flags;
291 
292 	dev_dbg(pps_gen->dev, "PPS generator event %u\n", event);
293 
294 	spin_lock_irqsave(&pps_gen->lock, flags);
295 
296 	pps_gen->event = event;
297 	pps_gen->sequence++;
298 
299 	pps_gen->last_ev++;
300 	wake_up_interruptible_all(&pps_gen->queue);
301 	kill_fasync(&pps_gen->async_queue, SIGIO, POLL_IN);
302 
303 	spin_unlock_irqrestore(&pps_gen->lock, flags);
304 }
305 EXPORT_SYMBOL(pps_gen_event);
306 
307 /*
308  * Module stuff
309  */
310 
311 static void __exit pps_gen_exit(void)
312 {
313 	class_unregister(&pps_gen_class);
314 	unregister_chrdev_region(pps_gen_devt, PPS_GEN_MAX_SOURCES);
315 }
316 
317 static int __init pps_gen_init(void)
318 {
319 	int err;
320 
321 	err = class_register(&pps_gen_class);
322 	if (err) {
323 		pr_err("failed to register class\n");
324 		return err;
325 	}
326 
327 	err = alloc_chrdev_region(&pps_gen_devt, 0,
328 					PPS_GEN_MAX_SOURCES, "pps-gen");
329 	if (err < 0) {
330 		pr_err("failed to allocate char device region\n");
331 		goto remove_class;
332 	}
333 
334 	return 0;
335 
336 remove_class:
337 	class_unregister(&pps_gen_class);
338 	return err;
339 }
340 
341 subsys_initcall(pps_gen_init);
342 module_exit(pps_gen_exit);
343 
344 MODULE_AUTHOR("Rodolfo Giometti <giometti@enneenne.com>");
345 MODULE_DESCRIPTION("LinuxPPS generators support");
346 MODULE_LICENSE("GPL");
347