aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-10-25 04:19:04 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-12-12 11:14:06 -0500
commit8ab30691826fc05efa47c4ffba19b80496bb3a2c (patch)
treeb1c405e1eebfd3127ccb5aba5c71eb547bc59687 /drivers
parente292b578c9bd587ad8fe230aa0500bde7be3c68a (diff)
mfd: Convert wm8994 to use generic regmap irq_chip
Factor out the irq_chip implementation, substantially reducing the code size for the driver. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/mfd/wm8994-irq.c196
2 files changed, 34 insertions, 163 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f1391c21ef26..017f6dbab333 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -477,6 +477,7 @@ config MFD_WM8994
477 bool "Support Wolfson Microelectronics WM8994" 477 bool "Support Wolfson Microelectronics WM8994"
478 select MFD_CORE 478 select MFD_CORE
479 select REGMAP_I2C 479 select REGMAP_I2C
480 select REGMAP_IRQ
480 depends on I2C=y && GENERIC_HARDIRQS 481 depends on I2C=y && GENERIC_HARDIRQS
481 help 482 help
482 The WM8994 is a highly integrated hi-fi CODEC designed for 483 The WM8994 is a highly integrated hi-fi CODEC designed for
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index f9dd6b691258..46b20c445ecf 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -18,238 +18,127 @@
18#include <linux/irq.h> 18#include <linux/irq.h>
19#include <linux/mfd/core.h> 19#include <linux/mfd/core.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/regmap.h>
21 22
22#include <linux/mfd/wm8994/core.h> 23#include <linux/mfd/wm8994/core.h>
23#include <linux/mfd/wm8994/registers.h> 24#include <linux/mfd/wm8994/registers.h>
24 25
25#include <linux/delay.h> 26#include <linux/delay.h>
26 27
27struct wm8994_irq_data { 28static struct regmap_irq wm8994_irqs[] = {
28 int reg;
29 int mask;
30};
31
32static struct wm8994_irq_data wm8994_irqs[] = {
33 [WM8994_IRQ_TEMP_SHUT] = { 29 [WM8994_IRQ_TEMP_SHUT] = {
34 .reg = 2, 30 .reg_offset = 1,
35 .mask = WM8994_TEMP_SHUT_EINT, 31 .mask = WM8994_TEMP_SHUT_EINT,
36 }, 32 },
37 [WM8994_IRQ_MIC1_DET] = { 33 [WM8994_IRQ_MIC1_DET] = {
38 .reg = 2, 34 .reg_offset = 1,
39 .mask = WM8994_MIC1_DET_EINT, 35 .mask = WM8994_MIC1_DET_EINT,
40 }, 36 },
41 [WM8994_IRQ_MIC1_SHRT] = { 37 [WM8994_IRQ_MIC1_SHRT] = {
42 .reg = 2, 38 .reg_offset = 1,
43 .mask = WM8994_MIC1_SHRT_EINT, 39 .mask = WM8994_MIC1_SHRT_EINT,
44 }, 40 },
45 [WM8994_IRQ_MIC2_DET] = { 41 [WM8994_IRQ_MIC2_DET] = {
46 .reg = 2, 42 .reg_offset = 1,
47 .mask = WM8994_MIC2_DET_EINT, 43 .mask = WM8994_MIC2_DET_EINT,
48 }, 44 },
49 [WM8994_IRQ_MIC2_SHRT] = { 45 [WM8994_IRQ_MIC2_SHRT] = {
50 .reg = 2, 46 .reg_offset = 1,
51 .mask = WM8994_MIC2_SHRT_EINT, 47 .mask = WM8994_MIC2_SHRT_EINT,
52 }, 48 },
53 [WM8994_IRQ_FLL1_LOCK] = { 49 [WM8994_IRQ_FLL1_LOCK] = {
54 .reg = 2, 50 .reg_offset = 1,
55 .mask = WM8994_FLL1_LOCK_EINT, 51 .mask = WM8994_FLL1_LOCK_EINT,
56 }, 52 },
57 [WM8994_IRQ_FLL2_LOCK] = { 53 [WM8994_IRQ_FLL2_LOCK] = {
58 .reg = 2, 54 .reg_offset = 1,
59 .mask = WM8994_FLL2_LOCK_EINT, 55 .mask = WM8994_FLL2_LOCK_EINT,
60 }, 56 },
61 [WM8994_IRQ_SRC1_LOCK] = { 57 [WM8994_IRQ_SRC1_LOCK] = {
62 .reg = 2, 58 .reg_offset = 1,
63 .mask = WM8994_SRC1_LOCK_EINT, 59 .mask = WM8994_SRC1_LOCK_EINT,
64 }, 60 },
65 [WM8994_IRQ_SRC2_LOCK] = { 61 [WM8994_IRQ_SRC2_LOCK] = {
66 .reg = 2, 62 .reg_offset = 1,
67 .mask = WM8994_SRC2_LOCK_EINT, 63 .mask = WM8994_SRC2_LOCK_EINT,
68 }, 64 },
69 [WM8994_IRQ_AIF1DRC1_SIG_DET] = { 65 [WM8994_IRQ_AIF1DRC1_SIG_DET] = {
70 .reg = 2, 66 .reg_offset = 1,
71 .mask = WM8994_AIF1DRC1_SIG_DET, 67 .mask = WM8994_AIF1DRC1_SIG_DET,
72 }, 68 },
73 [WM8994_IRQ_AIF1DRC2_SIG_DET] = { 69 [WM8994_IRQ_AIF1DRC2_SIG_DET] = {
74 .reg = 2, 70 .reg_offset = 1,
75 .mask = WM8994_AIF1DRC2_SIG_DET_EINT, 71 .mask = WM8994_AIF1DRC2_SIG_DET_EINT,
76 }, 72 },
77 [WM8994_IRQ_AIF2DRC_SIG_DET] = { 73 [WM8994_IRQ_AIF2DRC_SIG_DET] = {
78 .reg = 2, 74 .reg_offset = 1,
79 .mask = WM8994_AIF2DRC_SIG_DET_EINT, 75 .mask = WM8994_AIF2DRC_SIG_DET_EINT,
80 }, 76 },
81 [WM8994_IRQ_FIFOS_ERR] = { 77 [WM8994_IRQ_FIFOS_ERR] = {
82 .reg = 2, 78 .reg_offset = 1,
83 .mask = WM8994_FIFOS_ERR_EINT, 79 .mask = WM8994_FIFOS_ERR_EINT,
84 }, 80 },
85 [WM8994_IRQ_WSEQ_DONE] = { 81 [WM8994_IRQ_WSEQ_DONE] = {
86 .reg = 2, 82 .reg_offset = 1,
87 .mask = WM8994_WSEQ_DONE_EINT, 83 .mask = WM8994_WSEQ_DONE_EINT,
88 }, 84 },
89 [WM8994_IRQ_DCS_DONE] = { 85 [WM8994_IRQ_DCS_DONE] = {
90 .reg = 2, 86 .reg_offset = 1,
91 .mask = WM8994_DCS_DONE_EINT, 87 .mask = WM8994_DCS_DONE_EINT,
92 }, 88 },
93 [WM8994_IRQ_TEMP_WARN] = { 89 [WM8994_IRQ_TEMP_WARN] = {
94 .reg = 2, 90 .reg_offset = 1,
95 .mask = WM8994_TEMP_WARN_EINT, 91 .mask = WM8994_TEMP_WARN_EINT,
96 }, 92 },
97 [WM8994_IRQ_GPIO(1)] = { 93 [WM8994_IRQ_GPIO(1)] = {
98 .reg = 1,
99 .mask = WM8994_GP1_EINT, 94 .mask = WM8994_GP1_EINT,
100 }, 95 },
101 [WM8994_IRQ_GPIO(2)] = { 96 [WM8994_IRQ_GPIO(2)] = {
102 .reg = 1,
103 .mask = WM8994_GP2_EINT, 97 .mask = WM8994_GP2_EINT,
104 }, 98 },
105 [WM8994_IRQ_GPIO(3)] = { 99 [WM8994_IRQ_GPIO(3)] = {
106 .reg = 1,
107 .mask = WM8994_GP3_EINT, 100 .mask = WM8994_GP3_EINT,
108 }, 101 },
109 [WM8994_IRQ_GPIO(4)] = { 102 [WM8994_IRQ_GPIO(4)] = {
110 .reg = 1,
111 .mask = WM8994_GP4_EINT, 103 .mask = WM8994_GP4_EINT,
112 }, 104 },
113 [WM8994_IRQ_GPIO(5)] = { 105 [WM8994_IRQ_GPIO(5)] = {
114 .reg = 1,
115 .mask = WM8994_GP5_EINT, 106 .mask = WM8994_GP5_EINT,
116 }, 107 },
117 [WM8994_IRQ_GPIO(6)] = { 108 [WM8994_IRQ_GPIO(6)] = {
118 .reg = 1,
119 .mask = WM8994_GP6_EINT, 109 .mask = WM8994_GP6_EINT,
120 }, 110 },
121 [WM8994_IRQ_GPIO(7)] = { 111 [WM8994_IRQ_GPIO(7)] = {
122 .reg = 1,
123 .mask = WM8994_GP7_EINT, 112 .mask = WM8994_GP7_EINT,
124 }, 113 },
125 [WM8994_IRQ_GPIO(8)] = { 114 [WM8994_IRQ_GPIO(8)] = {
126 .reg = 1,
127 .mask = WM8994_GP8_EINT, 115 .mask = WM8994_GP8_EINT,
128 }, 116 },
129 [WM8994_IRQ_GPIO(9)] = { 117 [WM8994_IRQ_GPIO(9)] = {
130 .reg = 1,
131 .mask = WM8994_GP8_EINT, 118 .mask = WM8994_GP8_EINT,
132 }, 119 },
133 [WM8994_IRQ_GPIO(10)] = { 120 [WM8994_IRQ_GPIO(10)] = {
134 .reg = 1,
135 .mask = WM8994_GP10_EINT, 121 .mask = WM8994_GP10_EINT,
136 }, 122 },
137 [WM8994_IRQ_GPIO(11)] = { 123 [WM8994_IRQ_GPIO(11)] = {
138 .reg = 1,
139 .mask = WM8994_GP11_EINT, 124 .mask = WM8994_GP11_EINT,
140 }, 125 },
141}; 126};
142 127
143static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994, 128static struct regmap_irq_chip wm8994_irq_chip = {
144 int irq) 129 .name = "wm8994",
145{ 130 .irqs = wm8994_irqs,
146 return &wm8994_irqs[irq - wm8994->irq_base]; 131 .num_irqs = ARRAY_SIZE(wm8994_irqs),
147}
148
149static void wm8994_irq_lock(struct irq_data *data)
150{
151 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
152
153 mutex_lock(&wm8994->irq_lock);
154}
155
156static void wm8994_irq_sync_unlock(struct irq_data *data)
157{
158 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
159 int i;
160
161 for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
162 /* If there's been a change in the mask write it back
163 * to the hardware. */
164 if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) {
165 wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i];
166 wm8994_reg_write(wm8994,
167 WM8994_INTERRUPT_STATUS_1_MASK + i,
168 wm8994->irq_masks_cur[i]);
169 }
170 }
171
172 mutex_unlock(&wm8994->irq_lock);
173}
174
175static void wm8994_irq_enable(struct irq_data *data)
176{
177 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
178 struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
179 data->irq);
180
181 wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
182}
183
184static void wm8994_irq_disable(struct irq_data *data)
185{
186 struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
187 struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
188 data->irq);
189
190 wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
191}
192 132
193static struct irq_chip wm8994_irq_chip = { 133 .num_regs = 2,
194 .name = "wm8994", 134 .status_base = WM8994_INTERRUPT_STATUS_1,
195 .irq_bus_lock = wm8994_irq_lock, 135 .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
196 .irq_bus_sync_unlock = wm8994_irq_sync_unlock, 136 .ack_base = WM8994_INTERRUPT_STATUS_1,
197 .irq_disable = wm8994_irq_disable,
198 .irq_enable = wm8994_irq_enable,
199}; 137};
200 138
201/* The processing of the primary interrupt occurs in a thread so that
202 * we can interact with the device over I2C or SPI. */
203static irqreturn_t wm8994_irq_thread(int irq, void *data)
204{
205 struct wm8994 *wm8994 = data;
206 unsigned int i;
207 u16 status[WM8994_NUM_IRQ_REGS];
208 int ret;
209
210 ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1,
211 WM8994_NUM_IRQ_REGS, status);
212 if (ret < 0) {
213 dev_err(wm8994->dev, "Failed to read interrupt status: %d\n",
214 ret);
215 return IRQ_NONE;
216 }
217
218 /* Bit swap and apply masking */
219 for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) {
220 status[i] = be16_to_cpu(status[i]);
221 status[i] &= ~wm8994->irq_masks_cur[i];
222 }
223
224 /* Ack any unmasked IRQs */
225 for (i = 0; i < ARRAY_SIZE(status); i++) {
226 if (status[i])
227 wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i,
228 status[i]);
229 }
230
231 /* Report */
232 for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
233 if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
234 handle_nested_irq(wm8994->irq_base + i);
235 }
236
237 return IRQ_HANDLED;
238}
239
240int wm8994_irq_init(struct wm8994 *wm8994) 139int wm8994_irq_init(struct wm8994 *wm8994)
241{ 140{
242 int i, cur_irq, ret; 141 int ret;
243
244 mutex_init(&wm8994->irq_lock);
245
246 /* Mask the individual interrupt sources */
247 for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
248 wm8994->irq_masks_cur[i] = 0xffff;
249 wm8994->irq_masks_cache[i] = 0xffff;
250 wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i,
251 0xffff);
252 }
253 142
254 if (!wm8994->irq) { 143 if (!wm8994->irq) {
255 dev_warn(wm8994->dev, 144 dev_warn(wm8994->dev,
@@ -264,30 +153,12 @@ int wm8994_irq_init(struct wm8994 *wm8994)
264 return 0; 153 return 0;
265 } 154 }
266 155
267 /* Register them with genirq */ 156 ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
268 for (cur_irq = wm8994->irq_base; 157 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
269 cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; 158 wm8994->irq_base, &wm8994_irq_chip,
270 cur_irq++) { 159 &wm8994->irq_data);
271 irq_set_chip_data(cur_irq, wm8994);
272 irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip,
273 handle_edge_irq);
274 irq_set_nested_thread(cur_irq, 1);
275
276 /* ARM needs us to explicitly flag the IRQ as valid
277 * and will set them noprobe when we do so. */
278#ifdef CONFIG_ARM
279 set_irq_flags(cur_irq, IRQF_VALID);
280#else
281 irq_set_noprobe(cur_irq);
282#endif
283 }
284
285 ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread,
286 IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
287 "wm8994", wm8994);
288 if (ret != 0) { 160 if (ret != 0) {
289 dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n", 161 dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
290 wm8994->irq, ret);
291 return ret; 162 return ret;
292 } 163 }
293 164
@@ -299,6 +170,5 @@ int wm8994_irq_init(struct wm8994 *wm8994)
299 170
300void wm8994_irq_exit(struct wm8994 *wm8994) 171void wm8994_irq_exit(struct wm8994 *wm8994)
301{ 172{
302 if (wm8994->irq) 173 regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
303 free_irq(wm8994->irq, wm8994);
304} 174}