xref: /OK3568_Linux_fs/kernel/drivers/mfd/pcf50633-irq.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* NXP PCF50633 Power Management Unit (PMU) driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) 2006-2008 by Openmoko, Inc.
5*4882a593Smuzhiyun  * Author: Harald Welte <laforge@openmoko.org>
6*4882a593Smuzhiyun  * 	   Balaji Rao <balajirrao@openmoko.org>
7*4882a593Smuzhiyun  * All rights reserved.
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/mutex.h>
13*4882a593Smuzhiyun #include <linux/export.h>
14*4882a593Smuzhiyun #include <linux/slab.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/mfd/pcf50633/core.h>
17*4882a593Smuzhiyun #include <linux/mfd/pcf50633/mbc.h>
18*4882a593Smuzhiyun 
pcf50633_register_irq(struct pcf50633 * pcf,int irq,void (* handler)(int,void *),void * data)19*4882a593Smuzhiyun int pcf50633_register_irq(struct pcf50633 *pcf, int irq,
20*4882a593Smuzhiyun 			void (*handler) (int, void *), void *data)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun 	if (irq < 0 || irq >= PCF50633_NUM_IRQ || !handler)
23*4882a593Smuzhiyun 		return -EINVAL;
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	if (WARN_ON(pcf->irq_handler[irq].handler))
26*4882a593Smuzhiyun 		return -EBUSY;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	mutex_lock(&pcf->lock);
29*4882a593Smuzhiyun 	pcf->irq_handler[irq].handler = handler;
30*4882a593Smuzhiyun 	pcf->irq_handler[irq].data = data;
31*4882a593Smuzhiyun 	mutex_unlock(&pcf->lock);
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	return 0;
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_register_irq);
36*4882a593Smuzhiyun 
pcf50633_free_irq(struct pcf50633 * pcf,int irq)37*4882a593Smuzhiyun int pcf50633_free_irq(struct pcf50633 *pcf, int irq)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	if (irq < 0 || irq >= PCF50633_NUM_IRQ)
40*4882a593Smuzhiyun 		return -EINVAL;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	mutex_lock(&pcf->lock);
43*4882a593Smuzhiyun 	pcf->irq_handler[irq].handler = NULL;
44*4882a593Smuzhiyun 	mutex_unlock(&pcf->lock);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_free_irq);
49*4882a593Smuzhiyun 
__pcf50633_irq_mask_set(struct pcf50633 * pcf,int irq,u8 mask)50*4882a593Smuzhiyun static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	u8 reg, bit;
53*4882a593Smuzhiyun 	int idx;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	idx = irq >> 3;
56*4882a593Smuzhiyun 	reg = PCF50633_REG_INT1M + idx;
57*4882a593Smuzhiyun 	bit = 1 << (irq & 0x07);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	pcf50633_reg_set_bit_mask(pcf, reg, bit, mask ? bit : 0);
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	mutex_lock(&pcf->lock);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (mask)
64*4882a593Smuzhiyun 		pcf->mask_regs[idx] |= bit;
65*4882a593Smuzhiyun 	else
66*4882a593Smuzhiyun 		pcf->mask_regs[idx] &= ~bit;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	mutex_unlock(&pcf->lock);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return 0;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
pcf50633_irq_mask(struct pcf50633 * pcf,int irq)73*4882a593Smuzhiyun int pcf50633_irq_mask(struct pcf50633 *pcf, int irq)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	dev_dbg(pcf->dev, "Masking IRQ %d\n", irq);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return __pcf50633_irq_mask_set(pcf, irq, 1);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_irq_mask);
80*4882a593Smuzhiyun 
pcf50633_irq_unmask(struct pcf50633 * pcf,int irq)81*4882a593Smuzhiyun int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return __pcf50633_irq_mask_set(pcf, irq, 0);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_irq_unmask);
88*4882a593Smuzhiyun 
pcf50633_irq_mask_get(struct pcf50633 * pcf,int irq)89*4882a593Smuzhiyun int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	u8 reg, bits;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	reg =  irq >> 3;
94*4882a593Smuzhiyun 	bits = 1 << (irq & 0x07);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	return pcf->mask_regs[reg] & bits;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get);
99*4882a593Smuzhiyun 
pcf50633_irq_call_handler(struct pcf50633 * pcf,int irq)100*4882a593Smuzhiyun static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	if (pcf->irq_handler[irq].handler)
103*4882a593Smuzhiyun 		pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* Maximum amount of time ONKEY is held before emergency action is taken */
107*4882a593Smuzhiyun #define PCF50633_ONKEY1S_TIMEOUT 8
108*4882a593Smuzhiyun 
pcf50633_irq(int irq,void * data)109*4882a593Smuzhiyun static irqreturn_t pcf50633_irq(int irq, void *data)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	struct pcf50633 *pcf = data;
112*4882a593Smuzhiyun 	int ret, i, j;
113*4882a593Smuzhiyun 	u8 pcf_int[5], chgstat;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	/* Read the 5 INT regs in one transaction */
116*4882a593Smuzhiyun 	ret = pcf50633_read_block(pcf, PCF50633_REG_INT1,
117*4882a593Smuzhiyun 						ARRAY_SIZE(pcf_int), pcf_int);
118*4882a593Smuzhiyun 	if (ret != ARRAY_SIZE(pcf_int)) {
119*4882a593Smuzhiyun 		dev_err(pcf->dev, "Error reading INT registers\n");
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 		/*
122*4882a593Smuzhiyun 		 * If this doesn't ACK the interrupt to the chip, we'll be
123*4882a593Smuzhiyun 		 * called once again as we're level triggered.
124*4882a593Smuzhiyun 		 */
125*4882a593Smuzhiyun 		goto out;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* defeat 8s death from lowsys on A5 */
129*4882a593Smuzhiyun 	pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN,  0x04);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* We immediately read the usb and adapter status. We thus make sure
132*4882a593Smuzhiyun 	 * only of USBINS/USBREM IRQ handlers are called */
133*4882a593Smuzhiyun 	if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) {
134*4882a593Smuzhiyun 		chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
135*4882a593Smuzhiyun 		if (chgstat & (0x3 << 4))
136*4882a593Smuzhiyun 			pcf_int[0] &= ~PCF50633_INT1_USBREM;
137*4882a593Smuzhiyun 		else
138*4882a593Smuzhiyun 			pcf_int[0] &= ~PCF50633_INT1_USBINS;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* Make sure only one of ADPINS or ADPREM is set */
142*4882a593Smuzhiyun 	if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) {
143*4882a593Smuzhiyun 		chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2);
144*4882a593Smuzhiyun 		if (chgstat & (0x3 << 4))
145*4882a593Smuzhiyun 			pcf_int[0] &= ~PCF50633_INT1_ADPREM;
146*4882a593Smuzhiyun 		else
147*4882a593Smuzhiyun 			pcf_int[0] &= ~PCF50633_INT1_ADPINS;
148*4882a593Smuzhiyun 	}
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x "
151*4882a593Smuzhiyun 			"INT4=0x%02x INT5=0x%02x\n", pcf_int[0],
152*4882a593Smuzhiyun 			pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	/* Some revisions of the chip don't have a 8s standby mode on
155*4882a593Smuzhiyun 	 * ONKEY1S press. We try to manually do it in such cases. */
156*4882a593Smuzhiyun 	if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) {
157*4882a593Smuzhiyun 		dev_info(pcf->dev, "ONKEY1S held for %d secs\n",
158*4882a593Smuzhiyun 							pcf->onkey1s_held);
159*4882a593Smuzhiyun 		if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT)
160*4882a593Smuzhiyun 			if (pcf->pdata->force_shutdown)
161*4882a593Smuzhiyun 				pcf->pdata->force_shutdown(pcf);
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (pcf_int[2] & PCF50633_INT3_ONKEY1S) {
165*4882a593Smuzhiyun 		dev_info(pcf->dev, "ONKEY1S held\n");
166*4882a593Smuzhiyun 		pcf->onkey1s_held = 1 ;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 		/* Unmask IRQ_SECOND */
169*4882a593Smuzhiyun 		pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M,
170*4882a593Smuzhiyun 						PCF50633_INT1_SECOND);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 		/* Unmask IRQ_ONKEYR */
173*4882a593Smuzhiyun 		pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M,
174*4882a593Smuzhiyun 						PCF50633_INT2_ONKEYR);
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) {
178*4882a593Smuzhiyun 		pcf->onkey1s_held = 0;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		/* Mask SECOND and ONKEYR interrupts */
181*4882a593Smuzhiyun 		if (pcf->mask_regs[0] & PCF50633_INT1_SECOND)
182*4882a593Smuzhiyun 			pcf50633_reg_set_bit_mask(pcf,
183*4882a593Smuzhiyun 					PCF50633_REG_INT1M,
184*4882a593Smuzhiyun 					PCF50633_INT1_SECOND,
185*4882a593Smuzhiyun 					PCF50633_INT1_SECOND);
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 		if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR)
188*4882a593Smuzhiyun 			pcf50633_reg_set_bit_mask(pcf,
189*4882a593Smuzhiyun 					PCF50633_REG_INT2M,
190*4882a593Smuzhiyun 					PCF50633_INT2_ONKEYR,
191*4882a593Smuzhiyun 					PCF50633_INT2_ONKEYR);
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	/* Have we just resumed ? */
195*4882a593Smuzhiyun 	if (pcf->is_suspended) {
196*4882a593Smuzhiyun 		pcf->is_suspended = 0;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		/* Set the resume reason filtering out non resumers */
199*4882a593Smuzhiyun 		for (i = 0; i < ARRAY_SIZE(pcf_int); i++)
200*4882a593Smuzhiyun 			pcf->resume_reason[i] = pcf_int[i] &
201*4882a593Smuzhiyun 						pcf->pdata->resumers[i];
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 		/* Make sure we don't pass on any ONKEY events to
204*4882a593Smuzhiyun 		 * userspace now */
205*4882a593Smuzhiyun 		pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF);
206*4882a593Smuzhiyun 	}
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(pcf_int); i++) {
209*4882a593Smuzhiyun 		/* Unset masked interrupts */
210*4882a593Smuzhiyun 		pcf_int[i] &= ~pcf->mask_regs[i];
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 		for (j = 0; j < 8 ; j++)
213*4882a593Smuzhiyun 			if (pcf_int[i] & (1 << j))
214*4882a593Smuzhiyun 				pcf50633_irq_call_handler(pcf, (i * 8) + j);
215*4882a593Smuzhiyun 	}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun out:
218*4882a593Smuzhiyun 	return IRQ_HANDLED;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun #ifdef CONFIG_PM
222*4882a593Smuzhiyun 
pcf50633_irq_suspend(struct pcf50633 * pcf)223*4882a593Smuzhiyun int pcf50633_irq_suspend(struct pcf50633 *pcf)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 	int i;
227*4882a593Smuzhiyun 	u8 res[5];
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	/* Make sure our interrupt handlers are not called
231*4882a593Smuzhiyun 	 * henceforth */
232*4882a593Smuzhiyun 	disable_irq(pcf->irq);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	/* Save the masks */
235*4882a593Smuzhiyun 	ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M,
236*4882a593Smuzhiyun 				ARRAY_SIZE(pcf->suspend_irq_masks),
237*4882a593Smuzhiyun 					pcf->suspend_irq_masks);
238*4882a593Smuzhiyun 	if (ret < 0) {
239*4882a593Smuzhiyun 		dev_err(pcf->dev, "error saving irq masks\n");
240*4882a593Smuzhiyun 		goto out;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	/* Write wakeup irq masks */
244*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(res); i++)
245*4882a593Smuzhiyun 		res[i] = ~pcf->pdata->resumers[i];
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
248*4882a593Smuzhiyun 					ARRAY_SIZE(res), &res[0]);
249*4882a593Smuzhiyun 	if (ret < 0) {
250*4882a593Smuzhiyun 		dev_err(pcf->dev, "error writing wakeup irq masks\n");
251*4882a593Smuzhiyun 		goto out;
252*4882a593Smuzhiyun 	}
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	pcf->is_suspended = 1;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun out:
257*4882a593Smuzhiyun 	return ret;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
pcf50633_irq_resume(struct pcf50633 * pcf)260*4882a593Smuzhiyun int pcf50633_irq_resume(struct pcf50633 *pcf)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	int ret;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/* Write the saved mask registers */
265*4882a593Smuzhiyun 	ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M,
266*4882a593Smuzhiyun 				ARRAY_SIZE(pcf->suspend_irq_masks),
267*4882a593Smuzhiyun 					pcf->suspend_irq_masks);
268*4882a593Smuzhiyun 	if (ret < 0)
269*4882a593Smuzhiyun 		dev_err(pcf->dev, "Error restoring saved suspend masks\n");
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	enable_irq(pcf->irq);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	return ret;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun #endif
277*4882a593Smuzhiyun 
pcf50633_irq_init(struct pcf50633 * pcf,int irq)278*4882a593Smuzhiyun int pcf50633_irq_init(struct pcf50633 *pcf, int irq)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	int ret;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	pcf->irq = irq;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* Enable all interrupts except RTC SECOND */
285*4882a593Smuzhiyun 	pcf->mask_regs[0] = 0x80;
286*4882a593Smuzhiyun 	pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]);
287*4882a593Smuzhiyun 	pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00);
288*4882a593Smuzhiyun 	pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00);
289*4882a593Smuzhiyun 	pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00);
290*4882a593Smuzhiyun 	pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	ret = request_threaded_irq(irq, NULL, pcf50633_irq,
293*4882a593Smuzhiyun 					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
294*4882a593Smuzhiyun 					"pcf50633", pcf);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (ret)
297*4882a593Smuzhiyun 		dev_err(pcf->dev, "Failed to request IRQ %d\n", ret);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (enable_irq_wake(irq) < 0)
300*4882a593Smuzhiyun 		dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source"
301*4882a593Smuzhiyun 			"in this hardware revision", irq);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return ret;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
pcf50633_irq_free(struct pcf50633 * pcf)306*4882a593Smuzhiyun void pcf50633_irq_free(struct pcf50633 *pcf)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	free_irq(pcf->irq, pcf);
309*4882a593Smuzhiyun }
310