History

pps: pps-gpio PPS ECHO implementation

This patch implements the PPS ECHO functionality for pps-gpio, that sysfs claims is available already. Configuration is done via device tree bindings. No changes are made to userspace interfaces. This patch was originally written by Lukas Senger as part of a masters thesis project and modified for inclusion into the linux kernel by Tom Burkart.

Tom Burkart committed 7 years ago

Commit 4c69add1 parent 652e2212 files · +87 −3Browse files

Unified · Split

2 files
  1. drivers/pps/clients/pps-gpio.c +85 −3
  2. include/linux/pps-gpio.h +2 −0
drivers/pps/clients/pps-gpio.c+85−3
@@ -35,6 +35,8 @@ · 34 unmodified lines
35#include <linux/list.h>35#include <linux/list.h>
36#include <linux/of_device.h>36#include <linux/of_device.h>
37#include <linux/of_gpio.h>37#include <linux/of_gpio.h>
38#include <linux/timer.h>
39#include <linux/jiffies.h>
38 40
39/* Info for each registered platform device */41/* Info for each registered platform device */
40struct pps_gpio_device_data {42struct pps_gpio_device_data {
@@ -42,8 +44,12 @@ struct pps_gpio_device_data { · 1 unmodified line
42 struct pps_device *pps; /* PPS source device */44 struct pps_device *pps; /* PPS source device */
43 struct pps_source_info info; /* PPS source information */45 struct pps_source_info info; /* PPS source information */
44 struct gpio_desc *gpio_pin; /* GPIO port descriptors */46 struct gpio_desc *gpio_pin; /* GPIO port descriptors */
47 struct gpio_desc *echo_pin;
48 struct timer_list echo_timer; /* timer to reset echo active state */
45 bool assert_falling_edge;49 bool assert_falling_edge;
46 bool capture_clear;50 bool capture_clear;
51 unsigned int echo_active_ms; /* PPS echo active duration */
52 unsigned long echo_timeout; /* timer timeout value in jiffies */
47};53};
48 54
49/*55/*
@@ -64,19 +70,56 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data) · 14 unmodified lines
64 rising_edge = gpiod_get_value(info->gpio_pin);70 rising_edge = gpiod_get_value(info->gpio_pin);
65 if ((rising_edge && !info->assert_falling_edge) ||71 if ((rising_edge && !info->assert_falling_edge) ||
66 (!rising_edge && info->assert_falling_edge))72 (!rising_edge && info->assert_falling_edge))
67 pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);73 pps_event(info->pps, &ts, PPS_CAPTUREASSERT, data);
68 else if (info->capture_clear &&74 else if (info->capture_clear &&
69 ((rising_edge && info->assert_falling_edge) ||75 ((rising_edge && info->assert_falling_edge) ||
70 (!rising_edge && !info->assert_falling_edge)))76 (!rising_edge && !info->assert_falling_edge)))
71 pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);77 pps_event(info->pps, &ts, PPS_CAPTURECLEAR, data);
72 78
73 return IRQ_HANDLED;79 return IRQ_HANDLED;
74}80}
75 81
82/* This function will only be called when an ECHO GPIO is defined */
83static void pps_gpio_echo(struct pps_device *pps, int event, void *data)
84{
85 /* add_timer() needs to write into info->echo_timer */
86 struct pps_gpio_device_data *info = data;
87
88 switch (event) {
89 case PPS_CAPTUREASSERT:
90 if (pps->params.mode & PPS_ECHOASSERT)
91 gpiod_set_value(info->echo_pin, 1);
92 break;
93
94 case PPS_CAPTURECLEAR:
95 if (pps->params.mode & PPS_ECHOCLEAR)
96 gpiod_set_value(info->echo_pin, 1);
97 break;
98 }
99
100 /* fire the timer */
101 if (info->pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) {
102 info->echo_timer.expires = jiffies + info->echo_timeout;
103 add_timer(&info->echo_timer);
104 }
105}
106
107/* Timer callback to reset the echo pin to the inactive state */
108static void pps_gpio_echo_timer_callback(struct timer_list *t)
109{
110 const struct pps_gpio_device_data *info;
111
112 info = from_timer(info, t, echo_timer);
113
114 gpiod_set_value(info->echo_pin, 0);
115}
116
76static int pps_gpio_setup(struct platform_device *pdev)117static int pps_gpio_setup(struct platform_device *pdev)
77{118{
78 struct pps_gpio_device_data *data = platform_get_drvdata(pdev);119 struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
79 struct device_node *np = pdev->dev.of_node;120 struct device_node *np = pdev->dev.of_node;
121 int ret;
122 u32 value;
80 123
81 data->gpio_pin = devm_gpiod_get(&pdev->dev,124 data->gpio_pin = devm_gpiod_get(&pdev->dev,
82 NULL, /* request "gpios" */125 NULL, /* request "gpios" */
@@ -87,6 +130,33 @@ static int pps_gpio_setup(struct platform_device *pdev) · 4 unmodified lines
87 return PTR_ERR(data->gpio_pin);130 return PTR_ERR(data->gpio_pin);
88 }131 }
89 132
133 data->echo_pin = devm_gpiod_get_optional(&pdev->dev,
134 "echo",
135 GPIOD_OUT_LOW);
136 if (data->echo_pin) {
137 if (IS_ERR(data->echo_pin)) {
138 dev_err(&pdev->dev, "failed to request ECHO GPIO\n");
139 return PTR_ERR(data->echo_pin);
140 }
141
142 ret = of_property_read_u32(np,
143 "echo-active-ms",
144 &value);
145 if (ret) {
146 dev_err(&pdev->dev,
147 "failed to get echo-active-ms from OF\n");
148 return ret;
149 }
150 data->echo_active_ms = value;
151 /* sanity check on echo_active_ms */
152 if (!data->echo_active_ms || data->echo_active_ms > 999) {
153 dev_err(&pdev->dev,
154 "echo-active-ms: %u - bad value from OF\n",
155 data->echo_active_ms);
156 return -EINVAL;
157 }
158 }
159
90 if (of_property_read_bool(np, "assert-falling-edge"))160 if (of_property_read_bool(np, "assert-falling-edge"))
91 data->assert_falling_edge = true;161 data->assert_falling_edge = true;
92 return 0;162 return 0;
@@ -122,9 +192,11 @@ static int pps_gpio_probe(struct platform_device *pdev) · 29 unmodified lines
122 /* GPIO setup */192 /* GPIO setup */
123 if (pdata) {193 if (pdata) {
124 data->gpio_pin = pdata->gpio_pin;194 data->gpio_pin = pdata->gpio_pin;
195 data->echo_pin = pdata->echo_pin;
125 196
126 data->assert_falling_edge = pdata->assert_falling_edge;197 data->assert_falling_edge = pdata->assert_falling_edge;
127 data->capture_clear = pdata->capture_clear;198 data->capture_clear = pdata->capture_clear;
199 data->echo_active_ms = pdata->echo_active_ms;
128 } else {200 } else {
129 ret = pps_gpio_setup(pdev);201 ret = pps_gpio_setup(pdev);
130 if (ret)202 if (ret)
@@ -148,6 +220,11 @@ static int pps_gpio_probe(struct platform_device *pdev) · 17 unmodified lines
148 data->info.owner = THIS_MODULE;220 data->info.owner = THIS_MODULE;
149 snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",221 snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
150 pdev->name, pdev->id);222 pdev->name, pdev->id);
223 if (data->echo_pin) {
224 data->info.echo = pps_gpio_echo;
225 data->echo_timeout = msecs_to_jiffies(data->echo_active_ms);
226 timer_setup(&data->echo_timer, pps_gpio_echo_timer_callback, 0);
227 }
151 228
152 /* register PPS source */229 /* register PPS source */
153 pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;230 pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
@@ -180,6 +257,11 @@ static int pps_gpio_remove(struct platform_device *pdev) · 26 unmodified lines
180 struct pps_gpio_device_data *data = platform_get_drvdata(pdev);257 struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
181 258
182 pps_unregister_source(data->pps);259 pps_unregister_source(data->pps);
260 if (data->echo_pin) {
261 del_timer_sync(&data->echo_timer);
262 /* reset echo pin in any case */
263 gpiod_set_value(data->echo_pin, 0);
264 }
183 dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);265 dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
184 return 0;266 return 0;
185}267}
@@ -204,4 +286,4 @@ MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>"); · 18 unmodified lines
204MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");286MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
205MODULE_DESCRIPTION("Use GPIO pin as PPS source");287MODULE_DESCRIPTION("Use GPIO pin as PPS source");
206MODULE_LICENSE("GPL");288MODULE_LICENSE("GPL");
207MODULE_VERSION("1.1.0");289MODULE_VERSION("1.2.0");
include/linux/pps-gpio.h+2−0
@@ -24,8 +24,10 @@ · 23 unmodified lines
24 24
25struct pps_gpio_platform_data {25struct pps_gpio_platform_data {
26 struct gpio_desc *gpio_pin;26 struct gpio_desc *gpio_pin;
27 struct gpio_desc *echo_pin;
27 bool assert_falling_edge;28 bool assert_falling_edge;
28 bool capture_clear;29 bool capture_clear;
30 unsigned int echo_active_ms;
29};31};
30 32
31#endif /* _PPS_GPIO_H */33#endif /* _PPS_GPIO_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t