diff options
author | Marcin Wojtas <mw@semihalf.com> | 2020-12-23 12:38:26 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2020-12-28 12:25:30 +0000 |
commit | e2be70318d7b0ad9446d8a64ed1bc73e3316ee39 (patch) | |
tree | 6a124300d4ad82083daa35a6f5379743da130508 /drivers/spi/spi-orion.c | |
parent | a34d4197a144d83d508163404ad7d214082e909a (diff) | |
download | lwn-e2be70318d7b0ad9446d8a64ed1bc73e3316ee39.tar.gz lwn-e2be70318d7b0ad9446d8a64ed1bc73e3316ee39.zip |
spi: orion: enable clocks before spi_setup
The spi-orion driver disables its clocks whenever it is not used.
In usual case during boot (i.e. using SPI flash) it is not a problem,
as the child device driver is present and probed along with
spi_register_master() execution.
However in case the child device driver is not ready
(e.g. when its type is module_spi_driver) the spi_setup() callback
can be called after the spi-orion probe. It may happen,
that as a result there will be an attempt to access controller's
registers with the clocks disabled.
Prevent such situations and make sure the clocks are on,
each time the spi_setup() is called.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Signed-off-by: Konstantin Porotchkin <kostap@marvell.com>
Link: https://lore.kernel.org/r/20201223103827.29721-2-kostap@marvell.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-orion.c')
-rw-r--r-- | drivers/spi/spi-orion.c | 23 |
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index b57b8b3cc26e..133727552e99 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -96,10 +96,16 @@ struct orion_spi { struct clk *clk; struct clk *axi_clk; const struct orion_spi_dev *devdata; + struct device *dev; struct orion_child_options child[ORION_NUM_CHIPSELECTS]; }; +#ifdef CONFIG_PM +static int orion_spi_runtime_suspend(struct device *dev); +static int orion_spi_runtime_resume(struct device *dev); +#endif + static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg) { return orion_spi->base + reg; @@ -507,7 +513,21 @@ static int orion_spi_transfer_one(struct spi_master *master, static int orion_spi_setup(struct spi_device *spi) { - return orion_spi_setup_transfer(spi, NULL); + int ret; +#ifdef CONFIG_PM + struct orion_spi *orion_spi = spi_master_get_devdata(spi->master); + struct device *dev = orion_spi->dev; + + orion_spi_runtime_resume(dev); +#endif + + ret = orion_spi_setup_transfer(spi, NULL); + +#ifdef CONFIG_PM + orion_spi_runtime_suspend(dev); +#endif + + return ret; } static int orion_spi_reset(struct orion_spi *orion_spi) @@ -630,6 +650,7 @@ static int orion_spi_probe(struct platform_device *pdev) spi = spi_master_get_devdata(master); spi->master = master; + spi->dev = &pdev->dev; of_id = of_match_device(orion_spi_of_match_table, &pdev->dev); devdata = (of_id) ? of_id->data : &orion_spi_dev_data; |