0236676085cf096f6c4e0091ac3803d4f8fc1f3f
[cascardo/linux.git] / drivers / mfd / s5m-irq.c
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 *
171 irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
172 {
173         return &s5m8767_irqs[irq - s5m87xx->irq_base];
174 }
175
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
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
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
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 *
226 irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
227 {
228         return &s5m8763_irqs[irq - s5m87xx->irq_base];
229 }
230
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
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
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
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
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
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
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
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
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 }