diff options
Diffstat (limited to 'drivers/mfd/tps65910-irq.c')
-rw-r--r-- | drivers/mfd/tps65910-irq.c | 260 |
1 files changed, 0 insertions, 260 deletions
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c deleted file mode 100644 index 09aab3e4776d..000000000000 --- a/drivers/mfd/tps65910-irq.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | /* | ||
2 | * tps65910-irq.c -- TI TPS6591x | ||
3 | * | ||
4 | * Copyright 2010 Texas Instruments Inc. | ||
5 | * | ||
6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
7 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/bug.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/irqdomain.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/mfd/tps65910.h> | ||
26 | |||
27 | /* | ||
28 | * This is a threaded IRQ handler so can access I2C/SPI. Since all | ||
29 | * interrupts are clear on read the IRQ line will be reasserted and | ||
30 | * the physical IRQ will be handled again if another interrupt is | ||
31 | * asserted while we run - in the normal course of events this is a | ||
32 | * rare occurrence so we save I2C/SPI reads. We're also assuming that | ||
33 | * it's rare to get lots of interrupts firing simultaneously so try to | ||
34 | * minimise I/O. | ||
35 | */ | ||
36 | static irqreturn_t tps65910_irq(int irq, void *irq_data) | ||
37 | { | ||
38 | struct tps65910 *tps65910 = irq_data; | ||
39 | unsigned int reg; | ||
40 | u32 irq_sts; | ||
41 | u32 irq_mask; | ||
42 | int i; | ||
43 | |||
44 | tps65910_reg_read(tps65910, TPS65910_INT_STS, ®); | ||
45 | irq_sts = reg; | ||
46 | tps65910_reg_read(tps65910, TPS65910_INT_STS2, ®); | ||
47 | irq_sts |= reg << 8; | ||
48 | switch (tps65910_chip_id(tps65910)) { | ||
49 | case TPS65911: | ||
50 | tps65910_reg_read(tps65910, TPS65910_INT_STS3, ®); | ||
51 | irq_sts |= reg << 16; | ||
52 | } | ||
53 | |||
54 | tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); | ||
55 | irq_mask = reg; | ||
56 | tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); | ||
57 | irq_mask |= reg << 8; | ||
58 | switch (tps65910_chip_id(tps65910)) { | ||
59 | case TPS65911: | ||
60 | tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); | ||
61 | irq_mask |= reg << 16; | ||
62 | } | ||
63 | |||
64 | irq_sts &= ~irq_mask; | ||
65 | |||
66 | if (!irq_sts) | ||
67 | return IRQ_NONE; | ||
68 | |||
69 | for (i = 0; i < tps65910->irq_num; i++) { | ||
70 | |||
71 | if (!(irq_sts & (1 << i))) | ||
72 | continue; | ||
73 | |||
74 | handle_nested_irq(irq_find_mapping(tps65910->domain, i)); | ||
75 | } | ||
76 | |||
77 | /* Write the STS register back to clear IRQs we handled */ | ||
78 | reg = irq_sts & 0xFF; | ||
79 | irq_sts >>= 8; | ||
80 | tps65910_reg_write(tps65910, TPS65910_INT_STS, reg); | ||
81 | reg = irq_sts & 0xFF; | ||
82 | tps65910_reg_write(tps65910, TPS65910_INT_STS2, reg); | ||
83 | switch (tps65910_chip_id(tps65910)) { | ||
84 | case TPS65911: | ||
85 | reg = irq_sts >> 8; | ||
86 | tps65910_reg_write(tps65910, TPS65910_INT_STS3, reg); | ||
87 | } | ||
88 | |||
89 | return IRQ_HANDLED; | ||
90 | } | ||
91 | |||
92 | static void tps65910_irq_lock(struct irq_data *data) | ||
93 | { | ||
94 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
95 | |||
96 | mutex_lock(&tps65910->irq_lock); | ||
97 | } | ||
98 | |||
99 | static void tps65910_irq_sync_unlock(struct irq_data *data) | ||
100 | { | ||
101 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
102 | u32 reg_mask; | ||
103 | unsigned int reg; | ||
104 | |||
105 | tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); | ||
106 | reg_mask = reg; | ||
107 | tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); | ||
108 | reg_mask |= reg << 8; | ||
109 | switch (tps65910_chip_id(tps65910)) { | ||
110 | case TPS65911: | ||
111 | tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); | ||
112 | reg_mask |= reg << 16; | ||
113 | } | ||
114 | |||
115 | if (tps65910->irq_mask != reg_mask) { | ||
116 | reg = tps65910->irq_mask & 0xFF; | ||
117 | tps65910_reg_write(tps65910, TPS65910_INT_MSK, reg); | ||
118 | reg = tps65910->irq_mask >> 8 & 0xFF; | ||
119 | tps65910_reg_write(tps65910, TPS65910_INT_MSK2, reg); | ||
120 | switch (tps65910_chip_id(tps65910)) { | ||
121 | case TPS65911: | ||
122 | reg = tps65910->irq_mask >> 16; | ||
123 | tps65910_reg_write(tps65910, TPS65910_INT_MSK3, reg); | ||
124 | } | ||
125 | } | ||
126 | mutex_unlock(&tps65910->irq_lock); | ||
127 | } | ||
128 | |||
129 | static void tps65910_irq_enable(struct irq_data *data) | ||
130 | { | ||
131 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
132 | |||
133 | tps65910->irq_mask &= ~(1 << data->hwirq); | ||
134 | } | ||
135 | |||
136 | static void tps65910_irq_disable(struct irq_data *data) | ||
137 | { | ||
138 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
139 | |||
140 | tps65910->irq_mask |= (1 << data->hwirq); | ||
141 | } | ||
142 | |||
143 | #ifdef CONFIG_PM_SLEEP | ||
144 | static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable) | ||
145 | { | ||
146 | struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); | ||
147 | return irq_set_irq_wake(tps65910->chip_irq, enable); | ||
148 | } | ||
149 | #else | ||
150 | #define tps65910_irq_set_wake NULL | ||
151 | #endif | ||
152 | |||
153 | static struct irq_chip tps65910_irq_chip = { | ||
154 | .name = "tps65910", | ||
155 | .irq_bus_lock = tps65910_irq_lock, | ||
156 | .irq_bus_sync_unlock = tps65910_irq_sync_unlock, | ||
157 | .irq_disable = tps65910_irq_disable, | ||
158 | .irq_enable = tps65910_irq_enable, | ||
159 | .irq_set_wake = tps65910_irq_set_wake, | ||
160 | }; | ||
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 | |||
187 | int tps65910_irq_init(struct tps65910 *tps65910, int irq, | ||
188 | struct tps65910_platform_data *pdata) | ||
189 | { | ||
190 | int ret; | ||
191 | int flags = IRQF_ONESHOT; | ||
192 | |||
193 | if (!irq) { | ||
194 | dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | |||
198 | if (!pdata) { | ||
199 | dev_warn(tps65910->dev, "No interrupt support, no pdata\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | switch (tps65910_chip_id(tps65910)) { | ||
204 | case TPS65910: | ||
205 | tps65910->irq_num = TPS65910_NUM_IRQ; | ||
206 | break; | ||
207 | case TPS65911: | ||
208 | tps65910->irq_num = TPS65911_NUM_IRQ; | ||
209 | break; | ||
210 | } | ||
211 | |||
212 | if (pdata->irq_base > 0) { | ||
213 | pdata->irq_base = irq_alloc_descs(pdata->irq_base, 0, | ||
214 | tps65910->irq_num, -1); | ||
215 | if (pdata->irq_base < 0) { | ||
216 | dev_warn(tps65910->dev, "Failed to alloc IRQs: %d\n", | ||
217 | pdata->irq_base); | ||
218 | return pdata->irq_base; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | tps65910->irq_mask = 0xFFFFFF; | ||
223 | |||
224 | mutex_init(&tps65910->irq_lock); | ||
225 | tps65910->chip_irq = irq; | ||
226 | tps65910->irq_base = pdata->irq_base; | ||
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; | ||
242 | } | ||
243 | |||
244 | ret = request_threaded_irq(irq, NULL, tps65910_irq, flags, | ||
245 | "tps65910", tps65910); | ||
246 | |||
247 | irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); | ||
248 | |||
249 | if (ret != 0) | ||
250 | dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret); | ||
251 | |||
252 | return ret; | ||
253 | } | ||
254 | |||
255 | int tps65910_irq_exit(struct tps65910 *tps65910) | ||
256 | { | ||
257 | if (tps65910->chip_irq) | ||
258 | free_irq(tps65910->chip_irq, tps65910); | ||
259 | return 0; | ||
260 | } | ||