mfd: Modify samsung mfd driver for common api
[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>
66c9fbb9 17#include <linux/mfd/samsung/s5m-core.h>
5ac2ffa7 18
63063bfb 19struct sec_irq_data {
5ac2ffa7
SK
20 int reg;
21 int mask;
22};
23
63063bfb 24static struct sec_irq_data s5m8767_irqs[] = {
5ac2ffa7
SK
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
63063bfb 95static struct sec_irq_data s5m8763_irqs[] = {
5ac2ffa7
SK
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
63063bfb
SK
170static inline struct sec_irq_data *
171irq_to_s5m8767_irq(struct sec_pmic_dev *sec_pmic, int irq)
5ac2ffa7 172{
63063bfb 173 return &s5m8767_irqs[irq - sec_pmic->irq_base];
5ac2ffa7
SK
174}
175
176static void s5m8767_irq_lock(struct irq_data *data)
177{
63063bfb 178 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
5ac2ffa7 179
63063bfb 180 mutex_lock(&sec_pmic->irqlock);
5ac2ffa7
SK
181}
182
183static void s5m8767_irq_sync_unlock(struct irq_data *data)
184{
63063bfb 185 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
5ac2ffa7
SK
186 int i;
187
63063bfb
SK
188 for (i = 0; i < ARRAY_SIZE(sec_pmic->irq_masks_cur); i++) {
189 if (sec_pmic->irq_masks_cur[i] != sec_pmic->irq_masks_cache[i]) {
190 sec_pmic->irq_masks_cache[i] = sec_pmic->irq_masks_cur[i];
191 sec_reg_write(sec_pmic, S5M8767_REG_INT1M + i,
192 sec_pmic->irq_masks_cur[i]);
5ac2ffa7
SK
193 }
194 }
195
63063bfb 196 mutex_unlock(&sec_pmic->irqlock);
5ac2ffa7
SK
197}
198
199static void s5m8767_irq_unmask(struct irq_data *data)
200{
63063bfb
SK
201 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
202 struct sec_irq_data *irq_data = irq_to_s5m8767_irq(sec_pmic,
5ac2ffa7
SK
203 data->irq);
204
63063bfb 205 sec_pmic->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
5ac2ffa7
SK
206}
207
208static void s5m8767_irq_mask(struct irq_data *data)
209{
63063bfb
SK
210 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
211 struct sec_irq_data *irq_data = irq_to_s5m8767_irq(sec_pmic,
5ac2ffa7
SK
212 data->irq);
213
63063bfb 214 sec_pmic->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
5ac2ffa7
SK
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
63063bfb
SK
225static inline struct sec_irq_data *
226irq_to_s5m8763_irq(struct sec_pmic_dev *sec_pmic, int irq)
5ac2ffa7 227{
63063bfb 228 return &s5m8763_irqs[irq - sec_pmic->irq_base];
5ac2ffa7
SK
229}
230
231static void s5m8763_irq_lock(struct irq_data *data)
232{
63063bfb 233 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
5ac2ffa7 234
63063bfb 235 mutex_lock(&sec_pmic->irqlock);
5ac2ffa7
SK
236}
237
238static void s5m8763_irq_sync_unlock(struct irq_data *data)
239{
63063bfb 240 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
5ac2ffa7
SK
241 int i;
242
63063bfb
SK
243 for (i = 0; i < ARRAY_SIZE(sec_pmic->irq_masks_cur); i++) {
244 if (sec_pmic->irq_masks_cur[i] != sec_pmic->irq_masks_cache[i]) {
245 sec_pmic->irq_masks_cache[i] = sec_pmic->irq_masks_cur[i];
246 sec_reg_write(sec_pmic, S5M8763_REG_IRQM1 + i,
247 sec_pmic->irq_masks_cur[i]);
5ac2ffa7
SK
248 }
249 }
250
63063bfb 251 mutex_unlock(&sec_pmic->irqlock);
5ac2ffa7
SK
252}
253
254static void s5m8763_irq_unmask(struct irq_data *data)
255{
63063bfb
SK
256 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
257 struct sec_irq_data *irq_data = irq_to_s5m8763_irq(sec_pmic,
5ac2ffa7
SK
258 data->irq);
259
63063bfb 260 sec_pmic->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
5ac2ffa7
SK
261}
262
263static void s5m8763_irq_mask(struct irq_data *data)
264{
63063bfb
SK
265 struct sec_pmic_dev *sec_pmic = irq_data_get_irq_chip_data(data);
266 struct sec_irq_data *irq_data = irq_to_s5m8763_irq(sec_pmic,
5ac2ffa7
SK
267 data->irq);
268
63063bfb 269 sec_pmic->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
5ac2ffa7
SK
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{
63063bfb 283 struct sec_pmic_dev *sec_pmic = data;
5ac2ffa7
SK
284 u8 irq_reg[NUM_IRQ_REGS-1];
285 int ret;
286 int i;
287
288
63063bfb 289 ret = sec_bulk_read(sec_pmic, S5M8767_REG_INT1,
5ac2ffa7
SK
290 NUM_IRQ_REGS - 1, irq_reg);
291 if (ret < 0) {
63063bfb 292 dev_err(sec_pmic->dev, "Failed to read interrupt register: %d\n",
5ac2ffa7
SK
293 ret);
294 return IRQ_NONE;
295 }
296
297 for (i = 0; i < NUM_IRQ_REGS - 1; i++)
63063bfb 298 irq_reg[i] &= ~sec_pmic->irq_masks_cur[i];
5ac2ffa7
SK
299
300 for (i = 0; i < S5M8767_IRQ_NR; i++) {
301 if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
63063bfb 302 handle_nested_irq(sec_pmic->irq_base + i);
5ac2ffa7
SK
303 }
304
305 return IRQ_HANDLED;
306}
307
308static irqreturn_t s5m8763_irq_thread(int irq, void *data)
309{
63063bfb 310 struct sec_pmic_dev *sec_pmic = data;
5ac2ffa7
SK
311 u8 irq_reg[NUM_IRQ_REGS];
312 int ret;
313 int i;
314
63063bfb 315 ret = sec_bulk_read(sec_pmic, S5M8763_REG_IRQ1,
5ac2ffa7
SK
316 NUM_IRQ_REGS, irq_reg);
317 if (ret < 0) {
63063bfb 318 dev_err(sec_pmic->dev, "Failed to read interrupt register: %d\n",
5ac2ffa7
SK
319 ret);
320 return IRQ_NONE;
321 }
322
323 for (i = 0; i < NUM_IRQ_REGS; i++)
63063bfb 324 irq_reg[i] &= ~sec_pmic->irq_masks_cur[i];
5ac2ffa7
SK
325
326 for (i = 0; i < S5M8763_IRQ_NR; i++) {
327 if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
63063bfb 328 handle_nested_irq(sec_pmic->irq_base + i);
5ac2ffa7
SK
329 }
330
331 return IRQ_HANDLED;
332}
333
63063bfb 334int sec_irq_resume(struct sec_pmic_dev *sec_pmic)
5ac2ffa7 335{
63063bfb
SK
336 if (sec_pmic->irq && sec_pmic->irq_base) {
337 switch (sec_pmic->device_type) {
5ac2ffa7 338 case S5M8763X:
63063bfb 339 s5m8763_irq_thread(sec_pmic->irq_base, sec_pmic);
5ac2ffa7
SK
340 break;
341 case S5M8767X:
63063bfb 342 s5m8767_irq_thread(sec_pmic->irq_base, sec_pmic);
5ac2ffa7
SK
343 break;
344 default:
63063bfb 345 dev_err(sec_pmic->dev,
c7a1fcf3 346 "Unknown device type %d\n",
63063bfb 347 sec_pmic->device_type);
c7a1fcf3 348 return -EINVAL;
5ac2ffa7
SK
349
350 }
351 }
352 return 0;
353}
354
63063bfb 355int sec_irq_init(struct sec_pmic_dev *sec_pmic)
5ac2ffa7
SK
356{
357 int i;
358 int cur_irq;
359 int ret = 0;
63063bfb 360 int type = sec_pmic->device_type;
5ac2ffa7 361
63063bfb
SK
362 if (!sec_pmic->irq) {
363 dev_warn(sec_pmic->dev,
5ac2ffa7 364 "No interrupt specified, no interrupts\n");
63063bfb 365 sec_pmic->irq_base = 0;
5ac2ffa7
SK
366 return 0;
367 }
368
63063bfb
SK
369 if (!sec_pmic->irq_base) {
370 dev_err(sec_pmic->dev,
5ac2ffa7
SK
371 "No interrupt base specified, no interrupts\n");
372 return 0;
373 }
374
63063bfb 375 mutex_init(&sec_pmic->irqlock);
5ac2ffa7
SK
376
377 switch (type) {
378 case S5M8763X:
379 for (i = 0; i < NUM_IRQ_REGS; i++) {
63063bfb
SK
380 sec_pmic->irq_masks_cur[i] = 0xff;
381 sec_pmic->irq_masks_cache[i] = 0xff;
382 sec_reg_write(sec_pmic, S5M8763_REG_IRQM1 + i,
5ac2ffa7
SK
383 0xff);
384 }
385
63063bfb
SK
386 sec_reg_write(sec_pmic, S5M8763_REG_STATUSM1, 0xff);
387 sec_reg_write(sec_pmic, S5M8763_REG_STATUSM2, 0xff);
5ac2ffa7
SK
388
389 for (i = 0; i < S5M8763_IRQ_NR; i++) {
63063bfb
SK
390 cur_irq = i + sec_pmic->irq_base;
391 irq_set_chip_data(cur_irq, sec_pmic);
5ac2ffa7
SK
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
63063bfb 402 ret = request_threaded_irq(sec_pmic->irq, NULL,
5ac2ffa7
SK
403 s5m8763_irq_thread,
404 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
63063bfb 405 "sec-pmic-irq", sec_pmic);
5ac2ffa7 406 if (ret) {
63063bfb
SK
407 dev_err(sec_pmic->dev, "Failed to request IRQ %d: %d\n",
408 sec_pmic->irq, ret);
5ac2ffa7
SK
409 return ret;
410 }
411 break;
412 case S5M8767X:
413 for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
63063bfb
SK
414 sec_pmic->irq_masks_cur[i] = 0xff;
415 sec_pmic->irq_masks_cache[i] = 0xff;
416 sec_reg_write(sec_pmic, S5M8767_REG_INT1M + i,
5ac2ffa7
SK
417 0xff);
418 }
419 for (i = 0; i < S5M8767_IRQ_NR; i++) {
63063bfb
SK
420 cur_irq = i + sec_pmic->irq_base;
421 irq_set_chip_data(cur_irq, sec_pmic);
5ac2ffa7 422 if (ret) {
63063bfb 423 dev_err(sec_pmic->dev,
5ac2ffa7 424 "Failed to irq_set_chip_data %d: %d\n",
63063bfb 425 sec_pmic->irq, ret);
5ac2ffa7
SK
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
63063bfb 439 ret = request_threaded_irq(sec_pmic->irq, NULL,
5ac2ffa7
SK
440 s5m8767_irq_thread,
441 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
63063bfb 442 "sec-pmic-irq", sec_pmic);
5ac2ffa7 443 if (ret) {
63063bfb
SK
444 dev_err(sec_pmic->dev, "Failed to request IRQ %d: %d\n",
445 sec_pmic->irq, ret);
5ac2ffa7
SK
446 return ret;
447 }
448 break;
449 default:
63063bfb
SK
450 dev_err(sec_pmic->dev,
451 "Unknown device type %d\n", sec_pmic->device_type);
c7a1fcf3 452 return -EINVAL;
5ac2ffa7
SK
453 }
454
63063bfb 455 if (!sec_pmic->ono)
5ac2ffa7
SK
456 return 0;
457
458 switch (type) {
459 case S5M8763X:
63063bfb 460 ret = request_threaded_irq(sec_pmic->ono, NULL,
5ac2ffa7
SK
461 s5m8763_irq_thread,
462 IRQF_TRIGGER_FALLING |
463 IRQF_TRIGGER_RISING |
63063bfb
SK
464 IRQF_ONESHOT, "sec_pmic-ono",
465 sec_pmic);
5ac2ffa7
SK
466 break;
467 case S5M8767X:
63063bfb 468 ret = request_threaded_irq(sec_pmic->ono, NULL,
5ac2ffa7
SK
469 s5m8767_irq_thread,
470 IRQF_TRIGGER_FALLING |
471 IRQF_TRIGGER_RISING |
63063bfb 472 IRQF_ONESHOT, "sec_pmic-ono", sec_pmic);
5ac2ffa7
SK
473 break;
474 default:
c7a1fcf3 475 ret = -EINVAL;
5ac2ffa7
SK
476 break;
477 }
478
c7a1fcf3 479 if (ret) {
63063bfb
SK
480 dev_err(sec_pmic->dev, "Failed to request IRQ %d: %d\n",
481 sec_pmic->ono, ret);
c7a1fcf3
JC
482 return ret;
483 }
5ac2ffa7
SK
484
485 return 0;
486}
487
63063bfb 488void sec_irq_exit(struct sec_pmic_dev *sec_pmic)
5ac2ffa7 489{
63063bfb
SK
490 if (sec_pmic->ono)
491 free_irq(sec_pmic->ono, sec_pmic);
5ac2ffa7 492
63063bfb
SK
493 if (sec_pmic->irq)
494 free_irq(sec_pmic->irq, sec_pmic);
5ac2ffa7 495}
This page took 0.075923 seconds and 5 git commands to generate.