Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pps-gpio.c
Go to the documentation of this file.
1 /*
2  * pps-gpio.c -- PPS client driver using GPIO
3  *
4  *
5  * Copyright (C) 2010 Ricardo Martins <[email protected]>
6  * Copyright (C) 2011 James Nuss <[email protected]>
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 */
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 */
43 };
44 
45 /*
46  * Report the PPS event
47  */
48 
49 static 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 
72 static 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 
93 static unsigned long
94 get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
95 {
96  unsigned long flags = pdata->assert_falling_edge ?
98 
99  if (pdata->capture_clear) {
100  flags |= ((flags & IRQF_TRIGGER_RISING) ?
102  }
103 
104  return flags;
105 }
106 
107 static 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 |
140  if (pdata->capture_clear)
141  data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
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 
178 return_error:
179  gpio_free(pdata->gpio_pin);
180  return err;
181 }
182 
183 static 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 
197 static struct platform_driver pps_gpio_driver = {
198  .probe = pps_gpio_probe,
199  .remove = __devexit_p(pps_gpio_remove),
200  .driver = {
201  .name = PPS_GPIO_NAME,
202  .owner = THIS_MODULE
203  },
204 };
205 
206 static 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 
214 static void __exit pps_gpio_exit(void)
215 {
216  platform_driver_unregister(&pps_gpio_driver);
217  pr_debug("unregistered platform driver\n");
218 }
219 
220 module_init(pps_gpio_init);
221 module_exit(pps_gpio_exit);
222 
223 MODULE_AUTHOR("Ricardo Martins <[email protected]>");
224 MODULE_AUTHOR("James Nuss <[email protected]>");
225 MODULE_DESCRIPTION("Use GPIO pin as PPS source");
226 MODULE_LICENSE("GPL");
227 MODULE_VERSION("1.0.0");