diff options
author | Rhyland Klein <rklein@nvidia.com> | 2012-05-18 05:52:19 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-05-20 11:27:08 -0400 |
commit | 21f7541d8861fdcdff663c68903e961ca1b06dc6 (patch) | |
tree | 48e9c376058b13a653146bd67c9e097f794f2ce8 /drivers/mfd/tps65910-irq.c | |
parent | b09530ef844f0bf29ed3677080c02b179be84818 (diff) |
mfd: Add tps65910-irq devicetree init and irqdomain support
This change changes the tps65910-irq code to use irqdomain, and support
initialization from devicetree. This assumes that the irq_base in the
platform data is -1 if devicetree is used.
Signed-off-by: Rhyland Klein <rklein@nvidia.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/tps65910-irq.c')
-rw-r--r-- | drivers/mfd/tps65910-irq.c | 96 |
1 files changed, 62 insertions, 34 deletions
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index 0f1ff7fbdc74..09aab3e4776d 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c | |||
@@ -20,15 +20,10 @@ | |||
20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/irqdomain.h> | ||
23 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
24 | #include <linux/mfd/tps65910.h> | 25 | #include <linux/mfd/tps65910.h> |
25 | 26 | ||
26 | static inline int irq_to_tps65910_irq(struct tps65910 *tps65910, | ||
27 | int irq) | ||
28 | { | ||
29 | return (irq - tps65910->irq_base); | ||
30 | } | ||
31 | |||
32 | /* | 27 | /* |
33 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | 28 | * This is a threaded IRQ handler so can access I2C/SPI. Since all |
34 | * interrupts are clear on read the IRQ line will be reasserted and | 29 | * interrupts are clear on read the IRQ line will be reasserted and |
@@ -76,7 +71,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) | |||
76 | if (!(irq_sts & (1 << i))) | 71 | if (!(irq_sts & (1 << i))) |
77 | continue; | 72 | continue; |
78 | 73 | ||
79 | handle_nested_irq(tps65910->irq_base + i); | 74 | handle_nested_irq(irq_find_mapping(tps65910->domain, i)); |
80 | } | 75 | } |
81 | 76 | ||
82 | /* Write the STS register back to clear IRQs we handled */ | 77 | /* Write the STS register back to clear IRQs we handled */ |
@@ -135,14 +130,14 @@ static void tps65910_irq_enable(struct irq_data *data) | |||
135 | { | 130 | { |
136 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | 131 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); |
137 | 132 | ||
138 | tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq)); | 133 | tps65910->irq_mask &= ~(1 << data->hwirq); |
139 | } | 134 | } |
140 | 135 | ||
141 | static void tps65910_irq_disable(struct irq_data *data) | 136 | static void tps65910_irq_disable(struct irq_data *data) |
142 | { | 137 | { |
143 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | 138 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); |
144 | 139 | ||
145 | tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq)); | 140 | tps65910->irq_mask |= (1 << data->hwirq); |
146 | } | 141 | } |
147 | 142 | ||
148 | #ifdef CONFIG_PM_SLEEP | 143 | #ifdef CONFIG_PM_SLEEP |
@@ -164,10 +159,35 @@ static struct irq_chip tps65910_irq_chip = { | |||
164 | .irq_set_wake = tps65910_irq_set_wake, | 159 | .irq_set_wake = tps65910_irq_set_wake, |
165 | }; | 160 | }; |
166 | 161 | ||
162 | static int tps65910_irq_map(struct irq_domain *h, unsigned int virq, | ||
163 | irq_hw_number_t hw) | ||
164 | { | ||
165 | struct tps65910 *tps65910 = h->host_data; | ||
166 | |||
167 | irq_set_chip_data(virq, tps65910); | ||
168 | irq_set_chip_and_handler(virq, &tps65910_irq_chip, handle_edge_irq); | ||
169 | irq_set_nested_thread(virq, 1); | ||
170 | |||
171 | /* ARM needs us to explicitly flag the IRQ as valid | ||
172 | * and will set them noprobe when we do so. */ | ||
173 | #ifdef CONFIG_ARM | ||
174 | set_irq_flags(virq, IRQF_VALID); | ||
175 | #else | ||
176 | irq_set_noprobe(virq); | ||
177 | #endif | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static struct irq_domain_ops tps65910_domain_ops = { | ||
183 | .map = tps65910_irq_map, | ||
184 | .xlate = irq_domain_xlate_twocell, | ||
185 | }; | ||
186 | |||
167 | int tps65910_irq_init(struct tps65910 *tps65910, int irq, | 187 | int tps65910_irq_init(struct tps65910 *tps65910, int irq, |
168 | struct tps65910_platform_data *pdata) | 188 | struct tps65910_platform_data *pdata) |
169 | { | 189 | { |
170 | int ret, cur_irq; | 190 | int ret; |
171 | int flags = IRQF_ONESHOT; | 191 | int flags = IRQF_ONESHOT; |
172 | 192 | ||
173 | if (!irq) { | 193 | if (!irq) { |
@@ -175,17 +195,11 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, | |||
175 | return -EINVAL; | 195 | return -EINVAL; |
176 | } | 196 | } |
177 | 197 | ||
178 | if (!pdata || !pdata->irq_base) { | 198 | if (!pdata) { |
179 | dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n"); | 199 | dev_warn(tps65910->dev, "No interrupt support, no pdata\n"); |
180 | return -EINVAL; | 200 | return -EINVAL; |
181 | } | 201 | } |
182 | 202 | ||
183 | tps65910->irq_mask = 0xFFFFFF; | ||
184 | |||
185 | mutex_init(&tps65910->irq_lock); | ||
186 | tps65910->chip_irq = irq; | ||
187 | tps65910->irq_base = pdata->irq_base; | ||
188 | |||
189 | switch (tps65910_chip_id(tps65910)) { | 203 | switch (tps65910_chip_id(tps65910)) { |
190 | case TPS65910: | 204 | case TPS65910: |
191 | tps65910->irq_num = TPS65910_NUM_IRQ; | 205 | tps65910->irq_num = TPS65910_NUM_IRQ; |
@@ -195,22 +209,36 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, | |||
195 | break; | 209 | break; |
196 | } | 210 | } |
197 | 211 | ||
198 | /* Register with genirq */ | 212 | if (pdata->irq_base > 0) { |
199 | for (cur_irq = tps65910->irq_base; | 213 | pdata->irq_base = irq_alloc_descs(pdata->irq_base, 0, |
200 | cur_irq < tps65910->irq_num + tps65910->irq_base; | 214 | tps65910->irq_num, -1); |
201 | cur_irq++) { | 215 | if (pdata->irq_base < 0) { |
202 | irq_set_chip_data(cur_irq, tps65910); | 216 | dev_warn(tps65910->dev, "Failed to alloc IRQs: %d\n", |
203 | irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip, | 217 | pdata->irq_base); |
204 | handle_edge_irq); | 218 | return pdata->irq_base; |
205 | irq_set_nested_thread(cur_irq, 1); | 219 | } |
206 | 220 | } | |
207 | /* ARM needs us to explicitly flag the IRQ as valid | 221 | |
208 | * and will set them noprobe when we do so. */ | 222 | tps65910->irq_mask = 0xFFFFFF; |
209 | #ifdef CONFIG_ARM | 223 | |
210 | set_irq_flags(cur_irq, IRQF_VALID); | 224 | mutex_init(&tps65910->irq_lock); |
211 | #else | 225 | tps65910->chip_irq = irq; |
212 | irq_set_noprobe(cur_irq); | 226 | tps65910->irq_base = pdata->irq_base; |
213 | #endif | 227 | |
228 | if (pdata->irq_base > 0) | ||
229 | tps65910->domain = irq_domain_add_legacy(tps65910->dev->of_node, | ||
230 | tps65910->irq_num, | ||
231 | pdata->irq_base, | ||
232 | 0, | ||
233 | &tps65910_domain_ops, tps65910); | ||
234 | else | ||
235 | tps65910->domain = irq_domain_add_linear(tps65910->dev->of_node, | ||
236 | tps65910->irq_num, | ||
237 | &tps65910_domain_ops, tps65910); | ||
238 | |||
239 | if (!tps65910->domain) { | ||
240 | dev_err(tps65910->dev, "Failed to create IRQ domain\n"); | ||
241 | return -ENOMEM; | ||
214 | } | 242 | } |
215 | 243 | ||
216 | ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, | 244 | ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, |