Commit | Line | Data |
---|---|---|
03ac990e MW |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* | |
3 | * sl28cpld interrupt controller driver | |
4 | * | |
5 | * Copyright 2020 Kontron Europe GmbH | |
6 | */ | |
7 | ||
8 | #include <linux/interrupt.h> | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/mod_devicetable.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/property.h> | |
14 | #include <linux/regmap.h> | |
15 | ||
16 | #define INTC_IE 0x00 | |
17 | #define INTC_IP 0x01 | |
18 | ||
19 | static const struct regmap_irq sl28cpld_irqs[] = { | |
20 | REGMAP_IRQ_REG_LINE(0, 8), | |
21 | REGMAP_IRQ_REG_LINE(1, 8), | |
22 | REGMAP_IRQ_REG_LINE(2, 8), | |
23 | REGMAP_IRQ_REG_LINE(3, 8), | |
24 | REGMAP_IRQ_REG_LINE(4, 8), | |
25 | REGMAP_IRQ_REG_LINE(5, 8), | |
26 | REGMAP_IRQ_REG_LINE(6, 8), | |
27 | REGMAP_IRQ_REG_LINE(7, 8), | |
28 | }; | |
29 | ||
30 | struct sl28cpld_intc { | |
31 | struct regmap *regmap; | |
32 | struct regmap_irq_chip chip; | |
33 | struct regmap_irq_chip_data *irq_data; | |
34 | }; | |
35 | ||
36 | static int sl28cpld_intc_probe(struct platform_device *pdev) | |
37 | { | |
38 | struct device *dev = &pdev->dev; | |
39 | struct sl28cpld_intc *irqchip; | |
40 | int irq; | |
41 | u32 base; | |
42 | int ret; | |
43 | ||
44 | if (!dev->parent) | |
45 | return -ENODEV; | |
46 | ||
47 | irqchip = devm_kzalloc(dev, sizeof(*irqchip), GFP_KERNEL); | |
48 | if (!irqchip) | |
49 | return -ENOMEM; | |
50 | ||
51 | irqchip->regmap = dev_get_regmap(dev->parent, NULL); | |
52 | if (!irqchip->regmap) | |
53 | return -ENODEV; | |
54 | ||
55 | irq = platform_get_irq(pdev, 0); | |
56 | if (irq < 0) | |
57 | return irq; | |
58 | ||
59 | ret = device_property_read_u32(&pdev->dev, "reg", &base); | |
60 | if (ret) | |
61 | return -EINVAL; | |
62 | ||
63 | irqchip->chip.name = "sl28cpld-intc"; | |
64 | irqchip->chip.irqs = sl28cpld_irqs; | |
65 | irqchip->chip.num_irqs = ARRAY_SIZE(sl28cpld_irqs); | |
66 | irqchip->chip.num_regs = 1; | |
67 | irqchip->chip.status_base = base + INTC_IP; | |
68 | irqchip->chip.mask_base = base + INTC_IE; | |
e90f55e0 | 69 | irqchip->chip.mask_invert = true; |
03ac990e MW |
70 | irqchip->chip.ack_base = base + INTC_IP; |
71 | ||
72 | return devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev), | |
73 | irqchip->regmap, irq, | |
74 | IRQF_SHARED | IRQF_ONESHOT, 0, | |
75 | &irqchip->chip, | |
76 | &irqchip->irq_data); | |
77 | } | |
78 | ||
79 | static const struct of_device_id sl28cpld_intc_of_match[] = { | |
80 | { .compatible = "kontron,sl28cpld-intc" }, | |
81 | {} | |
82 | }; | |
83 | MODULE_DEVICE_TABLE(of, sl28cpld_intc_of_match); | |
84 | ||
85 | static struct platform_driver sl28cpld_intc_driver = { | |
86 | .probe = sl28cpld_intc_probe, | |
87 | .driver = { | |
88 | .name = "sl28cpld-intc", | |
89 | .of_match_table = sl28cpld_intc_of_match, | |
90 | } | |
91 | }; | |
92 | module_platform_driver(sl28cpld_intc_driver); | |
93 | ||
94 | MODULE_DESCRIPTION("sl28cpld Interrupt Controller Driver"); | |
95 | MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); | |
96 | MODULE_LICENSE("GPL"); |