diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-pxa2xx.c | 73 |
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 | ||
692 | static 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 | |||
700 | static 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 | |||
681 | static int setup_cs(struct spi_device *spi, struct chip_data *chip, | 713 | static 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 | ||
985 | out_error_clock_enabled: | 1024 | out_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 | ||
1119 | static 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 | |||
1127 | static 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 | ||
1073 | static const struct dev_pm_ops pxa2xx_spi_pm_ops = { | 1136 | static 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 | ||
1079 | static struct platform_driver driver = { | 1142 | static 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, |