aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/sec-irq.c
diff options
context:
space:
mode:
authorSangbeom Kim <sbkim73@samsung.com>2012-07-11 08:06:40 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-07-16 06:57:35 -0400
commit66c9fbb9895499ff3aede96845968138a5bec8ab (patch)
tree8c2ec903b0c7995e689a80712b8bf9539f4f1cf6 /drivers/mfd/sec-irq.c
parent1faedca9c7bfd3055204b9d10017ce77ad03fc72 (diff)
mfd: Rename s5m file and directories to samsung
Previously, Samsung PMIC naming rule start with prefix of s5m. But Naming rule is changed. From now on, Prefix will be changed to s2m. So, To support pmic series of s5m and s2m, change mfd file and directory name. Signed-off-by: Sangbeom Kim <sbkim73@samsung.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/sec-irq.c')
-rw-r--r--drivers/mfd/sec-irq.c495
1 files changed, 495 insertions, 0 deletions
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
new file mode 100644
index 000000000000..5e90cc1f0fd7
--- /dev/null
+++ b/drivers/mfd/sec-irq.c
@@ -0,0 +1,495 @@
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/samsung/s5m-core.h>
18
19struct s5m_irq_data {
20 int reg;
21 int mask;
22};
23
24static 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
95static 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
170static inline struct s5m_irq_data *
171irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
172{
173 return &s5m8767_irqs[irq - s5m87xx->irq_base];
174}
175
176static 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
183static 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
199static 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
208static 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
217static 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
225static inline struct s5m_irq_data *
226irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
227{
228 return &s5m8763_irqs[irq - s5m87xx->irq_base];
229}
230
231static 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
238static 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
254static 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
263static 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
272static 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
281static 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
308static 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
334int 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
355int 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
488void 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}