xref: /openbmc/linux/drivers/mfd/wm8350-irq.c (revision a09d2831)
1 /*
2  * wm8350-irq.c  --  IRQ support for Wolfson WM8350
3  *
4  * Copyright 2007, 2008, 2009 Wolfson Microelectronics PLC.
5  *
6  * Author: Liam Girdwood, Mark Brown
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  *
13  */
14 
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/bug.h>
19 #include <linux/device.h>
20 #include <linux/interrupt.h>
21 #include <linux/workqueue.h>
22 
23 #include <linux/mfd/wm8350/core.h>
24 #include <linux/mfd/wm8350/audio.h>
25 #include <linux/mfd/wm8350/comparator.h>
26 #include <linux/mfd/wm8350/gpio.h>
27 #include <linux/mfd/wm8350/pmic.h>
28 #include <linux/mfd/wm8350/rtc.h>
29 #include <linux/mfd/wm8350/supply.h>
30 #include <linux/mfd/wm8350/wdt.h>
31 
32 #define WM8350_NUM_IRQ_REGS 7
33 
34 #define WM8350_INT_OFFSET_1                     0
35 #define WM8350_INT_OFFSET_2                     1
36 #define WM8350_POWER_UP_INT_OFFSET              2
37 #define WM8350_UNDER_VOLTAGE_INT_OFFSET         3
38 #define WM8350_OVER_CURRENT_INT_OFFSET          4
39 #define WM8350_GPIO_INT_OFFSET                  5
40 #define WM8350_COMPARATOR_INT_OFFSET            6
41 
42 struct wm8350_irq_data {
43 	int primary;
44 	int reg;
45 	int mask;
46 	int primary_only;
47 };
48 
49 static struct wm8350_irq_data wm8350_irqs[] = {
50 	[WM8350_IRQ_OC_LS] = {
51 		.primary = WM8350_OC_INT,
52 		.reg = WM8350_OVER_CURRENT_INT_OFFSET,
53 		.mask = WM8350_OC_LS_EINT,
54 		.primary_only = 1,
55 	},
56 	[WM8350_IRQ_UV_DC1] = {
57 		.primary = WM8350_UV_INT,
58 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
59 		.mask = WM8350_UV_DC1_EINT,
60 	},
61 	[WM8350_IRQ_UV_DC2] = {
62 		.primary = WM8350_UV_INT,
63 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
64 		.mask = WM8350_UV_DC2_EINT,
65 	},
66 	[WM8350_IRQ_UV_DC3] = {
67 		.primary = WM8350_UV_INT,
68 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
69 		.mask = WM8350_UV_DC3_EINT,
70 	},
71 	[WM8350_IRQ_UV_DC4] = {
72 		.primary = WM8350_UV_INT,
73 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
74 		.mask = WM8350_UV_DC4_EINT,
75 	},
76 	[WM8350_IRQ_UV_DC5] = {
77 		.primary = WM8350_UV_INT,
78 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
79 		.mask = WM8350_UV_DC5_EINT,
80 	},
81 	[WM8350_IRQ_UV_DC6] = {
82 		.primary = WM8350_UV_INT,
83 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
84 		.mask = WM8350_UV_DC6_EINT,
85 	},
86 	[WM8350_IRQ_UV_LDO1] = {
87 		.primary = WM8350_UV_INT,
88 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
89 		.mask = WM8350_UV_LDO1_EINT,
90 	},
91 	[WM8350_IRQ_UV_LDO2] = {
92 		.primary = WM8350_UV_INT,
93 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
94 		.mask = WM8350_UV_LDO2_EINT,
95 	},
96 	[WM8350_IRQ_UV_LDO3] = {
97 		.primary = WM8350_UV_INT,
98 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
99 		.mask = WM8350_UV_LDO3_EINT,
100 	},
101 	[WM8350_IRQ_UV_LDO4] = {
102 		.primary = WM8350_UV_INT,
103 		.reg = WM8350_UNDER_VOLTAGE_INT_OFFSET,
104 		.mask = WM8350_UV_LDO4_EINT,
105 	},
106 	[WM8350_IRQ_CHG_BAT_HOT] = {
107 		.primary = WM8350_CHG_INT,
108 		.reg = WM8350_INT_OFFSET_1,
109 		.mask = WM8350_CHG_BAT_HOT_EINT,
110 	},
111 	[WM8350_IRQ_CHG_BAT_COLD] = {
112 		.primary = WM8350_CHG_INT,
113 		.reg = WM8350_INT_OFFSET_1,
114 		.mask = WM8350_CHG_BAT_COLD_EINT,
115 	},
116 	[WM8350_IRQ_CHG_BAT_FAIL] = {
117 		.primary = WM8350_CHG_INT,
118 		.reg = WM8350_INT_OFFSET_1,
119 		.mask = WM8350_CHG_BAT_FAIL_EINT,
120 	},
121 	[WM8350_IRQ_CHG_TO] = {
122 		.primary = WM8350_CHG_INT,
123 		.reg = WM8350_INT_OFFSET_1,
124 		.mask = WM8350_CHG_TO_EINT,
125 	},
126 	[WM8350_IRQ_CHG_END] = {
127 		.primary = WM8350_CHG_INT,
128 		.reg = WM8350_INT_OFFSET_1,
129 		.mask = WM8350_CHG_END_EINT,
130 	},
131 	[WM8350_IRQ_CHG_START] = {
132 		.primary = WM8350_CHG_INT,
133 		.reg = WM8350_INT_OFFSET_1,
134 		.mask = WM8350_CHG_START_EINT,
135 	},
136 	[WM8350_IRQ_CHG_FAST_RDY] = {
137 		.primary = WM8350_CHG_INT,
138 		.reg = WM8350_INT_OFFSET_1,
139 		.mask = WM8350_CHG_FAST_RDY_EINT,
140 	},
141 	[WM8350_IRQ_CHG_VBATT_LT_3P9] = {
142 		.primary = WM8350_CHG_INT,
143 		.reg = WM8350_INT_OFFSET_1,
144 		.mask = WM8350_CHG_VBATT_LT_3P9_EINT,
145 	},
146 	[WM8350_IRQ_CHG_VBATT_LT_3P1] = {
147 		.primary = WM8350_CHG_INT,
148 		.reg = WM8350_INT_OFFSET_1,
149 		.mask = WM8350_CHG_VBATT_LT_3P1_EINT,
150 	},
151 	[WM8350_IRQ_CHG_VBATT_LT_2P85] = {
152 		.primary = WM8350_CHG_INT,
153 		.reg = WM8350_INT_OFFSET_1,
154 		.mask = WM8350_CHG_VBATT_LT_2P85_EINT,
155 	},
156 	[WM8350_IRQ_RTC_ALM] = {
157 		.primary = WM8350_RTC_INT,
158 		.reg = WM8350_INT_OFFSET_1,
159 		.mask = WM8350_RTC_ALM_EINT,
160 	},
161 	[WM8350_IRQ_RTC_SEC] = {
162 		.primary = WM8350_RTC_INT,
163 		.reg = WM8350_INT_OFFSET_1,
164 		.mask = WM8350_RTC_SEC_EINT,
165 	},
166 	[WM8350_IRQ_RTC_PER] = {
167 		.primary = WM8350_RTC_INT,
168 		.reg = WM8350_INT_OFFSET_1,
169 		.mask = WM8350_RTC_PER_EINT,
170 	},
171 	[WM8350_IRQ_CS1] = {
172 		.primary = WM8350_CS_INT,
173 		.reg = WM8350_INT_OFFSET_2,
174 		.mask = WM8350_CS1_EINT,
175 	},
176 	[WM8350_IRQ_CS2] = {
177 		.primary = WM8350_CS_INT,
178 		.reg = WM8350_INT_OFFSET_2,
179 		.mask = WM8350_CS2_EINT,
180 	},
181 	[WM8350_IRQ_SYS_HYST_COMP_FAIL] = {
182 		.primary = WM8350_SYS_INT,
183 		.reg = WM8350_INT_OFFSET_2,
184 		.mask = WM8350_SYS_HYST_COMP_FAIL_EINT,
185 	},
186 	[WM8350_IRQ_SYS_CHIP_GT115] = {
187 		.primary = WM8350_SYS_INT,
188 		.reg = WM8350_INT_OFFSET_2,
189 		.mask = WM8350_SYS_CHIP_GT115_EINT,
190 	},
191 	[WM8350_IRQ_SYS_CHIP_GT140] = {
192 		.primary = WM8350_SYS_INT,
193 		.reg = WM8350_INT_OFFSET_2,
194 		.mask = WM8350_SYS_CHIP_GT140_EINT,
195 	},
196 	[WM8350_IRQ_SYS_WDOG_TO] = {
197 		.primary = WM8350_SYS_INT,
198 		.reg = WM8350_INT_OFFSET_2,
199 		.mask = WM8350_SYS_WDOG_TO_EINT,
200 	},
201 	[WM8350_IRQ_AUXADC_DATARDY] = {
202 		.primary = WM8350_AUXADC_INT,
203 		.reg = WM8350_INT_OFFSET_2,
204 		.mask = WM8350_AUXADC_DATARDY_EINT,
205 	},
206 	[WM8350_IRQ_AUXADC_DCOMP4] = {
207 		.primary = WM8350_AUXADC_INT,
208 		.reg = WM8350_INT_OFFSET_2,
209 		.mask = WM8350_AUXADC_DCOMP4_EINT,
210 	},
211 	[WM8350_IRQ_AUXADC_DCOMP3] = {
212 		.primary = WM8350_AUXADC_INT,
213 		.reg = WM8350_INT_OFFSET_2,
214 		.mask = WM8350_AUXADC_DCOMP3_EINT,
215 	},
216 	[WM8350_IRQ_AUXADC_DCOMP2] = {
217 		.primary = WM8350_AUXADC_INT,
218 		.reg = WM8350_INT_OFFSET_2,
219 		.mask = WM8350_AUXADC_DCOMP2_EINT,
220 	},
221 	[WM8350_IRQ_AUXADC_DCOMP1] = {
222 		.primary = WM8350_AUXADC_INT,
223 		.reg = WM8350_INT_OFFSET_2,
224 		.mask = WM8350_AUXADC_DCOMP1_EINT,
225 	},
226 	[WM8350_IRQ_USB_LIMIT] = {
227 		.primary = WM8350_USB_INT,
228 		.reg = WM8350_INT_OFFSET_2,
229 		.mask = WM8350_USB_LIMIT_EINT,
230 		.primary_only = 1,
231 	},
232 	[WM8350_IRQ_WKUP_OFF_STATE] = {
233 		.primary = WM8350_WKUP_INT,
234 		.reg = WM8350_COMPARATOR_INT_OFFSET,
235 		.mask = WM8350_WKUP_OFF_STATE_EINT,
236 	},
237 	[WM8350_IRQ_WKUP_HIB_STATE] = {
238 		.primary = WM8350_WKUP_INT,
239 		.reg = WM8350_COMPARATOR_INT_OFFSET,
240 		.mask = WM8350_WKUP_HIB_STATE_EINT,
241 	},
242 	[WM8350_IRQ_WKUP_CONV_FAULT] = {
243 		.primary = WM8350_WKUP_INT,
244 		.reg = WM8350_COMPARATOR_INT_OFFSET,
245 		.mask = WM8350_WKUP_CONV_FAULT_EINT,
246 	},
247 	[WM8350_IRQ_WKUP_WDOG_RST] = {
248 		.primary = WM8350_WKUP_INT,
249 		.reg = WM8350_COMPARATOR_INT_OFFSET,
250 		.mask = WM8350_WKUP_WDOG_RST_EINT,
251 	},
252 	[WM8350_IRQ_WKUP_GP_PWR_ON] = {
253 		.primary = WM8350_WKUP_INT,
254 		.reg = WM8350_COMPARATOR_INT_OFFSET,
255 		.mask = WM8350_WKUP_GP_PWR_ON_EINT,
256 	},
257 	[WM8350_IRQ_WKUP_ONKEY] = {
258 		.primary = WM8350_WKUP_INT,
259 		.reg = WM8350_COMPARATOR_INT_OFFSET,
260 		.mask = WM8350_WKUP_ONKEY_EINT,
261 	},
262 	[WM8350_IRQ_WKUP_GP_WAKEUP] = {
263 		.primary = WM8350_WKUP_INT,
264 		.reg = WM8350_COMPARATOR_INT_OFFSET,
265 		.mask = WM8350_WKUP_GP_WAKEUP_EINT,
266 	},
267 	[WM8350_IRQ_CODEC_JCK_DET_L] = {
268 		.primary = WM8350_CODEC_INT,
269 		.reg = WM8350_COMPARATOR_INT_OFFSET,
270 		.mask = WM8350_CODEC_JCK_DET_L_EINT,
271 	},
272 	[WM8350_IRQ_CODEC_JCK_DET_R] = {
273 		.primary = WM8350_CODEC_INT,
274 		.reg = WM8350_COMPARATOR_INT_OFFSET,
275 		.mask = WM8350_CODEC_JCK_DET_R_EINT,
276 	},
277 	[WM8350_IRQ_CODEC_MICSCD] = {
278 		.primary = WM8350_CODEC_INT,
279 		.reg = WM8350_COMPARATOR_INT_OFFSET,
280 		.mask = WM8350_CODEC_MICSCD_EINT,
281 	},
282 	[WM8350_IRQ_CODEC_MICD] = {
283 		.primary = WM8350_CODEC_INT,
284 		.reg = WM8350_COMPARATOR_INT_OFFSET,
285 		.mask = WM8350_CODEC_MICD_EINT,
286 	},
287 	[WM8350_IRQ_EXT_USB_FB] = {
288 		.primary = WM8350_EXT_INT,
289 		.reg = WM8350_COMPARATOR_INT_OFFSET,
290 		.mask = WM8350_EXT_USB_FB_EINT,
291 	},
292 	[WM8350_IRQ_EXT_WALL_FB] = {
293 		.primary = WM8350_EXT_INT,
294 		.reg = WM8350_COMPARATOR_INT_OFFSET,
295 		.mask = WM8350_EXT_WALL_FB_EINT,
296 	},
297 	[WM8350_IRQ_EXT_BAT_FB] = {
298 		.primary = WM8350_EXT_INT,
299 		.reg = WM8350_COMPARATOR_INT_OFFSET,
300 		.mask = WM8350_EXT_BAT_FB_EINT,
301 	},
302 	[WM8350_IRQ_GPIO(0)] = {
303 		.primary = WM8350_GP_INT,
304 		.reg = WM8350_GPIO_INT_OFFSET,
305 		.mask = WM8350_GP0_EINT,
306 	},
307 	[WM8350_IRQ_GPIO(1)] = {
308 		.primary = WM8350_GP_INT,
309 		.reg = WM8350_GPIO_INT_OFFSET,
310 		.mask = WM8350_GP1_EINT,
311 	},
312 	[WM8350_IRQ_GPIO(2)] = {
313 		.primary = WM8350_GP_INT,
314 		.reg = WM8350_GPIO_INT_OFFSET,
315 		.mask = WM8350_GP2_EINT,
316 	},
317 	[WM8350_IRQ_GPIO(3)] = {
318 		.primary = WM8350_GP_INT,
319 		.reg = WM8350_GPIO_INT_OFFSET,
320 		.mask = WM8350_GP3_EINT,
321 	},
322 	[WM8350_IRQ_GPIO(4)] = {
323 		.primary = WM8350_GP_INT,
324 		.reg = WM8350_GPIO_INT_OFFSET,
325 		.mask = WM8350_GP4_EINT,
326 	},
327 	[WM8350_IRQ_GPIO(5)] = {
328 		.primary = WM8350_GP_INT,
329 		.reg = WM8350_GPIO_INT_OFFSET,
330 		.mask = WM8350_GP5_EINT,
331 	},
332 	[WM8350_IRQ_GPIO(6)] = {
333 		.primary = WM8350_GP_INT,
334 		.reg = WM8350_GPIO_INT_OFFSET,
335 		.mask = WM8350_GP6_EINT,
336 	},
337 	[WM8350_IRQ_GPIO(7)] = {
338 		.primary = WM8350_GP_INT,
339 		.reg = WM8350_GPIO_INT_OFFSET,
340 		.mask = WM8350_GP7_EINT,
341 	},
342 	[WM8350_IRQ_GPIO(8)] = {
343 		.primary = WM8350_GP_INT,
344 		.reg = WM8350_GPIO_INT_OFFSET,
345 		.mask = WM8350_GP8_EINT,
346 	},
347 	[WM8350_IRQ_GPIO(9)] = {
348 		.primary = WM8350_GP_INT,
349 		.reg = WM8350_GPIO_INT_OFFSET,
350 		.mask = WM8350_GP9_EINT,
351 	},
352 	[WM8350_IRQ_GPIO(10)] = {
353 		.primary = WM8350_GP_INT,
354 		.reg = WM8350_GPIO_INT_OFFSET,
355 		.mask = WM8350_GP10_EINT,
356 	},
357 	[WM8350_IRQ_GPIO(11)] = {
358 		.primary = WM8350_GP_INT,
359 		.reg = WM8350_GPIO_INT_OFFSET,
360 		.mask = WM8350_GP11_EINT,
361 	},
362 	[WM8350_IRQ_GPIO(12)] = {
363 		.primary = WM8350_GP_INT,
364 		.reg = WM8350_GPIO_INT_OFFSET,
365 		.mask = WM8350_GP12_EINT,
366 	},
367 };
368 
369 static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
370 {
371 	mutex_lock(&wm8350->irq_mutex);
372 
373 	if (wm8350->irq[irq].handler)
374 		wm8350->irq[irq].handler(irq, wm8350->irq[irq].data);
375 	else {
376 		dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
377 			irq);
378 		wm8350_mask_irq(wm8350, irq);
379 	}
380 
381 	mutex_unlock(&wm8350->irq_mutex);
382 }
383 
384 /*
385  * This is a threaded IRQ handler so can access I2C/SPI.  Since all
386  * interrupts are clear on read the IRQ line will be reasserted and
387  * the physical IRQ will be handled again if another interrupt is
388  * asserted while we run - in the normal course of events this is a
389  * rare occurrence so we save I2C/SPI reads.
390  */
391 static irqreturn_t wm8350_irq(int irq, void *irq_data)
392 {
393 	struct wm8350 *wm8350 = irq_data;
394 	u16 level_one;
395 	u16 sub_reg[WM8350_NUM_IRQ_REGS];
396 	int read_done[WM8350_NUM_IRQ_REGS];
397 	struct wm8350_irq_data *data;
398 	int i;
399 
400 	/* TODO: Use block reads to improve performance? */
401 	level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
402 		& ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
403 
404 	if (!level_one)
405 		return IRQ_NONE;
406 
407 	memset(&read_done, 0, sizeof(read_done));
408 
409 	for (i = 0; i < ARRAY_SIZE(wm8350_irqs); i++) {
410 		data = &wm8350_irqs[i];
411 
412 		if (!(level_one & data->primary))
413 			continue;
414 
415 		if (!read_done[data->reg]) {
416 			sub_reg[data->reg] =
417 				wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 +
418 						data->reg);
419 			sub_reg[data->reg] &=
420 				~wm8350_reg_read(wm8350,
421 						 WM8350_INT_STATUS_1_MASK +
422 						 data->reg);
423 			read_done[data->reg] = 1;
424 		}
425 
426 		if (sub_reg[data->reg] & data->mask)
427 			wm8350_irq_call_handler(wm8350, i);
428 	}
429 
430 	return IRQ_HANDLED;
431 }
432 
433 int wm8350_register_irq(struct wm8350 *wm8350, int irq,
434 			irq_handler_t handler, unsigned long flags,
435 			const char *name, void *data)
436 {
437 	if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
438 		return -EINVAL;
439 
440 	if (wm8350->irq[irq].handler)
441 		return -EBUSY;
442 
443 	mutex_lock(&wm8350->irq_mutex);
444 	wm8350->irq[irq].handler = handler;
445 	wm8350->irq[irq].data = data;
446 	mutex_unlock(&wm8350->irq_mutex);
447 
448 	wm8350_unmask_irq(wm8350, irq);
449 
450 	return 0;
451 }
452 EXPORT_SYMBOL_GPL(wm8350_register_irq);
453 
454 int wm8350_free_irq(struct wm8350 *wm8350, int irq)
455 {
456 	if (irq < 0 || irq > WM8350_NUM_IRQ)
457 		return -EINVAL;
458 
459 	wm8350_mask_irq(wm8350, irq);
460 
461 	mutex_lock(&wm8350->irq_mutex);
462 	wm8350->irq[irq].handler = NULL;
463 	mutex_unlock(&wm8350->irq_mutex);
464 	return 0;
465 }
466 EXPORT_SYMBOL_GPL(wm8350_free_irq);
467 
468 int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
469 {
470 	return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK +
471 			       wm8350_irqs[irq].reg,
472 			       wm8350_irqs[irq].mask);
473 }
474 EXPORT_SYMBOL_GPL(wm8350_mask_irq);
475 
476 int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
477 {
478 	return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK +
479 				 wm8350_irqs[irq].reg,
480 				 wm8350_irqs[irq].mask);
481 }
482 EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
483 
484 int wm8350_irq_init(struct wm8350 *wm8350, int irq,
485 		    struct wm8350_platform_data *pdata)
486 {
487 	int ret;
488 	int flags = IRQF_ONESHOT;
489 
490 	if (!irq) {
491 		dev_err(wm8350->dev, "No IRQ configured\n");
492 		return -EINVAL;
493 	}
494 
495 	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
496 	wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
497 	wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
498 	wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
499 	wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
500 	wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
501 
502 	mutex_init(&wm8350->irq_mutex);
503 	wm8350->chip_irq = irq;
504 
505 	if (pdata && pdata->irq_high) {
506 		flags |= IRQF_TRIGGER_HIGH;
507 
508 		wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
509 				WM8350_IRQ_POL);
510 	} else {
511 		flags |= IRQF_TRIGGER_LOW;
512 
513 		wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
514 				  WM8350_IRQ_POL);
515 	}
516 
517 	ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
518 				   "wm8350", wm8350);
519 	if (ret != 0)
520 		dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
521 
522 	return ret;
523 }
524 
525 int wm8350_irq_exit(struct wm8350 *wm8350)
526 {
527 	free_irq(wm8350->chip_irq, wm8350);
528 	return 0;
529 }
530