pps: descriptor-based gpio
[sfrench/cifs-2.6.git] / drivers / pps / clients / pps-gpio.c
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
23 #define PPS_GPIO_NAME "pps-gpio"
24 #define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
25
26 #include <linux/init.h>
27 #include <linux/kernel.h>
28 #include <linux/interrupt.h>
29 #include <linux/module.h>
30 #include <linux/platform_device.h>
31 #include <linux/slab.h>
32 #include <linux/pps_kernel.h>
33 #include <linux/pps-gpio.h>
34 #include <linux/gpio/consumer.h>
35 #include <linux/list.h>
36 #include <linux/of_device.h>
37 #include <linux/of_gpio.h>
38
39 /* Info for each registered platform device */
40 struct pps_gpio_device_data {
41         int irq;                        /* IRQ used as PPS source */
42         struct pps_device *pps;         /* PPS source device */
43         struct pps_source_info info;    /* PPS source information */
44         struct gpio_desc *gpio_pin;     /* GPIO port descriptors */
45         bool assert_falling_edge;
46         bool capture_clear;
47 };
48
49 /*
50  * Report the PPS event
51  */
52
53 static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
54 {
55         const struct pps_gpio_device_data *info;
56         struct pps_event_time ts;
57         int rising_edge;
58
59         /* Get the time stamp first */
60         pps_get_ts(&ts);
61
62         info = data;
63
64         rising_edge = gpiod_get_value(info->gpio_pin);
65         if ((rising_edge && !info->assert_falling_edge) ||
66                         (!rising_edge && info->assert_falling_edge))
67                 pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
68         else if (info->capture_clear &&
69                         ((rising_edge && info->assert_falling_edge) ||
70                         (!rising_edge && !info->assert_falling_edge)))
71                 pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
72
73         return IRQ_HANDLED;
74 }
75
76 static int pps_gpio_setup(struct platform_device *pdev)
77 {
78         struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
79         struct device_node *np = pdev->dev.of_node;
80
81         data->gpio_pin = devm_gpiod_get(&pdev->dev,
82                 NULL,   /* request "gpios" */
83                 GPIOD_IN);
84         if (IS_ERR(data->gpio_pin)) {
85                 dev_err(&pdev->dev,
86                         "failed to request PPS GPIO\n");
87                 return PTR_ERR(data->gpio_pin);
88         }
89
90         if (of_property_read_bool(np, "assert-falling-edge"))
91                 data->assert_falling_edge = true;
92         return 0;
93 }
94
95 static unsigned long
96 get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
97 {
98         unsigned long flags = data->assert_falling_edge ?
99                 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
100
101         if (data->capture_clear) {
102                 flags |= ((flags & IRQF_TRIGGER_RISING) ?
103                                 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
104         }
105
106         return flags;
107 }
108
109 static int pps_gpio_probe(struct platform_device *pdev)
110 {
111         struct pps_gpio_device_data *data;
112         int ret;
113         int pps_default_params;
114         const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
115
116         /* allocate space for device info */
117         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
118         if (!data)
119                 return -ENOMEM;
120         platform_set_drvdata(pdev, data);
121
122         /* GPIO setup */
123         if (pdata) {
124                 data->gpio_pin = pdata->gpio_pin;
125
126                 data->assert_falling_edge = pdata->assert_falling_edge;
127                 data->capture_clear = pdata->capture_clear;
128         } else {
129                 ret = pps_gpio_setup(pdev);
130                 if (ret)
131                         return -EINVAL;
132         }
133
134         /* IRQ setup */
135         ret = gpiod_to_irq(data->gpio_pin);
136         if (ret < 0) {
137                 dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
138                 return -EINVAL;
139         }
140         data->irq = ret;
141
142         /* initialize PPS specific parts of the bookkeeping data structure. */
143         data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
144                 PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
145         if (data->capture_clear)
146                 data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
147                         PPS_ECHOCLEAR;
148         data->info.owner = THIS_MODULE;
149         snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
150                  pdev->name, pdev->id);
151
152         /* register PPS source */
153         pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
154         if (data->capture_clear)
155                 pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
156         data->pps = pps_register_source(&data->info, pps_default_params);
157         if (IS_ERR(data->pps)) {
158                 dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n",
159                         data->irq);
160                 return PTR_ERR(data->pps);
161         }
162
163         /* register IRQ interrupt handler */
164         ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
165                         get_irqf_trigger_flags(data), data->info.name, data);
166         if (ret) {
167                 pps_unregister_source(data->pps);
168                 dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq);
169                 return -EINVAL;
170         }
171
172         dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
173                  data->irq);
174
175         return 0;
176 }
177
178 static int pps_gpio_remove(struct platform_device *pdev)
179 {
180         struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
181
182         pps_unregister_source(data->pps);
183         dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
184         return 0;
185 }
186
187 static const struct of_device_id pps_gpio_dt_ids[] = {
188         { .compatible = "pps-gpio", },
189         { /* sentinel */ }
190 };
191 MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
192
193 static struct platform_driver pps_gpio_driver = {
194         .probe          = pps_gpio_probe,
195         .remove         = pps_gpio_remove,
196         .driver         = {
197                 .name   = PPS_GPIO_NAME,
198                 .of_match_table = pps_gpio_dt_ids,
199         },
200 };
201
202 module_platform_driver(pps_gpio_driver);
203 MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
204 MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
205 MODULE_DESCRIPTION("Use GPIO pin as PPS source");
206 MODULE_LICENSE("GPL");
207 MODULE_VERSION("1.1.0");