pps-gpio.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. #include <linux/of_device.h>
  35. #include <linux/of_gpio.h>
  36. /* Info for each registered platform device */
  37. struct pps_gpio_device_data {
  38. int irq; /* IRQ used as PPS source */
  39. struct pps_device *pps; /* PPS source device */
  40. struct pps_source_info info; /* PPS source information */
  41. bool assert_falling_edge;
  42. bool capture_clear;
  43. unsigned int gpio_pin;
  44. };
  45. /*
  46. * Report the PPS event
  47. */
  48. static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
  49. {
  50. const struct pps_gpio_device_data *info;
  51. struct pps_event_time ts;
  52. int rising_edge;
  53. /* Get the time stamp first */
  54. pps_get_ts(&ts);
  55. info = data;
  56. rising_edge = gpio_get_value(info->gpio_pin);
  57. if ((rising_edge && !info->assert_falling_edge) ||
  58. (!rising_edge && info->assert_falling_edge))
  59. pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
  60. else if (info->capture_clear &&
  61. ((rising_edge && info->assert_falling_edge) ||
  62. (!rising_edge && !info->assert_falling_edge)))
  63. pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
  64. return IRQ_HANDLED;
  65. }
  66. static unsigned long
  67. get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
  68. {
  69. unsigned long flags = data->assert_falling_edge ?
  70. IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
  71. if (data->capture_clear) {
  72. flags |= ((flags & IRQF_TRIGGER_RISING) ?
  73. IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
  74. }
  75. return flags;
  76. }
  77. static int pps_gpio_probe(struct platform_device *pdev)
  78. {
  79. struct pps_gpio_device_data *data;
  80. const char *gpio_label;
  81. int ret;
  82. int pps_default_params;
  83. const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
  84. struct device_node *np = pdev->dev.of_node;
  85. /* allocate space for device info */
  86. data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
  87. GFP_KERNEL);
  88. if (!data)
  89. return -ENOMEM;
  90. if (pdata) {
  91. data->gpio_pin = pdata->gpio_pin;
  92. gpio_label = pdata->gpio_label;
  93. data->assert_falling_edge = pdata->assert_falling_edge;
  94. data->capture_clear = pdata->capture_clear;
  95. } else {
  96. ret = of_get_gpio(np, 0);
  97. if (ret < 0) {
  98. dev_err(&pdev->dev, "failed to get GPIO from device tree\n");
  99. return ret;
  100. }
  101. data->gpio_pin = ret;
  102. gpio_label = PPS_GPIO_NAME;
  103. if (of_get_property(np, "assert-falling-edge", NULL))
  104. data->assert_falling_edge = true;
  105. }
  106. /* GPIO setup */
  107. ret = devm_gpio_request(&pdev->dev, data->gpio_pin, gpio_label);
  108. if (ret) {
  109. dev_err(&pdev->dev, "failed to request GPIO %u\n",
  110. data->gpio_pin);
  111. return ret;
  112. }
  113. ret = gpio_direction_input(data->gpio_pin);
  114. if (ret) {
  115. dev_err(&pdev->dev, "failed to set pin direction\n");
  116. return -EINVAL;
  117. }
  118. /* IRQ setup */
  119. ret = gpio_to_irq(data->gpio_pin);
  120. if (ret < 0) {
  121. dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
  122. return -EINVAL;
  123. }
  124. data->irq = ret;
  125. /* initialize PPS specific parts of the bookkeeping data structure. */
  126. data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
  127. PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
  128. if (data->capture_clear)
  129. data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
  130. PPS_ECHOCLEAR;
  131. data->info.owner = THIS_MODULE;
  132. snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
  133. pdev->name, pdev->id);
  134. /* register PPS source */
  135. pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
  136. if (data->capture_clear)
  137. pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
  138. data->pps = pps_register_source(&data->info, pps_default_params);
  139. if (data->pps == NULL) {
  140. dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n",
  141. data->irq);
  142. return -EINVAL;
  143. }
  144. /* register IRQ interrupt handler */
  145. ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
  146. get_irqf_trigger_flags(data), data->info.name, data);
  147. if (ret) {
  148. pps_unregister_source(data->pps);
  149. dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq);
  150. return -EINVAL;
  151. }
  152. platform_set_drvdata(pdev, data);
  153. dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
  154. data->irq);
  155. return 0;
  156. }
  157. static int pps_gpio_remove(struct platform_device *pdev)
  158. {
  159. struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
  160. pps_unregister_source(data->pps);
  161. dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
  162. return 0;
  163. }
  164. static const struct of_device_id pps_gpio_dt_ids[] = {
  165. { .compatible = "pps-gpio", },
  166. { /* sentinel */ }
  167. };
  168. MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
  169. static struct platform_driver pps_gpio_driver = {
  170. .probe = pps_gpio_probe,
  171. .remove = pps_gpio_remove,
  172. .driver = {
  173. .name = PPS_GPIO_NAME,
  174. .of_match_table = pps_gpio_dt_ids,
  175. },
  176. };
  177. module_platform_driver(pps_gpio_driver);
  178. MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
  179. MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
  180. MODULE_DESCRIPTION("Use GPIO pin as PPS source");
  181. MODULE_LICENSE("GPL");
  182. MODULE_VERSION("1.0.0");