aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-03-22 16:19:28 -0400
committerPaul Mundt <lethal@linux-sh.org>2011-03-23 05:57:37 -0400
commita696b89c582e3201ef10bfb0d0b3594e29b75e0f (patch)
treef9dbbc6e14d4576c65298e365ad63f24626fdbcd /drivers
parentf47adbb988aa4436135799fd26710bff2c1b1eb6 (diff)
sh: Use struct syscore_ops instead of sysdevs
Convert the SuperH clocks framework and shared interrupt handling code to using struct syscore_ops instead of a sysdev classes and sysdevs for power managment. This reduces the code size significantly and simplifies it. The optimizations causing things not to be restored after creating a hibernation image are removed, but they might lead to undesirable effects during resume from hibernation (e.g. the clocks would be left as the boot kernel set them, which might be not the same way as the hibernated kernel had seen them before the hibernation). This also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/sh/clk/core.c68
-rw-r--r--drivers/sh/intc/core.c95
-rw-r--r--drivers/sh/intc/internals.h1
3 files changed, 65 insertions, 99 deletions
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index 5f63c3b83828..4f64183b27fa 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -21,7 +21,7 @@
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/list.h> 23#include <linux/list.h>
24#include <linux/sysdev.h> 24#include <linux/syscore_ops.h>
25#include <linux/seq_file.h> 25#include <linux/seq_file.h>
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/io.h> 27#include <linux/io.h>
@@ -630,68 +630,36 @@ long clk_round_parent(struct clk *clk, unsigned long target,
630EXPORT_SYMBOL_GPL(clk_round_parent); 630EXPORT_SYMBOL_GPL(clk_round_parent);
631 631
632#ifdef CONFIG_PM 632#ifdef CONFIG_PM
633static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) 633static void clks_core_resume(void)
634{ 634{
635 static pm_message_t prev_state;
636 struct clk *clkp; 635 struct clk *clkp;
637 636
638 switch (state.event) { 637 list_for_each_entry(clkp, &clock_list, node) {
639 case PM_EVENT_ON: 638 if (likely(clkp->ops)) {
640 /* Resumeing from hibernation */ 639 unsigned long rate = clkp->rate;
641 if (prev_state.event != PM_EVENT_FREEZE) 640
642 break; 641 if (likely(clkp->ops->set_parent))
643 642 clkp->ops->set_parent(clkp,
644 list_for_each_entry(clkp, &clock_list, node) { 643 clkp->parent);
645 if (likely(clkp->ops)) { 644 if (likely(clkp->ops->set_rate))
646 unsigned long rate = clkp->rate; 645 clkp->ops->set_rate(clkp, rate);
647 646 else if (likely(clkp->ops->recalc))
648 if (likely(clkp->ops->set_parent)) 647 clkp->rate = clkp->ops->recalc(clkp);
649 clkp->ops->set_parent(clkp,
650 clkp->parent);
651 if (likely(clkp->ops->set_rate))
652 clkp->ops->set_rate(clkp, rate);
653 else if (likely(clkp->ops->recalc))
654 clkp->rate = clkp->ops->recalc(clkp);
655 }
656 } 648 }
657 break;
658 case PM_EVENT_FREEZE:
659 break;
660 case PM_EVENT_SUSPEND:
661 break;
662 } 649 }
663
664 prev_state = state;
665 return 0;
666}
667
668static int clks_sysdev_resume(struct sys_device *dev)
669{
670 return clks_sysdev_suspend(dev, PMSG_ON);
671} 650}
672 651
673static struct sysdev_class clks_sysdev_class = { 652static struct syscore_ops clks_syscore_ops = {
674 .name = "clks", 653 .resume = clks_core_resume,
675};
676
677static struct sysdev_driver clks_sysdev_driver = {
678 .suspend = clks_sysdev_suspend,
679 .resume = clks_sysdev_resume,
680};
681
682static struct sys_device clks_sysdev_dev = {
683 .cls = &clks_sysdev_class,
684}; 654};
685 655
686static int __init clk_sysdev_init(void) 656static int __init clk_syscore_init(void)
687{ 657{
688 sysdev_class_register(&clks_sysdev_class); 658 register_syscore_ops(&clks_syscore_ops);
689 sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
690 sysdev_register(&clks_sysdev_dev);
691 659
692 return 0; 660 return 0;
693} 661}
694subsys_initcall(clk_sysdev_init); 662subsys_initcall(clk_syscore_init);
695#endif 663#endif
696 664
697/* 665/*
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
379static ssize_t 380static int intc_suspend(void)
380show_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
389static 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
391static int intc_suspend(struct sys_device *dev, pm_message_t state) 406static 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
447static int intc_resume(struct sys_device *dev) 435struct 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
452struct sysdev_class intc_sysdev_class = { 440struct 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 */ 444static ssize_t
445show_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
454static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL);
455
459static int __init register_intc_sysdevs(void) 456static 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) {
diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
index 0cf8260971d4..df36a421e675 100644
--- a/drivers/sh/intc/internals.h
+++ b/drivers/sh/intc/internals.h
@@ -53,7 +53,6 @@ struct intc_desc_int {
53 struct list_head list; 53 struct list_head list;
54 struct sys_device sysdev; 54 struct sys_device sysdev;
55 struct radix_tree_root tree; 55 struct radix_tree_root tree;
56 pm_message_t state;
57 raw_spinlock_t lock; 56 raw_spinlock_t lock;
58 unsigned int index; 57 unsigned int index;
59 unsigned long *reg; 58 unsigned long *reg;