pps-gpio.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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. #define PPS_GPIO_NAME "pps-gpio"
  23. #define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
  24. #include <linux/init.h>
  25. #include <linux/kernel.h>
  26. #include <linux/interrupt.h>
  27. #include <linux/module.h>
  28. #include <linux/platform_device.h>
  29. #include <linux/slab.h>
  30. #include <linux/pps_kernel.h>
  31. #include <linux/pps-gpio.h>
  32. #include <linux/gpio.h>
  33. #include <linux/list.h>
  34. /* Info for each registered platform device */
  35. struct pps_gpio_device_data {
  36. int irq; /* IRQ used as PPS source */
  37. struct pps_device *pps; /* PPS source device */
  38. struct pps_source_info info; /* PPS source information */
  39. const struct pps_gpio_platform_data *pdata;
  40. };
  41. /*
  42. * Report the PPS event
  43. */
  44. static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
  45. {
  46. const struct pps_gpio_device_data *info;
  47. struct pps_event_time ts;
  48. int rising_edge;
  49. /* Get the time stamp first */
  50. pps_get_ts(&ts);
  51. info = data;
  52. rising_edge = gpio_get_value(info->pdata->gpio_pin);
  53. if ((rising_edge && !info->pdata->assert_falling_edge) ||
  54. (!rising_edge && info->pdata->assert_falling_edge))
  55. pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
  56. else if (info->pdata->capture_clear &&
  57. ((rising_edge && info->pdata->assert_falling_edge) ||
  58. (!rising_edge && !info->pdata->assert_falling_edge)))
  59. pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
  60. return IRQ_HANDLED;
  61. }
  62. static int pps_gpio_setup(struct platform_device *pdev)
  63. {
  64. int ret;
  65. const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
  66. ret = gpio_request(pdata->gpio_pin, pdata->gpio_label);
  67. if (ret) {
  68. pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
  69. return -EINVAL;
  70. }
  71. ret = gpio_direction_input(pdata->gpio_pin);
  72. if (ret) {
  73. pr_warning("failed to set pin direction\n");
  74. gpio_free(pdata->gpio_pin);
  75. return -EINVAL;
  76. }
  77. return 0;
  78. }
  79. static unsigned long
  80. get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
  81. {
  82. unsigned long flags = pdata->assert_falling_edge ?
  83. IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
  84. if (pdata->capture_clear) {
  85. flags |= ((flags & IRQF_TRIGGER_RISING) ?
  86. IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
  87. }
  88. return flags;
  89. }
  90. static int pps_gpio_probe(struct platform_device *pdev)
  91. {
  92. struct pps_gpio_device_data *data;
  93. int irq;
  94. int ret;
  95. int err;
  96. int pps_default_params;
  97. const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
  98. /* GPIO setup */
  99. ret = pps_gpio_setup(pdev);
  100. if (ret)
  101. return -EINVAL;
  102. /* IRQ setup */
  103. irq = gpio_to_irq(pdata->gpio_pin);
  104. if (irq < 0) {
  105. pr_err("failed to map GPIO to IRQ: %d\n", irq);
  106. err = -EINVAL;
  107. goto return_error;
  108. }
  109. /* allocate space for device info */
  110. data = kzalloc(sizeof(struct pps_gpio_device_data), GFP_KERNEL);
  111. if (data == NULL) {
  112. err = -ENOMEM;
  113. goto return_error;
  114. }
  115. /* initialize PPS specific parts of the bookkeeping data structure. */
  116. data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
  117. PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
  118. if (pdata->capture_clear)
  119. data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
  120. PPS_ECHOCLEAR;
  121. data->info.owner = THIS_MODULE;
  122. snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
  123. pdev->name, pdev->id);
  124. /* register PPS source */
  125. pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
  126. if (pdata->capture_clear)
  127. pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
  128. data->pps = pps_register_source(&data->info, pps_default_params);
  129. if (data->pps == NULL) {
  130. kfree(data);
  131. pr_err("failed to register IRQ %d as PPS source\n", irq);
  132. err = -EINVAL;
  133. goto return_error;
  134. }
  135. data->irq = irq;
  136. data->pdata = pdata;
  137. /* register IRQ interrupt handler */
  138. ret = request_irq(irq, pps_gpio_irq_handler,
  139. get_irqf_trigger_flags(pdata), data->info.name, data);
  140. if (ret) {
  141. pps_unregister_source(data->pps);
  142. kfree(data);
  143. pr_err("failed to acquire IRQ %d\n", irq);
  144. err = -EINVAL;
  145. goto return_error;
  146. }
  147. platform_set_drvdata(pdev, data);
  148. dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq);
  149. return 0;
  150. return_error:
  151. gpio_free(pdata->gpio_pin);
  152. return err;
  153. }
  154. static int pps_gpio_remove(struct platform_device *pdev)
  155. {
  156. struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
  157. const struct pps_gpio_platform_data *pdata = data->pdata;
  158. platform_set_drvdata(pdev, NULL);
  159. free_irq(data->irq, data);
  160. gpio_free(pdata->gpio_pin);
  161. pps_unregister_source(data->pps);
  162. pr_info("removed IRQ %d as PPS source\n", data->irq);
  163. kfree(data);
  164. return 0;
  165. }
  166. static struct platform_driver pps_gpio_driver = {
  167. .probe = pps_gpio_probe,
  168. .remove = __devexit_p(pps_gpio_remove),
  169. .driver = {
  170. .name = PPS_GPIO_NAME,
  171. .owner = THIS_MODULE
  172. },
  173. };
  174. static int __init pps_gpio_init(void)
  175. {
  176. int ret = platform_driver_register(&pps_gpio_driver);
  177. if (ret < 0)
  178. pr_err("failed to register platform driver\n");
  179. return ret;
  180. }
  181. static void __exit pps_gpio_exit(void)
  182. {
  183. platform_driver_unregister(&pps_gpio_driver);
  184. pr_debug("unregistered platform driver\n");
  185. }
  186. module_init(pps_gpio_init);
  187. module_exit(pps_gpio_exit);
  188. MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
  189. MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
  190. MODULE_DESCRIPTION("Use GPIO pin as PPS source");
  191. MODULE_LICENSE("GPL");
  192. MODULE_VERSION("1.0.0");