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