root/drivers/pps/clients/pps-gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pps_gpio_irq_handler
  2. pps_gpio_echo
  3. pps_gpio_echo_timer_callback
  4. pps_gpio_setup
  5. get_irqf_trigger_flags
  6. pps_gpio_probe
  7. pps_gpio_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * pps-gpio.c -- PPS client driver using GPIO
   4  *
   5  * Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
   6  * Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
   7  */
   8 
   9 #define PPS_GPIO_NAME "pps-gpio"
  10 #define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
  11 
  12 #include <linux/init.h>
  13 #include <linux/kernel.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/module.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/slab.h>
  18 #include <linux/pps_kernel.h>
  19 #include <linux/pps-gpio.h>
  20 #include <linux/gpio/consumer.h>
  21 #include <linux/list.h>
  22 #include <linux/of_device.h>
  23 #include <linux/of_gpio.h>
  24 #include <linux/timer.h>
  25 #include <linux/jiffies.h>
  26 
  27 /* Info for each registered platform device */
  28 struct pps_gpio_device_data {
  29         int irq;                        /* IRQ used as PPS source */
  30         struct pps_device *pps;         /* PPS source device */
  31         struct pps_source_info info;    /* PPS source information */
  32         struct gpio_desc *gpio_pin;     /* GPIO port descriptors */
  33         struct gpio_desc *echo_pin;
  34         struct timer_list echo_timer;   /* timer to reset echo active state */
  35         bool assert_falling_edge;
  36         bool capture_clear;
  37         unsigned int echo_active_ms;    /* PPS echo active duration */
  38         unsigned long echo_timeout;     /* timer timeout value in jiffies */
  39 };
  40 
  41 /*
  42  * Report the PPS event
  43  */
  44 
  45 static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
  46 {
  47         const struct pps_gpio_device_data *info;
  48         struct pps_event_time ts;
  49         int rising_edge;
  50 
  51         /* Get the time stamp first */
  52         pps_get_ts(&ts);
  53 
  54         info = data;
  55 
  56         rising_edge = gpiod_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, data);
  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, data);
  64 
  65         return IRQ_HANDLED;
  66 }
  67 
  68 /* This function will only be called when an ECHO GPIO is defined */
  69 static void pps_gpio_echo(struct pps_device *pps, int event, void *data)
  70 {
  71         /* add_timer() needs to write into info->echo_timer */
  72         struct pps_gpio_device_data *info = data;
  73 
  74         switch (event) {
  75         case PPS_CAPTUREASSERT:
  76                 if (pps->params.mode & PPS_ECHOASSERT)
  77                         gpiod_set_value(info->echo_pin, 1);
  78                 break;
  79 
  80         case PPS_CAPTURECLEAR:
  81                 if (pps->params.mode & PPS_ECHOCLEAR)
  82                         gpiod_set_value(info->echo_pin, 1);
  83                 break;
  84         }
  85 
  86         /* fire the timer */
  87         if (info->pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) {
  88                 info->echo_timer.expires = jiffies + info->echo_timeout;
  89                 add_timer(&info->echo_timer);
  90         }
  91 }
  92 
  93 /* Timer callback to reset the echo pin to the inactive state */
  94 static void pps_gpio_echo_timer_callback(struct timer_list *t)
  95 {
  96         const struct pps_gpio_device_data *info;
  97 
  98         info = from_timer(info, t, echo_timer);
  99 
 100         gpiod_set_value(info->echo_pin, 0);
 101 }
 102 
 103 static int pps_gpio_setup(struct platform_device *pdev)
 104 {
 105         struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
 106         struct device_node *np = pdev->dev.of_node;
 107         int ret;
 108         u32 value;
 109 
 110         data->gpio_pin = devm_gpiod_get(&pdev->dev,
 111                 NULL,   /* request "gpios" */
 112                 GPIOD_IN);
 113         if (IS_ERR(data->gpio_pin)) {
 114                 dev_err(&pdev->dev,
 115                         "failed to request PPS GPIO\n");
 116                 return PTR_ERR(data->gpio_pin);
 117         }
 118 
 119         data->echo_pin = devm_gpiod_get_optional(&pdev->dev,
 120                         "echo",
 121                         GPIOD_OUT_LOW);
 122         if (data->echo_pin) {
 123                 if (IS_ERR(data->echo_pin)) {
 124                         dev_err(&pdev->dev, "failed to request ECHO GPIO\n");
 125                         return PTR_ERR(data->echo_pin);
 126                 }
 127 
 128                 ret = of_property_read_u32(np,
 129                         "echo-active-ms",
 130                         &value);
 131                 if (ret) {
 132                         dev_err(&pdev->dev,
 133                                 "failed to get echo-active-ms from OF\n");
 134                         return ret;
 135                 }
 136                 data->echo_active_ms = value;
 137                 /* sanity check on echo_active_ms */
 138                 if (!data->echo_active_ms || data->echo_active_ms > 999) {
 139                         dev_err(&pdev->dev,
 140                                 "echo-active-ms: %u - bad value from OF\n",
 141                                 data->echo_active_ms);
 142                         return -EINVAL;
 143                 }
 144         }
 145 
 146         if (of_property_read_bool(np, "assert-falling-edge"))
 147                 data->assert_falling_edge = true;
 148         return 0;
 149 }
 150 
 151 static unsigned long
 152 get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
 153 {
 154         unsigned long flags = data->assert_falling_edge ?
 155                 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
 156 
 157         if (data->capture_clear) {
 158                 flags |= ((flags & IRQF_TRIGGER_RISING) ?
 159                                 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
 160         }
 161 
 162         return flags;
 163 }
 164 
 165 static int pps_gpio_probe(struct platform_device *pdev)
 166 {
 167         struct pps_gpio_device_data *data;
 168         int ret;
 169         int pps_default_params;
 170         const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
 171 
 172         /* allocate space for device info */
 173         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 174         if (!data)
 175                 return -ENOMEM;
 176         platform_set_drvdata(pdev, data);
 177 
 178         /* GPIO setup */
 179         if (pdata) {
 180                 data->gpio_pin = pdata->gpio_pin;
 181                 data->echo_pin = pdata->echo_pin;
 182 
 183                 data->assert_falling_edge = pdata->assert_falling_edge;
 184                 data->capture_clear = pdata->capture_clear;
 185                 data->echo_active_ms = pdata->echo_active_ms;
 186         } else {
 187                 ret = pps_gpio_setup(pdev);
 188                 if (ret)
 189                         return -EINVAL;
 190         }
 191 
 192         /* IRQ setup */
 193         ret = gpiod_to_irq(data->gpio_pin);
 194         if (ret < 0) {
 195                 dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
 196                 return -EINVAL;
 197         }
 198         data->irq = ret;
 199 
 200         /* initialize PPS specific parts of the bookkeeping data structure. */
 201         data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
 202                 PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
 203         if (data->capture_clear)
 204                 data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
 205                         PPS_ECHOCLEAR;
 206         data->info.owner = THIS_MODULE;
 207         snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
 208                  pdev->name, pdev->id);
 209         if (data->echo_pin) {
 210                 data->info.echo = pps_gpio_echo;
 211                 data->echo_timeout = msecs_to_jiffies(data->echo_active_ms);
 212                 timer_setup(&data->echo_timer, pps_gpio_echo_timer_callback, 0);
 213         }
 214 
 215         /* register PPS source */
 216         pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
 217         if (data->capture_clear)
 218                 pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
 219         data->pps = pps_register_source(&data->info, pps_default_params);
 220         if (IS_ERR(data->pps)) {
 221                 dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n",
 222                         data->irq);
 223                 return PTR_ERR(data->pps);
 224         }
 225 
 226         /* register IRQ interrupt handler */
 227         ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
 228                         get_irqf_trigger_flags(data), data->info.name, data);
 229         if (ret) {
 230                 pps_unregister_source(data->pps);
 231                 dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq);
 232                 return -EINVAL;
 233         }
 234 
 235         dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
 236                  data->irq);
 237 
 238         return 0;
 239 }
 240 
 241 static int pps_gpio_remove(struct platform_device *pdev)
 242 {
 243         struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
 244 
 245         pps_unregister_source(data->pps);
 246         if (data->echo_pin) {
 247                 del_timer_sync(&data->echo_timer);
 248                 /* reset echo pin in any case */
 249                 gpiod_set_value(data->echo_pin, 0);
 250         }
 251         dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
 252         return 0;
 253 }
 254 
 255 static const struct of_device_id pps_gpio_dt_ids[] = {
 256         { .compatible = "pps-gpio", },
 257         { /* sentinel */ }
 258 };
 259 MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
 260 
 261 static struct platform_driver pps_gpio_driver = {
 262         .probe          = pps_gpio_probe,
 263         .remove         = pps_gpio_remove,
 264         .driver         = {
 265                 .name   = PPS_GPIO_NAME,
 266                 .of_match_table = pps_gpio_dt_ids,
 267         },
 268 };
 269 
 270 module_platform_driver(pps_gpio_driver);
 271 MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
 272 MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
 273 MODULE_DESCRIPTION("Use GPIO pin as PPS source");
 274 MODULE_LICENSE("GPL");
 275 MODULE_VERSION("1.2.0");

/* [<][>][^][v][top][bottom][index][help] */