diff options
author | Heiner Kallweit <hkallweit1@gmail.com> | 2015-08-26 15:21:55 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-08-28 13:15:18 -0400 |
commit | e9abb4db8d108624c293f06dce06b2978e626a13 (patch) | |
tree | 04132b9da13d86f0df51dbb415cc0683d44850aa | |
parent | 3c5395b66ff69d8d568d0b9ff8b1077e044def5b (diff) |
spi: fsl-espi: add runtime PM
Add runtime PM and use autosuspend instead of suspending the
SPI controller after each transfer.
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 71 |
1 files changed, 54 insertions, 17 deletions
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index fe54e5788245..db82c872c0f9 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/of_platform.h> | 21 | #include <linux/of_platform.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/spi/spi.h> | 23 | #include <linux/spi/spi.h> |
24 | #include <linux/pm_runtime.h> | ||
24 | #include <sysdev/fsl_soc.h> | 25 | #include <sysdev/fsl_soc.h> |
25 | 26 | ||
26 | #include "spi-fsl-lib.h" | 27 | #include "spi-fsl-lib.h" |
@@ -85,6 +86,8 @@ struct fsl_espi_transfer { | |||
85 | #define SPCOM_TRANLEN(x) ((x) << 0) | 86 | #define SPCOM_TRANLEN(x) ((x) << 0) |
86 | #define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ | 87 | #define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ |
87 | 88 | ||
89 | #define AUTOSUSPEND_TIMEOUT 2000 | ||
90 | |||
88 | static void fsl_espi_change_mode(struct spi_device *spi) | 91 | static void fsl_espi_change_mode(struct spi_device *spi) |
89 | { | 92 | { |
90 | struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); | 93 | struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); |
@@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi) | |||
485 | mpc8xxx_spi = spi_master_get_devdata(spi->master); | 488 | mpc8xxx_spi = spi_master_get_devdata(spi->master); |
486 | reg_base = mpc8xxx_spi->reg_base; | 489 | reg_base = mpc8xxx_spi->reg_base; |
487 | 490 | ||
491 | pm_runtime_get_sync(mpc8xxx_spi->dev); | ||
492 | |||
488 | hw_mode = cs->hw_mode; /* Save original settings */ | 493 | hw_mode = cs->hw_mode; /* Save original settings */ |
489 | cs->hw_mode = mpc8xxx_spi_read_reg( | 494 | cs->hw_mode = mpc8xxx_spi_read_reg( |
490 | ®_base->csmode[spi->chip_select]); | 495 | ®_base->csmode[spi->chip_select]); |
@@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi) | |||
507 | mpc8xxx_spi_write_reg(®_base->mode, loop_mode); | 512 | mpc8xxx_spi_write_reg(®_base->mode, loop_mode); |
508 | 513 | ||
509 | retval = fsl_espi_setup_transfer(spi, NULL); | 514 | retval = fsl_espi_setup_transfer(spi, NULL); |
515 | |||
516 | pm_runtime_mark_last_busy(mpc8xxx_spi->dev); | ||
517 | pm_runtime_put_autosuspend(mpc8xxx_spi->dev); | ||
518 | |||
510 | if (retval < 0) { | 519 | if (retval < 0) { |
511 | cs->hw_mode = hw_mode; /* Restore settings */ | 520 | cs->hw_mode = hw_mode; /* Restore settings */ |
512 | return retval; | 521 | return retval; |
@@ -604,15 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) | |||
604 | return ret; | 613 | return ret; |
605 | } | 614 | } |
606 | 615 | ||
607 | static int fsl_espi_suspend(struct spi_master *master) | 616 | #ifdef CONFIG_PM |
617 | static int fsl_espi_runtime_suspend(struct device *dev) | ||
608 | { | 618 | { |
609 | struct mpc8xxx_spi *mpc8xxx_spi; | 619 | struct spi_master *master = dev_get_drvdata(dev); |
610 | struct fsl_espi_reg *reg_base; | 620 | struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); |
621 | struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; | ||
611 | u32 regval; | 622 | u32 regval; |
612 | 623 | ||
613 | mpc8xxx_spi = spi_master_get_devdata(master); | ||
614 | reg_base = mpc8xxx_spi->reg_base; | ||
615 | |||
616 | regval = mpc8xxx_spi_read_reg(®_base->mode); | 624 | regval = mpc8xxx_spi_read_reg(®_base->mode); |
617 | regval &= ~SPMODE_ENABLE; | 625 | regval &= ~SPMODE_ENABLE; |
618 | mpc8xxx_spi_write_reg(®_base->mode, regval); | 626 | mpc8xxx_spi_write_reg(®_base->mode, regval); |
@@ -620,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master) | |||
620 | return 0; | 628 | return 0; |
621 | } | 629 | } |
622 | 630 | ||
623 | static int fsl_espi_resume(struct spi_master *master) | 631 | static int fsl_espi_runtime_resume(struct device *dev) |
624 | { | 632 | { |
625 | struct mpc8xxx_spi *mpc8xxx_spi; | 633 | struct spi_master *master = dev_get_drvdata(dev); |
626 | struct fsl_espi_reg *reg_base; | 634 | struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); |
635 | struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; | ||
627 | u32 regval; | 636 | u32 regval; |
628 | 637 | ||
629 | mpc8xxx_spi = spi_master_get_devdata(master); | ||
630 | reg_base = mpc8xxx_spi->reg_base; | ||
631 | |||
632 | regval = mpc8xxx_spi_read_reg(®_base->mode); | 638 | regval = mpc8xxx_spi_read_reg(®_base->mode); |
633 | regval |= SPMODE_ENABLE; | 639 | regval |= SPMODE_ENABLE; |
634 | mpc8xxx_spi_write_reg(®_base->mode, regval); | 640 | mpc8xxx_spi_write_reg(®_base->mode, regval); |
635 | 641 | ||
636 | return 0; | 642 | return 0; |
637 | } | 643 | } |
644 | #endif | ||
638 | 645 | ||
639 | static struct spi_master * fsl_espi_probe(struct device *dev, | 646 | static struct spi_master * fsl_espi_probe(struct device *dev, |
640 | struct resource *mem, unsigned int irq) | 647 | struct resource *mem, unsigned int irq) |
@@ -662,8 +669,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev, | |||
662 | master->setup = fsl_espi_setup; | 669 | master->setup = fsl_espi_setup; |
663 | master->cleanup = fsl_espi_cleanup; | 670 | master->cleanup = fsl_espi_cleanup; |
664 | master->transfer_one_message = fsl_espi_do_one_msg; | 671 | master->transfer_one_message = fsl_espi_do_one_msg; |
665 | master->prepare_transfer_hardware = fsl_espi_resume; | 672 | master->auto_runtime_pm = true; |
666 | master->unprepare_transfer_hardware = fsl_espi_suspend; | ||
667 | 673 | ||
668 | mpc8xxx_spi = spi_master_get_devdata(master); | 674 | mpc8xxx_spi = spi_master_get_devdata(master); |
669 | 675 | ||
@@ -725,14 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev, | |||
725 | 731 | ||
726 | mpc8xxx_spi_write_reg(®_base->mode, regval); | 732 | mpc8xxx_spi_write_reg(®_base->mode, regval); |
727 | 733 | ||
734 | pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT); | ||
735 | pm_runtime_use_autosuspend(dev); | ||
736 | pm_runtime_set_active(dev); | ||
737 | pm_runtime_enable(dev); | ||
738 | pm_runtime_get_sync(dev); | ||
739 | |||
728 | ret = devm_spi_register_master(dev, master); | 740 | ret = devm_spi_register_master(dev, master); |
729 | if (ret < 0) | 741 | if (ret < 0) |
730 | goto err_probe; | 742 | goto err_pm; |
731 | 743 | ||
732 | dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); | 744 | dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); |
733 | 745 | ||
746 | pm_runtime_mark_last_busy(dev); | ||
747 | pm_runtime_put_autosuspend(dev); | ||
748 | |||
734 | return master; | 749 | return master; |
735 | 750 | ||
751 | err_pm: | ||
752 | pm_runtime_put_noidle(dev); | ||
753 | pm_runtime_disable(dev); | ||
754 | pm_runtime_set_suspended(dev); | ||
736 | err_probe: | 755 | err_probe: |
737 | spi_master_put(master); | 756 | spi_master_put(master); |
738 | err: | 757 | err: |
@@ -797,6 +816,13 @@ err: | |||
797 | return ret; | 816 | return ret; |
798 | } | 817 | } |
799 | 818 | ||
819 | static int of_fsl_espi_remove(struct platform_device *dev) | ||
820 | { | ||
821 | pm_runtime_disable(&dev->dev); | ||
822 | |||
823 | return 0; | ||
824 | } | ||
825 | |||
800 | #ifdef CONFIG_PM_SLEEP | 826 | #ifdef CONFIG_PM_SLEEP |
801 | static int of_fsl_espi_suspend(struct device *dev) | 827 | static int of_fsl_espi_suspend(struct device *dev) |
802 | { | 828 | { |
@@ -809,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev) | |||
809 | return ret; | 835 | return ret; |
810 | } | 836 | } |
811 | 837 | ||
812 | return fsl_espi_suspend(master); | 838 | ret = pm_runtime_force_suspend(dev); |
839 | if (ret < 0) | ||
840 | return ret; | ||
841 | |||
842 | return 0; | ||
813 | } | 843 | } |
814 | 844 | ||
815 | static int of_fsl_espi_resume(struct device *dev) | 845 | static int of_fsl_espi_resume(struct device *dev) |
@@ -819,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev) | |||
819 | struct mpc8xxx_spi *mpc8xxx_spi; | 849 | struct mpc8xxx_spi *mpc8xxx_spi; |
820 | struct fsl_espi_reg *reg_base; | 850 | struct fsl_espi_reg *reg_base; |
821 | u32 regval; | 851 | u32 regval; |
822 | int i; | 852 | int i, ret; |
823 | 853 | ||
824 | mpc8xxx_spi = spi_master_get_devdata(master); | 854 | mpc8xxx_spi = spi_master_get_devdata(master); |
825 | reg_base = mpc8xxx_spi->reg_base; | 855 | reg_base = mpc8xxx_spi->reg_base; |
@@ -839,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev) | |||
839 | 869 | ||
840 | mpc8xxx_spi_write_reg(®_base->mode, regval); | 870 | mpc8xxx_spi_write_reg(®_base->mode, regval); |
841 | 871 | ||
872 | ret = pm_runtime_force_resume(dev); | ||
873 | if (ret < 0) | ||
874 | return ret; | ||
875 | |||
842 | return spi_master_resume(master); | 876 | return spi_master_resume(master); |
843 | } | 877 | } |
844 | #endif /* CONFIG_PM_SLEEP */ | 878 | #endif /* CONFIG_PM_SLEEP */ |
845 | 879 | ||
846 | static const struct dev_pm_ops espi_pm = { | 880 | static const struct dev_pm_ops espi_pm = { |
881 | SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend, | ||
882 | fsl_espi_runtime_resume, NULL) | ||
847 | SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) | 883 | SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) |
848 | }; | 884 | }; |
849 | 885 | ||
@@ -860,6 +896,7 @@ static struct platform_driver fsl_espi_driver = { | |||
860 | .pm = &espi_pm, | 896 | .pm = &espi_pm, |
861 | }, | 897 | }, |
862 | .probe = of_fsl_espi_probe, | 898 | .probe = of_fsl_espi_probe, |
899 | .remove = of_fsl_espi_remove, | ||
863 | }; | 900 | }; |
864 | module_platform_driver(fsl_espi_driver); | 901 | module_platform_driver(fsl_espi_driver); |
865 | 902 | ||