aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/ab8500-core.c108
1 files changed, 105 insertions, 3 deletions
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 08850f0d1523..6a59919fc331 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -91,6 +91,15 @@
91#define AB8500_IT_MASK23_REG 0x56 91#define AB8500_IT_MASK23_REG 0x56
92#define AB8500_IT_MASK24_REG 0x57 92#define AB8500_IT_MASK24_REG 0x57
93 93
94/*
95 * latch hierarchy registers
96 */
97#define AB8500_IT_LATCHHIER1_REG 0x60
98#define AB8500_IT_LATCHHIER2_REG 0x61
99#define AB8500_IT_LATCHHIER3_REG 0x62
100
101#define AB8500_IT_LATCHHIER_NUM 3
102
94#define AB8500_REV_REG 0x80 103#define AB8500_REV_REG 0x80
95#define AB8500_IC_NAME_REG 0x82 104#define AB8500_IC_NAME_REG 0x82
96#define AB8500_SWITCH_OFF_STATUS 0x00 105#define AB8500_SWITCH_OFF_STATUS 0x00
@@ -340,6 +349,90 @@ static struct irq_chip ab8500_irq_chip = {
340 .irq_unmask = ab8500_irq_unmask, 349 .irq_unmask = ab8500_irq_unmask,
341}; 350};
342 351
352static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
353 int latch_offset, u8 latch_val)
354{
355 int int_bit = __ffs(latch_val);
356 int line, i;
357
358 do {
359 int_bit = __ffs(latch_val);
360
361 for (i = 0; i < ab8500->mask_size; i++)
362 if (ab8500->irq_reg_offset[i] == latch_offset)
363 break;
364
365 if (i >= ab8500->mask_size) {
366 dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
367 latch_offset);
368 return -ENXIO;
369 }
370
371 line = (i << 3) + int_bit;
372 latch_val &= ~(1 << int_bit);
373
374 handle_nested_irq(ab8500->irq_base + line);
375 } while (latch_val);
376
377 return 0;
378}
379
380static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
381 int hier_offset, u8 hier_val)
382{
383 int latch_bit, status;
384 u8 latch_offset, latch_val;
385
386 do {
387 latch_bit = __ffs(hier_val);
388 latch_offset = (hier_offset << 3) + latch_bit;
389
390 /* Fix inconsistent ITFromLatch25 bit mapping... */
391 if (unlikely(latch_offset == 17))
392 latch_offset = 24;
393
394 status = get_register_interruptible(ab8500,
395 AB8500_INTERRUPT,
396 AB8500_IT_LATCH1_REG + latch_offset,
397 &latch_val);
398 if (status < 0 || latch_val == 0)
399 goto discard;
400
401 status = ab8500_handle_hierarchical_line(ab8500,
402 latch_offset, latch_val);
403 if (status < 0)
404 return status;
405discard:
406 hier_val &= ~(1 << latch_bit);
407 } while (hier_val);
408
409 return 0;
410}
411
412static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
413{
414 struct ab8500 *ab8500 = dev;
415 u8 i;
416
417 dev_vdbg(ab8500->dev, "interrupt\n");
418
419 /* Hierarchical interrupt version */
420 for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
421 int status;
422 u8 hier_val;
423
424 status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
425 AB8500_IT_LATCHHIER1_REG + i, &hier_val);
426 if (status < 0 || hier_val == 0)
427 continue;
428
429 status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
430 if (status < 0)
431 break;
432 }
433 return IRQ_HANDLED;
434}
435
343static irqreturn_t ab8500_irq(int irq, void *dev) 436static irqreturn_t ab8500_irq(int irq, void *dev)
344{ 437{
345 struct ab8500 *ab8500 = dev; 438 struct ab8500 *ab8500 = dev;
@@ -1179,9 +1272,18 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
1179 if (ret) 1272 if (ret)
1180 goto out_freeoldmask; 1273 goto out_freeoldmask;
1181 1274
1182 ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq, 1275 /* Activate this feature only in ab9540 */
1183 IRQF_ONESHOT | IRQF_NO_SUSPEND, 1276 /* till tests are done on ab8500 1p2 or later*/
1184 "ab8500", ab8500); 1277 if (is_ab9540(ab8500))
1278 ret = request_threaded_irq(ab8500->irq, NULL,
1279 ab8500_hierarchical_irq,
1280 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1281 "ab8500", ab8500);
1282 else
1283 ret = request_threaded_irq(ab8500->irq, NULL,
1284 ab8500_irq,
1285 IRQF_ONESHOT | IRQF_NO_SUSPEND,
1286 "ab8500", ab8500);
1185 if (ret) 1287 if (ret)
1186 goto out_removeirq; 1288 goto out_removeirq;
1187 } 1289 }