diff options
Diffstat (limited to 'drivers/gpio/langwell_gpio.c')
-rw-r--r-- | drivers/gpio/langwell_gpio.c | 212 |
1 files changed, 180 insertions, 32 deletions
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 8383a8d7f994..644ba1255d3c 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c | |||
@@ -18,10 +18,12 @@ | |||
18 | /* Supports: | 18 | /* Supports: |
19 | * Moorestown platform Langwell chip. | 19 | * Moorestown platform Langwell chip. |
20 | * Medfield platform Penwell chip. | 20 | * Medfield platform Penwell chip. |
21 | * Whitney point. | ||
21 | */ | 22 | */ |
22 | 23 | ||
23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
24 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/platform_device.h> | ||
25 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
26 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
27 | #include <linux/stddef.h> | 29 | #include <linux/stddef.h> |
@@ -31,6 +33,7 @@ | |||
31 | #include <linux/io.h> | 33 | #include <linux/io.h> |
32 | #include <linux/gpio.h> | 34 | #include <linux/gpio.h> |
33 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/pm_runtime.h> | ||
34 | 37 | ||
35 | /* | 38 | /* |
36 | * Langwell chip has 64 pins and thus there are 2 32bit registers to control | 39 | * Langwell chip has 64 pins and thus there are 2 32bit registers to control |
@@ -61,6 +64,7 @@ struct lnw_gpio { | |||
61 | void *reg_base; | 64 | void *reg_base; |
62 | spinlock_t lock; | 65 | spinlock_t lock; |
63 | unsigned irq_base; | 66 | unsigned irq_base; |
67 | struct pci_dev *pdev; | ||
64 | }; | 68 | }; |
65 | 69 | ||
66 | static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, | 70 | static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, |
@@ -102,11 +106,18 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | |||
102 | u32 value; | 106 | u32 value; |
103 | unsigned long flags; | 107 | unsigned long flags; |
104 | 108 | ||
109 | if (lnw->pdev) | ||
110 | pm_runtime_get(&lnw->pdev->dev); | ||
111 | |||
105 | spin_lock_irqsave(&lnw->lock, flags); | 112 | spin_lock_irqsave(&lnw->lock, flags); |
106 | value = readl(gpdr); | 113 | value = readl(gpdr); |
107 | value &= ~BIT(offset % 32); | 114 | value &= ~BIT(offset % 32); |
108 | writel(value, gpdr); | 115 | writel(value, gpdr); |
109 | spin_unlock_irqrestore(&lnw->lock, flags); | 116 | spin_unlock_irqrestore(&lnw->lock, flags); |
117 | |||
118 | if (lnw->pdev) | ||
119 | pm_runtime_put(&lnw->pdev->dev); | ||
120 | |||
110 | return 0; | 121 | return 0; |
111 | } | 122 | } |
112 | 123 | ||
@@ -118,11 +129,19 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip, | |||
118 | unsigned long flags; | 129 | unsigned long flags; |
119 | 130 | ||
120 | lnw_gpio_set(chip, offset, value); | 131 | lnw_gpio_set(chip, offset, value); |
132 | |||
133 | if (lnw->pdev) | ||
134 | pm_runtime_get(&lnw->pdev->dev); | ||
135 | |||
121 | spin_lock_irqsave(&lnw->lock, flags); | 136 | spin_lock_irqsave(&lnw->lock, flags); |
122 | value = readl(gpdr); | 137 | value = readl(gpdr); |
123 | value |= BIT(offset % 32);; | 138 | value |= BIT(offset % 32); |
124 | writel(value, gpdr); | 139 | writel(value, gpdr); |
125 | spin_unlock_irqrestore(&lnw->lock, flags); | 140 | spin_unlock_irqrestore(&lnw->lock, flags); |
141 | |||
142 | if (lnw->pdev) | ||
143 | pm_runtime_put(&lnw->pdev->dev); | ||
144 | |||
126 | return 0; | 145 | return 0; |
127 | } | 146 | } |
128 | 147 | ||
@@ -132,10 +151,10 @@ static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | |||
132 | return lnw->irq_base + offset; | 151 | return lnw->irq_base + offset; |
133 | } | 152 | } |
134 | 153 | ||
135 | static int lnw_irq_type(unsigned irq, unsigned type) | 154 | static int lnw_irq_type(struct irq_data *d, unsigned type) |
136 | { | 155 | { |
137 | struct lnw_gpio *lnw = get_irq_chip_data(irq); | 156 | struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d); |
138 | u32 gpio = irq - lnw->irq_base; | 157 | u32 gpio = d->irq - lnw->irq_base; |
139 | unsigned long flags; | 158 | unsigned long flags; |
140 | u32 value; | 159 | u32 value; |
141 | void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); | 160 | void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER); |
@@ -143,6 +162,10 @@ static int lnw_irq_type(unsigned irq, unsigned type) | |||
143 | 162 | ||
144 | if (gpio >= lnw->chip.ngpio) | 163 | if (gpio >= lnw->chip.ngpio) |
145 | return -EINVAL; | 164 | return -EINVAL; |
165 | |||
166 | if (lnw->pdev) | ||
167 | pm_runtime_get(&lnw->pdev->dev); | ||
168 | |||
146 | spin_lock_irqsave(&lnw->lock, flags); | 169 | spin_lock_irqsave(&lnw->lock, flags); |
147 | if (type & IRQ_TYPE_EDGE_RISING) | 170 | if (type & IRQ_TYPE_EDGE_RISING) |
148 | value = readl(grer) | BIT(gpio % 32); | 171 | value = readl(grer) | BIT(gpio % 32); |
@@ -157,22 +180,25 @@ static int lnw_irq_type(unsigned irq, unsigned type) | |||
157 | writel(value, gfer); | 180 | writel(value, gfer); |
158 | spin_unlock_irqrestore(&lnw->lock, flags); | 181 | spin_unlock_irqrestore(&lnw->lock, flags); |
159 | 182 | ||
183 | if (lnw->pdev) | ||
184 | pm_runtime_put(&lnw->pdev->dev); | ||
185 | |||
160 | return 0; | 186 | return 0; |
161 | }; | 187 | } |
162 | 188 | ||
163 | static void lnw_irq_unmask(unsigned irq) | 189 | static void lnw_irq_unmask(struct irq_data *d) |
164 | { | 190 | { |
165 | }; | 191 | } |
166 | 192 | ||
167 | static void lnw_irq_mask(unsigned irq) | 193 | static void lnw_irq_mask(struct irq_data *d) |
168 | { | 194 | { |
169 | }; | 195 | } |
170 | 196 | ||
171 | static struct irq_chip lnw_irqchip = { | 197 | static struct irq_chip lnw_irqchip = { |
172 | .name = "LNW-GPIO", | 198 | .name = "LNW-GPIO", |
173 | .mask = lnw_irq_mask, | 199 | .irq_mask = lnw_irq_mask, |
174 | .unmask = lnw_irq_unmask, | 200 | .irq_unmask = lnw_irq_unmask, |
175 | .set_type = lnw_irq_type, | 201 | .irq_set_type = lnw_irq_type, |
176 | }; | 202 | }; |
177 | 203 | ||
178 | static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ | 204 | static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */ |
@@ -185,28 +211,63 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); | |||
185 | 211 | ||
186 | static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) | 212 | static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) |
187 | { | 213 | { |
188 | struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq); | 214 | struct irq_data *data = irq_desc_get_irq_data(desc); |
189 | u32 base, gpio; | 215 | struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); |
216 | struct irq_chip *chip = irq_data_get_irq_chip(data); | ||
217 | u32 base, gpio, mask; | ||
218 | unsigned long pending; | ||
190 | void __iomem *gedr; | 219 | void __iomem *gedr; |
191 | u32 gedr_v; | ||
192 | 220 | ||
193 | /* check GPIO controller to check which pin triggered the interrupt */ | 221 | /* check GPIO controller to check which pin triggered the interrupt */ |
194 | for (base = 0; base < lnw->chip.ngpio; base += 32) { | 222 | for (base = 0; base < lnw->chip.ngpio; base += 32) { |
195 | gedr = gpio_reg(&lnw->chip, base, GEDR); | 223 | gedr = gpio_reg(&lnw->chip, base, GEDR); |
196 | gedr_v = readl(gedr); | 224 | pending = readl(gedr); |
197 | if (!gedr_v) | 225 | while (pending) { |
198 | continue; | 226 | gpio = __ffs(pending); |
199 | for (gpio = base; gpio < base + 32; gpio++) | 227 | mask = BIT(gpio); |
200 | if (gedr_v & BIT(gpio % 32)) { | 228 | pending &= ~mask; |
201 | pr_debug("pin %d triggered\n", gpio); | 229 | /* Clear before handling so we can't lose an edge */ |
202 | generic_handle_irq(lnw->irq_base + gpio); | 230 | writel(mask, gedr); |
203 | } | 231 | generic_handle_irq(lnw->irq_base + base + gpio); |
204 | /* clear the edge detect status bit */ | 232 | } |
205 | writel(gedr_v, gedr); | ||
206 | } | 233 | } |
207 | desc->chip->eoi(irq); | 234 | |
235 | chip->irq_eoi(data); | ||
236 | } | ||
237 | |||
238 | #ifdef CONFIG_PM | ||
239 | static int lnw_gpio_runtime_resume(struct device *dev) | ||
240 | { | ||
241 | return 0; | ||
208 | } | 242 | } |
209 | 243 | ||
244 | static int lnw_gpio_runtime_suspend(struct device *dev) | ||
245 | { | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int lnw_gpio_runtime_idle(struct device *dev) | ||
250 | { | ||
251 | int err = pm_schedule_suspend(dev, 500); | ||
252 | |||
253 | if (!err) | ||
254 | return 0; | ||
255 | |||
256 | return -EBUSY; | ||
257 | } | ||
258 | |||
259 | #else | ||
260 | #define lnw_gpio_runtime_suspend NULL | ||
261 | #define lnw_gpio_runtime_resume NULL | ||
262 | #define lnw_gpio_runtime_idle NULL | ||
263 | #endif | ||
264 | |||
265 | static const struct dev_pm_ops lnw_gpio_pm_ops = { | ||
266 | .runtime_suspend = lnw_gpio_runtime_suspend, | ||
267 | .runtime_resume = lnw_gpio_runtime_resume, | ||
268 | .runtime_idle = lnw_gpio_runtime_idle, | ||
269 | }; | ||
270 | |||
210 | static int __devinit lnw_gpio_probe(struct pci_dev *pdev, | 271 | static int __devinit lnw_gpio_probe(struct pci_dev *pdev, |
211 | const struct pci_device_id *id) | 272 | const struct pci_device_id *id) |
212 | { | 273 | { |
@@ -266,21 +327,26 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, | |||
266 | lnw->chip.base = gpio_base; | 327 | lnw->chip.base = gpio_base; |
267 | lnw->chip.ngpio = id->driver_data; | 328 | lnw->chip.ngpio = id->driver_data; |
268 | lnw->chip.can_sleep = 0; | 329 | lnw->chip.can_sleep = 0; |
330 | lnw->pdev = pdev; | ||
269 | pci_set_drvdata(pdev, lnw); | 331 | pci_set_drvdata(pdev, lnw); |
270 | retval = gpiochip_add(&lnw->chip); | 332 | retval = gpiochip_add(&lnw->chip); |
271 | if (retval) { | 333 | if (retval) { |
272 | dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); | 334 | dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); |
273 | goto err5; | 335 | goto err5; |
274 | } | 336 | } |
275 | set_irq_data(pdev->irq, lnw); | 337 | irq_set_handler_data(pdev->irq, lnw); |
276 | set_irq_chained_handler(pdev->irq, lnw_irq_handler); | 338 | irq_set_chained_handler(pdev->irq, lnw_irq_handler); |
277 | for (i = 0; i < lnw->chip.ngpio; i++) { | 339 | for (i = 0; i < lnw->chip.ngpio; i++) { |
278 | set_irq_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, | 340 | irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, |
279 | handle_simple_irq, "demux"); | 341 | handle_simple_irq, "demux"); |
280 | set_irq_chip_data(i + lnw->irq_base, lnw); | 342 | irq_set_chip_data(i + lnw->irq_base, lnw); |
281 | } | 343 | } |
282 | 344 | ||
283 | spin_lock_init(&lnw->lock); | 345 | spin_lock_init(&lnw->lock); |
346 | |||
347 | pm_runtime_put_noidle(&pdev->dev); | ||
348 | pm_runtime_allow(&pdev->dev); | ||
349 | |||
284 | goto done; | 350 | goto done; |
285 | err5: | 351 | err5: |
286 | kfree(lnw); | 352 | kfree(lnw); |
@@ -298,11 +364,93 @@ static struct pci_driver lnw_gpio_driver = { | |||
298 | .name = "langwell_gpio", | 364 | .name = "langwell_gpio", |
299 | .id_table = lnw_gpio_ids, | 365 | .id_table = lnw_gpio_ids, |
300 | .probe = lnw_gpio_probe, | 366 | .probe = lnw_gpio_probe, |
367 | .driver = { | ||
368 | .pm = &lnw_gpio_pm_ops, | ||
369 | }, | ||
370 | }; | ||
371 | |||
372 | |||
373 | static int __devinit wp_gpio_probe(struct platform_device *pdev) | ||
374 | { | ||
375 | struct lnw_gpio *lnw; | ||
376 | struct gpio_chip *gc; | ||
377 | struct resource *rc; | ||
378 | int retval = 0; | ||
379 | |||
380 | rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
381 | if (!rc) | ||
382 | return -EINVAL; | ||
383 | |||
384 | lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL); | ||
385 | if (!lnw) { | ||
386 | dev_err(&pdev->dev, | ||
387 | "can't allocate whitneypoint_gpio chip data\n"); | ||
388 | return -ENOMEM; | ||
389 | } | ||
390 | lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc)); | ||
391 | if (lnw->reg_base == NULL) { | ||
392 | retval = -EINVAL; | ||
393 | goto err_kmalloc; | ||
394 | } | ||
395 | spin_lock_init(&lnw->lock); | ||
396 | gc = &lnw->chip; | ||
397 | gc->label = dev_name(&pdev->dev); | ||
398 | gc->owner = THIS_MODULE; | ||
399 | gc->direction_input = lnw_gpio_direction_input; | ||
400 | gc->direction_output = lnw_gpio_direction_output; | ||
401 | gc->get = lnw_gpio_get; | ||
402 | gc->set = lnw_gpio_set; | ||
403 | gc->to_irq = NULL; | ||
404 | gc->base = 0; | ||
405 | gc->ngpio = 64; | ||
406 | gc->can_sleep = 0; | ||
407 | retval = gpiochip_add(gc); | ||
408 | if (retval) { | ||
409 | dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n", | ||
410 | retval); | ||
411 | goto err_ioremap; | ||
412 | } | ||
413 | platform_set_drvdata(pdev, lnw); | ||
414 | return 0; | ||
415 | err_ioremap: | ||
416 | iounmap(lnw->reg_base); | ||
417 | err_kmalloc: | ||
418 | kfree(lnw); | ||
419 | return retval; | ||
420 | } | ||
421 | |||
422 | static int __devexit wp_gpio_remove(struct platform_device *pdev) | ||
423 | { | ||
424 | struct lnw_gpio *lnw = platform_get_drvdata(pdev); | ||
425 | int err; | ||
426 | err = gpiochip_remove(&lnw->chip); | ||
427 | if (err) | ||
428 | dev_err(&pdev->dev, "failed to remove gpio_chip.\n"); | ||
429 | iounmap(lnw->reg_base); | ||
430 | kfree(lnw); | ||
431 | platform_set_drvdata(pdev, NULL); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static struct platform_driver wp_gpio_driver = { | ||
436 | .probe = wp_gpio_probe, | ||
437 | .remove = __devexit_p(wp_gpio_remove), | ||
438 | .driver = { | ||
439 | .name = "wp_gpio", | ||
440 | .owner = THIS_MODULE, | ||
441 | }, | ||
301 | }; | 442 | }; |
302 | 443 | ||
303 | static int __init lnw_gpio_init(void) | 444 | static int __init lnw_gpio_init(void) |
304 | { | 445 | { |
305 | return pci_register_driver(&lnw_gpio_driver); | 446 | int ret; |
447 | ret = pci_register_driver(&lnw_gpio_driver); | ||
448 | if (ret < 0) | ||
449 | return ret; | ||
450 | ret = platform_driver_register(&wp_gpio_driver); | ||
451 | if (ret < 0) | ||
452 | pci_unregister_driver(&lnw_gpio_driver); | ||
453 | return ret; | ||
306 | } | 454 | } |
307 | 455 | ||
308 | device_initcall(lnw_gpio_init); | 456 | device_initcall(lnw_gpio_init); |