aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pps
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/pps
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'drivers/pps')
-rw-r--r--drivers/pps/Kconfig1
-rw-r--r--drivers/pps/clients/Kconfig9
-rw-r--r--drivers/pps/clients/Makefile1
-rw-r--r--drivers/pps/clients/pps-gpio.c227
-rw-r--r--drivers/pps/clients/pps-ktimer.c12
-rw-r--r--drivers/pps/clients/pps_parport.c9
-rw-r--r--drivers/pps/kapi.c20
-rw-r--r--drivers/pps/pps.c10
8 files changed, 33 insertions, 256 deletions
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 982d16b5a84..258ca596e1b 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -6,6 +6,7 @@ menu "PPS support"
6 6
7config PPS 7config PPS
8 tristate "PPS support" 8 tristate "PPS support"
9 depends on EXPERIMENTAL
9 ---help--- 10 ---help---
10 PPS (Pulse Per Second) is a special pulse provided by some GPS 11 PPS (Pulse Per Second) is a special pulse provided by some GPS
11 antennae. Userland can use it to get a high-precision time 12 antennae. Userland can use it to get a high-precision time
diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
index 445197d4a8c..8520a7f4dd6 100644
--- a/drivers/pps/clients/Kconfig
+++ b/drivers/pps/clients/Kconfig
@@ -29,13 +29,4 @@ config PPS_CLIENT_PARPORT
29 If you say yes here you get support for a PPS source connected 29 If you say yes here you get support for a PPS source connected
30 with the interrupt pin of your parallel port. 30 with the interrupt pin of your parallel port.
31 31
32config PPS_CLIENT_GPIO
33 tristate "PPS client using GPIO"
34 depends on PPS && GENERIC_HARDIRQS
35 help
36 If you say yes here you get support for a PPS source using
37 GPIO. To be useful you must also register a platform device
38 specifying the GPIO pin and other options, usually in your board
39 setup.
40
41endif 32endif
diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile
index a461d15f4a2..4feb7e9e71e 100644
--- a/drivers/pps/clients/Makefile
+++ b/drivers/pps/clients/Makefile
@@ -5,6 +5,5 @@
5obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o 5obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
6obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o 6obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
7obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o 7obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
8obj-$(CONFIG_PPS_CLIENT_GPIO) += pps-gpio.o
9 8
10ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG 9ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
deleted file mode 100644
index 2bf0c1b608d..00000000000
--- a/drivers/pps/clients/pps-gpio.c
+++ /dev/null
@@ -1,227 +0,0 @@
1/*
2 * pps-gpio.c -- PPS client driver using GPIO
3 *
4 *
5 * Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
6 * Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#define PPS_GPIO_NAME "pps-gpio"
24#define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
25
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/interrupt.h>
29#include <linux/module.h>
30#include <linux/platform_device.h>
31#include <linux/slab.h>
32#include <linux/pps_kernel.h>
33#include <linux/pps-gpio.h>
34#include <linux/gpio.h>
35#include <linux/list.h>
36
37/* Info for each registered platform device */
38struct pps_gpio_device_data {
39 int irq; /* IRQ used as PPS source */
40 struct pps_device *pps; /* PPS source device */
41 struct pps_source_info info; /* PPS source information */
42 const struct pps_gpio_platform_data *pdata;
43};
44
45/*
46 * Report the PPS event
47 */
48
49static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
50{
51 const struct pps_gpio_device_data *info;
52 struct pps_event_time ts;
53 int rising_edge;
54
55 /* Get the time stamp first */
56 pps_get_ts(&ts);
57
58 info = data;
59
60 rising_edge = gpio_get_value(info->pdata->gpio_pin);
61 if ((rising_edge && !info->pdata->assert_falling_edge) ||
62 (!rising_edge && info->pdata->assert_falling_edge))
63 pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
64 else if (info->pdata->capture_clear &&
65 ((rising_edge && info->pdata->assert_falling_edge) ||
66 (!rising_edge && !info->pdata->assert_falling_edge)))
67 pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
68
69 return IRQ_HANDLED;
70}
71
72static int pps_gpio_setup(struct platform_device *pdev)
73{
74 int ret;
75 const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
76
77 ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
78 if (ret) {
79 pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
80 return -EINVAL;
81 }
82
83 ret = gpio_direction_input(pdata->gpio_pin);
84 if (ret) {
85 pr_warning("failed to set pin direction\n");
86 gpio_free(pdata->gpio_pin);
87 return -EINVAL;
88 }
89
90 return 0;
91}
92
93static unsigned long
94get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
95{
96 unsigned long flags = pdata->assert_falling_edge ?
97 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
98
99 if (pdata->capture_clear) {
100 flags |= ((flags & IRQF_TRIGGER_RISING) ?
101 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
102 }
103
104 return flags;
105}
106
107static int pps_gpio_probe(struct platform_device *pdev)
108{
109 struct pps_gpio_device_data *data;
110 int irq;
111 int ret;
112 int err;
113 int pps_default_params;
114 const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
115
116
117 /* GPIO setup */
118 ret = pps_gpio_setup(pdev);
119 if (ret)
120 return -EINVAL;
121
122 /* IRQ setup */
123 irq = gpio_to_irq(pdata->gpio_pin);
124 if (irq < 0) {
125 pr_err("failed to map GPIO to IRQ: %d\n", irq);
126 err = -EINVAL;
127 goto return_error;
128 }
129
130 /* allocate space for device info */
131 data = kzalloc(sizeof(struct pps_gpio_device_data), GFP_KERNEL);
132 if (data == NULL) {
133 err = -ENOMEM;
134 goto return_error;
135 }
136
137 /* initialize PPS specific parts of the bookkeeping data structure. */
138 data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
139 PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
140 if (pdata->capture_clear)
141 data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
142 PPS_ECHOCLEAR;
143 data->info.owner = THIS_MODULE;
144 snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
145 pdev->name, pdev->id);
146
147 /* register PPS source */
148 pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
149 if (pdata->capture_clear)
150 pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
151 data->pps = pps_register_source(&data->info, pps_default_params);
152 if (data->pps == NULL) {
153 kfree(data);
154 pr_err("failed to register IRQ %d as PPS source\n", irq);
155 err = -EINVAL;
156 goto return_error;
157 }
158
159 data->irq = irq;
160 data->pdata = pdata;
161
162 /* register IRQ interrupt handler */
163 ret = request_irq(irq, pps_gpio_irq_handler,
164 get_irqf_trigger_flags(pdata), data->info.name, data);
165 if (ret) {
166 pps_unregister_source(data->pps);
167 kfree(data);
168 pr_err("failed to acquire IRQ %d\n", irq);
169 err = -EINVAL;
170 goto return_error;
171 }
172
173 platform_set_drvdata(pdev, data);
174 dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);
175
176 return 0;
177
178return_error:
179 gpio_free(pdata->gpio_pin);
180 return err;
181}
182
183static int pps_gpio_remove(struct platform_device *pdev)
184{
185 struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
186 const struct pps_gpio_platform_data *pdata = data->pdata;
187
188 platform_set_drvdata(pdev, NULL);
189 free_irq(data->irq, data);
190 gpio_free(pdata->gpio_pin);
191 pps_unregister_source(data->pps);
192 pr_info("removed IRQ %d as PPS source\n", data->irq);
193 kfree(data);
194 return 0;
195}
196
197static struct platform_driver pps_gpio_driver = {
198 .probe = pps_gpio_probe,
199 .remove = pps_gpio_remove,
200 .driver = {
201 .name = PPS_GPIO_NAME,
202 .owner = THIS_MODULE
203 },
204};
205
206static int __init pps_gpio_init(void)
207{
208 int ret = platform_driver_register(&pps_gpio_driver);
209 if (ret < 0)
210 pr_err("failed to register platform driver\n");
211 return ret;
212}
213
214static void __exit pps_gpio_exit(void)
215{
216 platform_driver_unregister(&pps_gpio_driver);
217 pr_debug("unregistered platform driver\n");
218}
219
220module_init(pps_gpio_init);
221module_exit(pps_gpio_exit);
222
223MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
224MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
225MODULE_DESCRIPTION("Use GPIO pin as PPS source");
226MODULE_LICENSE("GPL");
227MODULE_VERSION("1.0.0");
diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index 436b4e4e71a..82583b0ff82 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -52,6 +52,17 @@ static void pps_ktimer_event(unsigned long ptr)
52} 52}
53 53
54/* 54/*
55 * The echo function
56 */
57
58static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
59{
60 dev_info(pps->dev, "echo %s %s\n",
61 event & PPS_CAPTUREASSERT ? "assert" : "",
62 event & PPS_CAPTURECLEAR ? "clear" : "");
63}
64
65/*
55 * The PPS info struct 66 * The PPS info struct
56 */ 67 */
57 68
@@ -61,6 +72,7 @@ static struct pps_source_info pps_ktimer_info = {
61 .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | 72 .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
62 PPS_ECHOASSERT | 73 PPS_ECHOASSERT |
63 PPS_CANWAIT | PPS_TSFMT_TSPEC, 74 PPS_CANWAIT | PPS_TSFMT_TSPEC,
75 .echo = pps_ktimer_echo,
64 .owner = THIS_MODULE, 76 .owner = THIS_MODULE,
65}; 77};
66 78
diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
index e1b4705ae3e..c571d6dd8f6 100644
--- a/drivers/pps/clients/pps_parport.c
+++ b/drivers/pps/clients/pps_parport.c
@@ -133,6 +133,14 @@ out_both:
133 return; 133 return;
134} 134}
135 135
136/* the PPS echo function */
137static void pps_echo(struct pps_device *pps, int event, void *data)
138{
139 dev_info(pps->dev, "echo %s %s\n",
140 event & PPS_CAPTUREASSERT ? "assert" : "",
141 event & PPS_CAPTURECLEAR ? "clear" : "");
142}
143
136static void parport_attach(struct parport *port) 144static void parport_attach(struct parport *port)
137{ 145{
138 struct pps_client_pp *device; 146 struct pps_client_pp *device;
@@ -143,6 +151,7 @@ static void parport_attach(struct parport *port)
143 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ 151 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
144 PPS_ECHOASSERT | PPS_ECHOCLEAR | \ 152 PPS_ECHOASSERT | PPS_ECHOCLEAR | \
145 PPS_CANWAIT | PPS_TSFMT_TSPEC, 153 PPS_CANWAIT | PPS_TSFMT_TSPEC,
154 .echo = pps_echo,
146 .owner = THIS_MODULE, 155 .owner = THIS_MODULE,
147 .dev = NULL 156 .dev = NULL
148 }; 157 };
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index f197e8ea185..a4e8eb9fece 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -52,14 +52,6 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
52 ts->sec += offset->sec; 52 ts->sec += offset->sec;
53} 53}
54 54
55static void pps_echo_client_default(struct pps_device *pps, int event,
56 void *data)
57{
58 dev_info(pps->dev, "echo %s %s\n",
59 event & PPS_CAPTUREASSERT ? "assert" : "",
60 event & PPS_CAPTURECLEAR ? "clear" : "");
61}
62
63/* 55/*
64 * Exported functions 56 * Exported functions
65 */ 57 */
@@ -88,6 +80,13 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
88 err = -EINVAL; 80 err = -EINVAL;
89 goto pps_register_source_exit; 81 goto pps_register_source_exit;
90 } 82 }
83 if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
84 info->echo == NULL) {
85 pr_err("%s: echo function is not defined\n",
86 info->name);
87 err = -EINVAL;
88 goto pps_register_source_exit;
89 }
91 if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { 90 if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
92 pr_err("%s: unspecified time format\n", 91 pr_err("%s: unspecified time format\n",
93 info->name); 92 info->name);
@@ -109,11 +108,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
109 pps->params.mode = default_params; 108 pps->params.mode = default_params;
110 pps->info = *info; 109 pps->info = *info;
111 110
112 /* check for default echo function */
113 if ((pps->info.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) &&
114 pps->info.echo == NULL)
115 pps->info.echo = pps_echo_client_default;
116
117 init_waitqueue_head(&pps->queue); 111 init_waitqueue_head(&pps->queue);
118 spin_lock_init(&pps->lock); 112 spin_lock_init(&pps->lock);
119 113
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index 2420d5af058..2baadd21b7a 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -306,7 +306,7 @@ int pps_register_cdev(struct pps_device *pps)
306 if (err < 0) 306 if (err < 0)
307 return err; 307 return err;
308 308
309 pps->id &= MAX_IDR_MASK; 309 pps->id &= MAX_ID_MASK;
310 if (pps->id >= PPS_MAX_SOURCES) { 310 if (pps->id >= PPS_MAX_SOURCES) {
311 pr_err("%s: too many PPS sources in the system\n", 311 pr_err("%s: too many PPS sources in the system\n",
312 pps->info.name); 312 pps->info.name);
@@ -327,10 +327,8 @@ int pps_register_cdev(struct pps_device *pps)
327 } 327 }
328 pps->dev = device_create(pps_class, pps->info.dev, devt, pps, 328 pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
329 "pps%d", pps->id); 329 "pps%d", pps->id);
330 if (IS_ERR(pps->dev)) { 330 if (IS_ERR(pps->dev))
331 err = PTR_ERR(pps->dev);
332 goto del_cdev; 331 goto del_cdev;
333 }
334 332
335 pps->dev->release = pps_device_destruct; 333 pps->dev->release = pps_device_destruct;
336 334
@@ -371,9 +369,9 @@ static int __init pps_init(void)
371 int err; 369 int err;
372 370
373 pps_class = class_create(THIS_MODULE, "pps"); 371 pps_class = class_create(THIS_MODULE, "pps");
374 if (IS_ERR(pps_class)) { 372 if (!pps_class) {
375 pr_err("failed to allocate class\n"); 373 pr_err("failed to allocate class\n");
376 return PTR_ERR(pps_class); 374 return -ENOMEM;
377 } 375 }
378 pps_class->dev_attrs = pps_attrs; 376 pps_class->dev_attrs = pps_attrs;
379 377