1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Intel Reference Systems cplds
5 * Copyright (C) 2014 Robert Jarzmik
7 * Cplds motherboard driver, supporting lubbock and mainstone SoC board.
10 #include <linux/bitops.h>
11 #include <linux/gpio.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <linux/irqdomain.h>
17 #include <linux/mfd/core.h>
18 #include <linux/module.h>
19 #include <linux/of_platform.h>
21 #define FPGA_IRQ_MASK_EN 0x0
22 #define FPGA_IRQ_SET_CLR 0x10
24 #define CPLDS_NB_IRQ 32
29 unsigned int irq_mask
;
30 struct gpio_desc
*gpio0
;
31 struct irq_domain
*irqdomain
;
34 static irqreturn_t
cplds_irq_handler(int in_irq
, void *d
)
36 struct cplds
*fpga
= d
;
37 unsigned long pending
;
41 pending
= readl(fpga
->base
+ FPGA_IRQ_SET_CLR
) & fpga
->irq_mask
;
42 for_each_set_bit(bit
, &pending
, CPLDS_NB_IRQ
) {
43 generic_handle_irq(irq_find_mapping(fpga
->irqdomain
,
51 static void cplds_irq_mask(struct irq_data
*d
)
53 struct cplds
*fpga
= irq_data_get_irq_chip_data(d
);
54 unsigned int cplds_irq
= irqd_to_hwirq(d
);
55 unsigned int bit
= BIT(cplds_irq
);
57 fpga
->irq_mask
&= ~bit
;
58 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
61 static void cplds_irq_unmask(struct irq_data
*d
)
63 struct cplds
*fpga
= irq_data_get_irq_chip_data(d
);
64 unsigned int cplds_irq
= irqd_to_hwirq(d
);
65 unsigned int set
, bit
= BIT(cplds_irq
);
67 set
= readl(fpga
->base
+ FPGA_IRQ_SET_CLR
);
68 writel(set
& ~bit
, fpga
->base
+ FPGA_IRQ_SET_CLR
);
70 fpga
->irq_mask
|= bit
;
71 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
74 static struct irq_chip cplds_irq_chip
= {
76 .irq_ack
= cplds_irq_mask
,
77 .irq_mask
= cplds_irq_mask
,
78 .irq_unmask
= cplds_irq_unmask
,
79 .flags
= IRQCHIP_MASK_ON_SUSPEND
| IRQCHIP_SKIP_SET_WAKE
,
82 static int cplds_irq_domain_map(struct irq_domain
*d
, unsigned int irq
,
83 irq_hw_number_t hwirq
)
85 struct cplds
*fpga
= d
->host_data
;
87 irq_set_chip_and_handler(irq
, &cplds_irq_chip
, handle_level_irq
);
88 irq_set_chip_data(irq
, fpga
);
93 static const struct irq_domain_ops cplds_irq_domain_ops
= {
94 .xlate
= irq_domain_xlate_twocell
,
95 .map
= cplds_irq_domain_map
,
98 static int cplds_resume(struct platform_device
*pdev
)
100 struct cplds
*fpga
= platform_get_drvdata(pdev
);
102 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
107 static int cplds_probe(struct platform_device
*pdev
)
109 struct resource
*res
;
113 unsigned long irqflags
= 0;
115 fpga
= devm_kzalloc(&pdev
->dev
, sizeof(*fpga
), GFP_KERNEL
);
119 fpga
->irq
= platform_get_irq(pdev
, 0);
123 base_irq
= platform_get_irq(pdev
, 1);
127 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
128 fpga
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
129 if (IS_ERR(fpga
->base
))
130 return PTR_ERR(fpga
->base
);
132 platform_set_drvdata(pdev
, fpga
);
134 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
135 writel(0, fpga
->base
+ FPGA_IRQ_SET_CLR
);
137 irqflags
= irq_get_trigger_type(fpga
->irq
);
138 ret
= devm_request_irq(&pdev
->dev
, fpga
->irq
, cplds_irq_handler
,
139 irqflags
, dev_name(&pdev
->dev
), fpga
);
141 return -EPROBE_DEFER
;
144 dev_err(&pdev
->dev
, "couldn't request main irq%d: %d\n",
149 irq_set_irq_wake(fpga
->irq
, 1);
150 fpga
->irqdomain
= irq_domain_add_linear(pdev
->dev
.of_node
,
152 &cplds_irq_domain_ops
, fpga
);
153 if (!fpga
->irqdomain
)
157 ret
= irq_create_strict_mappings(fpga
->irqdomain
, base_irq
, 0,
160 dev_err(&pdev
->dev
, "couldn't create the irq mapping %d..%d\n",
161 base_irq
, base_irq
+ CPLDS_NB_IRQ
);
169 static int cplds_remove(struct platform_device
*pdev
)
171 struct cplds
*fpga
= platform_get_drvdata(pdev
);
173 irq_set_chip_and_handler(fpga
->irq
, NULL
, NULL
);
178 static const struct of_device_id cplds_id_table
[] = {
179 { .compatible
= "intel,lubbock-cplds-irqs", },
180 { .compatible
= "intel,mainstone-cplds-irqs", },
183 MODULE_DEVICE_TABLE(of
, cplds_id_table
);
185 static struct platform_driver cplds_driver
= {
187 .name
= "pxa_cplds_irqs",
188 .of_match_table
= of_match_ptr(cplds_id_table
),
190 .probe
= cplds_probe
,
191 .remove
= cplds_remove
,
192 .resume
= cplds_resume
,
195 module_platform_driver(cplds_driver
);
197 MODULE_DESCRIPTION("PXA Cplds interrupts driver");
198 MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
199 MODULE_LICENSE("GPL");