aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2013-01-22 05:26:30 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-08 07:15:32 -0500
commit7d94a50585884180a487ce17e8ddbfa37f7694b6 (patch)
treef165ad3bce743f1a902fbe7deaed07fa465403ba /drivers/spi
parent5928808ef623347e0d4aa22327b992e9e125b6ad (diff)
spi/pxa2xx: add support for runtime PM
Drivers should put the device into low power states proactively whenever the device is not in use. Thus implement support for runtime PM and use the autosuspend feature to make sure that we can still perform well in case we see lots of SPI traffic within short period of time. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Lu Cao <lucao@marvell.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-pxa2xx.c73
1 files changed, 67 insertions, 6 deletions
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index c3d78073d1ad..7f8f939835fd 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -30,6 +30,7 @@
30#include <linux/gpio.h> 30#include <linux/gpio.h>
31#include <linux/slab.h> 31#include <linux/slab.h>
32#include <linux/clk.h> 32#include <linux/clk.h>
33#include <linux/pm_runtime.h>
33 34
34#include <asm/io.h> 35#include <asm/io.h>
35#include <asm/irq.h> 36#include <asm/irq.h>
@@ -417,10 +418,20 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
417{ 418{
418 struct driver_data *drv_data = dev_id; 419 struct driver_data *drv_data = dev_id;
419 void __iomem *reg = drv_data->ioaddr; 420 void __iomem *reg = drv_data->ioaddr;
420 u32 sccr1_reg = read_SSCR1(reg); 421 u32 sccr1_reg;
421 u32 mask = drv_data->mask_sr; 422 u32 mask = drv_data->mask_sr;
422 u32 status; 423 u32 status;
423 424
425 /*
426 * The IRQ might be shared with other peripherals so we must first
427 * check that are we RPM suspended or not. If we are we assume that
428 * the IRQ was not for us (we shouldn't be RPM suspended when the
429 * interrupt is enabled).
430 */
431 if (pm_runtime_suspended(&drv_data->pdev->dev))
432 return IRQ_NONE;
433
434 sccr1_reg = read_SSCR1(reg);
424 status = read_SSSR(reg); 435 status = read_SSSR(reg);
425 436
426 /* Ignore possible writes if we don't need to write */ 437 /* Ignore possible writes if we don't need to write */
@@ -678,6 +689,27 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
678 return 0; 689 return 0;
679} 690}
680 691
692static int pxa2xx_spi_prepare_transfer(struct spi_master *master)
693{
694 struct driver_data *drv_data = spi_master_get_devdata(master);
695
696 pm_runtime_get_sync(&drv_data->pdev->dev);
697 return 0;
698}
699
700static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
701{
702 struct driver_data *drv_data = spi_master_get_devdata(master);
703
704 /* Disable the SSP now */
705 write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
706 drv_data->ioaddr);
707
708 pm_runtime_mark_last_busy(&drv_data->pdev->dev);
709 pm_runtime_put_autosuspend(&drv_data->pdev->dev);
710 return 0;
711}
712
681static int setup_cs(struct spi_device *spi, struct chip_data *chip, 713static int setup_cs(struct spi_device *spi, struct chip_data *chip,
682 struct pxa2xx_spi_chip *chip_info) 714 struct pxa2xx_spi_chip *chip_info)
683{ 715{
@@ -915,6 +947,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
915 master->cleanup = cleanup; 947 master->cleanup = cleanup;
916 master->setup = setup; 948 master->setup = setup;
917 master->transfer_one_message = pxa2xx_spi_transfer_one_message; 949 master->transfer_one_message = pxa2xx_spi_transfer_one_message;
950 master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer;
951 master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer;
918 952
919 drv_data->ssp_type = ssp->type; 953 drv_data->ssp_type = ssp->type;
920 drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT); 954 drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT);
@@ -980,6 +1014,11 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
980 goto out_error_clock_enabled; 1014 goto out_error_clock_enabled;
981 } 1015 }
982 1016
1017 pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
1018 pm_runtime_use_autosuspend(&pdev->dev);
1019 pm_runtime_set_active(&pdev->dev);
1020 pm_runtime_enable(&pdev->dev);
1021
983 return status; 1022 return status;
984 1023
985out_error_clock_enabled: 1024out_error_clock_enabled:
@@ -1002,6 +1041,8 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
1002 return 0; 1041 return 0;
1003 ssp = drv_data->ssp; 1042 ssp = drv_data->ssp;
1004 1043
1044 pm_runtime_get_sync(&pdev->dev);
1045
1005 /* Disable the SSP at the peripheral and SOC level */ 1046 /* Disable the SSP at the peripheral and SOC level */
1006 write_SSCR0(0, drv_data->ioaddr); 1047 write_SSCR0(0, drv_data->ioaddr);
1007 clk_disable_unprepare(ssp->clk); 1048 clk_disable_unprepare(ssp->clk);
@@ -1010,6 +1051,9 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
1010 if (drv_data->master_info->enable_dma) 1051 if (drv_data->master_info->enable_dma)
1011 pxa2xx_spi_dma_release(drv_data); 1052 pxa2xx_spi_dma_release(drv_data);
1012 1053
1054 pm_runtime_put_noidle(&pdev->dev);
1055 pm_runtime_disable(&pdev->dev);
1056
1013 /* Release IRQ */ 1057 /* Release IRQ */
1014 free_irq(ssp->irq, drv_data); 1058 free_irq(ssp->irq, drv_data);
1015 1059
@@ -1069,20 +1113,37 @@ static int pxa2xx_spi_resume(struct device *dev)
1069 1113
1070 return 0; 1114 return 0;
1071} 1115}
1116#endif
1117
1118#ifdef CONFIG_PM_RUNTIME
1119static int pxa2xx_spi_runtime_suspend(struct device *dev)
1120{
1121 struct driver_data *drv_data = dev_get_drvdata(dev);
1122
1123 clk_disable_unprepare(drv_data->ssp->clk);
1124 return 0;
1125}
1126
1127static int pxa2xx_spi_runtime_resume(struct device *dev)
1128{
1129 struct driver_data *drv_data = dev_get_drvdata(dev);
1130
1131 clk_prepare_enable(drv_data->ssp->clk);
1132 return 0;
1133}
1134#endif
1072 1135
1073static const struct dev_pm_ops pxa2xx_spi_pm_ops = { 1136static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
1074 .suspend = pxa2xx_spi_suspend, 1137 SET_SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume)
1075 .resume = pxa2xx_spi_resume, 1138 SET_RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend,
1139 pxa2xx_spi_runtime_resume, NULL)
1076}; 1140};
1077#endif
1078 1141
1079static struct platform_driver driver = { 1142static struct platform_driver driver = {
1080 .driver = { 1143 .driver = {
1081 .name = "pxa2xx-spi", 1144 .name = "pxa2xx-spi",
1082 .owner = THIS_MODULE, 1145 .owner = THIS_MODULE,
1083#ifdef CONFIG_PM
1084 .pm = &pxa2xx_spi_pm_ops, 1146 .pm = &pxa2xx_spi_pm_ops,
1085#endif
1086 }, 1147 },
1087 .probe = pxa2xx_spi_probe, 1148 .probe = pxa2xx_spi_probe,
1088 .remove = pxa2xx_spi_remove, 1149 .remove = pxa2xx_spi_remove,