diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2015-04-08 17:41:28 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2015-04-08 17:41:28 -0400 |
commit | fdb7144ba36ef0c1882df3484cc9dfb7d57b2a26 (patch) | |
tree | 5f4e49482da1f1a06ecf81c0031e058f42b1443c /drivers/irqchip | |
parent | b594c6e20c7ff65e0f0775cb1866e97501c96846 (diff) | |
parent | c9558659e68ee30740f265c54f792bf75add21f2 (diff) |
Merge tag 'irqchip-core-4.0' of git://git.infradead.org/users/jcooper/linux into irq/core
irqchip core changes for v4.0 from Jason Cooper
- ST
- New driver, irq-st
- Renesas
- Use u32 type for 32bit regs
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/Kconfig | 7 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-irqc.c | 4 | ||||
-rw-r--r-- | drivers/irqchip/irq-st.c | 206 |
4 files changed, 216 insertions, 2 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index cc79d2a5a8c2..c8d260e33a90 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -110,6 +110,13 @@ config RENESAS_IRQC | |||
110 | bool | 110 | bool |
111 | select IRQ_DOMAIN | 111 | select IRQ_DOMAIN |
112 | 112 | ||
113 | config ST_IRQCHIP | ||
114 | bool | ||
115 | select REGMAP | ||
116 | select MFD_SYSCON | ||
117 | help | ||
118 | Enables SysCfg Controlled IRQs on STi based platforms. | ||
119 | |||
113 | config TB10X_IRQC | 120 | config TB10X_IRQC |
114 | bool | 121 | bool |
115 | select IRQ_DOMAIN | 122 | select IRQ_DOMAIN |
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 42965d2476bb..9bb4fd191e94 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -33,6 +33,7 @@ obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o | |||
33 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o | 33 | obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o |
34 | obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o | 34 | obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o |
35 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o | 35 | obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o |
36 | obj-$(CONFIG_ST_IRQCHIP) += irq-st.o | ||
36 | obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o | 37 | obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o |
37 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o | 38 | obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o |
38 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o | 39 | obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o |
diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 384e6ed61d7c..2ea3412fdf8c 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c | |||
@@ -94,7 +94,7 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) | |||
94 | struct irqc_priv *p = irq_data_get_irq_chip_data(d); | 94 | struct irqc_priv *p = irq_data_get_irq_chip_data(d); |
95 | int hw_irq = irqd_to_hwirq(d); | 95 | int hw_irq = irqd_to_hwirq(d); |
96 | unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK]; | 96 | unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK]; |
97 | unsigned long tmp; | 97 | u32 tmp; |
98 | 98 | ||
99 | irqc_dbg(&p->irq[hw_irq], "sense"); | 99 | irqc_dbg(&p->irq[hw_irq], "sense"); |
100 | 100 | ||
@@ -112,7 +112,7 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id) | |||
112 | { | 112 | { |
113 | struct irqc_irq *i = dev_id; | 113 | struct irqc_irq *i = dev_id; |
114 | struct irqc_priv *p = i->p; | 114 | struct irqc_priv *p = i->p; |
115 | unsigned long bit = BIT(i->hw_irq); | 115 | u32 bit = BIT(i->hw_irq); |
116 | 116 | ||
117 | irqc_dbg(i, "demux1"); | 117 | irqc_dbg(i, "demux1"); |
118 | 118 | ||
diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c new file mode 100644 index 000000000000..9af48a85c16f --- /dev/null +++ b/drivers/irqchip/irq-st.c | |||
@@ -0,0 +1,206 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 STMicroelectronics – All Rights Reserved | ||
3 | * | ||
4 | * Author: Lee Jones <lee.jones@linaro.org> | ||
5 | * | ||
6 | * This is a re-write of Christophe Kerello's PMU driver. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <dt-bindings/interrupt-controller/irq-st.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/mfd/syscon.h> | ||
16 | #include <linux/of_device.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #define STIH415_SYSCFG_642 0x0a8 | ||
22 | #define STIH416_SYSCFG_7543 0x87c | ||
23 | #define STIH407_SYSCFG_5102 0x198 | ||
24 | #define STID127_SYSCFG_734 0x088 | ||
25 | |||
26 | #define ST_A9_IRQ_MASK 0x001FFFFF | ||
27 | #define ST_A9_IRQ_MAX_CHANS 2 | ||
28 | |||
29 | #define ST_A9_IRQ_EN_CTI_0 BIT(0) | ||
30 | #define ST_A9_IRQ_EN_CTI_1 BIT(1) | ||
31 | #define ST_A9_IRQ_EN_PMU_0 BIT(2) | ||
32 | #define ST_A9_IRQ_EN_PMU_1 BIT(3) | ||
33 | #define ST_A9_IRQ_EN_PL310_L2 BIT(4) | ||
34 | #define ST_A9_IRQ_EN_EXT_0 BIT(5) | ||
35 | #define ST_A9_IRQ_EN_EXT_1 BIT(6) | ||
36 | #define ST_A9_IRQ_EN_EXT_2 BIT(7) | ||
37 | |||
38 | #define ST_A9_FIQ_N_SEL(dev, chan) (dev << (8 + (chan * 3))) | ||
39 | #define ST_A9_IRQ_N_SEL(dev, chan) (dev << (14 + (chan * 3))) | ||
40 | #define ST_A9_EXTIRQ_INV_SEL(dev) (dev << 20) | ||
41 | |||
42 | struct st_irq_syscfg { | ||
43 | struct regmap *regmap; | ||
44 | unsigned int syscfg; | ||
45 | unsigned int config; | ||
46 | bool ext_inverted; | ||
47 | }; | ||
48 | |||
49 | static const struct of_device_id st_irq_syscfg_match[] = { | ||
50 | { | ||
51 | .compatible = "st,stih415-irq-syscfg", | ||
52 | .data = (void *)STIH415_SYSCFG_642, | ||
53 | }, | ||
54 | { | ||
55 | .compatible = "st,stih416-irq-syscfg", | ||
56 | .data = (void *)STIH416_SYSCFG_7543, | ||
57 | }, | ||
58 | { | ||
59 | .compatible = "st,stih407-irq-syscfg", | ||
60 | .data = (void *)STIH407_SYSCFG_5102, | ||
61 | }, | ||
62 | { | ||
63 | .compatible = "st,stid127-irq-syscfg", | ||
64 | .data = (void *)STID127_SYSCFG_734, | ||
65 | }, | ||
66 | {} | ||
67 | }; | ||
68 | |||
69 | static int st_irq_xlate(struct platform_device *pdev, | ||
70 | int device, int channel, bool irq) | ||
71 | { | ||
72 | struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev); | ||
73 | |||
74 | /* Set the device enable bit. */ | ||
75 | switch (device) { | ||
76 | case ST_IRQ_SYSCFG_EXT_0: | ||
77 | ddata->config |= ST_A9_IRQ_EN_EXT_0; | ||
78 | break; | ||
79 | case ST_IRQ_SYSCFG_EXT_1: | ||
80 | ddata->config |= ST_A9_IRQ_EN_EXT_1; | ||
81 | break; | ||
82 | case ST_IRQ_SYSCFG_EXT_2: | ||
83 | ddata->config |= ST_A9_IRQ_EN_EXT_2; | ||
84 | break; | ||
85 | case ST_IRQ_SYSCFG_CTI_0: | ||
86 | ddata->config |= ST_A9_IRQ_EN_CTI_0; | ||
87 | break; | ||
88 | case ST_IRQ_SYSCFG_CTI_1: | ||
89 | ddata->config |= ST_A9_IRQ_EN_CTI_1; | ||
90 | break; | ||
91 | case ST_IRQ_SYSCFG_PMU_0: | ||
92 | ddata->config |= ST_A9_IRQ_EN_PMU_0; | ||
93 | break; | ||
94 | case ST_IRQ_SYSCFG_PMU_1: | ||
95 | ddata->config |= ST_A9_IRQ_EN_PMU_1; | ||
96 | break; | ||
97 | case ST_IRQ_SYSCFG_pl310_L2: | ||
98 | ddata->config |= ST_A9_IRQ_EN_PL310_L2; | ||
99 | break; | ||
100 | case ST_IRQ_SYSCFG_DISABLED: | ||
101 | return 0; | ||
102 | default: | ||
103 | dev_err(&pdev->dev, "Unrecognised device %d\n", device); | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | |||
107 | /* Select IRQ/FIQ channel for device. */ | ||
108 | ddata->config |= irq ? | ||
109 | ST_A9_IRQ_N_SEL(device, channel) : | ||
110 | ST_A9_FIQ_N_SEL(device, channel); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int st_irq_syscfg_enable(struct platform_device *pdev) | ||
116 | { | ||
117 | struct device_node *np = pdev->dev.of_node; | ||
118 | struct st_irq_syscfg *ddata = dev_get_drvdata(&pdev->dev); | ||
119 | int channels, ret, i; | ||
120 | u32 device, invert; | ||
121 | |||
122 | channels = of_property_count_u32_elems(np, "st,irq-device"); | ||
123 | if (channels != ST_A9_IRQ_MAX_CHANS) { | ||
124 | dev_err(&pdev->dev, "st,enable-irq-device must have 2 elems\n"); | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | channels = of_property_count_u32_elems(np, "st,fiq-device"); | ||
129 | if (channels != ST_A9_IRQ_MAX_CHANS) { | ||
130 | dev_err(&pdev->dev, "st,enable-fiq-device must have 2 elems\n"); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | for (i = 0; i < ST_A9_IRQ_MAX_CHANS; i++) { | ||
135 | of_property_read_u32_index(np, "st,irq-device", i, &device); | ||
136 | |||
137 | ret = st_irq_xlate(pdev, device, i, true); | ||
138 | if (ret) | ||
139 | return ret; | ||
140 | |||
141 | of_property_read_u32_index(np, "st,fiq-device", i, &device); | ||
142 | |||
143 | ret = st_irq_xlate(pdev, device, i, false); | ||
144 | if (ret) | ||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | /* External IRQs may be inverted. */ | ||
149 | of_property_read_u32(np, "st,invert-ext", &invert); | ||
150 | ddata->config |= ST_A9_EXTIRQ_INV_SEL(invert); | ||
151 | |||
152 | return regmap_update_bits(ddata->regmap, ddata->syscfg, | ||
153 | ST_A9_IRQ_MASK, ddata->config); | ||
154 | } | ||
155 | |||
156 | static int st_irq_syscfg_probe(struct platform_device *pdev) | ||
157 | { | ||
158 | struct device_node *np = pdev->dev.of_node; | ||
159 | const struct of_device_id *match; | ||
160 | struct st_irq_syscfg *ddata; | ||
161 | |||
162 | ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
163 | if (!ddata) | ||
164 | return -ENOMEM; | ||
165 | |||
166 | match = of_match_device(st_irq_syscfg_match, &pdev->dev); | ||
167 | if (!match) | ||
168 | return -ENODEV; | ||
169 | |||
170 | ddata->syscfg = (unsigned int)match->data; | ||
171 | |||
172 | ddata->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); | ||
173 | if (IS_ERR(ddata->regmap)) { | ||
174 | dev_err(&pdev->dev, "syscfg phandle missing\n"); | ||
175 | return PTR_ERR(ddata->regmap); | ||
176 | } | ||
177 | |||
178 | dev_set_drvdata(&pdev->dev, ddata); | ||
179 | |||
180 | return st_irq_syscfg_enable(pdev); | ||
181 | } | ||
182 | |||
183 | static int st_irq_syscfg_resume(struct device *dev) | ||
184 | { | ||
185 | struct st_irq_syscfg *ddata = dev_get_drvdata(dev); | ||
186 | |||
187 | return regmap_update_bits(ddata->regmap, ddata->syscfg, | ||
188 | ST_A9_IRQ_MASK, ddata->config); | ||
189 | } | ||
190 | |||
191 | static SIMPLE_DEV_PM_OPS(st_irq_syscfg_pm_ops, NULL, st_irq_syscfg_resume); | ||
192 | |||
193 | static struct platform_driver st_irq_syscfg_driver = { | ||
194 | .driver = { | ||
195 | .name = "st_irq_syscfg", | ||
196 | .pm = &st_irq_syscfg_pm_ops, | ||
197 | .of_match_table = st_irq_syscfg_match, | ||
198 | }, | ||
199 | .probe = st_irq_syscfg_probe, | ||
200 | }; | ||
201 | |||
202 | static int __init st_irq_syscfg_init(void) | ||
203 | { | ||
204 | return platform_driver_register(&st_irq_syscfg_driver); | ||
205 | } | ||
206 | core_initcall(st_irq_syscfg_init); | ||