Skip to content
Snippets Groups Projects

Linux GPIO PPS echo patch

  • Clone with SSH
  • Clone with HTTPS
  • Embed
  • Share
    The snippet can be accessed without any authentication.
    Authored by Lukas Senger
    ppsecho.patch 5.39 KiB
    diff --git a/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
    index 9ee4bdfa6167..bc299f581868 100644
    --- a/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
    +++ b/arch/arm/boot/dts/overlays/pps-gpio-overlay.dts
    @@ -11,6 +11,7 @@
     				pinctrl-names = "default";
     				pinctrl-0 = <&pps_pins>;
     				gpios = <&gpio 18 0>;
    +				echo-gpios = <&gpio 17 0>;
     				status = "okay";
     			};
     		};
    @@ -20,9 +21,9 @@
     		target = <&gpio>;
     		__overlay__ {
     			pps_pins: pps_pins@12 {
    -				brcm,pins =     <18>;
    -				brcm,function = <0>;    // in
    -				brcm,pull =     <0>;    // off
    +				brcm,pins =     <18 17>;
    +				brcm,function = <0 1>;    // in  out
    +				brcm,pull =     <0 0>;    // off off
     			};
     		};
     	};
    @@ -32,6 +33,8 @@
     			  <&pps>,"reg:0",
     			  <&pps_pins>,"brcm,pins:0",
     			  <&pps_pins>,"reg:0";
    +		echopin = <&pps>,"echo-gpios:4",
    +			  <&pps_pins>,"brcm,pins:4";
     		assert_falling_edge = <&pps>,"assert-falling-edge?";
     	};
     };
    diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
    index 333ad7d5b45b..08f2ebdab5e5 100644
    --- a/drivers/pps/clients/pps-gpio.c
    +++ b/drivers/pps/clients/pps-gpio.c
    @@ -35,6 +35,8 @@
     #include <linux/list.h>
     #include <linux/of_device.h>
     #include <linux/of_gpio.h>
    +#include <linux/delay.h>
    +
     
     /* Info for each registered platform device */
     struct pps_gpio_device_data {
    @@ -44,6 +46,7 @@ struct pps_gpio_device_data {
     	bool assert_falling_edge;
     	bool capture_clear;
     	unsigned int gpio_pin;
    +	unsigned int echo_pin;
     };
     
     /*
    @@ -64,15 +67,46 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
     	rising_edge = gpio_get_value(info->gpio_pin);
     	if ((rising_edge && !info->assert_falling_edge) ||
     			(!rising_edge && info->assert_falling_edge))
    -		pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
    +		pps_event(info->pps, &ts, PPS_CAPTUREASSERT, data);
     	else if (info->capture_clear &&
     			((rising_edge && info->assert_falling_edge) ||
     			 (!rising_edge && !info->assert_falling_edge)))
    -		pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
    +		pps_event(info->pps, &ts, PPS_CAPTURECLEAR, data);
    +
    +	if (info->pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))
    +		return IRQ_WAKE_THREAD;
    +	return IRQ_HANDLED;
    +}
    +
    +static void pps_gpio_echo(struct pps_device *pps, int event, void *data)
    +{
    +	const struct pps_gpio_device_data *info;
    +
    +	info = data;
    +
    +	if (event == PPS_CAPTUREASSERT && (pps->params.mode & PPS_ECHOASSERT))
    +		gpio_set_value(info->echo_pin, 1);
    +	else if (event == PPS_CAPTURECLEAR && (pps->params.mode & PPS_ECHOCLEAR))
    +		gpio_set_value(info->echo_pin, 1);
    +}
    +
    +
    +/* If we sent an echo pulse, we set the output pin back to low. This results in
    + * an echo pulse of roughly 100ms length.
    + */
    +static irqreturn_t pps_gpio_irq_threaded(int irq, void *data)
    +{
    +	const struct pps_gpio_device_data *info;
    +
    +	info = data;
    +
    +	msleep(100);
    +	gpio_set_value(info->echo_pin, 0);
     
     	return IRQ_HANDLED;
     }
     
    +
     static unsigned long
     get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
     {
    @@ -104,17 +138,24 @@ static int pps_gpio_probe(struct platform_device *pdev)
     
     	if (pdata) {
     		data->gpio_pin = pdata->gpio_pin;
    +		data->echo_pin = pdata->echo_pin;
     		gpio_label = pdata->gpio_label;
     
     		data->assert_falling_edge = pdata->assert_falling_edge;
     		data->capture_clear = pdata->capture_clear;
     	} else {
    -		ret = of_get_gpio(np, 0);
    +		ret = of_get_named_gpio(np, "gpios", 0);
     		if (ret < 0) {
     			dev_err(&pdev->dev, "failed to get GPIO from device tree\n");
     			return ret;
     		}
     		data->gpio_pin = ret;
    +		ret = of_get_named_gpio(np, "echo-gpios", 0);
    +		if (ret < 0) {
    +			dev_err(&pdev->dev, "failed to get second GPIO from device tree\n");
    +			return ret;
    +		}
    +		data->echo_pin = ret;
     		gpio_label = PPS_GPIO_NAME;
     
     		if (of_get_property(np, "assert-falling-edge", NULL))
    @@ -131,7 +172,20 @@ static int pps_gpio_probe(struct platform_device *pdev)
     
     	ret = gpio_direction_input(data->gpio_pin);
     	if (ret) {
    -		dev_err(&pdev->dev, "failed to set pin direction\n");
    +		dev_err(&pdev->dev, "failed to set pin as input\n");
    +		return -EINVAL;
    +	}
    +
    +	ret = devm_gpio_request(&pdev->dev, data->echo_pin, gpio_label);
    +	if (ret) {
    +		dev_err(&pdev->dev, "failed to request GPIO %u\n",
    +			data->echo_pin);
    +		return ret;
    +	}
    +
    +	ret = gpio_direction_output(data->echo_pin, 0);
    +	if (ret) {
    +		dev_err(&pdev->dev, "failed to set pin as output\n");
     		return -EINVAL;
     	}
     
    @@ -152,6 +206,7 @@ static int pps_gpio_probe(struct platform_device *pdev)
     	data->info.owner = THIS_MODULE;
     	snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
     		 pdev->name, pdev->id);
    +	data->info.echo = pps_gpio_echo;
     
     	/* register PPS source */
     	pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
    @@ -165,7 +220,8 @@ static int pps_gpio_probe(struct platform_device *pdev)
     	}
     
     	/* register IRQ interrupt handler */
    -	ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
    +	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
    +			pps_gpio_irq_handler, pps_gpio_irq_threaded,
     			get_irqf_trigger_flags(data), data->info.name, data);
     	if (ret) {
     		pps_unregister_source(data->pps);
    diff --git a/include/linux/pps-gpio.h b/include/linux/pps-gpio.h
    index 0035abe41b9a..055edd43012a 100644
    --- a/include/linux/pps-gpio.h
    +++ b/include/linux/pps-gpio.h
    @@ -26,6 +26,7 @@ struct pps_gpio_platform_data {
     	bool assert_falling_edge;
     	bool capture_clear;
     	unsigned int gpio_pin;
    +	unsigned int echo_pin;
     	const char *gpio_label;
     };
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment