aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-msm-v2.c
diff options
context:
space:
mode:
authorRohit Vaswani <rvaswani@codeaurora.org>2013-06-10 18:50:21 -0400
committerDavid Brown <davidb@codeaurora.org>2013-06-12 17:50:12 -0400
commit43f68444bce70e360ff6ce3653a54e511625f651 (patch)
tree31a695accad61e88f5f584acca4d9abc0d708eea /drivers/gpio/gpio-msm-v2.c
parenteda9dcfa56f4864e0e4340f5af3f3e39f514b726 (diff)
gpio: msm: Add device tree and irqdomain support for gpio-msm-v2
This cleans up the gpio-msm-v2 driver of all the global define usage. The number of gpios are now defined in the device tree. This enables adding irqdomain support as well. Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org> Acked-by: Grant Likely <grant.likely@linaro.org> Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'drivers/gpio/gpio-msm-v2.c')
-rw-r--r--drivers/gpio/gpio-msm-v2.c190
1 files changed, 113 insertions, 77 deletions
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index 75cc8215f15b..f4491a497cc8 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -19,17 +19,21 @@
19 19
20#include <linux/bitmap.h> 20#include <linux/bitmap.h>
21#include <linux/bitops.h> 21#include <linux/bitops.h>
22#include <linux/err.h>
22#include <linux/gpio.h> 23#include <linux/gpio.h>
23#include <linux/init.h> 24#include <linux/init.h>
24#include <linux/interrupt.h> 25#include <linux/interrupt.h>
25#include <linux/io.h> 26#include <linux/io.h>
26#include <linux/irqchip/chained_irq.h> 27#include <linux/irqchip/chained_irq.h>
27#include <linux/irq.h> 28#include <linux/irq.h>
29#include <linux/irqdomain.h>
28#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/of_address.h>
29#include <linux/platform_device.h> 32#include <linux/platform_device.h>
30#include <linux/spinlock.h> 33#include <linux/spinlock.h>
34#include <linux/slab.h>
31 35
32#include <mach/msm_iomap.h> 36#define MAX_NR_GPIO 300
33 37
34/* Bits of interest in the GPIO_IN_OUT register. 38/* Bits of interest in the GPIO_IN_OUT register.
35 */ 39 */
@@ -76,13 +80,6 @@ enum {
76 TARGET_PROC_NONE = 7, 80 TARGET_PROC_NONE = 7,
77}; 81};
78 82
79
80#define GPIO_INTR_CFG_SU(gpio) (MSM_TLMM_BASE + 0x0400 + (0x04 * (gpio)))
81#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
82#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
83#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
84#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
85
86/** 83/**
87 * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure 84 * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
88 * 85 *
@@ -101,11 +98,27 @@ enum {
101 */ 98 */
102struct msm_gpio_dev { 99struct msm_gpio_dev {
103 struct gpio_chip gpio_chip; 100 struct gpio_chip gpio_chip;
104 DECLARE_BITMAP(enabled_irqs, NR_GPIO_IRQS); 101 DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
105 DECLARE_BITMAP(wake_irqs, NR_GPIO_IRQS); 102 DECLARE_BITMAP(wake_irqs, MAX_NR_GPIO);
106 DECLARE_BITMAP(dual_edge_irqs, NR_GPIO_IRQS); 103 DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
104 struct irq_domain *domain;
105 unsigned int summary_irq;
106 void __iomem *msm_tlmm_base;
107}; 107};
108 108
109struct msm_gpio_dev msm_gpio;
110
111#define GPIO_INTR_CFG_SU(gpio) (msm_gpio.msm_tlmm_base + 0x0400 + \
112 (0x04 * (gpio)))
113#define GPIO_CONFIG(gpio) (msm_gpio.msm_tlmm_base + 0x1000 + \
114 (0x10 * (gpio)))
115#define GPIO_IN_OUT(gpio) (msm_gpio.msm_tlmm_base + 0x1004 + \
116 (0x10 * (gpio)))
117#define GPIO_INTR_CFG(gpio) (msm_gpio.msm_tlmm_base + 0x1008 + \
118 (0x10 * (gpio)))
119#define GPIO_INTR_STATUS(gpio) (msm_gpio.msm_tlmm_base + 0x100c + \
120 (0x10 * (gpio)))
121
109static DEFINE_SPINLOCK(tlmm_lock); 122static DEFINE_SPINLOCK(tlmm_lock);
110 123
111static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip) 124static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
@@ -168,27 +181,19 @@ static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
168 181
169static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 182static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
170{ 183{
171 return MSM_GPIO_TO_INT(chip->base + offset); 184 struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
185 struct irq_domain *domain = g_dev->domain;
186
187 return irq_create_mapping(domain, offset);
172} 188}
173 189
174static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq) 190static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
175{ 191{
176 return irq - MSM_GPIO_TO_INT(chip->base); 192 struct irq_data *irq_data = irq_get_irq_data(irq);
193
194 return irq_data->hwirq;
177} 195}
178 196
179static struct msm_gpio_dev msm_gpio = {
180 .gpio_chip = {
181 .base = 0,
182 .ngpio = NR_GPIO_IRQS,
183 .direction_input = msm_gpio_direction_input,
184 .direction_output = msm_gpio_direction_output,
185 .get = msm_gpio_get,
186 .set = msm_gpio_set,
187 .to_irq = msm_gpio_to_irq,
188 .request = msm_gpio_request,
189 .free = msm_gpio_free,
190 },
191};
192 197
193/* For dual-edge interrupts in software, since the hardware has no 198/* For dual-edge interrupts in software, since the hardware has no
194 * such support: 199 * such support:
@@ -226,9 +231,9 @@ static void msm_gpio_update_dual_edge_pos(unsigned gpio)
226 if (intstat || val == val2) 231 if (intstat || val == val2)
227 return; 232 return;
228 } while (loop_limit-- > 0); 233 } while (loop_limit-- > 0);
229 pr_err("dual-edge irq failed to stabilize, " 234 pr_err("%s: dual-edge irq failed to stabilize, "
230 "interrupts dropped. %#08x != %#08x\n", 235 "interrupts dropped. %#08x != %#08x\n",
231 val, val2); 236 __func__, val, val2);
232} 237}
233 238
234static void msm_gpio_irq_ack(struct irq_data *d) 239static void msm_gpio_irq_ack(struct irq_data *d)
@@ -315,10 +320,10 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
315 320
316 chained_irq_enter(chip, desc); 321 chained_irq_enter(chip, desc);
317 322
318 for_each_set_bit(i, msm_gpio.enabled_irqs, NR_GPIO_IRQS) { 323 for_each_set_bit(i, msm_gpio.enabled_irqs, MAX_NR_GPIO) {
319 if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS)) 324 if (readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS))
320 generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip, 325 generic_handle_irq(irq_find_mapping(msm_gpio.domain,
321 i)); 326 i));
322 } 327 }
323 328
324 chained_irq_exit(chip, desc); 329 chained_irq_exit(chip, desc);
@@ -329,13 +334,13 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
329 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); 334 int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
330 335
331 if (on) { 336 if (on) {
332 if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS)) 337 if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO))
333 irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 1); 338 irq_set_irq_wake(msm_gpio.summary_irq, 1);
334 set_bit(gpio, msm_gpio.wake_irqs); 339 set_bit(gpio, msm_gpio.wake_irqs);
335 } else { 340 } else {
336 clear_bit(gpio, msm_gpio.wake_irqs); 341 clear_bit(gpio, msm_gpio.wake_irqs);
337 if (bitmap_empty(msm_gpio.wake_irqs, NR_GPIO_IRQS)) 342 if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO))
338 irq_set_irq_wake(TLMM_SCSS_SUMMARY_IRQ, 0); 343 irq_set_irq_wake(msm_gpio.summary_irq, 0);
339 } 344 }
340 345
341 return 0; 346 return 0;
@@ -350,30 +355,86 @@ static struct irq_chip msm_gpio_irq_chip = {
350 .irq_set_wake = msm_gpio_irq_set_wake, 355 .irq_set_wake = msm_gpio_irq_set_wake,
351}; 356};
352 357
353static int msm_gpio_probe(struct platform_device *dev) 358static struct lock_class_key msm_gpio_lock_class;
359
360static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq,
361 irq_hw_number_t hwirq)
362{
363 irq_set_lockdep_class(irq, &msm_gpio_lock_class);
364 irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
365 handle_level_irq);
366 set_irq_flags(irq, IRQF_VALID);
367
368 return 0;
369}
370
371static const struct irq_domain_ops msm_gpio_irq_domain_ops = {
372 .xlate = irq_domain_xlate_twocell,
373 .map = msm_gpio_irq_domain_map,
374};
375
376static int msm_gpio_probe(struct platform_device *pdev)
354{ 377{
355 int i, irq, ret; 378 int ret, ngpio;
379 struct resource *res;
380
381 if (!of_property_read_u32(pdev->dev.of_node, "ngpio", &ngpio)) {
382 dev_err(&pdev->dev, "%s: ngpio property missing\n", __func__);
383 return -EINVAL;
384 }
385
386 if (ngpio > MAX_NR_GPIO)
387 WARN(1, "ngpio exceeds the MAX_NR_GPIO. Increase MAX_NR_GPIO\n");
388
389 bitmap_zero(msm_gpio.enabled_irqs, MAX_NR_GPIO);
390 bitmap_zero(msm_gpio.wake_irqs, MAX_NR_GPIO);
391 bitmap_zero(msm_gpio.dual_edge_irqs, MAX_NR_GPIO);
392
393 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
394 msm_gpio.msm_tlmm_base = devm_ioremap_resource(&pdev->dev, res);
395 if (IS_ERR(msm_gpio.msm_tlmm_base))
396 return PTR_ERR(msm_gpio.msm_tlmm_base);
397
398 msm_gpio.gpio_chip.ngpio = ngpio;
399 msm_gpio.gpio_chip.label = pdev->name;
400 msm_gpio.gpio_chip.dev = &pdev->dev;
401 msm_gpio.gpio_chip.base = 0;
402 msm_gpio.gpio_chip.direction_input = msm_gpio_direction_input;
403 msm_gpio.gpio_chip.direction_output = msm_gpio_direction_output;
404 msm_gpio.gpio_chip.get = msm_gpio_get;
405 msm_gpio.gpio_chip.set = msm_gpio_set;
406 msm_gpio.gpio_chip.to_irq = msm_gpio_to_irq;
407 msm_gpio.gpio_chip.request = msm_gpio_request;
408 msm_gpio.gpio_chip.free = msm_gpio_free;
356 409
357 bitmap_zero(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
358 bitmap_zero(msm_gpio.wake_irqs, NR_GPIO_IRQS);
359 bitmap_zero(msm_gpio.dual_edge_irqs, NR_GPIO_IRQS);
360 msm_gpio.gpio_chip.label = dev->name;
361 ret = gpiochip_add(&msm_gpio.gpio_chip); 410 ret = gpiochip_add(&msm_gpio.gpio_chip);
362 if (ret < 0) 411 if (ret < 0) {
412 dev_err(&pdev->dev, "gpiochip_add failed with error %d\n", ret);
363 return ret; 413 return ret;
414 }
364 415
365 for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) { 416 msm_gpio.summary_irq = platform_get_irq(pdev, 0);
366 irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i); 417 if (msm_gpio.summary_irq < 0) {
367 irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, 418 dev_err(&pdev->dev, "No Summary irq defined for msmgpio\n");
368 handle_level_irq); 419 return msm_gpio.summary_irq;
369 set_irq_flags(irq, IRQF_VALID);
370 } 420 }
371 421
372 irq_set_chained_handler(TLMM_SCSS_SUMMARY_IRQ, 422 msm_gpio.domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
373 msm_summary_irq_handler); 423 &msm_gpio_irq_domain_ops,
424 &msm_gpio);
425 if (!msm_gpio.domain)
426 return -ENODEV;
427
428 irq_set_chained_handler(msm_gpio.summary_irq, msm_summary_irq_handler);
429
374 return 0; 430 return 0;
375} 431}
376 432
433static struct of_device_id msm_gpio_of_match[] = {
434 { .compatible = "qcom,msm-gpio", },
435 { },
436};
437
377static int msm_gpio_remove(struct platform_device *dev) 438static int msm_gpio_remove(struct platform_device *dev)
378{ 439{
379 int ret = gpiochip_remove(&msm_gpio.gpio_chip); 440 int ret = gpiochip_remove(&msm_gpio.gpio_chip);
@@ -381,7 +442,7 @@ static int msm_gpio_remove(struct platform_device *dev)
381 if (ret < 0) 442 if (ret < 0)
382 return ret; 443 return ret;
383 444
384 irq_set_handler(TLMM_SCSS_SUMMARY_IRQ, NULL); 445 irq_set_handler(msm_gpio.summary_irq, NULL);
385 446
386 return 0; 447 return 0;
387} 448}
@@ -392,36 +453,11 @@ static struct platform_driver msm_gpio_driver = {
392 .driver = { 453 .driver = {
393 .name = "msmgpio", 454 .name = "msmgpio",
394 .owner = THIS_MODULE, 455 .owner = THIS_MODULE,
456 .of_match_table = msm_gpio_of_match,
395 }, 457 },
396}; 458};
397 459
398static struct platform_device msm_device_gpio = { 460module_platform_driver(msm_gpio_driver)
399 .name = "msmgpio",
400 .id = -1,
401};
402
403static int __init msm_gpio_init(void)
404{
405 int rc;
406
407 rc = platform_driver_register(&msm_gpio_driver);
408 if (!rc) {
409 rc = platform_device_register(&msm_device_gpio);
410 if (rc)
411 platform_driver_unregister(&msm_gpio_driver);
412 }
413
414 return rc;
415}
416
417static void __exit msm_gpio_exit(void)
418{
419 platform_device_unregister(&msm_device_gpio);
420 platform_driver_unregister(&msm_gpio_driver);
421}
422
423postcore_initcall(msm_gpio_init);
424module_exit(msm_gpio_exit);
425 461
426MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>"); 462MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
427MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs"); 463MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");