diff options
-rw-r--r-- | arch/arm/boot/dts/qcom-apq8060-dragonboard.dts | 21 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom-apq8064.dtsi | 46 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom-mdm9615.dtsi | 9 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom-msm8660.dtsi | 47 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 2 | ||||
-rw-r--r-- | drivers/mfd/qcom-pm8xxx.c | 75 | ||||
-rw-r--r-- | drivers/pinctrl/qcom/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | 157 | ||||
-rw-r--r-- | include/linux/irq.h | 1 | ||||
-rw-r--r-- | include/linux/irqdomain.h | 5 | ||||
-rw-r--r-- | kernel/irq/chip.c | 11 | ||||
-rw-r--r-- | kernel/irq/irqdomain.c | 45 |
12 files changed, 236 insertions, 184 deletions
diff --git a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts index 497bb065eb9d..4e6c50d45cb2 100644 --- a/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom-apq8060-dragonboard.dts | |||
@@ -93,9 +93,8 @@ | |||
93 | vdd-supply = <&pm8058_l14>; // 2.85V | 93 | vdd-supply = <&pm8058_l14>; // 2.85V |
94 | aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>; | 94 | aset-gpios = <&pm8058_gpio 35 GPIO_ACTIVE_LOW>; |
95 | capella,aset-resistance-ohms = <100000>; | 95 | capella,aset-resistance-ohms = <100000>; |
96 | /* GPIO34 has interrupt 225 on the PM8058 */ | ||
97 | /* Trig on both edges - getting close or far away */ | 96 | /* Trig on both edges - getting close or far away */ |
98 | interrupts-extended = <&pm8058 225 IRQ_TYPE_EDGE_BOTH>; | 97 | interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>; |
99 | /* MPP05 analog input to the XOADC */ | 98 | /* MPP05 analog input to the XOADC */ |
100 | io-channels = <&xoadc 0x00 0x05>; | 99 | io-channels = <&xoadc 0x00 0x05>; |
101 | io-channel-names = "aout"; | 100 | io-channel-names = "aout"; |
@@ -515,9 +514,8 @@ | |||
515 | ak8975@c { | 514 | ak8975@c { |
516 | compatible = "asahi-kasei,ak8975"; | 515 | compatible = "asahi-kasei,ak8975"; |
517 | reg = <0x0c>; | 516 | reg = <0x0c>; |
518 | /* FIXME: GPIO33 has interrupt 224 on the PM8058 */ | 517 | interrupt-parent = <&pm8058_gpio>; |
519 | interrupt-parent = <&pm8058>; | 518 | interrupts = <33 IRQ_TYPE_EDGE_RISING>; |
520 | interrupts = <224 IRQ_TYPE_EDGE_RISING>; | ||
521 | pinctrl-names = "default"; | 519 | pinctrl-names = "default"; |
522 | pinctrl-0 = <&dragon_ak8975_gpios>; | 520 | pinctrl-0 = <&dragon_ak8975_gpios>; |
523 | vid-supply = <&pm8058_lvs0>; // 1.8V | 521 | vid-supply = <&pm8058_lvs0>; // 1.8V |
@@ -526,9 +524,8 @@ | |||
526 | bmp085@77 { | 524 | bmp085@77 { |
527 | compatible = "bosch,bmp085"; | 525 | compatible = "bosch,bmp085"; |
528 | reg = <0x77>; | 526 | reg = <0x77>; |
529 | /* FIXME: GPIO16 has interrupt 207 on the PM8058 */ | 527 | interrupt-parent = <&pm8058_gpio>; |
530 | interrupt-parent = <&pm8058>; | 528 | interrupts = <16 IRQ_TYPE_EDGE_RISING>; |
531 | interrupts = <207 IRQ_TYPE_EDGE_RISING>; | ||
532 | reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>; | 529 | reset-gpios = <&tlmm 86 GPIO_ACTIVE_LOW>; |
533 | pinctrl-names = "default"; | 530 | pinctrl-names = "default"; |
534 | pinctrl-0 = <&dragon_bmp085_gpios>; | 531 | pinctrl-0 = <&dragon_bmp085_gpios>; |
@@ -539,12 +536,11 @@ | |||
539 | compatible = "invensense,mpu3050"; | 536 | compatible = "invensense,mpu3050"; |
540 | reg = <0x68>; | 537 | reg = <0x68>; |
541 | /* | 538 | /* |
542 | * GPIO17 has interrupt 208 on the | 539 | * GPIO17 is pulled high by a 10k |
543 | * PM8058, it is pulled high by a 10k | ||
544 | * resistor to VLOGIC so needs to be | 540 | * resistor to VLOGIC so needs to be |
545 | * active low/falling edge. | 541 | * active low/falling edge. |
546 | */ | 542 | */ |
547 | interrupts-extended = <&pm8058 208 IRQ_TYPE_EDGE_FALLING>; | 543 | interrupts-extended = <&pm8058_gpio 17 IRQ_TYPE_EDGE_FALLING>; |
548 | pinctrl-names = "default"; | 544 | pinctrl-names = "default"; |
549 | pinctrl-0 = <&dragon_mpu3050_gpios>; | 545 | pinctrl-0 = <&dragon_mpu3050_gpios>; |
550 | vlogic-supply = <&pm8058_lvs0>; // 1.8V | 546 | vlogic-supply = <&pm8058_lvs0>; // 1.8V |
@@ -589,11 +585,10 @@ | |||
589 | compatible = "smsc,lan9221", "smsc,lan9115"; | 585 | compatible = "smsc,lan9221", "smsc,lan9115"; |
590 | reg = <2 0x0 0x100>; | 586 | reg = <2 0x0 0x100>; |
591 | /* | 587 | /* |
592 | * GPIO7 has interrupt 198 on the PM8058 | ||
593 | * The second interrupt is the PME interrupt | 588 | * The second interrupt is the PME interrupt |
594 | * for network wakeup, connected to the TLMM. | 589 | * for network wakeup, connected to the TLMM. |
595 | */ | 590 | */ |
596 | interrupts-extended = <&pm8058 198 IRQ_TYPE_EDGE_FALLING>, | 591 | interrupts-extended = <&pm8058_gpio 7 IRQ_TYPE_EDGE_FALLING>, |
597 | <&tlmm 29 IRQ_TYPE_EDGE_RISING>; | 592 | <&tlmm 29 IRQ_TYPE_EDGE_RISING>; |
598 | reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>; | 593 | reset-gpios = <&tlmm 30 GPIO_ACTIVE_LOW>; |
599 | vdd33a-supply = <&dragon_veth>; | 594 | vdd33a-supply = <&dragon_veth>; |
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi index 48c3cf427610..4744fe757cf4 100644 --- a/arch/arm/boot/dts/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom-apq8064.dtsi | |||
@@ -705,50 +705,8 @@ | |||
705 | compatible = "qcom,pm8921-gpio", | 705 | compatible = "qcom,pm8921-gpio", |
706 | "qcom,ssbi-gpio"; | 706 | "qcom,ssbi-gpio"; |
707 | reg = <0x150>; | 707 | reg = <0x150>; |
708 | interrupts = <192 IRQ_TYPE_NONE>, | 708 | interrupt-controller; |
709 | <193 IRQ_TYPE_NONE>, | 709 | #interrupt-cells = <2>; |
710 | <194 IRQ_TYPE_NONE>, | ||
711 | <195 IRQ_TYPE_NONE>, | ||
712 | <196 IRQ_TYPE_NONE>, | ||
713 | <197 IRQ_TYPE_NONE>, | ||
714 | <198 IRQ_TYPE_NONE>, | ||
715 | <199 IRQ_TYPE_NONE>, | ||
716 | <200 IRQ_TYPE_NONE>, | ||
717 | <201 IRQ_TYPE_NONE>, | ||
718 | <202 IRQ_TYPE_NONE>, | ||
719 | <203 IRQ_TYPE_NONE>, | ||
720 | <204 IRQ_TYPE_NONE>, | ||
721 | <205 IRQ_TYPE_NONE>, | ||
722 | <206 IRQ_TYPE_NONE>, | ||
723 | <207 IRQ_TYPE_NONE>, | ||
724 | <208 IRQ_TYPE_NONE>, | ||
725 | <209 IRQ_TYPE_NONE>, | ||
726 | <210 IRQ_TYPE_NONE>, | ||
727 | <211 IRQ_TYPE_NONE>, | ||
728 | <212 IRQ_TYPE_NONE>, | ||
729 | <213 IRQ_TYPE_NONE>, | ||
730 | <214 IRQ_TYPE_NONE>, | ||
731 | <215 IRQ_TYPE_NONE>, | ||
732 | <216 IRQ_TYPE_NONE>, | ||
733 | <217 IRQ_TYPE_NONE>, | ||
734 | <218 IRQ_TYPE_NONE>, | ||
735 | <219 IRQ_TYPE_NONE>, | ||
736 | <220 IRQ_TYPE_NONE>, | ||
737 | <221 IRQ_TYPE_NONE>, | ||
738 | <222 IRQ_TYPE_NONE>, | ||
739 | <223 IRQ_TYPE_NONE>, | ||
740 | <224 IRQ_TYPE_NONE>, | ||
741 | <225 IRQ_TYPE_NONE>, | ||
742 | <226 IRQ_TYPE_NONE>, | ||
743 | <227 IRQ_TYPE_NONE>, | ||
744 | <228 IRQ_TYPE_NONE>, | ||
745 | <229 IRQ_TYPE_NONE>, | ||
746 | <230 IRQ_TYPE_NONE>, | ||
747 | <231 IRQ_TYPE_NONE>, | ||
748 | <232 IRQ_TYPE_NONE>, | ||
749 | <233 IRQ_TYPE_NONE>, | ||
750 | <234 IRQ_TYPE_NONE>, | ||
751 | <235 IRQ_TYPE_NONE>; | ||
752 | gpio-controller; | 710 | gpio-controller; |
753 | #gpio-cells = <2>; | 711 | #gpio-cells = <2>; |
754 | 712 | ||
diff --git a/arch/arm/boot/dts/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom-mdm9615.dtsi index c852b69229c9..0ed6fc3e873c 100644 --- a/arch/arm/boot/dts/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom-mdm9615.dtsi | |||
@@ -323,13 +323,8 @@ | |||
323 | 323 | ||
324 | pmicgpio: gpio@150 { | 324 | pmicgpio: gpio@150 { |
325 | compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; | 325 | compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; |
326 | interrupt-parent = <&pmicintc>; | 326 | interrupt-controller; |
327 | interrupts = <24 IRQ_TYPE_NONE>, | 327 | #interrupt-cells = <2>; |
328 | <25 IRQ_TYPE_NONE>, | ||
329 | <26 IRQ_TYPE_NONE>, | ||
330 | <27 IRQ_TYPE_NONE>, | ||
331 | <28 IRQ_TYPE_NONE>, | ||
332 | <29 IRQ_TYPE_NONE>; | ||
333 | gpio-controller; | 328 | gpio-controller; |
334 | #gpio-cells = <2>; | 329 | #gpio-cells = <2>; |
335 | }; | 330 | }; |
diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi index 70698941f64c..a4eeebcfd63a 100644 --- a/arch/arm/boot/dts/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom-msm8660.dtsi | |||
@@ -285,51 +285,8 @@ | |||
285 | compatible = "qcom,pm8058-gpio", | 285 | compatible = "qcom,pm8058-gpio", |
286 | "qcom,ssbi-gpio"; | 286 | "qcom,ssbi-gpio"; |
287 | reg = <0x150>; | 287 | reg = <0x150>; |
288 | interrupt-parent = <&pm8058>; | 288 | interrupt-controller; |
289 | interrupts = <192 IRQ_TYPE_NONE>, | 289 | #interrupt-cells = <2>; |
290 | <193 IRQ_TYPE_NONE>, | ||
291 | <194 IRQ_TYPE_NONE>, | ||
292 | <195 IRQ_TYPE_NONE>, | ||
293 | <196 IRQ_TYPE_NONE>, | ||
294 | <197 IRQ_TYPE_NONE>, | ||
295 | <198 IRQ_TYPE_NONE>, | ||
296 | <199 IRQ_TYPE_NONE>, | ||
297 | <200 IRQ_TYPE_NONE>, | ||
298 | <201 IRQ_TYPE_NONE>, | ||
299 | <202 IRQ_TYPE_NONE>, | ||
300 | <203 IRQ_TYPE_NONE>, | ||
301 | <204 IRQ_TYPE_NONE>, | ||
302 | <205 IRQ_TYPE_NONE>, | ||
303 | <206 IRQ_TYPE_NONE>, | ||
304 | <207 IRQ_TYPE_NONE>, | ||
305 | <208 IRQ_TYPE_NONE>, | ||
306 | <209 IRQ_TYPE_NONE>, | ||
307 | <210 IRQ_TYPE_NONE>, | ||
308 | <211 IRQ_TYPE_NONE>, | ||
309 | <212 IRQ_TYPE_NONE>, | ||
310 | <213 IRQ_TYPE_NONE>, | ||
311 | <214 IRQ_TYPE_NONE>, | ||
312 | <215 IRQ_TYPE_NONE>, | ||
313 | <216 IRQ_TYPE_NONE>, | ||
314 | <217 IRQ_TYPE_NONE>, | ||
315 | <218 IRQ_TYPE_NONE>, | ||
316 | <219 IRQ_TYPE_NONE>, | ||
317 | <220 IRQ_TYPE_NONE>, | ||
318 | <221 IRQ_TYPE_NONE>, | ||
319 | <222 IRQ_TYPE_NONE>, | ||
320 | <223 IRQ_TYPE_NONE>, | ||
321 | <224 IRQ_TYPE_NONE>, | ||
322 | <225 IRQ_TYPE_NONE>, | ||
323 | <226 IRQ_TYPE_NONE>, | ||
324 | <227 IRQ_TYPE_NONE>, | ||
325 | <228 IRQ_TYPE_NONE>, | ||
326 | <229 IRQ_TYPE_NONE>, | ||
327 | <230 IRQ_TYPE_NONE>, | ||
328 | <231 IRQ_TYPE_NONE>, | ||
329 | <232 IRQ_TYPE_NONE>, | ||
330 | <233 IRQ_TYPE_NONE>, | ||
331 | <234 IRQ_TYPE_NONE>, | ||
332 | <235 IRQ_TYPE_NONE>; | ||
333 | gpio-controller; | 290 | gpio-controller; |
334 | #gpio-cells = <2>; | 291 | #gpio-cells = <2>; |
335 | 292 | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 76f9909cf396..5f1349c86a6f 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -928,7 +928,7 @@ config UCB1400_CORE | |||
928 | config MFD_PM8XXX | 928 | config MFD_PM8XXX |
929 | tristate "Qualcomm PM8xxx PMIC chips driver" | 929 | tristate "Qualcomm PM8xxx PMIC chips driver" |
930 | depends on (ARM || HEXAGON || COMPILE_TEST) | 930 | depends on (ARM || HEXAGON || COMPILE_TEST) |
931 | select IRQ_DOMAIN | 931 | select IRQ_DOMAIN_HIERARCHY |
932 | select MFD_CORE | 932 | select MFD_CORE |
933 | select REGMAP | 933 | select REGMAP |
934 | help | 934 | help |
diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index e6e8d81c15fd..8eb2528793f9 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c | |||
@@ -70,22 +70,23 @@ | |||
70 | #define PM8XXX_NR_IRQS 256 | 70 | #define PM8XXX_NR_IRQS 256 |
71 | #define PM8821_NR_IRQS 112 | 71 | #define PM8821_NR_IRQS 112 |
72 | 72 | ||
73 | struct pm_irq_data { | ||
74 | int num_irqs; | ||
75 | struct irq_chip *irq_chip; | ||
76 | void (*irq_handler)(struct irq_desc *desc); | ||
77 | }; | ||
78 | |||
73 | struct pm_irq_chip { | 79 | struct pm_irq_chip { |
74 | struct regmap *regmap; | 80 | struct regmap *regmap; |
75 | spinlock_t pm_irq_lock; | 81 | spinlock_t pm_irq_lock; |
76 | struct irq_domain *irqdomain; | 82 | struct irq_domain *irqdomain; |
77 | unsigned int num_irqs; | ||
78 | unsigned int num_blocks; | 83 | unsigned int num_blocks; |
79 | unsigned int num_masters; | 84 | unsigned int num_masters; |
85 | const struct pm_irq_data *pm_irq_data; | ||
86 | /* MUST BE AT THE END OF THIS STRUCT */ | ||
80 | u8 config[0]; | 87 | u8 config[0]; |
81 | }; | 88 | }; |
82 | 89 | ||
83 | struct pm_irq_data { | ||
84 | int num_irqs; | ||
85 | const struct irq_domain_ops *irq_domain_ops; | ||
86 | void (*irq_handler)(struct irq_desc *desc); | ||
87 | }; | ||
88 | |||
89 | static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, | 90 | static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, |
90 | unsigned int *ip) | 91 | unsigned int *ip) |
91 | { | 92 | { |
@@ -375,21 +376,38 @@ static struct irq_chip pm8xxx_irq_chip = { | |||
375 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, | 376 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, |
376 | }; | 377 | }; |
377 | 378 | ||
378 | static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq, | 379 | static void pm8xxx_irq_domain_map(struct pm_irq_chip *chip, |
379 | irq_hw_number_t hwirq) | 380 | struct irq_domain *domain, unsigned int irq, |
381 | irq_hw_number_t hwirq, unsigned int type) | ||
380 | { | 382 | { |
381 | struct pm_irq_chip *chip = d->host_data; | 383 | irq_domain_set_info(domain, irq, hwirq, chip->pm_irq_data->irq_chip, |
382 | 384 | chip, handle_level_irq, NULL, NULL); | |
383 | irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq); | ||
384 | irq_set_chip_data(irq, chip); | ||
385 | irq_set_noprobe(irq); | 385 | irq_set_noprobe(irq); |
386 | } | ||
387 | |||
388 | static int pm8xxx_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, | ||
389 | unsigned int nr_irqs, void *data) | ||
390 | { | ||
391 | struct pm_irq_chip *chip = domain->host_data; | ||
392 | struct irq_fwspec *fwspec = data; | ||
393 | irq_hw_number_t hwirq; | ||
394 | unsigned int type; | ||
395 | int ret, i; | ||
396 | |||
397 | ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type); | ||
398 | if (ret) | ||
399 | return ret; | ||
400 | |||
401 | for (i = 0; i < nr_irqs; i++) | ||
402 | pm8xxx_irq_domain_map(chip, domain, virq + i, hwirq + i, type); | ||
386 | 403 | ||
387 | return 0; | 404 | return 0; |
388 | } | 405 | } |
389 | 406 | ||
390 | static const struct irq_domain_ops pm8xxx_irq_domain_ops = { | 407 | static const struct irq_domain_ops pm8xxx_irq_domain_ops = { |
391 | .xlate = irq_domain_xlate_twocell, | 408 | .alloc = pm8xxx_irq_domain_alloc, |
392 | .map = pm8xxx_irq_domain_map, | 409 | .free = irq_domain_free_irqs_common, |
410 | .translate = irq_domain_translate_twocell, | ||
393 | }; | 411 | }; |
394 | 412 | ||
395 | static void pm8821_irq_mask_ack(struct irq_data *d) | 413 | static void pm8821_irq_mask_ack(struct irq_data *d) |
@@ -473,23 +491,6 @@ static struct irq_chip pm8821_irq_chip = { | |||
473 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, | 491 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, |
474 | }; | 492 | }; |
475 | 493 | ||
476 | static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq, | ||
477 | irq_hw_number_t hwirq) | ||
478 | { | ||
479 | struct pm_irq_chip *chip = d->host_data; | ||
480 | |||
481 | irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq); | ||
482 | irq_set_chip_data(irq, chip); | ||
483 | irq_set_noprobe(irq); | ||
484 | |||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static const struct irq_domain_ops pm8821_irq_domain_ops = { | ||
489 | .xlate = irq_domain_xlate_twocell, | ||
490 | .map = pm8821_irq_domain_map, | ||
491 | }; | ||
492 | |||
493 | static const struct regmap_config ssbi_regmap_config = { | 494 | static const struct regmap_config ssbi_regmap_config = { |
494 | .reg_bits = 16, | 495 | .reg_bits = 16, |
495 | .val_bits = 8, | 496 | .val_bits = 8, |
@@ -501,13 +502,13 @@ static const struct regmap_config ssbi_regmap_config = { | |||
501 | 502 | ||
502 | static const struct pm_irq_data pm8xxx_data = { | 503 | static const struct pm_irq_data pm8xxx_data = { |
503 | .num_irqs = PM8XXX_NR_IRQS, | 504 | .num_irqs = PM8XXX_NR_IRQS, |
504 | .irq_domain_ops = &pm8xxx_irq_domain_ops, | 505 | .irq_chip = &pm8xxx_irq_chip, |
505 | .irq_handler = pm8xxx_irq_handler, | 506 | .irq_handler = pm8xxx_irq_handler, |
506 | }; | 507 | }; |
507 | 508 | ||
508 | static const struct pm_irq_data pm8821_data = { | 509 | static const struct pm_irq_data pm8821_data = { |
509 | .num_irqs = PM8821_NR_IRQS, | 510 | .num_irqs = PM8821_NR_IRQS, |
510 | .irq_domain_ops = &pm8821_irq_domain_ops, | 511 | .irq_chip = &pm8821_irq_chip, |
511 | .irq_handler = pm8821_irq_handler, | 512 | .irq_handler = pm8821_irq_handler, |
512 | }; | 513 | }; |
513 | 514 | ||
@@ -571,14 +572,14 @@ static int pm8xxx_probe(struct platform_device *pdev) | |||
571 | 572 | ||
572 | platform_set_drvdata(pdev, chip); | 573 | platform_set_drvdata(pdev, chip); |
573 | chip->regmap = regmap; | 574 | chip->regmap = regmap; |
574 | chip->num_irqs = data->num_irqs; | 575 | chip->num_blocks = DIV_ROUND_UP(data->num_irqs, 8); |
575 | chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); | ||
576 | chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); | 576 | chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); |
577 | chip->pm_irq_data = data; | ||
577 | spin_lock_init(&chip->pm_irq_lock); | 578 | spin_lock_init(&chip->pm_irq_lock); |
578 | 579 | ||
579 | chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, | 580 | chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, |
580 | data->num_irqs, | 581 | data->num_irqs, |
581 | data->irq_domain_ops, | 582 | &pm8xxx_irq_domain_ops, |
582 | chip); | 583 | chip); |
583 | if (!chip->irqdomain) | 584 | if (!chip->irqdomain) |
584 | return -ENODEV; | 585 | return -ENODEV; |
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 93efbffcd3a4..2e66ab72c10b 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig | |||
@@ -150,6 +150,7 @@ config PINCTRL_QCOM_SSBI_PMIC | |||
150 | select PINMUX | 150 | select PINMUX |
151 | select PINCONF | 151 | select PINCONF |
152 | select GENERIC_PINCONF | 152 | select GENERIC_PINCONF |
153 | select IRQ_DOMAIN_HIERARCHY | ||
153 | help | 154 | help |
154 | This is the pinctrl, pinmux, pinconf and gpiolib driver for the | 155 | This is the pinctrl, pinmux, pinconf and gpiolib driver for the |
155 | Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, | 156 | Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, |
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index ded7d765af2e..08dd62b5cebe 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | |||
@@ -55,6 +55,8 @@ | |||
55 | 55 | ||
56 | #define PM8XXX_MAX_GPIOS 44 | 56 | #define PM8XXX_MAX_GPIOS 44 |
57 | 57 | ||
58 | #define PM8XXX_GPIO_PHYSICAL_OFFSET 1 | ||
59 | |||
58 | /* custom pinconf parameters */ | 60 | /* custom pinconf parameters */ |
59 | #define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1) | 61 | #define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1) |
60 | #define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2) | 62 | #define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2) |
@@ -99,6 +101,9 @@ struct pm8xxx_gpio { | |||
99 | 101 | ||
100 | struct pinctrl_desc desc; | 102 | struct pinctrl_desc desc; |
101 | unsigned npins; | 103 | unsigned npins; |
104 | |||
105 | struct fwnode_handle *fwnode; | ||
106 | struct irq_domain *domain; | ||
102 | }; | 107 | }; |
103 | 108 | ||
104 | static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = { | 109 | static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = { |
@@ -499,11 +504,12 @@ static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset) | |||
499 | 504 | ||
500 | if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) { | 505 | if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) { |
501 | ret = pin->output_value; | 506 | ret = pin->output_value; |
502 | } else { | 507 | } else if (pin->irq >= 0) { |
503 | ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); | 508 | ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); |
504 | if (!ret) | 509 | if (!ret) |
505 | ret = !!state; | 510 | ret = !!state; |
506 | } | 511 | } else |
512 | ret = -EINVAL; | ||
507 | 513 | ||
508 | return ret; | 514 | return ret; |
509 | } | 515 | } |
@@ -533,7 +539,7 @@ static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip, | |||
533 | if (flags) | 539 | if (flags) |
534 | *flags = gpio_desc->args[1]; | 540 | *flags = gpio_desc->args[1]; |
535 | 541 | ||
536 | return gpio_desc->args[0] - 1; | 542 | return gpio_desc->args[0] - PM8XXX_GPIO_PHYSICAL_OFFSET; |
537 | } | 543 | } |
538 | 544 | ||
539 | 545 | ||
@@ -541,8 +547,31 @@ static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | |||
541 | { | 547 | { |
542 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip); | 548 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip); |
543 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; | 549 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; |
550 | struct irq_fwspec fwspec; | ||
551 | int ret; | ||
552 | |||
553 | fwspec.fwnode = pctrl->fwnode; | ||
554 | fwspec.param_count = 2; | ||
555 | fwspec.param[0] = offset + PM8XXX_GPIO_PHYSICAL_OFFSET; | ||
556 | fwspec.param[1] = IRQ_TYPE_EDGE_RISING; | ||
557 | |||
558 | ret = irq_create_fwspec_mapping(&fwspec); | ||
559 | |||
560 | /* | ||
561 | * Cache the IRQ since pm8xxx_gpio_get() needs this to get determine the | ||
562 | * line level. | ||
563 | */ | ||
564 | pin->irq = ret; | ||
565 | |||
566 | return ret; | ||
567 | } | ||
568 | |||
569 | static void pm8xxx_gpio_free(struct gpio_chip *chip, unsigned int offset) | ||
570 | { | ||
571 | struct pm8xxx_gpio *pctrl = gpiochip_get_data(chip); | ||
572 | struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; | ||
544 | 573 | ||
545 | return pin->irq; | 574 | pin->irq = -1; |
546 | } | 575 | } |
547 | 576 | ||
548 | #ifdef CONFIG_DEBUG_FS | 577 | #ifdef CONFIG_DEBUG_FS |
@@ -571,7 +600,7 @@ static void pm8xxx_gpio_dbg_show_one(struct seq_file *s, | |||
571 | "no", "high", "medium", "low" | 600 | "no", "high", "medium", "low" |
572 | }; | 601 | }; |
573 | 602 | ||
574 | seq_printf(s, " gpio%-2d:", offset + 1); | 603 | seq_printf(s, " gpio%-2d:", offset + PM8XXX_GPIO_PHYSICAL_OFFSET); |
575 | if (pin->disable) { | 604 | if (pin->disable) { |
576 | seq_puts(s, " ---"); | 605 | seq_puts(s, " ---"); |
577 | } else { | 606 | } else { |
@@ -603,6 +632,7 @@ static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
603 | #endif | 632 | #endif |
604 | 633 | ||
605 | static const struct gpio_chip pm8xxx_gpio_template = { | 634 | static const struct gpio_chip pm8xxx_gpio_template = { |
635 | .free = pm8xxx_gpio_free, | ||
606 | .direction_input = pm8xxx_gpio_direction_input, | 636 | .direction_input = pm8xxx_gpio_direction_input, |
607 | .direction_output = pm8xxx_gpio_direction_output, | 637 | .direction_output = pm8xxx_gpio_direction_output, |
608 | .get = pm8xxx_gpio_get, | 638 | .get = pm8xxx_gpio_get, |
@@ -664,13 +694,75 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, | |||
664 | return 0; | 694 | return 0; |
665 | } | 695 | } |
666 | 696 | ||
697 | static struct irq_chip pm8xxx_irq_chip = { | ||
698 | .name = "ssbi-gpio", | ||
699 | .irq_mask_ack = irq_chip_mask_ack_parent, | ||
700 | .irq_unmask = irq_chip_unmask_parent, | ||
701 | .irq_set_type = irq_chip_set_type_parent, | ||
702 | .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, | ||
703 | }; | ||
704 | |||
705 | static int pm8xxx_domain_translate(struct irq_domain *domain, | ||
706 | struct irq_fwspec *fwspec, | ||
707 | unsigned long *hwirq, | ||
708 | unsigned int *type) | ||
709 | { | ||
710 | struct pm8xxx_gpio *pctrl = container_of(domain->host_data, | ||
711 | struct pm8xxx_gpio, chip); | ||
712 | |||
713 | if (fwspec->param_count != 2 || fwspec->param[0] < 1 || | ||
714 | fwspec->param[0] > pctrl->chip.ngpio) | ||
715 | return -EINVAL; | ||
716 | |||
717 | *hwirq = fwspec->param[0] - PM8XXX_GPIO_PHYSICAL_OFFSET; | ||
718 | *type = fwspec->param[1]; | ||
719 | |||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static int pm8xxx_domain_alloc(struct irq_domain *domain, unsigned int virq, | ||
724 | unsigned int nr_irqs, void *data) | ||
725 | { | ||
726 | struct pm8xxx_gpio *pctrl = container_of(domain->host_data, | ||
727 | struct pm8xxx_gpio, chip); | ||
728 | struct irq_fwspec *fwspec = data; | ||
729 | struct irq_fwspec parent_fwspec; | ||
730 | irq_hw_number_t hwirq; | ||
731 | unsigned int type; | ||
732 | int ret, i; | ||
733 | |||
734 | ret = pm8xxx_domain_translate(domain, fwspec, &hwirq, &type); | ||
735 | if (ret) | ||
736 | return ret; | ||
737 | |||
738 | for (i = 0; i < nr_irqs; i++) | ||
739 | irq_domain_set_info(domain, virq + i, hwirq + i, | ||
740 | &pm8xxx_irq_chip, pctrl, handle_level_irq, | ||
741 | NULL, NULL); | ||
742 | |||
743 | parent_fwspec.fwnode = domain->parent->fwnode; | ||
744 | parent_fwspec.param_count = 2; | ||
745 | parent_fwspec.param[0] = hwirq + 0xc0; | ||
746 | parent_fwspec.param[1] = fwspec->param[1]; | ||
747 | |||
748 | return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, | ||
749 | &parent_fwspec); | ||
750 | } | ||
751 | |||
752 | static const struct irq_domain_ops pm8xxx_domain_ops = { | ||
753 | .activate = gpiochip_irq_domain_activate, | ||
754 | .alloc = pm8xxx_domain_alloc, | ||
755 | .deactivate = gpiochip_irq_domain_deactivate, | ||
756 | .free = irq_domain_free_irqs_common, | ||
757 | .translate = pm8xxx_domain_translate, | ||
758 | }; | ||
759 | |||
667 | static const struct of_device_id pm8xxx_gpio_of_match[] = { | 760 | static const struct of_device_id pm8xxx_gpio_of_match[] = { |
668 | { .compatible = "qcom,pm8018-gpio" }, | 761 | { .compatible = "qcom,pm8018-gpio", .data = (void *) 6 }, |
669 | { .compatible = "qcom,pm8038-gpio" }, | 762 | { .compatible = "qcom,pm8038-gpio", .data = (void *) 12 }, |
670 | { .compatible = "qcom,pm8058-gpio" }, | 763 | { .compatible = "qcom,pm8058-gpio", .data = (void *) 44 }, |
671 | { .compatible = "qcom,pm8917-gpio" }, | 764 | { .compatible = "qcom,pm8917-gpio", .data = (void *) 38 }, |
672 | { .compatible = "qcom,pm8921-gpio" }, | 765 | { .compatible = "qcom,pm8921-gpio", .data = (void *) 44 }, |
673 | { .compatible = "qcom,ssbi-gpio" }, | ||
674 | { }, | 766 | { }, |
675 | }; | 767 | }; |
676 | MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); | 768 | MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); |
@@ -678,22 +770,18 @@ MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); | |||
678 | static int pm8xxx_gpio_probe(struct platform_device *pdev) | 770 | static int pm8xxx_gpio_probe(struct platform_device *pdev) |
679 | { | 771 | { |
680 | struct pm8xxx_pin_data *pin_data; | 772 | struct pm8xxx_pin_data *pin_data; |
773 | struct irq_domain *parent_domain; | ||
774 | struct device_node *parent_node; | ||
681 | struct pinctrl_pin_desc *pins; | 775 | struct pinctrl_pin_desc *pins; |
682 | struct pm8xxx_gpio *pctrl; | 776 | struct pm8xxx_gpio *pctrl; |
683 | int ret; | 777 | int ret, i; |
684 | int i, npins; | ||
685 | 778 | ||
686 | pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); | 779 | pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); |
687 | if (!pctrl) | 780 | if (!pctrl) |
688 | return -ENOMEM; | 781 | return -ENOMEM; |
689 | 782 | ||
690 | pctrl->dev = &pdev->dev; | 783 | pctrl->dev = &pdev->dev; |
691 | npins = platform_irq_count(pdev); | 784 | pctrl->npins = (uintptr_t) device_get_match_data(&pdev->dev); |
692 | if (!npins) | ||
693 | return -EINVAL; | ||
694 | if (npins < 0) | ||
695 | return npins; | ||
696 | pctrl->npins = npins; | ||
697 | 785 | ||
698 | pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); | 786 | pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); |
699 | if (!pctrl->regmap) { | 787 | if (!pctrl->regmap) { |
@@ -720,12 +808,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) | |||
720 | 808 | ||
721 | for (i = 0; i < pctrl->desc.npins; i++) { | 809 | for (i = 0; i < pctrl->desc.npins; i++) { |
722 | pin_data[i].reg = SSBI_REG_ADDR_GPIO(i); | 810 | pin_data[i].reg = SSBI_REG_ADDR_GPIO(i); |
723 | pin_data[i].irq = platform_get_irq(pdev, i); | 811 | pin_data[i].irq = -1; |
724 | if (pin_data[i].irq < 0) { | ||
725 | dev_err(&pdev->dev, | ||
726 | "missing interrupts for pin %d\n", i); | ||
727 | return pin_data[i].irq; | ||
728 | } | ||
729 | 812 | ||
730 | ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); | 813 | ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); |
731 | if (ret) | 814 | if (ret) |
@@ -756,10 +839,29 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) | |||
756 | pctrl->chip.of_gpio_n_cells = 2; | 839 | pctrl->chip.of_gpio_n_cells = 2; |
757 | pctrl->chip.label = dev_name(pctrl->dev); | 840 | pctrl->chip.label = dev_name(pctrl->dev); |
758 | pctrl->chip.ngpio = pctrl->npins; | 841 | pctrl->chip.ngpio = pctrl->npins; |
842 | |||
843 | parent_node = of_irq_find_parent(pctrl->dev->of_node); | ||
844 | if (!parent_node) | ||
845 | return -ENXIO; | ||
846 | |||
847 | parent_domain = irq_find_host(parent_node); | ||
848 | of_node_put(parent_node); | ||
849 | if (!parent_domain) | ||
850 | return -ENXIO; | ||
851 | |||
852 | pctrl->fwnode = of_node_to_fwnode(pctrl->dev->of_node); | ||
853 | pctrl->domain = irq_domain_create_hierarchy(parent_domain, 0, | ||
854 | pctrl->chip.ngpio, | ||
855 | pctrl->fwnode, | ||
856 | &pm8xxx_domain_ops, | ||
857 | &pctrl->chip); | ||
858 | if (!pctrl->domain) | ||
859 | return -ENODEV; | ||
860 | |||
759 | ret = gpiochip_add_data(&pctrl->chip, pctrl); | 861 | ret = gpiochip_add_data(&pctrl->chip, pctrl); |
760 | if (ret) { | 862 | if (ret) { |
761 | dev_err(&pdev->dev, "failed register gpiochip\n"); | 863 | dev_err(&pdev->dev, "failed register gpiochip\n"); |
762 | return ret; | 864 | goto err_chip_add_data; |
763 | } | 865 | } |
764 | 866 | ||
765 | /* | 867 | /* |
@@ -789,6 +891,8 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) | |||
789 | 891 | ||
790 | unregister_gpiochip: | 892 | unregister_gpiochip: |
791 | gpiochip_remove(&pctrl->chip); | 893 | gpiochip_remove(&pctrl->chip); |
894 | err_chip_add_data: | ||
895 | irq_domain_remove(pctrl->domain); | ||
792 | 896 | ||
793 | return ret; | 897 | return ret; |
794 | } | 898 | } |
@@ -798,6 +902,7 @@ static int pm8xxx_gpio_remove(struct platform_device *pdev) | |||
798 | struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev); | 902 | struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev); |
799 | 903 | ||
800 | gpiochip_remove(&pctrl->chip); | 904 | gpiochip_remove(&pctrl->chip); |
905 | irq_domain_remove(pctrl->domain); | ||
801 | 906 | ||
802 | return 0; | 907 | return 0; |
803 | } | 908 | } |
diff --git a/include/linux/irq.h b/include/linux/irq.h index def2b2aac8b1..9a1a67d2e07d 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h | |||
@@ -605,6 +605,7 @@ extern void irq_chip_disable_parent(struct irq_data *data); | |||
605 | extern void irq_chip_ack_parent(struct irq_data *data); | 605 | extern void irq_chip_ack_parent(struct irq_data *data); |
606 | extern int irq_chip_retrigger_hierarchy(struct irq_data *data); | 606 | extern int irq_chip_retrigger_hierarchy(struct irq_data *data); |
607 | extern void irq_chip_mask_parent(struct irq_data *data); | 607 | extern void irq_chip_mask_parent(struct irq_data *data); |
608 | extern void irq_chip_mask_ack_parent(struct irq_data *data); | ||
608 | extern void irq_chip_unmask_parent(struct irq_data *data); | 609 | extern void irq_chip_unmask_parent(struct irq_data *data); |
609 | extern void irq_chip_eoi_parent(struct irq_data *data); | 610 | extern void irq_chip_eoi_parent(struct irq_data *data); |
610 | extern int irq_chip_set_affinity_parent(struct irq_data *data, | 611 | extern int irq_chip_set_affinity_parent(struct irq_data *data, |
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 35965f41d7be..fcefe0c7263f 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h | |||
@@ -419,6 +419,11 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, | |||
419 | const u32 *intspec, unsigned int intsize, | 419 | const u32 *intspec, unsigned int intsize, |
420 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 420 | irq_hw_number_t *out_hwirq, unsigned int *out_type); |
421 | 421 | ||
422 | int irq_domain_translate_twocell(struct irq_domain *d, | ||
423 | struct irq_fwspec *fwspec, | ||
424 | unsigned long *out_hwirq, | ||
425 | unsigned int *out_type); | ||
426 | |||
422 | /* IPI functions */ | 427 | /* IPI functions */ |
423 | int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); | 428 | int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); |
424 | int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest); | 429 | int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest); |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 086d5a34b5a0..0aefc2e69cf5 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -1278,6 +1278,17 @@ void irq_chip_mask_parent(struct irq_data *data) | |||
1278 | EXPORT_SYMBOL_GPL(irq_chip_mask_parent); | 1278 | EXPORT_SYMBOL_GPL(irq_chip_mask_parent); |
1279 | 1279 | ||
1280 | /** | 1280 | /** |
1281 | * irq_chip_mask_ack_parent - Mask and acknowledge the parent interrupt | ||
1282 | * @data: Pointer to interrupt specific data | ||
1283 | */ | ||
1284 | void irq_chip_mask_ack_parent(struct irq_data *data) | ||
1285 | { | ||
1286 | data = data->parent_data; | ||
1287 | data->chip->irq_mask_ack(data); | ||
1288 | } | ||
1289 | EXPORT_SYMBOL_GPL(irq_chip_mask_ack_parent); | ||
1290 | |||
1291 | /** | ||
1281 | * irq_chip_unmask_parent - Unmask the parent interrupt | 1292 | * irq_chip_unmask_parent - Unmask the parent interrupt |
1282 | * @data: Pointer to interrupt specific data | 1293 | * @data: Pointer to interrupt specific data |
1283 | */ | 1294 | */ |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8b0be4bd6565..56a30d542b8e 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -729,16 +729,17 @@ static int irq_domain_translate(struct irq_domain *d, | |||
729 | return 0; | 729 | return 0; |
730 | } | 730 | } |
731 | 731 | ||
732 | static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data, | 732 | static void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args, |
733 | unsigned int count, | ||
733 | struct irq_fwspec *fwspec) | 734 | struct irq_fwspec *fwspec) |
734 | { | 735 | { |
735 | int i; | 736 | int i; |
736 | 737 | ||
737 | fwspec->fwnode = irq_data->np ? &irq_data->np->fwnode : NULL; | 738 | fwspec->fwnode = np ? &np->fwnode : NULL; |
738 | fwspec->param_count = irq_data->args_count; | 739 | fwspec->param_count = count; |
739 | 740 | ||
740 | for (i = 0; i < irq_data->args_count; i++) | 741 | for (i = 0; i < count; i++) |
741 | fwspec->param[i] = irq_data->args[i]; | 742 | fwspec->param[i] = args[i]; |
742 | } | 743 | } |
743 | 744 | ||
744 | unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) | 745 | unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) |
@@ -836,7 +837,9 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data) | |||
836 | { | 837 | { |
837 | struct irq_fwspec fwspec; | 838 | struct irq_fwspec fwspec; |
838 | 839 | ||
839 | of_phandle_args_to_fwspec(irq_data, &fwspec); | 840 | of_phandle_args_to_fwspec(irq_data->np, irq_data->args, |
841 | irq_data->args_count, &fwspec); | ||
842 | |||
840 | return irq_create_fwspec_mapping(&fwspec); | 843 | return irq_create_fwspec_mapping(&fwspec); |
841 | } | 844 | } |
842 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | 845 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); |
@@ -928,11 +931,10 @@ int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, | |||
928 | const u32 *intspec, unsigned int intsize, | 931 | const u32 *intspec, unsigned int intsize, |
929 | irq_hw_number_t *out_hwirq, unsigned int *out_type) | 932 | irq_hw_number_t *out_hwirq, unsigned int *out_type) |
930 | { | 933 | { |
931 | if (WARN_ON(intsize < 2)) | 934 | struct irq_fwspec fwspec; |
932 | return -EINVAL; | 935 | |
933 | *out_hwirq = intspec[0]; | 936 | of_phandle_args_to_fwspec(ctrlr, intspec, intsize, &fwspec); |
934 | *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; | 937 | return irq_domain_translate_twocell(d, &fwspec, out_hwirq, out_type); |
935 | return 0; | ||
936 | } | 938 | } |
937 | EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell); | 939 | EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell); |
938 | 940 | ||
@@ -968,6 +970,27 @@ const struct irq_domain_ops irq_domain_simple_ops = { | |||
968 | }; | 970 | }; |
969 | EXPORT_SYMBOL_GPL(irq_domain_simple_ops); | 971 | EXPORT_SYMBOL_GPL(irq_domain_simple_ops); |
970 | 972 | ||
973 | /** | ||
974 | * irq_domain_translate_twocell() - Generic translate for direct two cell | ||
975 | * bindings | ||
976 | * | ||
977 | * Device Tree IRQ specifier translation function which works with two cell | ||
978 | * bindings where the cell values map directly to the hwirq number | ||
979 | * and linux irq flags. | ||
980 | */ | ||
981 | int irq_domain_translate_twocell(struct irq_domain *d, | ||
982 | struct irq_fwspec *fwspec, | ||
983 | unsigned long *out_hwirq, | ||
984 | unsigned int *out_type) | ||
985 | { | ||
986 | if (WARN_ON(fwspec->param_count < 2)) | ||
987 | return -EINVAL; | ||
988 | *out_hwirq = fwspec->param[0]; | ||
989 | *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; | ||
990 | return 0; | ||
991 | } | ||
992 | EXPORT_SYMBOL_GPL(irq_domain_translate_twocell); | ||
993 | |||
971 | int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, | 994 | int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, |
972 | int node, const struct irq_affinity_desc *affinity) | 995 | int node, const struct irq_affinity_desc *affinity) |
973 | { | 996 | { |