twl6030-irq.c (78518ffa08fceee42d61359303c58bdd0a82033f) twl6030-irq.c (ec1a07b3440cc28946a77a974c21570bbef6ffa1)
1/*
2 * twl6030-irq.c - TWL6030 irq support
3 *
4 * Copyright (C) 2005-2009 Texas Instruments, Inc.
5 *
6 * Modifications to defer interrupt handling to a kernel thread:
7 * Copyright (C) 2006 MontaVista Software, Inc.
8 *

--- 39 unchanged lines hidden (view full) ---

48 * TWL6030 (unlike its predecessors, which had two level interrupt handling)
49 * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C.
50 * It exposes status bits saying who has raised an interrupt. There are
51 * three mask registers that corresponds to these status registers, that
52 * enables/disables these interrupts.
53 *
54 * We set up IRQs starting at a platform-specified base. An interrupt map table,
55 * specifies mapping between interrupt number and the associated module.
1/*
2 * twl6030-irq.c - TWL6030 irq support
3 *
4 * Copyright (C) 2005-2009 Texas Instruments, Inc.
5 *
6 * Modifications to defer interrupt handling to a kernel thread:
7 * Copyright (C) 2006 MontaVista Software, Inc.
8 *

--- 39 unchanged lines hidden (view full) ---

48 * TWL6030 (unlike its predecessors, which had two level interrupt handling)
49 * three interrupt registers INT_STS_A, INT_STS_B and INT_STS_C.
50 * It exposes status bits saying who has raised an interrupt. There are
51 * three mask registers that corresponds to these status registers, that
52 * enables/disables these interrupts.
53 *
54 * We set up IRQs starting at a platform-specified base. An interrupt map table,
55 * specifies mapping between interrupt number and the associated module.
56 *
57 */
58#define TWL6030_NR_IRQS 20
59
60static int twl6030_interrupt_mapping[24] = {
61 PWR_INTR_OFFSET, /* Bit 0 PWRON */
62 PWR_INTR_OFFSET, /* Bit 1 RPWRON */
63 PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */
64 RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */

--- 282 unchanged lines hidden (view full) ---

347 return ret;
348}
349EXPORT_SYMBOL(twl6030_mmc_card_detect);
350
351int twl6030_init_irq(struct device *dev, int irq_num)
352{
353 struct device_node *node = dev->of_node;
354 int nr_irqs, irq_base, irq_end;
56 */
57#define TWL6030_NR_IRQS 20
58
59static int twl6030_interrupt_mapping[24] = {
60 PWR_INTR_OFFSET, /* Bit 0 PWRON */
61 PWR_INTR_OFFSET, /* Bit 1 RPWRON */
62 PWR_INTR_OFFSET, /* Bit 2 BAT_VLOW */
63 RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */

--- 282 unchanged lines hidden (view full) ---

346 return ret;
347}
348EXPORT_SYMBOL(twl6030_mmc_card_detect);
349
350int twl6030_init_irq(struct device *dev, int irq_num)
351{
352 struct device_node *node = dev->of_node;
353 int nr_irqs, irq_base, irq_end;
355
356 int status = 0;
357 int i;
358 struct task_struct *task;
354 struct task_struct *task;
359 int ret;
360 u8 mask[4];
355 static struct irq_chip twl6030_irq_chip;
356 int status = 0;
357 int i;
358 u8 mask[4];
361
359
362 static struct irq_chip twl6030_irq_chip;
363
364 nr_irqs = TWL6030_NR_IRQS;
365
366 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
367 if (IS_ERR_VALUE(irq_base)) {
368 dev_err(dev, "Fail to allocate IRQ descs\n");
369 return irq_base;
370 }
371
372 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
373 &irq_domain_simple_ops, NULL);
374
375 irq_end = irq_base + nr_irqs;
376
377 mask[1] = 0xFF;
378 mask[2] = 0xFF;
379 mask[3] = 0xFF;
360 nr_irqs = TWL6030_NR_IRQS;
361
362 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
363 if (IS_ERR_VALUE(irq_base)) {
364 dev_err(dev, "Fail to allocate IRQ descs\n");
365 return irq_base;
366 }
367
368 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
369 &irq_domain_simple_ops, NULL);
370
371 irq_end = irq_base + nr_irqs;
372
373 mask[1] = 0xFF;
374 mask[2] = 0xFF;
375 mask[3] = 0xFF;
380 ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
381 REG_INT_MSK_LINE_A, 3); /* MASK ALL INT LINES */
382 ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
383 REG_INT_MSK_STS_A, 3); /* MASK ALL INT STS */
384 ret = twl_i2c_write(TWL_MODULE_PIH, &mask[0],
385 REG_INT_STS_A, 3); /* clear INT_STS_A,B,C */
386
376
377 /* mask all int lines */
378 twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
379 /* mask all int sts */
380 twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
381 /* clear INT_STS_A,B,C */
382 twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
383
387 twl6030_irq_base = irq_base;
388
384 twl6030_irq_base = irq_base;
385
389 /* install an irq handler for each of the modules;
386 /*
387 * install an irq handler for each of the modules;
390 * clone dummy irq_chip since PIH can't *do* anything
391 */
392 twl6030_irq_chip = dummy_irq_chip;
393 twl6030_irq_chip.name = "twl6030";
394 twl6030_irq_chip.irq_set_type = NULL;
395 twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
396
397 for (i = irq_base; i < irq_end; i++) {
398 irq_set_chip_and_handler(i, &twl6030_irq_chip,
399 handle_simple_irq);
400 irq_set_chip_data(i, (void *)irq_num);
401 activate_irq(i);
402 }
403
388 * clone dummy irq_chip since PIH can't *do* anything
389 */
390 twl6030_irq_chip = dummy_irq_chip;
391 twl6030_irq_chip.name = "twl6030";
392 twl6030_irq_chip.irq_set_type = NULL;
393 twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
394
395 for (i = irq_base; i < irq_end; i++) {
396 irq_set_chip_and_handler(i, &twl6030_irq_chip,
397 handle_simple_irq);
398 irq_set_chip_data(i, (void *)irq_num);
399 activate_irq(i);
400 }
401
404 pr_info("twl6030: %s (irq %d) chaining IRQs %d..%d\n", "PIH",
402 dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
405 irq_num, irq_base, irq_end);
406
407 /* install an irq handler to demultiplex the TWL6030 interrupt */
408 init_completion(&irq_event);
409
403 irq_num, irq_base, irq_end);
404
405 /* install an irq handler to demultiplex the TWL6030 interrupt */
406 init_completion(&irq_event);
407
410 status = request_irq(irq_num, handle_twl6030_pih, 0,
411 "TWL6030-PIH", &irq_event);
408 status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
409 &irq_event);
412 if (status < 0) {
410 if (status < 0) {
413 pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
411 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
414 goto fail_irq;
415 }
416
417 task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
418 if (IS_ERR(task)) {
412 goto fail_irq;
413 }
414
415 task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
416 if (IS_ERR(task)) {
419 pr_err("twl6030: could not create irq %d thread!\n", irq_num);
417 dev_err(dev, "could not create irq %d thread!\n", irq_num);
420 status = PTR_ERR(task);
421 goto fail_kthread;
422 }
423
424 twl_irq = irq_num;
425 register_pm_notifier(&twl6030_irq_pm_notifier_block);
426 return irq_base;
427
428fail_kthread:
429 free_irq(irq_num, &irq_event);
430
431fail_irq:
432 for (i = irq_base; i < irq_end; i++)
433 irq_set_chip_and_handler(i, NULL, NULL);
418 status = PTR_ERR(task);
419 goto fail_kthread;
420 }
421
422 twl_irq = irq_num;
423 register_pm_notifier(&twl6030_irq_pm_notifier_block);
424 return irq_base;
425
426fail_kthread:
427 free_irq(irq_num, &irq_event);
428
429fail_irq:
430 for (i = irq_base; i < irq_end; i++)
431 irq_set_chip_and_handler(i, NULL, NULL);
432
434 return status;
435}
436
437int twl6030_exit_irq(void)
438{
439 unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
440
441 if (twl6030_irq_base) {
442 pr_err("twl6030: can't yet clean up IRQs?\n");
443 return -ENOSYS;
444 }
445 return 0;
446}
447
433 return status;
434}
435
436int twl6030_exit_irq(void)
437{
438 unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
439
440 if (twl6030_irq_base) {
441 pr_err("twl6030: can't yet clean up IRQs?\n");
442 return -ENOSYS;
443 }
444 return 0;
445}
446