diff options
Diffstat (limited to 'drivers/spi/spi-fsl-espi.c')
-rw-r--r-- | drivers/spi/spi-fsl-espi.c | 89 |
1 files changed, 55 insertions, 34 deletions
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index d3f05a052..c27124a5e 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -21,6 +21,7 @@ #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/pm_runtime.h> #include <sysdev/fsl_soc.h> #include "spi-fsl-lib.h" @@ -85,6 +86,8 @@ struct fsl_espi_transfer { #define SPCOM_TRANLEN(x) ((x) << 0) #define SPCOM_TRANLEN_MAX 0xFFFF /* Max transaction length */ +#define AUTOSUSPEND_TIMEOUT 2000 + static void fsl_espi_change_mode(struct spi_device *spi) { struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master); @@ -485,6 +488,8 @@ static int fsl_espi_setup(struct spi_device *spi) mpc8xxx_spi = spi_master_get_devdata(spi->master); reg_base = mpc8xxx_spi->reg_base; + pm_runtime_get_sync(mpc8xxx_spi->dev); + hw_mode = cs->hw_mode; /* Save original settings */ cs->hw_mode = mpc8xxx_spi_read_reg( ®_base->csmode[spi->chip_select]); @@ -507,6 +512,10 @@ static int fsl_espi_setup(struct spi_device *spi) mpc8xxx_spi_write_reg(®_base->mode, loop_mode); retval = fsl_espi_setup_transfer(spi, NULL); + + pm_runtime_mark_last_busy(mpc8xxx_spi->dev); + pm_runtime_put_autosuspend(mpc8xxx_spi->dev); + if (retval < 0) { cs->hw_mode = hw_mode; /* Restore settings */ return retval; @@ -604,20 +613,14 @@ static irqreturn_t fsl_espi_irq(s32 irq, void *context_data) return ret; } -static void fsl_espi_remove(struct mpc8xxx_spi *mspi) +#ifdef CONFIG_PM +static int fsl_espi_runtime_suspend(struct device *dev) { - iounmap(mspi->reg_base); -} - -static int fsl_espi_suspend(struct spi_master *master) -{ - struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; + struct spi_master *master = dev_get_drvdata(dev); + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); + struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; u32 regval; - mpc8xxx_spi = spi_master_get_devdata(master); - reg_base = mpc8xxx_spi->reg_base; - regval = mpc8xxx_spi_read_reg(®_base->mode); regval &= ~SPMODE_ENABLE; mpc8xxx_spi_write_reg(®_base->mode, regval); @@ -625,21 +628,20 @@ static int fsl_espi_suspend(struct spi_master *master) return 0; } -static int fsl_espi_resume(struct spi_master *master) +static int fsl_espi_runtime_resume(struct device *dev) { - struct mpc8xxx_spi *mpc8xxx_spi; - struct fsl_espi_reg *reg_base; + struct spi_master *master = dev_get_drvdata(dev); + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); + struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; u32 regval; - mpc8xxx_spi = spi_master_get_devdata(master); - reg_base = mpc8xxx_spi->reg_base; - regval = mpc8xxx_spi_read_reg(®_base->mode); regval |= SPMODE_ENABLE; mpc8xxx_spi_write_reg(®_base->mode, regval); return 0; } +#endif static struct spi_master * fsl_espi_probe(struct device *dev, struct resource *mem, unsigned int irq) @@ -667,25 +669,23 @@ static struct spi_master * fsl_espi_probe(struct device *dev, master->setup = fsl_espi_setup; master->cleanup = fsl_espi_cleanup; master->transfer_one_message = fsl_espi_do_one_msg; - master->prepare_transfer_hardware = fsl_espi_resume; - master->unprepare_transfer_hardware = fsl_espi_suspend; + master->auto_runtime_pm = true; mpc8xxx_spi = spi_master_get_devdata(master); - mpc8xxx_spi->spi_remove = fsl_espi_remove; - mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem)); - if (!mpc8xxx_spi->reg_base) { - ret = -ENOMEM; + mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); + if (IS_ERR(mpc8xxx_spi->reg_base)) { + ret = PTR_ERR(mpc8xxx_spi->reg_base); goto err_probe; } reg_base = mpc8xxx_spi->reg_base; /* Register for SPI Interrupt */ - ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq, + ret = devm_request_irq(dev, mpc8xxx_spi->irq, fsl_espi_irq, 0, "fsl_espi", mpc8xxx_spi); if (ret) - goto free_irq; + goto err_probe; if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) { mpc8xxx_spi->rx_shift = 16; @@ -731,18 +731,27 @@ static struct spi_master * fsl_espi_probe(struct device *dev, mpc8xxx_spi_write_reg(®_base->mode, regval); - ret = spi_register_master(master); + pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + ret = devm_spi_register_master(dev, master); if (ret < 0) - goto unreg_master; + goto err_pm; dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return master; -unreg_master: - free_irq(mpc8xxx_spi->irq, mpc8xxx_spi); -free_irq: - iounmap(mpc8xxx_spi->reg_base); +err_pm: + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); err_probe: spi_master_put(master); err: @@ -809,7 +818,9 @@ err: static int of_fsl_espi_remove(struct platform_device *dev) { - return mpc8xxx_spi_remove(&dev->dev); + pm_runtime_disable(&dev->dev); + + return 0; } #ifdef CONFIG_PM_SLEEP @@ -824,7 +835,11 @@ static int of_fsl_espi_suspend(struct device *dev) return ret; } - return fsl_espi_suspend(master); + ret = pm_runtime_force_suspend(dev); + if (ret < 0) + return ret; + + return 0; } static int of_fsl_espi_resume(struct device *dev) @@ -834,7 +849,7 @@ static int of_fsl_espi_resume(struct device *dev) struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_espi_reg *reg_base; u32 regval; - int i; + int i, ret; mpc8xxx_spi = spi_master_get_devdata(master); reg_base = mpc8xxx_spi->reg_base; @@ -854,11 +869,17 @@ static int of_fsl_espi_resume(struct device *dev) mpc8xxx_spi_write_reg(®_base->mode, regval); + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + return spi_master_resume(master); } #endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops espi_pm = { + SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend, + fsl_espi_runtime_resume, NULL) SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) }; |