• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * s5m-irq.c
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd
5  *              http://www.samsung.com
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  *
12  */
13 
14 #include <linux/device.h>
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <linux/mfd/s5m87xx/s5m-core.h>
18 
19 struct s5m_irq_data {
20 	int reg;
21 	int mask;
22 };
23 
24 static struct s5m_irq_data s5m8767_irqs[] = {
25 	[S5M8767_IRQ_PWRR] = {
26 		.reg = 1,
27 		.mask = S5M8767_IRQ_PWRR_MASK,
28 	},
29 	[S5M8767_IRQ_PWRF] = {
30 		.reg = 1,
31 		.mask = S5M8767_IRQ_PWRF_MASK,
32 	},
33 	[S5M8767_IRQ_PWR1S] = {
34 		.reg = 1,
35 		.mask = S5M8767_IRQ_PWR1S_MASK,
36 	},
37 	[S5M8767_IRQ_JIGR] = {
38 		.reg = 1,
39 		.mask = S5M8767_IRQ_JIGR_MASK,
40 	},
41 	[S5M8767_IRQ_JIGF] = {
42 		.reg = 1,
43 		.mask = S5M8767_IRQ_JIGF_MASK,
44 	},
45 	[S5M8767_IRQ_LOWBAT2] = {
46 		.reg = 1,
47 		.mask = S5M8767_IRQ_LOWBAT2_MASK,
48 	},
49 	[S5M8767_IRQ_LOWBAT1] = {
50 		.reg = 1,
51 		.mask = S5M8767_IRQ_LOWBAT1_MASK,
52 	},
53 	[S5M8767_IRQ_MRB] = {
54 		.reg = 2,
55 		.mask = S5M8767_IRQ_MRB_MASK,
56 	},
57 	[S5M8767_IRQ_DVSOK2] = {
58 		.reg = 2,
59 		.mask = S5M8767_IRQ_DVSOK2_MASK,
60 	},
61 	[S5M8767_IRQ_DVSOK3] = {
62 		.reg = 2,
63 		.mask = S5M8767_IRQ_DVSOK3_MASK,
64 	},
65 	[S5M8767_IRQ_DVSOK4] = {
66 		.reg = 2,
67 		.mask = S5M8767_IRQ_DVSOK4_MASK,
68 	},
69 	[S5M8767_IRQ_RTC60S] = {
70 		.reg = 3,
71 		.mask = S5M8767_IRQ_RTC60S_MASK,
72 	},
73 	[S5M8767_IRQ_RTCA1] = {
74 		.reg = 3,
75 		.mask = S5M8767_IRQ_RTCA1_MASK,
76 	},
77 	[S5M8767_IRQ_RTCA2] = {
78 		.reg = 3,
79 		.mask = S5M8767_IRQ_RTCA2_MASK,
80 	},
81 	[S5M8767_IRQ_SMPL] = {
82 		.reg = 3,
83 		.mask = S5M8767_IRQ_SMPL_MASK,
84 	},
85 	[S5M8767_IRQ_RTC1S] = {
86 		.reg = 3,
87 		.mask = S5M8767_IRQ_RTC1S_MASK,
88 	},
89 	[S5M8767_IRQ_WTSR] = {
90 		.reg = 3,
91 		.mask = S5M8767_IRQ_WTSR_MASK,
92 	},
93 };
94 
95 static struct s5m_irq_data s5m8763_irqs[] = {
96 	[S5M8763_IRQ_DCINF] = {
97 		.reg = 1,
98 		.mask = S5M8763_IRQ_DCINF_MASK,
99 	},
100 	[S5M8763_IRQ_DCINR] = {
101 		.reg = 1,
102 		.mask = S5M8763_IRQ_DCINR_MASK,
103 	},
104 	[S5M8763_IRQ_JIGF] = {
105 		.reg = 1,
106 		.mask = S5M8763_IRQ_JIGF_MASK,
107 	},
108 	[S5M8763_IRQ_JIGR] = {
109 		.reg = 1,
110 		.mask = S5M8763_IRQ_JIGR_MASK,
111 	},
112 	[S5M8763_IRQ_PWRONF] = {
113 		.reg = 1,
114 		.mask = S5M8763_IRQ_PWRONF_MASK,
115 	},
116 	[S5M8763_IRQ_PWRONR] = {
117 		.reg = 1,
118 		.mask = S5M8763_IRQ_PWRONR_MASK,
119 	},
120 	[S5M8763_IRQ_WTSREVNT] = {
121 		.reg = 2,
122 		.mask = S5M8763_IRQ_WTSREVNT_MASK,
123 	},
124 	[S5M8763_IRQ_SMPLEVNT] = {
125 		.reg = 2,
126 		.mask = S5M8763_IRQ_SMPLEVNT_MASK,
127 	},
128 	[S5M8763_IRQ_ALARM1] = {
129 		.reg = 2,
130 		.mask = S5M8763_IRQ_ALARM1_MASK,
131 	},
132 	[S5M8763_IRQ_ALARM0] = {
133 		.reg = 2,
134 		.mask = S5M8763_IRQ_ALARM0_MASK,
135 	},
136 	[S5M8763_IRQ_ONKEY1S] = {
137 		.reg = 3,
138 		.mask = S5M8763_IRQ_ONKEY1S_MASK,
139 	},
140 	[S5M8763_IRQ_TOPOFFR] = {
141 		.reg = 3,
142 		.mask = S5M8763_IRQ_TOPOFFR_MASK,
143 	},
144 	[S5M8763_IRQ_DCINOVPR] = {
145 		.reg = 3,
146 		.mask = S5M8763_IRQ_DCINOVPR_MASK,
147 	},
148 	[S5M8763_IRQ_CHGRSTF] = {
149 		.reg = 3,
150 		.mask = S5M8763_IRQ_CHGRSTF_MASK,
151 	},
152 	[S5M8763_IRQ_DONER] = {
153 		.reg = 3,
154 		.mask = S5M8763_IRQ_DONER_MASK,
155 	},
156 	[S5M8763_IRQ_CHGFAULT] = {
157 		.reg = 3,
158 		.mask = S5M8763_IRQ_CHGFAULT_MASK,
159 	},
160 	[S5M8763_IRQ_LOBAT1] = {
161 		.reg = 4,
162 		.mask = S5M8763_IRQ_LOBAT1_MASK,
163 	},
164 	[S5M8763_IRQ_LOBAT2] = {
165 		.reg = 4,
166 		.mask = S5M8763_IRQ_LOBAT2_MASK,
167 	},
168 };
169 
170 static inline struct s5m_irq_data *
irq_to_s5m8767_irq(struct s5m87xx_dev * s5m87xx,int irq)171 irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
172 {
173 	return &s5m8767_irqs[irq - s5m87xx->irq_base];
174 }
175 
s5m8767_irq_lock(struct irq_data * data)176 static void s5m8767_irq_lock(struct irq_data *data)
177 {
178 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
179 
180 	mutex_lock(&s5m87xx->irqlock);
181 }
182 
s5m8767_irq_sync_unlock(struct irq_data * data)183 static void s5m8767_irq_sync_unlock(struct irq_data *data)
184 {
185 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
186 	int i;
187 
188 	for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
189 		if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
190 			s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
191 			s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
192 					s5m87xx->irq_masks_cur[i]);
193 		}
194 	}
195 
196 	mutex_unlock(&s5m87xx->irqlock);
197 }
198 
s5m8767_irq_unmask(struct irq_data * data)199 static void s5m8767_irq_unmask(struct irq_data *data)
200 {
201 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
202 	struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
203 							       data->irq);
204 
205 	s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
206 }
207 
s5m8767_irq_mask(struct irq_data * data)208 static void s5m8767_irq_mask(struct irq_data *data)
209 {
210 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
211 	struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
212 							       data->irq);
213 
214 	s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
215 }
216 
217 static struct irq_chip s5m8767_irq_chip = {
218 	.name = "s5m8767",
219 	.irq_bus_lock = s5m8767_irq_lock,
220 	.irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
221 	.irq_mask = s5m8767_irq_mask,
222 	.irq_unmask = s5m8767_irq_unmask,
223 };
224 
225 static inline struct s5m_irq_data *
irq_to_s5m8763_irq(struct s5m87xx_dev * s5m87xx,int irq)226 irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
227 {
228 	return &s5m8763_irqs[irq - s5m87xx->irq_base];
229 }
230 
s5m8763_irq_lock(struct irq_data * data)231 static void s5m8763_irq_lock(struct irq_data *data)
232 {
233 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
234 
235 	mutex_lock(&s5m87xx->irqlock);
236 }
237 
s5m8763_irq_sync_unlock(struct irq_data * data)238 static void s5m8763_irq_sync_unlock(struct irq_data *data)
239 {
240 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
241 	int i;
242 
243 	for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
244 		if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
245 			s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
246 			s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
247 					s5m87xx->irq_masks_cur[i]);
248 		}
249 	}
250 
251 	mutex_unlock(&s5m87xx->irqlock);
252 }
253 
s5m8763_irq_unmask(struct irq_data * data)254 static void s5m8763_irq_unmask(struct irq_data *data)
255 {
256 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
257 	struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
258 							       data->irq);
259 
260 	s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
261 }
262 
s5m8763_irq_mask(struct irq_data * data)263 static void s5m8763_irq_mask(struct irq_data *data)
264 {
265 	struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
266 	struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
267 							       data->irq);
268 
269 	s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
270 }
271 
272 static struct irq_chip s5m8763_irq_chip = {
273 	.name = "s5m8763",
274 	.irq_bus_lock = s5m8763_irq_lock,
275 	.irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
276 	.irq_mask = s5m8763_irq_mask,
277 	.irq_unmask = s5m8763_irq_unmask,
278 };
279 
280 
s5m8767_irq_thread(int irq,void * data)281 static irqreturn_t s5m8767_irq_thread(int irq, void *data)
282 {
283 	struct s5m87xx_dev *s5m87xx = data;
284 	u8 irq_reg[NUM_IRQ_REGS-1];
285 	int ret;
286 	int i;
287 
288 
289 	ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1,
290 				NUM_IRQ_REGS - 1, irq_reg);
291 	if (ret < 0) {
292 		dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
293 				ret);
294 		return IRQ_NONE;
295 	}
296 
297 	for (i = 0; i < NUM_IRQ_REGS - 1; i++)
298 		irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
299 
300 	for (i = 0; i < S5M8767_IRQ_NR; i++) {
301 		if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
302 			handle_nested_irq(s5m87xx->irq_base + i);
303 	}
304 
305 	return IRQ_HANDLED;
306 }
307 
s5m8763_irq_thread(int irq,void * data)308 static irqreturn_t s5m8763_irq_thread(int irq, void *data)
309 {
310 	struct s5m87xx_dev *s5m87xx = data;
311 	u8 irq_reg[NUM_IRQ_REGS];
312 	int ret;
313 	int i;
314 
315 	ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1,
316 				NUM_IRQ_REGS, irq_reg);
317 	if (ret < 0) {
318 		dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
319 				ret);
320 		return IRQ_NONE;
321 	}
322 
323 	for (i = 0; i < NUM_IRQ_REGS; i++)
324 		irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
325 
326 	for (i = 0; i < S5M8763_IRQ_NR; i++) {
327 		if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
328 			handle_nested_irq(s5m87xx->irq_base + i);
329 	}
330 
331 	return IRQ_HANDLED;
332 }
333 
s5m_irq_resume(struct s5m87xx_dev * s5m87xx)334 int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
335 {
336 	if (s5m87xx->irq && s5m87xx->irq_base){
337 		switch (s5m87xx->device_type) {
338 		case S5M8763X:
339 			s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
340 			break;
341 		case S5M8767X:
342 			s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
343 			break;
344 		default:
345 			dev_err(s5m87xx->dev,
346 				"Unknown device type %d\n",
347 				s5m87xx->device_type);
348 			return -EINVAL;
349 
350 		}
351 	}
352 	return 0;
353 }
354 
s5m_irq_init(struct s5m87xx_dev * s5m87xx)355 int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
356 {
357 	int i;
358 	int cur_irq;
359 	int ret = 0;
360 	int type = s5m87xx->device_type;
361 
362 	if (!s5m87xx->irq) {
363 		dev_warn(s5m87xx->dev,
364 			 "No interrupt specified, no interrupts\n");
365 		s5m87xx->irq_base = 0;
366 		return 0;
367 	}
368 
369 	if (!s5m87xx->irq_base) {
370 		dev_err(s5m87xx->dev,
371 			"No interrupt base specified, no interrupts\n");
372 		return 0;
373 	}
374 
375 	mutex_init(&s5m87xx->irqlock);
376 
377 	switch (type) {
378 	case S5M8763X:
379 		for (i = 0; i < NUM_IRQ_REGS; i++) {
380 			s5m87xx->irq_masks_cur[i] = 0xff;
381 			s5m87xx->irq_masks_cache[i] = 0xff;
382 			s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
383 						0xff);
384 		}
385 
386 		s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff);
387 		s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff);
388 
389 		for (i = 0; i < S5M8763_IRQ_NR; i++) {
390 			cur_irq = i + s5m87xx->irq_base;
391 			irq_set_chip_data(cur_irq, s5m87xx);
392 			irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
393 						 handle_edge_irq);
394 			irq_set_nested_thread(cur_irq, 1);
395 #ifdef CONFIG_ARM
396 			set_irq_flags(cur_irq, IRQF_VALID);
397 #else
398 			irq_set_noprobe(cur_irq);
399 #endif
400 		}
401 
402 		ret = request_threaded_irq(s5m87xx->irq, NULL,
403 					s5m8763_irq_thread,
404 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
405 					"s5m87xx-irq", s5m87xx);
406 		if (ret) {
407 			dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
408 				s5m87xx->irq, ret);
409 			return ret;
410 		}
411 		break;
412 	case S5M8767X:
413 		for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
414 			s5m87xx->irq_masks_cur[i] = 0xff;
415 			s5m87xx->irq_masks_cache[i] = 0xff;
416 			s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
417 						0xff);
418 		}
419 		for (i = 0; i < S5M8767_IRQ_NR; i++) {
420 			cur_irq = i + s5m87xx->irq_base;
421 			irq_set_chip_data(cur_irq, s5m87xx);
422 			if (ret) {
423 				dev_err(s5m87xx->dev,
424 					"Failed to irq_set_chip_data %d: %d\n",
425 					s5m87xx->irq, ret);
426 				return ret;
427 			}
428 
429 			irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
430 						 handle_edge_irq);
431 			irq_set_nested_thread(cur_irq, 1);
432 #ifdef CONFIG_ARM
433 			set_irq_flags(cur_irq, IRQF_VALID);
434 #else
435 			irq_set_noprobe(cur_irq);
436 #endif
437 		}
438 
439 		ret = request_threaded_irq(s5m87xx->irq, NULL,
440 					   s5m8767_irq_thread,
441 					   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
442 					   "s5m87xx-irq", s5m87xx);
443 		if (ret) {
444 			dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
445 				s5m87xx->irq, ret);
446 			return ret;
447 		}
448 		break;
449 	default:
450 		dev_err(s5m87xx->dev,
451 			"Unknown device type %d\n", s5m87xx->device_type);
452 		return -EINVAL;
453 	}
454 
455 	if (!s5m87xx->ono)
456 		return 0;
457 
458 	switch (type) {
459 	case S5M8763X:
460 		ret = request_threaded_irq(s5m87xx->ono, NULL,
461 						s5m8763_irq_thread,
462 						IRQF_TRIGGER_FALLING |
463 						IRQF_TRIGGER_RISING |
464 						IRQF_ONESHOT, "s5m87xx-ono",
465 						s5m87xx);
466 		break;
467 	case S5M8767X:
468 		ret = request_threaded_irq(s5m87xx->ono, NULL,
469 					s5m8767_irq_thread,
470 					IRQF_TRIGGER_FALLING |
471 					IRQF_TRIGGER_RISING |
472 					IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
473 		break;
474 	default:
475 		ret = -EINVAL;
476 		break;
477 	}
478 
479 	if (ret) {
480 		dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
481 			s5m87xx->ono, ret);
482 		return ret;
483 	}
484 
485 	return 0;
486 }
487 
s5m_irq_exit(struct s5m87xx_dev * s5m87xx)488 void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
489 {
490 	if (s5m87xx->ono)
491 		free_irq(s5m87xx->ono, s5m87xx);
492 
493 	if (s5m87xx->irq)
494 		free_irq(s5m87xx->irq, s5m87xx);
495 }
496