summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-stm32-exti.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-stm32-exti.c')
-rw-r--r--drivers/irqchip/irq-stm32-exti.c233
1 files changed, 140 insertions, 93 deletions
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 7bd1d4cb2e19..e00f2fa27f00 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -14,8 +14,10 @@
14#include <linux/irqchip.h> 14#include <linux/irqchip.h>
15#include <linux/irqchip/chained_irq.h> 15#include <linux/irqchip/chained_irq.h>
16#include <linux/irqdomain.h> 16#include <linux/irqdomain.h>
17#include <linux/module.h>
17#include <linux/of_address.h> 18#include <linux/of_address.h>
18#include <linux/of_irq.h> 19#include <linux/of_irq.h>
20#include <linux/of_platform.h>
19#include <linux/syscore_ops.h> 21#include <linux/syscore_ops.h>
20 22
21#include <dt-bindings/interrupt-controller/arm-gic.h> 23#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -37,12 +39,6 @@ struct stm32_exti_bank {
37 39
38#define UNDEF_REG ~0 40#define UNDEF_REG ~0
39 41
40enum stm32_exti_hwspinlock {
41 HWSPINLOCK_UNKNOWN,
42 HWSPINLOCK_NONE,
43 HWSPINLOCK_READY,
44};
45
46struct stm32_desc_irq { 42struct stm32_desc_irq {
47 u32 exti; 43 u32 exti;
48 u32 irq_parent; 44 u32 irq_parent;
@@ -69,8 +65,6 @@ struct stm32_exti_host_data {
69 void __iomem *base; 65 void __iomem *base;
70 struct stm32_exti_chip_data *chips_data; 66 struct stm32_exti_chip_data *chips_data;
71 const struct stm32_exti_drv_data *drv_data; 67 const struct stm32_exti_drv_data *drv_data;
72 struct device_node *node;
73 enum stm32_exti_hwspinlock hwlock_state;
74 struct hwspinlock *hwlock; 68 struct hwspinlock *hwlock;
75}; 69};
76 70
@@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d,
285 279
286static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) 280static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
287{ 281{
288 struct stm32_exti_host_data *host_data = chip_data->host_data; 282 int ret, timeout = 0;
289 struct hwspinlock *hwlock;
290 int id, ret = 0, timeout = 0;
291
292 /* first time, check for hwspinlock availability */
293 if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) {
294 id = of_hwspin_lock_get_id(host_data->node, 0);
295 if (id >= 0) {
296 hwlock = hwspin_lock_request_specific(id);
297 if (hwlock) {
298 /* found valid hwspinlock */
299 host_data->hwlock_state = HWSPINLOCK_READY;
300 host_data->hwlock = hwlock;
301 pr_debug("%s hwspinlock = %d\n", __func__, id);
302 } else {
303 host_data->hwlock_state = HWSPINLOCK_NONE;
304 }
305 } else if (id != -EPROBE_DEFER) {
306 host_data->hwlock_state = HWSPINLOCK_NONE;
307 } else {
308 /* hwspinlock driver shall be ready at that stage */
309 ret = -EPROBE_DEFER;
310 }
311 }
312 283
313 if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) { 284 if (!chip_data->host_data->hwlock)
314 /* 285 return 0;
315 * Use the x_raw API since we are under spin_lock protection. 286
316 * Do not use the x_timeout API because we are under irq_disable 287 /*
317 * mode (see __setup_irq()) 288 * Use the x_raw API since we are under spin_lock protection.
318 */ 289 * Do not use the x_timeout API because we are under irq_disable
319 do { 290 * mode (see __setup_irq())
320 ret = hwspin_trylock_raw(host_data->hwlock); 291 */
321 if (!ret) 292 do {
322 return 0; 293 ret = hwspin_trylock_raw(chip_data->host_data->hwlock);
323 294 if (!ret)
324 udelay(HWSPNLCK_RETRY_DELAY); 295 return 0;
325 timeout += HWSPNLCK_RETRY_DELAY; 296
326 } while (timeout < HWSPNLCK_TIMEOUT); 297 udelay(HWSPNLCK_RETRY_DELAY);
327 298 timeout += HWSPNLCK_RETRY_DELAY;
328 if (ret == -EBUSY) 299 } while (timeout < HWSPNLCK_TIMEOUT);
329 ret = -ETIMEDOUT; 300
330 } 301 if (ret == -EBUSY)
302 ret = -ETIMEDOUT;
331 303
332 if (ret) 304 if (ret)
333 pr_err("%s can't get hwspinlock (%d)\n", __func__, ret); 305 pr_err("%s can't get hwspinlock (%d)\n", __func__, ret);
@@ -337,7 +309,7 @@ static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data)
337 309
338static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data) 310static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data)
339{ 311{
340 if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY)) 312 if (chip_data->host_data->hwlock)
341 hwspin_unlock_raw(chip_data->host_data->hwlock); 313 hwspin_unlock_raw(chip_data->host_data->hwlock);
342} 314}
343 315
@@ -586,8 +558,7 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
586 return -EINVAL; 558 return -EINVAL;
587} 559}
588 560
589#ifdef CONFIG_PM 561static int __maybe_unused stm32_exti_h_suspend(void)
590static int stm32_exti_h_suspend(void)
591{ 562{
592 struct stm32_exti_chip_data *chip_data; 563 struct stm32_exti_chip_data *chip_data;
593 int i; 564 int i;
@@ -602,7 +573,7 @@ static int stm32_exti_h_suspend(void)
602 return 0; 573 return 0;
603} 574}
604 575
605static void stm32_exti_h_resume(void) 576static void __maybe_unused stm32_exti_h_resume(void)
606{ 577{
607 struct stm32_exti_chip_data *chip_data; 578 struct stm32_exti_chip_data *chip_data;
608 int i; 579 int i;
@@ -616,17 +587,22 @@ static void stm32_exti_h_resume(void)
616} 587}
617 588
618static struct syscore_ops stm32_exti_h_syscore_ops = { 589static struct syscore_ops stm32_exti_h_syscore_ops = {
590#ifdef CONFIG_PM_SLEEP
619 .suspend = stm32_exti_h_suspend, 591 .suspend = stm32_exti_h_suspend,
620 .resume = stm32_exti_h_resume, 592 .resume = stm32_exti_h_resume,
593#endif
621}; 594};
622 595
623static void stm32_exti_h_syscore_init(void) 596static void stm32_exti_h_syscore_init(struct stm32_exti_host_data *host_data)
624{ 597{
598 stm32_host_data = host_data;
625 register_syscore_ops(&stm32_exti_h_syscore_ops); 599 register_syscore_ops(&stm32_exti_h_syscore_ops);
626} 600}
627#else 601
628static inline void stm32_exti_h_syscore_init(void) {} 602static void stm32_exti_h_syscore_deinit(void)
629#endif 603{
604 unregister_syscore_ops(&stm32_exti_h_syscore_ops);
605}
630 606
631static struct irq_chip stm32_exti_h_chip = { 607static struct irq_chip stm32_exti_h_chip = {
632 .name = "stm32-exti-h", 608 .name = "stm32-exti-h",
@@ -683,8 +659,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd,
683 return NULL; 659 return NULL;
684 660
685 host_data->drv_data = dd; 661 host_data->drv_data = dd;
686 host_data->node = node;
687 host_data->hwlock_state = HWSPINLOCK_UNKNOWN;
688 host_data->chips_data = kcalloc(dd->bank_nr, 662 host_data->chips_data = kcalloc(dd->bank_nr,
689 sizeof(struct stm32_exti_chip_data), 663 sizeof(struct stm32_exti_chip_data),
690 GFP_KERNEL); 664 GFP_KERNEL);
@@ -711,7 +685,8 @@ free_host_data:
711 685
712static struct 686static struct
713stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, 687stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
714 u32 bank_idx) 688 u32 bank_idx,
689 struct device_node *node)
715{ 690{
716 const struct stm32_exti_bank *stm32_bank; 691 const struct stm32_exti_bank *stm32_bank;
717 struct stm32_exti_chip_data *chip_data; 692 struct stm32_exti_chip_data *chip_data;
@@ -731,7 +706,7 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
731 writel_relaxed(0, base + stm32_bank->imr_ofst); 706 writel_relaxed(0, base + stm32_bank->imr_ofst);
732 writel_relaxed(0, base + stm32_bank->emr_ofst); 707 writel_relaxed(0, base + stm32_bank->emr_ofst);
733 708
734 pr_info("%pOF: bank%d\n", h_data->node, bank_idx); 709 pr_info("%pOF: bank%d\n", node, bank_idx);
735 710
736 return chip_data; 711 return chip_data;
737} 712}
@@ -771,7 +746,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
771 struct stm32_exti_chip_data *chip_data; 746 struct stm32_exti_chip_data *chip_data;
772 747
773 stm32_bank = drv_data->exti_banks[i]; 748 stm32_bank = drv_data->exti_banks[i];
774 chip_data = stm32_exti_chip_init(host_data, i); 749 chip_data = stm32_exti_chip_init(host_data, i, node);
775 750
776 gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); 751 gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);
777 752
@@ -815,50 +790,130 @@ static const struct irq_domain_ops stm32_exti_h_domain_ops = {
815 .xlate = irq_domain_xlate_twocell, 790 .xlate = irq_domain_xlate_twocell,
816}; 791};
817 792
818static int 793static void stm32_exti_remove_irq(void *data)
819__init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, 794{
820 struct device_node *node, 795 struct irq_domain *domain = data;
821 struct device_node *parent) 796
797 irq_domain_remove(domain);
798}
799
800static int stm32_exti_remove(struct platform_device *pdev)
801{
802 stm32_exti_h_syscore_deinit();
803 return 0;
804}
805
806static int stm32_exti_probe(struct platform_device *pdev)
822{ 807{
808 int ret, i;
809 struct device *dev = &pdev->dev;
810 struct device_node *np = dev->of_node;
823 struct irq_domain *parent_domain, *domain; 811 struct irq_domain *parent_domain, *domain;
824 struct stm32_exti_host_data *host_data; 812 struct stm32_exti_host_data *host_data;
825 int ret, i; 813 const struct stm32_exti_drv_data *drv_data;
814 struct resource *res;
826 815
827 parent_domain = irq_find_host(parent); 816 host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
828 if (!parent_domain) { 817 if (!host_data)
829 pr_err("interrupt-parent not found\n"); 818 return -ENOMEM;
830 return -EINVAL; 819
820 /* check for optional hwspinlock which may be not available yet */
821 ret = of_hwspin_lock_get_id(np, 0);
822 if (ret == -EPROBE_DEFER)
823 /* hwspinlock framework not yet ready */
824 return ret;
825
826 if (ret >= 0) {
827 host_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
828 if (!host_data->hwlock) {
829 dev_err(dev, "Failed to request hwspinlock\n");
830 return -EINVAL;
831 }
832 } else if (ret != -ENOENT) {
833 /* note: ENOENT is a valid case (means 'no hwspinlock') */
834 dev_err(dev, "Failed to get hwspinlock\n");
835 return ret;
831 } 836 }
832 837
833 host_data = stm32_exti_host_init(drv_data, node); 838 /* initialize host_data */
834 if (!host_data) 839 drv_data = of_device_get_match_data(dev);
840 if (!drv_data) {
841 dev_err(dev, "no of match data\n");
842 return -ENODEV;
843 }
844 host_data->drv_data = drv_data;
845
846 host_data->chips_data = devm_kcalloc(dev, drv_data->bank_nr,
847 sizeof(*host_data->chips_data),
848 GFP_KERNEL);
849 if (!host_data->chips_data)
835 return -ENOMEM; 850 return -ENOMEM;
836 851
852 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
853 host_data->base = devm_ioremap_resource(dev, res);
854 if (IS_ERR(host_data->base)) {
855 dev_err(dev, "Unable to map registers\n");
856 return PTR_ERR(host_data->base);
857 }
858
837 for (i = 0; i < drv_data->bank_nr; i++) 859 for (i = 0; i < drv_data->bank_nr; i++)
838 stm32_exti_chip_init(host_data, i); 860 stm32_exti_chip_init(host_data, i, np);
861
862 parent_domain = irq_find_host(of_irq_find_parent(np));
863 if (!parent_domain) {
864 dev_err(dev, "GIC interrupt-parent not found\n");
865 return -EINVAL;
866 }
839 867
840 domain = irq_domain_add_hierarchy(parent_domain, 0, 868 domain = irq_domain_add_hierarchy(parent_domain, 0,
841 drv_data->bank_nr * IRQS_PER_BANK, 869 drv_data->bank_nr * IRQS_PER_BANK,
842 node, &stm32_exti_h_domain_ops, 870 np, &stm32_exti_h_domain_ops,
843 host_data); 871 host_data);
844 872
845 if (!domain) { 873 if (!domain) {
846 pr_err("%pOFn: Could not register exti domain.\n", node); 874 dev_err(dev, "Could not register exti domain\n");
847 ret = -ENOMEM; 875 return -ENOMEM;
848 goto out_unmap;
849 } 876 }
850 877
851 stm32_exti_h_syscore_init(); 878 ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq, domain);
879 if (ret)
880 return ret;
881
882 stm32_exti_h_syscore_init(host_data);
852 883
853 return 0; 884 return 0;
885}
854 886
855out_unmap: 887/* platform driver only for MP1 */
856 iounmap(host_data->base); 888static const struct of_device_id stm32_exti_ids[] = {
857 kfree(host_data->chips_data); 889 { .compatible = "st,stm32mp1-exti", .data = &stm32mp1_drv_data},
858 kfree(host_data); 890 {},
859 return ret; 891};
892MODULE_DEVICE_TABLE(of, stm32_exti_ids);
893
894static struct platform_driver stm32_exti_driver = {
895 .probe = stm32_exti_probe,
896 .remove = stm32_exti_remove,
897 .driver = {
898 .name = "stm32_exti",
899 .of_match_table = stm32_exti_ids,
900 },
901};
902
903static int __init stm32_exti_arch_init(void)
904{
905 return platform_driver_register(&stm32_exti_driver);
860} 906}
861 907
908static void __exit stm32_exti_arch_exit(void)
909{
910 return platform_driver_unregister(&stm32_exti_driver);
911}
912
913arch_initcall(stm32_exti_arch_init);
914module_exit(stm32_exti_arch_exit);
915
916/* no platform driver for F4 and H7 */
862static int __init stm32f4_exti_of_init(struct device_node *np, 917static int __init stm32f4_exti_of_init(struct device_node *np,
863 struct device_node *parent) 918 struct device_node *parent)
864{ 919{
@@ -874,11 +929,3 @@ static int __init stm32h7_exti_of_init(struct device_node *np,
874} 929}
875 930
876IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); 931IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);
877
878static int __init stm32mp1_exti_of_init(struct device_node *np,
879 struct device_node *parent)
880{
881 return stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent);
882}
883
884IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init);