diff options
Diffstat (limited to 'drivers/sh/intc/core.c')
-rw-r--r-- | drivers/sh/intc/core.c | 95 |
1 files changed, 47 insertions, 48 deletions
diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 9739431092d1..5833afbf08d7 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/sh_intc.h> | 26 | #include <linux/sh_intc.h> |
27 | #include <linux/sysdev.h> | 27 | #include <linux/sysdev.h> |
28 | #include <linux/syscore_ops.h> | ||
28 | #include <linux/list.h> | 29 | #include <linux/list.h> |
29 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
30 | #include <linux/radix-tree.h> | 31 | #include <linux/radix-tree.h> |
@@ -376,91 +377,89 @@ err0: | |||
376 | return -ENOMEM; | 377 | return -ENOMEM; |
377 | } | 378 | } |
378 | 379 | ||
379 | static ssize_t | 380 | static int intc_suspend(void) |
380 | show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) | ||
381 | { | 381 | { |
382 | struct intc_desc_int *d; | 382 | struct intc_desc_int *d; |
383 | 383 | ||
384 | d = container_of(dev, struct intc_desc_int, sysdev); | 384 | list_for_each_entry(d, &intc_list, list) { |
385 | int irq; | ||
385 | 386 | ||
386 | return sprintf(buf, "%s\n", d->chip.name); | 387 | /* enable wakeup irqs belonging to this intc controller */ |
387 | } | 388 | for_each_active_irq(irq) { |
389 | struct irq_data *data; | ||
390 | struct irq_desc *desc; | ||
391 | struct irq_chip *chip; | ||
388 | 392 | ||
389 | static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL); | 393 | data = irq_get_irq_data(irq); |
394 | chip = irq_data_get_irq_chip(data); | ||
395 | if (chip != &d->chip) | ||
396 | continue; | ||
397 | desc = irq_to_desc(irq); | ||
398 | if ((desc->status & IRQ_WAKEUP)) | ||
399 | chip->irq_enable(data); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | return 0; | ||
404 | } | ||
390 | 405 | ||
391 | static int intc_suspend(struct sys_device *dev, pm_message_t state) | 406 | static void intc_resume(void) |
392 | { | 407 | { |
393 | struct intc_desc_int *d; | 408 | struct intc_desc_int *d; |
394 | struct irq_data *data; | ||
395 | struct irq_desc *desc; | ||
396 | struct irq_chip *chip; | ||
397 | int irq; | ||
398 | |||
399 | /* get intc controller associated with this sysdev */ | ||
400 | d = container_of(dev, struct intc_desc_int, sysdev); | ||
401 | 409 | ||
402 | switch (state.event) { | 410 | list_for_each_entry(d, &intc_list, list) { |
403 | case PM_EVENT_ON: | 411 | int irq; |
404 | if (d->state.event != PM_EVENT_FREEZE) | ||
405 | break; | ||
406 | 412 | ||
407 | for_each_active_irq(irq) { | 413 | for_each_active_irq(irq) { |
408 | desc = irq_to_desc(irq); | 414 | struct irq_data *data; |
415 | struct irq_desc *desc; | ||
416 | struct irq_chip *chip; | ||
417 | |||
409 | data = irq_get_irq_data(irq); | 418 | data = irq_get_irq_data(irq); |
410 | chip = irq_data_get_irq_chip(data); | 419 | chip = irq_data_get_irq_chip(data); |
411 | |||
412 | /* | 420 | /* |
413 | * This will catch the redirect and VIRQ cases | 421 | * This will catch the redirect and VIRQ cases |
414 | * due to the dummy_irq_chip being inserted. | 422 | * due to the dummy_irq_chip being inserted. |
415 | */ | 423 | */ |
416 | if (chip != &d->chip) | 424 | if (chip != &d->chip) |
417 | continue; | 425 | continue; |
426 | desc = irq_to_desc(irq); | ||
418 | if (desc->status & IRQ_DISABLED) | 427 | if (desc->status & IRQ_DISABLED) |
419 | chip->irq_disable(data); | 428 | chip->irq_disable(data); |
420 | else | 429 | else |
421 | chip->irq_enable(data); | 430 | chip->irq_enable(data); |
422 | } | 431 | } |
423 | break; | ||
424 | case PM_EVENT_FREEZE: | ||
425 | /* nothing has to be done */ | ||
426 | break; | ||
427 | case PM_EVENT_SUSPEND: | ||
428 | /* enable wakeup irqs belonging to this intc controller */ | ||
429 | for_each_active_irq(irq) { | ||
430 | desc = irq_to_desc(irq); | ||
431 | data = irq_get_irq_data(irq); | ||
432 | chip = irq_data_get_irq_chip(data); | ||
433 | |||
434 | if (chip != &d->chip) | ||
435 | continue; | ||
436 | if ((desc->status & IRQ_WAKEUP)) | ||
437 | chip->irq_enable(data); | ||
438 | } | ||
439 | break; | ||
440 | } | 432 | } |
441 | |||
442 | d->state = state; | ||
443 | |||
444 | return 0; | ||
445 | } | 433 | } |
446 | 434 | ||
447 | static int intc_resume(struct sys_device *dev) | 435 | struct syscore_ops intc_syscore_ops = { |
448 | { | 436 | .suspend = intc_suspend, |
449 | return intc_suspend(dev, PMSG_ON); | 437 | .resume = intc_resume, |
450 | } | 438 | }; |
451 | 439 | ||
452 | struct sysdev_class intc_sysdev_class = { | 440 | struct sysdev_class intc_sysdev_class = { |
453 | .name = "intc", | 441 | .name = "intc", |
454 | .suspend = intc_suspend, | ||
455 | .resume = intc_resume, | ||
456 | }; | 442 | }; |
457 | 443 | ||
458 | /* register this intc as sysdev to allow suspend/resume */ | 444 | static ssize_t |
445 | show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) | ||
446 | { | ||
447 | struct intc_desc_int *d; | ||
448 | |||
449 | d = container_of(dev, struct intc_desc_int, sysdev); | ||
450 | |||
451 | return sprintf(buf, "%s\n", d->chip.name); | ||
452 | } | ||
453 | |||
454 | static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL); | ||
455 | |||
459 | static int __init register_intc_sysdevs(void) | 456 | static int __init register_intc_sysdevs(void) |
460 | { | 457 | { |
461 | struct intc_desc_int *d; | 458 | struct intc_desc_int *d; |
462 | int error; | 459 | int error; |
463 | 460 | ||
461 | register_syscore_ops(&intc_syscore_ops); | ||
462 | |||
464 | error = sysdev_class_register(&intc_sysdev_class); | 463 | error = sysdev_class_register(&intc_sysdev_class); |
465 | if (!error) { | 464 | if (!error) { |
466 | list_for_each_entry(d, &intc_list, list) { | 465 | list_for_each_entry(d, &intc_list, list) { |