2 * Intel Reference Systems cplds
4 * Copyright (C) 2014 Robert Jarzmik
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Cplds motherboard driver, supporting lubbock and mainstone SoC board.
14 #include <linux/bitops.h>
15 #include <linux/gpio.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/irqdomain.h>
21 #include <linux/mfd/core.h>
22 #include <linux/module.h>
23 #include <linux/of_platform.h>
25 #define FPGA_IRQ_MASK_EN 0x0
26 #define FPGA_IRQ_SET_CLR 0x10
28 #define CPLDS_NB_IRQ 32
33 unsigned int irq_mask
;
34 struct gpio_desc
*gpio0
;
35 struct irq_domain
*irqdomain
;
38 static irqreturn_t
cplds_irq_handler(int in_irq
, void *d
)
40 struct cplds
*fpga
= d
;
41 unsigned long pending
;
45 pending
= readl(fpga
->base
+ FPGA_IRQ_SET_CLR
) & fpga
->irq_mask
;
46 for_each_set_bit(bit
, &pending
, CPLDS_NB_IRQ
) {
47 generic_handle_irq(irq_find_mapping(fpga
->irqdomain
,
55 static void cplds_irq_mask(struct irq_data
*d
)
57 struct cplds
*fpga
= irq_data_get_irq_chip_data(d
);
58 unsigned int cplds_irq
= irqd_to_hwirq(d
);
59 unsigned int bit
= BIT(cplds_irq
);
61 fpga
->irq_mask
&= ~bit
;
62 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
65 static void cplds_irq_unmask(struct irq_data
*d
)
67 struct cplds
*fpga
= irq_data_get_irq_chip_data(d
);
68 unsigned int cplds_irq
= irqd_to_hwirq(d
);
69 unsigned int set
, bit
= BIT(cplds_irq
);
71 set
= readl(fpga
->base
+ FPGA_IRQ_SET_CLR
);
72 writel(set
& ~bit
, fpga
->base
+ FPGA_IRQ_SET_CLR
);
74 fpga
->irq_mask
|= bit
;
75 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
78 static struct irq_chip cplds_irq_chip
= {
80 .irq_ack
= cplds_irq_mask
,
81 .irq_mask
= cplds_irq_mask
,
82 .irq_unmask
= cplds_irq_unmask
,
83 .flags
= IRQCHIP_MASK_ON_SUSPEND
| IRQCHIP_SKIP_SET_WAKE
,
86 static int cplds_irq_domain_map(struct irq_domain
*d
, unsigned int irq
,
87 irq_hw_number_t hwirq
)
89 struct cplds
*fpga
= d
->host_data
;
91 irq_set_chip_and_handler(irq
, &cplds_irq_chip
, handle_level_irq
);
92 irq_set_chip_data(irq
, fpga
);
97 static const struct irq_domain_ops cplds_irq_domain_ops
= {
98 .xlate
= irq_domain_xlate_twocell
,
99 .map
= cplds_irq_domain_map
,
102 static int cplds_resume(struct platform_device
*pdev
)
104 struct cplds
*fpga
= platform_get_drvdata(pdev
);
106 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
111 static int cplds_probe(struct platform_device
*pdev
)
113 struct resource
*res
;
117 unsigned long irqflags
= 0;
119 fpga
= devm_kzalloc(&pdev
->dev
, sizeof(*fpga
), GFP_KERNEL
);
123 fpga
->irq
= platform_get_irq(pdev
, 0);
127 base_irq
= platform_get_irq(pdev
, 1);
131 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
132 fpga
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
133 if (IS_ERR(fpga
->base
))
134 return PTR_ERR(fpga
->base
);
136 platform_set_drvdata(pdev
, fpga
);
138 writel(fpga
->irq_mask
, fpga
->base
+ FPGA_IRQ_MASK_EN
);
139 writel(0, fpga
->base
+ FPGA_IRQ_SET_CLR
);
141 irqflags
= irq_get_trigger_type(fpga
->irq
);
142 ret
= devm_request_irq(&pdev
->dev
, fpga
->irq
, cplds_irq_handler
,
143 irqflags
, dev_name(&pdev
->dev
), fpga
);
145 return -EPROBE_DEFER
;
148 dev_err(&pdev
->dev
, "couldn't request main irq%d: %d\n",
153 irq_set_irq_wake(fpga
->irq
, 1);
154 fpga
->irqdomain
= irq_domain_add_linear(pdev
->dev
.of_node
,
156 &cplds_irq_domain_ops
, fpga
);
157 if (!fpga
->irqdomain
)
161 ret
= irq_create_strict_mappings(fpga
->irqdomain
, base_irq
, 0,
164 dev_err(&pdev
->dev
, "couldn't create the irq mapping %d..%d\n",
165 base_irq
, base_irq
+ CPLDS_NB_IRQ
);
173 static int cplds_remove(struct platform_device
*pdev
)
175 struct cplds
*fpga
= platform_get_drvdata(pdev
);
177 irq_set_chip_and_handler(fpga
->irq
, NULL
, NULL
);
182 static const struct of_device_id cplds_id_table
[] = {
183 { .compatible
= "intel,lubbock-cplds-irqs", },
184 { .compatible
= "intel,mainstone-cplds-irqs", },
187 MODULE_DEVICE_TABLE(of
, cplds_id_table
);
189 static struct platform_driver cplds_driver
= {
191 .name
= "pxa_cplds_irqs",
192 .of_match_table
= of_match_ptr(cplds_id_table
),
194 .probe
= cplds_probe
,
195 .remove
= cplds_remove
,
196 .resume
= cplds_resume
,
199 module_platform_driver(cplds_driver
);
201 MODULE_DESCRIPTION("PXA Cplds interrupts driver");
202 MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
203 MODULE_LICENSE("GPL");