aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/exynos-combiner.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-04 15:31:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-04 15:31:18 -0400
commit6fa52ed33bea997374a88dbacbba5bf8c7ac4fef (patch)
treea0904b78d66c9b99d6acf944cf58bcaa0cffc511 /drivers/irqchip/exynos-combiner.c
parent1db772216f48978d5146b858586f6178433aad38 (diff)
parentbc8fd900c4d460b4e4bf785bb48bfced0ac9941b (diff)
Merge tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver changes from Olof Johansson: "This is a rather large set of patches for device drivers that for one reason or another the subsystem maintainer preferred to get merged through the arm-soc tree. There are both new drivers as well as existing drivers that are getting converted from platform-specific code into standalone drivers using the appropriate subsystem specific interfaces. In particular, we can now have pinctrl, clk, clksource and irqchip drivers in one file per driver, without the need to call into platform specific interface, or to get called from platform specific code, as long as all information about the hardware is provided through a device tree. Most of the drivers we touch this time are for clocksource. Since now most of them are part of drivers/clocksource, I expect that we won't have to touch these again from arm-soc and can let the clocksource maintainers take care of these in the future. Another larger part of this series is specific to the exynos platform, which is seeing some significant effort in upstreaming and modernization of its device drivers this time around, which unfortunately is also the cause for the churn and a lot of the merge conflicts. There is one new subsystem that gets merged as part of this series: the reset controller interface, which is a very simple interface for taking devices on the SoC out of reset or back into reset. Patches to use this interface on i.MX follow later in this merge window, and we are going to have other platforms (at least tegra and sirf) get converted in 3.11. This will let us get rid of platform specific callbacks in a number of platform independent device drivers." * tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (256 commits) irqchip: s3c24xx: add missing __init annotations ARM: dts: Disable the RTC by default on exynos5 clk: exynos5250: Fix parent clock for sclk_mmc{0,1,2,3} ARM: exynos: restore mach/regs-clock.h for exynos5 clocksource: exynos_mct: fix build error on non-DT pinctrl: vt8500: wmt: Fix checking return value of pinctrl_register() irqchip: vt8500: Convert arch-vt8500 to new irqchip infrastructure reset: NULL deref on allocation failure reset: Add reset controller API dt: describe base reset signal binding ARM: EXYNOS: Add arm-pmu DT binding for exynos421x ARM: EXYNOS: Add arm-pmu DT binding for exynos5250 ARM: EXYNOS: Enable PMUs for exynos4 irqchip: exynos-combiner: Correct combined IRQs for exynos4 irqchip: exynos-combiner: Add set_irq_affinity function for combiner_irq ARM: EXYNOS: fix compilation error introduced due to common clock migration clk: exynos5250: Fix divider values for sclk_mmc{0,1,2,3} clk: exynos4: export clocks required for fimc-is clk: samsung: Fix compilation error clk: tegra: fix enum tegra114_clk to match binding ...
Diffstat (limited to 'drivers/irqchip/exynos-combiner.c')
-rw-r--r--drivers/irqchip/exynos-combiner.c80
1 files changed, 62 insertions, 18 deletions
diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c
index 6a5201351507..02492ab20d22 100644
--- a/drivers/irqchip/exynos-combiner.c
+++ b/drivers/irqchip/exynos-combiner.c
@@ -32,6 +32,7 @@ struct combiner_chip_data {
32 unsigned int irq_offset; 32 unsigned int irq_offset;
33 unsigned int irq_mask; 33 unsigned int irq_mask;
34 void __iomem *base; 34 void __iomem *base;
35 unsigned int parent_irq;
35}; 36};
36 37
37static struct irq_domain *combiner_irq_domain; 38static struct irq_domain *combiner_irq_domain;
@@ -88,22 +89,46 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
88 chained_irq_exit(chip, desc); 89 chained_irq_exit(chip, desc);
89} 90}
90 91
92#ifdef CONFIG_SMP
93static int combiner_set_affinity(struct irq_data *d,
94 const struct cpumask *mask_val, bool force)
95{
96 struct combiner_chip_data *chip_data = irq_data_get_irq_chip_data(d);
97 struct irq_chip *chip = irq_get_chip(chip_data->parent_irq);
98 struct irq_data *data = irq_get_irq_data(chip_data->parent_irq);
99
100 if (chip && chip->irq_set_affinity)
101 return chip->irq_set_affinity(data, mask_val, force);
102 else
103 return -EINVAL;
104}
105#endif
106
91static struct irq_chip combiner_chip = { 107static struct irq_chip combiner_chip = {
92 .name = "COMBINER", 108 .name = "COMBINER",
93 .irq_mask = combiner_mask_irq, 109 .irq_mask = combiner_mask_irq,
94 .irq_unmask = combiner_unmask_irq, 110 .irq_unmask = combiner_unmask_irq,
111#ifdef CONFIG_SMP
112 .irq_set_affinity = combiner_set_affinity,
113#endif
95}; 114};
96 115
97static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq) 116static unsigned int max_combiner_nr(void)
98{ 117{
99 unsigned int max_nr;
100
101 if (soc_is_exynos5250()) 118 if (soc_is_exynos5250())
102 max_nr = EXYNOS5_MAX_COMBINER_NR; 119 return EXYNOS5_MAX_COMBINER_NR;
120 else if (soc_is_exynos4412())
121 return EXYNOS4412_MAX_COMBINER_NR;
122 else if (soc_is_exynos4212())
123 return EXYNOS4212_MAX_COMBINER_NR;
103 else 124 else
104 max_nr = EXYNOS4_MAX_COMBINER_NR; 125 return EXYNOS4210_MAX_COMBINER_NR;
126}
105 127
106 if (combiner_nr >= max_nr) 128static void __init combiner_cascade_irq(unsigned int combiner_nr,
129 unsigned int irq)
130{
131 if (combiner_nr >= max_combiner_nr())
107 BUG(); 132 BUG();
108 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0) 133 if (irq_set_handler_data(irq, &combiner_data[combiner_nr]) != 0)
109 BUG(); 134 BUG();
@@ -111,12 +136,13 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
111} 136}
112 137
113static void __init combiner_init_one(unsigned int combiner_nr, 138static void __init combiner_init_one(unsigned int combiner_nr,
114 void __iomem *base) 139 void __iomem *base, unsigned int irq)
115{ 140{
116 combiner_data[combiner_nr].base = base; 141 combiner_data[combiner_nr].base = base;
117 combiner_data[combiner_nr].irq_offset = irq_find_mapping( 142 combiner_data[combiner_nr].irq_offset = irq_find_mapping(
118 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER); 143 combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
119 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3); 144 combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
145 combiner_data[combiner_nr].parent_irq = irq;
120 146
121 /* Disable all interrupts */ 147 /* Disable all interrupts */
122 __raw_writel(combiner_data[combiner_nr].irq_mask, 148 __raw_writel(combiner_data[combiner_nr].irq_mask,
@@ -167,23 +193,38 @@ static struct irq_domain_ops combiner_irq_domain_ops = {
167 .map = combiner_irq_domain_map, 193 .map = combiner_irq_domain_map,
168}; 194};
169 195
196static unsigned int exynos4x12_combiner_extra_irq(int group)
197{
198 switch (group) {
199 case 16:
200 return IRQ_SPI(107);
201 case 17:
202 return IRQ_SPI(108);
203 case 18:
204 return IRQ_SPI(48);
205 case 19:
206 return IRQ_SPI(42);
207 default:
208 return 0;
209 }
210}
211
170void __init combiner_init(void __iomem *combiner_base, 212void __init combiner_init(void __iomem *combiner_base,
171 struct device_node *np) 213 struct device_node *np)
172{ 214{
173 int i, irq, irq_base; 215 int i, irq, irq_base;
174 unsigned int max_nr, nr_irq; 216 unsigned int max_nr, nr_irq;
175 217
218 max_nr = max_combiner_nr();
219
176 if (np) { 220 if (np) {
177 if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) { 221 if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
178 pr_warning("%s: number of combiners not specified, " 222 pr_info("%s: number of combiners not specified, "
179 "setting default as %d.\n", 223 "setting default as %d.\n",
180 __func__, EXYNOS4_MAX_COMBINER_NR); 224 __func__, max_nr);
181 max_nr = EXYNOS4_MAX_COMBINER_NR;
182 } 225 }
183 } else {
184 max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
185 EXYNOS4_MAX_COMBINER_NR;
186 } 226 }
227
187 nr_irq = max_nr * MAX_IRQ_IN_COMBINER; 228 nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
188 229
189 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0); 230 irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
@@ -200,12 +241,15 @@ void __init combiner_init(void __iomem *combiner_base,
200 } 241 }
201 242
202 for (i = 0; i < max_nr; i++) { 243 for (i = 0; i < max_nr; i++) {
203 combiner_init_one(i, combiner_base + (i >> 2) * 0x10); 244 if (i < EXYNOS4210_MAX_COMBINER_NR || soc_is_exynos5250())
204 irq = IRQ_SPI(i); 245 irq = IRQ_SPI(i);
246 else
247 irq = exynos4x12_combiner_extra_irq(i);
205#ifdef CONFIG_OF 248#ifdef CONFIG_OF
206 if (np) 249 if (np)
207 irq = irq_of_parse_and_map(np, i); 250 irq = irq_of_parse_and_map(np, i);
208#endif 251#endif
252 combiner_init_one(i, combiner_base + (i >> 2) * 0x10, irq);
209 combiner_cascade_irq(i, irq); 253 combiner_cascade_irq(i, irq);
210 } 254 }
211} 255}