aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pps
diff options
context:
space:
mode:
authorJan Luebbe <jlu@pengutronix.de>2013-07-03 18:09:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-03 19:08:06 -0400
commitc5dbcf8b70b50b1f6ef4850f61d79204ea46d761 (patch)
tree6c161151b513d5543d4c635cf91d5c8cd77efbe2 /drivers/pps
parent05212be363363efbc003d4fa1eaf8e48dfbe425a (diff)
pps-gpio: add device-tree binding and support
Instead of allocating a struct pps_gpio_platform_data in the DT case, store the necessary information in struct pps_gpio_device_data itself. This avoids an additional allocation and the ifdef. It also gets rid of some indirection. Also use dev_err instead of pr_err in the changed code. Signed-off-by: Jan Luebbe <jlu@pengutronix.de> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Rodolfo Giometti <giometti@enneenne.com> Cc: Grant Likely <grant.likely@linaro.org> Cc: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/pps')
-rw-r--r--drivers/pps/clients/pps-gpio.c127
1 files changed, 73 insertions, 54 deletions
diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c
index 5bd3bf093b54..eae0eda9ff39 100644
--- a/drivers/pps/clients/pps-gpio.c
+++ b/drivers/pps/clients/pps-gpio.c
@@ -33,13 +33,17 @@
33#include <linux/pps-gpio.h> 33#include <linux/pps-gpio.h>
34#include <linux/gpio.h> 34#include <linux/gpio.h>
35#include <linux/list.h> 35#include <linux/list.h>
36#include <linux/of_device.h>
37#include <linux/of_gpio.h>
36 38
37/* Info for each registered platform device */ 39/* Info for each registered platform device */
38struct pps_gpio_device_data { 40struct pps_gpio_device_data {
39 int irq; /* IRQ used as PPS source */ 41 int irq; /* IRQ used as PPS source */
40 struct pps_device *pps; /* PPS source device */ 42 struct pps_device *pps; /* PPS source device */
41 struct pps_source_info info; /* PPS source information */ 43 struct pps_source_info info; /* PPS source information */
42 const struct pps_gpio_platform_data *pdata; 44 bool assert_falling_edge;
45 bool capture_clear;
46 unsigned int gpio_pin;
43}; 47};
44 48
45/* 49/*
@@ -57,45 +61,25 @@ static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
57 61
58 info = data; 62 info = data;
59 63
60 rising_edge = gpio_get_value(info->pdata->gpio_pin); 64 rising_edge = gpio_get_value(info->gpio_pin);
61 if ((rising_edge && !info->pdata->assert_falling_edge) || 65 if ((rising_edge && !info->assert_falling_edge) ||
62 (!rising_edge && info->pdata->assert_falling_edge)) 66 (!rising_edge && info->assert_falling_edge))
63 pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL); 67 pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
64 else if (info->pdata->capture_clear && 68 else if (info->capture_clear &&
65 ((rising_edge && info->pdata->assert_falling_edge) || 69 ((rising_edge && info->assert_falling_edge) ||
66 (!rising_edge && !info->pdata->assert_falling_edge))) 70 (!rising_edge && !info->assert_falling_edge)))
67 pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL); 71 pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
68 72
69 return IRQ_HANDLED; 73 return IRQ_HANDLED;
70} 74}
71 75
72static int pps_gpio_setup(struct platform_device *pdev)
73{
74 int ret;
75 const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
76
77 ret = devm_gpio_request(&pdev->dev, pdata->gpio_pin, pdata->gpio_label);
78 if (ret) {
79 pr_warning("failed to request GPIO %u\n", pdata->gpio_pin);
80 return -EINVAL;
81 }
82
83 ret = gpio_direction_input(pdata->gpio_pin);
84 if (ret) {
85 pr_warning("failed to set pin direction\n");
86 return -EINVAL;
87 }
88
89 return 0;
90}
91
92static unsigned long 76static unsigned long
93get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata) 77get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
94{ 78{
95 unsigned long flags = pdata->assert_falling_edge ? 79 unsigned long flags = data->assert_falling_edge ?
96 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; 80 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
97 81
98 if (pdata->capture_clear) { 82 if (data->capture_clear) {
99 flags |= ((flags & IRQF_TRIGGER_RISING) ? 83 flags |= ((flags & IRQF_TRIGGER_RISING) ?
100 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING); 84 IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
101 } 85 }
@@ -106,34 +90,63 @@ get_irqf_trigger_flags(const struct pps_gpio_platform_data *pdata)
106static int pps_gpio_probe(struct platform_device *pdev) 90static int pps_gpio_probe(struct platform_device *pdev)
107{ 91{
108 struct pps_gpio_device_data *data; 92 struct pps_gpio_device_data *data;
109 int irq; 93 const char *gpio_label;
110 int ret; 94 int ret;
111 int pps_default_params; 95 int pps_default_params;
112 const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data; 96 const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
97 struct device_node *np = pdev->dev.of_node;
98
99 /* allocate space for device info */
100 data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
101 GFP_KERNEL);
102 if (!data)
103 return -ENOMEM;
113 104
105 if (pdata) {
106 data->gpio_pin = pdata->gpio_pin;
107 gpio_label = pdata->gpio_label;
108
109 data->assert_falling_edge = pdata->assert_falling_edge;
110 data->capture_clear = pdata->capture_clear;
111 } else {
112 ret = of_get_gpio(np, 0);
113 if (ret < 0) {
114 dev_err(&pdev->dev, "failed to get GPIO from device tree\n");
115 return ret;
116 }
117 data->gpio_pin = ret;
118 gpio_label = PPS_GPIO_NAME;
119
120 if (of_get_property(np, "assert-falling-edge", NULL))
121 data->assert_falling_edge = true;
122 }
114 123
115 /* GPIO setup */ 124 /* GPIO setup */
116 ret = pps_gpio_setup(pdev); 125 ret = devm_gpio_request(&pdev->dev, data->gpio_pin, gpio_label);
117 if (ret) 126 if (ret) {
127 dev_err(&pdev->dev, "failed to request GPIO %u\n",
128 data->gpio_pin);
129 return ret;
130 }
131
132 ret = gpio_direction_input(data->gpio_pin);
133 if (ret) {
134 dev_err(&pdev->dev, "failed to set pin direction\n");
118 return -EINVAL; 135 return -EINVAL;
136 }
119 137
120 /* IRQ setup */ 138 /* IRQ setup */
121 irq = gpio_to_irq(pdata->gpio_pin); 139 ret = gpio_to_irq(data->gpio_pin);
122 if (irq < 0) { 140 if (ret < 0) {
123 pr_err("failed to map GPIO to IRQ: %d\n", irq); 141 dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
124 return -EINVAL; 142 return -EINVAL;
125 } 143 }
126 144 data->irq = ret;
127 /* allocate space for device info */
128 data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
129 GFP_KERNEL);
130 if (data == NULL)
131 return -ENOMEM;
132 145
133 /* initialize PPS specific parts of the bookkeeping data structure. */ 146 /* initialize PPS specific parts of the bookkeeping data structure. */
134 data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | 147 data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
135 PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC; 148 PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
136 if (pdata->capture_clear) 149 if (data->capture_clear)
137 data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR | 150 data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
138 PPS_ECHOCLEAR; 151 PPS_ECHOCLEAR;
139 data->info.owner = THIS_MODULE; 152 data->info.owner = THIS_MODULE;
@@ -142,28 +155,27 @@ static int pps_gpio_probe(struct platform_device *pdev)
142 155
143 /* register PPS source */ 156 /* register PPS source */
144 pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT; 157 pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
145 if (pdata->capture_clear) 158 if (data->capture_clear)
146 pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR; 159 pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
147 data->pps = pps_register_source(&data->info, pps_default_params); 160 data->pps = pps_register_source(&data->info, pps_default_params);
148 if (data->pps == NULL) { 161 if (data->pps == NULL) {
149 pr_err("failed to register IRQ %d as PPS source\n", irq); 162 dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n",
163 data->irq);
150 return -EINVAL; 164 return -EINVAL;
151 } 165 }
152 166
153 data->irq = irq;
154 data->pdata = pdata;
155
156 /* register IRQ interrupt handler */ 167 /* register IRQ interrupt handler */
157 ret = devm_request_irq(&pdev->dev, irq, pps_gpio_irq_handler, 168 ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
158 get_irqf_trigger_flags(pdata), data->info.name, data); 169 get_irqf_trigger_flags(data), data->info.name, data);
159 if (ret) { 170 if (ret) {
160 pps_unregister_source(data->pps); 171 pps_unregister_source(data->pps);
161 pr_err("failed to acquire IRQ %d\n", irq); 172 dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq);
162 return -EINVAL; 173 return -EINVAL;
163 } 174 }
164 175
165 platform_set_drvdata(pdev, data); 176 platform_set_drvdata(pdev, data);
166 dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n", irq); 177 dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
178 data->irq);
167 179
168 return 0; 180 return 0;
169} 181}
@@ -174,16 +186,23 @@ static int pps_gpio_remove(struct platform_device *pdev)
174 186
175 platform_set_drvdata(pdev, NULL); 187 platform_set_drvdata(pdev, NULL);
176 pps_unregister_source(data->pps); 188 pps_unregister_source(data->pps);
177 pr_info("removed IRQ %d as PPS source\n", data->irq); 189 dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
178 return 0; 190 return 0;
179} 191}
180 192
193static const struct of_device_id pps_gpio_dt_ids[] = {
194 { .compatible = "pps-gpio", },
195 { /* sentinel */ }
196};
197MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
198
181static struct platform_driver pps_gpio_driver = { 199static struct platform_driver pps_gpio_driver = {
182 .probe = pps_gpio_probe, 200 .probe = pps_gpio_probe,
183 .remove = pps_gpio_remove, 201 .remove = pps_gpio_remove,
184 .driver = { 202 .driver = {
185 .name = PPS_GPIO_NAME, 203 .name = PPS_GPIO_NAME,
186 .owner = THIS_MODULE 204 .owner = THIS_MODULE,
205 .of_match_table = of_match_ptr(pps_gpio_dt_ids),
187 }, 206 },
188}; 207};
189 208