wm8350-irq.c revision 0c7229f93a529145d52e1bd7b29e6c98a3a3294d
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
42struct wm8350_irq_data {
43	int primary;
44	int reg;
45	int mask;
46	int primary_only;
47};
48
49static 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
369static 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(wm8350, 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 */
391static 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
433int wm8350_register_irq(struct wm8350 *wm8350, int irq,
434			void (*handler) (struct wm8350 *, int, void *),
435			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	return 0;
449}
450EXPORT_SYMBOL_GPL(wm8350_register_irq);
451
452int wm8350_free_irq(struct wm8350 *wm8350, int irq)
453{
454	if (irq < 0 || irq > WM8350_NUM_IRQ)
455		return -EINVAL;
456
457	mutex_lock(&wm8350->irq_mutex);
458	wm8350->irq[irq].handler = NULL;
459	mutex_unlock(&wm8350->irq_mutex);
460	return 0;
461}
462EXPORT_SYMBOL_GPL(wm8350_free_irq);
463
464int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
465{
466	return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK +
467			       wm8350_irqs[irq].reg,
468			       wm8350_irqs[irq].mask);
469}
470EXPORT_SYMBOL_GPL(wm8350_mask_irq);
471
472int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
473{
474	return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK +
475				 wm8350_irqs[irq].reg,
476				 wm8350_irqs[irq].mask);
477}
478EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
479
480int wm8350_irq_init(struct wm8350 *wm8350, int irq,
481		    struct wm8350_platform_data *pdata)
482{
483	int ret;
484	int flags = IRQF_ONESHOT;
485
486	if (!irq) {
487		dev_err(wm8350->dev, "No IRQ configured\n");
488		return -EINVAL;
489	}
490
491	wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
492	wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
493	wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
494	wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
495	wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
496	wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
497
498	mutex_init(&wm8350->irq_mutex);
499	wm8350->chip_irq = irq;
500
501	if (pdata && pdata->irq_high) {
502		flags |= IRQF_TRIGGER_HIGH;
503
504		wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
505				WM8350_IRQ_POL);
506	} else {
507		flags |= IRQF_TRIGGER_LOW;
508
509		wm8350_clear_bits(wm8350, WM8350_SYSTEM_CONTROL_1,
510				  WM8350_IRQ_POL);
511	}
512
513	ret = request_threaded_irq(irq, NULL, wm8350_irq, flags,
514				   "wm8350", wm8350);
515	if (ret != 0)
516		dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret);
517
518	return ret;
519}
520
521int wm8350_irq_exit(struct wm8350 *wm8350)
522{
523	free_irq(wm8350->chip_irq, wm8350);
524	return 0;
525}
526