spi: orion: enable clocks before spi_setup
authorMarcin Wojtas <mw@semihalf.com>
Wed, 23 Dec 2020 10:38:26 +0000 (12:38 +0200)
committerMark Brown <broonie@kernel.org>
Mon, 28 Dec 2020 12:25:30 +0000 (12:25 +0000)
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>
drivers/spi/spi-orion.c

index b57b8b3..1337275 100644 (file)
@@ -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;