greybus: spilib: make spilib independent of gbphy
authorViresh Kumar <viresh.kumar@linaro.org>
Thu, 21 Jul 2016 21:45:06 +0000 (14:45 -0700)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 22 Jul 2016 02:03:05 +0000 (19:03 -0700)
spilib is used by multiple users currently (spi.c and fw-core.c) but
commit aa52b62a0556 broke that hierarchy and introduced gbphy dependent
code in spilib.

This may have unreliable consequences as we are doing following
operation unconditionally now:

gbphy_dev = to_gbphy_dev(spi->parent);
gbphy_runtime_get_sync(gbphy_dev);

which may not go well when the parent is of type &bundle->dev
(fw-core.c).

This patch introduces spilib_ops and lets the users of the core register
them. This shall have no functional change for the spi.c usecase and
shall fix the unreliable results for the fw-core.c usecase.

Tested by writing to mtd0 dev and verifying (with print messages) that
the below routines are getting called for a gpbridge-test module.

Fixes: aa52b62a0556 ("spi: Add runtime_pm support")
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/fw-core.c
drivers/staging/greybus/spi.c
drivers/staging/greybus/spilib.c
drivers/staging/greybus/spilib.h

index 9639732..19f92fb 100644 (file)
@@ -38,7 +38,7 @@ static int gb_fw_spi_connection_init(struct gb_connection *connection)
        if (ret)
                return ret;
 
-       ret = gb_spilib_master_init(connection, &connection->bundle->dev);
+       ret = gb_spilib_master_init(connection, &connection->bundle->dev, NULL);
        if (ret) {
                gb_connection_disable(connection);
                return ret;
index 2e6e328..bb76b3c 100644 (file)
 #include "gbphy.h"
 #include "spilib.h"
 
+#ifndef SPI_CORE_SUPPORT_PM
+static int gbphy_spi_prepare_transfer_hardware(struct device *dev)
+{
+       return gbphy_runtime_get_sync(to_gbphy_dev(dev));
+}
+
+static void gbphy_spi_unprepare_transfer_hardware(struct device *dev)
+{
+       gbphy_runtime_put_autosuspend(to_gbphy_dev(dev));
+}
+
+static struct spilib_ops __spilib_ops = {
+       .prepare_transfer_hardware = gbphy_spi_prepare_transfer_hardware,
+       .unprepare_transfer_hardware = gbphy_spi_unprepare_transfer_hardware,
+};
+
+static struct spilib_ops *spilib_ops = &__spilib_ops;
+#else
+static struct spilib_ops *spilib_ops = NULL;
+#endif
+
 static int gb_spi_probe(struct gbphy_device *gbphy_dev,
                        const struct gbphy_device_id *id)
 {
@@ -29,7 +50,7 @@ static int gb_spi_probe(struct gbphy_device *gbphy_dev,
        if (ret)
                goto exit_connection_destroy;
 
-       ret = gb_spilib_master_init(connection, &gbphy_dev->dev);
+       ret = gb_spilib_master_init(connection, &gbphy_dev->dev, spilib_ops);
        if (ret)
                goto exit_connection_disable;
 
index e4c82e0..9427c31 100644 (file)
 
 #include "greybus.h"
 #include "spilib.h"
-#include "gbphy.h"
 
 struct gb_spilib {
        struct gb_connection    *connection;
        struct device           *parent;
        struct spi_transfer     *first_xfer;
        struct spi_transfer     *last_xfer;
+       struct spilib_ops       *ops;
        u32                     rx_xfer_offset;
        u32                     tx_xfer_offset;
        u32                     last_xfer_size;
@@ -373,25 +373,21 @@ out:
        return ret;
 }
 
-#ifndef SPI_CORE_SUPPORT_PM
 static int gb_spi_prepare_transfer_hardware(struct spi_master *master)
 {
        struct gb_spilib *spi = spi_master_get_devdata(master);
-       struct gbphy_device *gbphy_dev = to_gbphy_dev(spi->parent);
 
-       return gbphy_runtime_get_sync(gbphy_dev);
+       return spi->ops->prepare_transfer_hardware(spi->parent);
 }
 
 static int gb_spi_unprepare_transfer_hardware(struct spi_master *master)
 {
        struct gb_spilib *spi = spi_master_get_devdata(master);
-       struct gbphy_device *gbphy_dev = to_gbphy_dev(spi->parent);
 
-       gbphy_runtime_put_autosuspend(gbphy_dev);
+       spi->ops->unprepare_transfer_hardware(spi->parent);
 
        return 0;
 }
-#endif
 
 static int gb_spi_setup(struct spi_device *spi)
 {
@@ -483,7 +479,8 @@ static int gb_spi_setup_device(struct gb_spilib *spi, u8 cs)
        return 0;
 }
 
-int gb_spilib_master_init(struct gb_connection *connection, struct device *dev)
+int gb_spilib_master_init(struct gb_connection *connection, struct device *dev,
+                         struct spilib_ops *ops)
 {
        struct gb_spilib *spi;
        struct spi_master *master;
@@ -501,6 +498,7 @@ int gb_spilib_master_init(struct gb_connection *connection, struct device *dev)
        spi->connection = connection;
        gb_connection_set_data(connection, master);
        spi->parent = dev;
+       spi->ops = ops;
 
        /* get master configuration */
        ret = gb_spi_get_master_config(spi);
@@ -518,11 +516,17 @@ int gb_spilib_master_init(struct gb_connection *connection, struct device *dev)
        master->setup = gb_spi_setup;
        master->transfer_one_message = gb_spi_transfer_one_message;
 
-#ifndef SPI_CORE_SUPPORT_PM
-       master->prepare_transfer_hardware = gb_spi_prepare_transfer_hardware;
-       master->unprepare_transfer_hardware =
+       if (ops && ops->prepare_transfer_hardware) {
+               master->prepare_transfer_hardware =
+                       gb_spi_prepare_transfer_hardware;
+       }
+
+       if (ops && ops->unprepare_transfer_hardware) {
+               master->unprepare_transfer_hardware =
                        gb_spi_unprepare_transfer_hardware;
-#else
+       }
+
+#ifdef SPI_CORE_SUPPORT_PM
        master->auto_runtime_pm = true;
 #endif
 
index 9be1b31..566d0dd 100644 (file)
 #ifndef __SPILIB_H
 #define __SPILIB_H
 
+struct device;
 struct gb_connection;
 
-int gb_spilib_master_init(struct gb_connection *connection, struct device *dev);
+struct spilib_ops {
+       int (*prepare_transfer_hardware)(struct device *dev);
+       void (*unprepare_transfer_hardware)(struct device *dev);
+};
+
+int gb_spilib_master_init(struct gb_connection *connection, struct device *dev, struct spilib_ops *ops);
 void gb_spilib_master_exit(struct gb_connection *connection);
 
 #endif /* __SPILIB_H */