Skip to content

Commit 7d94a50

Browse files
westeribroonie
authored andcommitted
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 <[email protected]> Tested-by: Lu Cao <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 5928808 commit 7d94a50

File tree

1 file changed

+67
-6
lines changed

1 file changed

+67
-6
lines changed

drivers/spi/spi-pxa2xx.c

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/gpio.h>
3131
#include <linux/slab.h>
3232
#include <linux/clk.h>
33+
#include <linux/pm_runtime.h>
3334

3435
#include <asm/io.h>
3536
#include <asm/irq.h>
@@ -417,10 +418,20 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
417418
{
418419
struct driver_data *drv_data = dev_id;
419420
void __iomem *reg = drv_data->ioaddr;
420-
u32 sccr1_reg = read_SSCR1(reg);
421+
u32 sccr1_reg;
421422
u32 mask = drv_data->mask_sr;
422423
u32 status;
423424

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);
424435
status = read_SSSR(reg);
425436

426437
/* 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,
678689
return 0;
679690
}
680691

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+
681713
static int setup_cs(struct spi_device *spi, struct chip_data *chip,
682714
struct pxa2xx_spi_chip *chip_info)
683715
{
@@ -915,6 +947,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
915947
master->cleanup = cleanup;
916948
master->setup = setup;
917949
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;
918952

919953
drv_data->ssp_type = ssp->type;
920954
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)
9801014
goto out_error_clock_enabled;
9811015
}
9821016

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+
9831022
return status;
9841023

9851024
out_error_clock_enabled:
@@ -1002,6 +1041,8 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
10021041
return 0;
10031042
ssp = drv_data->ssp;
10041043

1044+
pm_runtime_get_sync(&pdev->dev);
1045+
10051046
/* Disable the SSP at the peripheral and SOC level */
10061047
write_SSCR0(0, drv_data->ioaddr);
10071048
clk_disable_unprepare(ssp->clk);
@@ -1010,6 +1051,9 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
10101051
if (drv_data->master_info->enable_dma)
10111052
pxa2xx_spi_dma_release(drv_data);
10121053

1054+
pm_runtime_put_noidle(&pdev->dev);
1055+
pm_runtime_disable(&pdev->dev);
1056+
10131057
/* Release IRQ */
10141058
free_irq(ssp->irq, drv_data);
10151059

@@ -1069,20 +1113,37 @@ static int pxa2xx_spi_resume(struct device *dev)
10691113

10701114
return 0;
10711115
}
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
10721135

10731136
static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
1074-
.suspend = pxa2xx_spi_suspend,
1075-
.resume = pxa2xx_spi_resume,
1137+
SET_SYSTEM_SLEEP_PM_OPS(pxa2xx_spi_suspend, pxa2xx_spi_resume)
1138+
SET_RUNTIME_PM_OPS(pxa2xx_spi_runtime_suspend,
1139+
pxa2xx_spi_runtime_resume, NULL)
10761140
};
1077-
#endif
10781141

10791142
static struct platform_driver driver = {
10801143
.driver = {
10811144
.name = "pxa2xx-spi",
10821145
.owner = THIS_MODULE,
1083-
#ifdef CONFIG_PM
10841146
.pm = &pxa2xx_spi_pm_ops,
1085-
#endif
10861147
},
10871148
.probe = pxa2xx_spi_probe,
10881149
.remove = pxa2xx_spi_remove,

0 commit comments

Comments
 (0)