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