aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-msm.txt26
-rw-r--r--arch/arm/boot/dts/msm8660-surf.dts11
-rw-r--r--arch/arm/boot/dts/msm8960-cdp.dts11
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/gpio-msm-v2.c190
5 files changed, 162 insertions, 78 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-msm.txt b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
new file mode 100644
index 000000000000..ac20e68a004e
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-msm.txt
@@ -0,0 +1,26 @@
1MSM GPIO controller bindings
2
3Required properties:
4- compatible:
5 - "qcom,msm-gpio" for MSM controllers
6- #gpio-cells : Should be two.
7 - first cell is the pin number
8 - second cell is used to specify optional parameters (unused)
9- gpio-controller : Marks the device node as a GPIO controller.
10- #interrupt-cells : Should be 2.
11- interrupt-controller: Mark the device node as an interrupt controller
12- interrupts : Specify the TLMM summary interrupt number
13- ngpio : Specify the number of MSM GPIOs
14
15Example:
16
17 msmgpio: gpio@fd510000 {
18 compatible = "qcom,msm-gpio";
19 gpio-controller;
20 #gpio-cells = <2>;
21 interrupt-controller;
22 #interrupt-cells = <2>;
23 reg = <0xfd510000 0x4000>;
24 interrupts = <0 208 0>;
25 ngpio = <150>;
26 };
diff --git a/arch/arm/boot/dts/msm8660-surf.dts b/arch/arm/boot/dts/msm8660-surf.dts
index 9bf49b3826ea..8931906b9263 100644
--- a/arch/arm/boot/dts/msm8660-surf.dts
+++ b/arch/arm/boot/dts/msm8660-surf.dts
@@ -26,6 +26,17 @@
26 cpu-offset = <0x40000>; 26 cpu-offset = <0x40000>;
27 }; 27 };
28 28
29 msmgpio: gpio@800000 {
30 compatible = "qcom,msm-gpio";
31 reg = <0x00800000 0x1000>;
32 gpio-controller;
33 #gpio-cells = <2>;
34 ngpio = <173>;
35 interrupts = <0 32 0x4>;
36 interrupt-controller;
37 #interrupt-cells = <2>;
38 };
39
29 serial@19c400000 { 40 serial@19c400000 {
30 compatible = "qcom,msm-hsuart", "qcom,msm-uart"; 41 compatible = "qcom,msm-hsuart", "qcom,msm-uart";
31 reg = <0x19c40000 0x1000>, 42 reg = <0x19c40000 0x1000>,
diff --git a/arch/arm/boot/dts/msm8960-cdp.dts b/arch/arm/boot/dts/msm8960-cdp.dts
index 2e4d87a125d6..52fe25328883 100644
--- a/arch/arm/boot/dts/msm8960-cdp.dts
+++ b/arch/arm/boot/dts/msm8960-cdp.dts
@@ -26,6 +26,17 @@
26 cpu-offset = <0x80000>; 26 cpu-offset = <0x80000>;
27 }; 27 };
28 28
29 msmgpio: gpio@fd510000 {
30 compatible = "qcom,msm-gpio";
31 gpio-controller;
32 #gpio-cells = <2>;
33 ngpio = <150>;
34 interrupts = <0 32 0x4>;
35 interrupt-controller;
36 #interrupt-cells = <2>;
37 reg = <0xfd510000 0x4000>;
38 };
39
29 serial@19c400000 { 40 serial@19c400000 {
30 compatible = "qcom,msm-hsuart", "qcom,msm-uart"; 41 compatible = "qcom,msm-hsuart", "qcom,msm-uart";
31 reg = <0x16440000 0x1000>, 42 reg = <0x16440000 0x1000>,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 87d567089f13..6d61a12b68ff 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -165,7 +165,7 @@ config GPIO_MSM_V1
165 165
166config GPIO_MSM_V2 166config GPIO_MSM_V2
167 tristate "Qualcomm MSM GPIO v2" 167 tristate "Qualcomm MSM GPIO v2"
168 depends on GPIOLIB && ARCH_MSM 168 depends on GPIOLIB && OF && ARCH_MSM
169 help 169 help
170 Say yes here to support the GPIO interface on ARM v7 based 170 Say yes here to support the GPIO interface on ARM v7 based
171 Qualcomm MSM chips. Most of the pins on the MSM can be 171 Qualcomm MSM chips. Most of the pins on the MSM can be
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");