greybus: firmware: Add SPI protocol support
authorViresh Kumar <viresh.kumar@linaro.org>
Sat, 14 May 2016 18:12:24 +0000 (23:42 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Sat, 14 May 2016 22:23:52 +0000 (00:23 +0200)
This patch adds SPI Protocol support to firmware core, which allows the
AP to access an SPI flash memory present with an Interface.

Tested by using the API from fw-management driver and compiling it.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/fw-core.c

index 0a456c5..90d3222 100644 (file)
 #include <linux/firmware.h>
 #include "firmware.h"
 #include "greybus.h"
+#include "spilib.h"
 
 struct gb_fw_core {
        struct gb_connection    *download_connection;
        struct gb_connection    *mgmt_connection;
+       struct gb_connection    *spi_connection;
 };
 
 struct gb_connection *to_fw_mgmt_connection(struct device *dev)
@@ -24,6 +26,35 @@ struct gb_connection *to_fw_mgmt_connection(struct device *dev)
        return fw_core->mgmt_connection;
 }
 
+static int gb_fw_spi_connection_init(struct gb_connection *connection)
+{
+       int ret;
+
+       if (!connection)
+               return 0;
+
+       ret = gb_connection_enable(connection);
+       if (ret)
+               return ret;
+
+       ret = gb_spilib_master_init(connection, &connection->bundle->dev);
+       if (ret) {
+               gb_connection_disable(connection);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void gb_fw_spi_connection_exit(struct gb_connection *connection)
+{
+       if (!connection)
+               return;
+
+       gb_spilib_master_exit(connection);
+       gb_connection_disable(connection);
+}
+
 static int gb_fw_core_probe(struct gb_bundle *bundle,
                            const struct greybus_bundle_id *id)
 {
@@ -85,6 +116,25 @@ static int gb_fw_core_probe(struct gb_bundle *bundle,
                        }
 
                        break;
+               case GREYBUS_PROTOCOL_SPI:
+                       /* Disallow multiple SPI CPorts */
+                       if (fw_core->spi_connection) {
+                               dev_err(&bundle->dev,
+                                       "multiple SPI CPorts found\n");
+                               ret = -EINVAL;
+                               goto err_destroy_connections;
+                       }
+
+                       connection = gb_connection_create(bundle, cport_id,
+                                                         NULL);
+                       if (IS_ERR(connection)) {
+                               dev_err(&bundle->dev, "failed to create SPI connection (%ld)\n",
+                                       PTR_ERR(connection));
+                       } else {
+                               fw_core->spi_connection = connection;
+                       }
+
+                       break;
                default:
                        dev_err(&bundle->dev, "invalid protocol id (0x%02x)\n",
                                protocol_id);
@@ -109,6 +159,15 @@ static int gb_fw_core_probe(struct gb_bundle *bundle,
                fw_core->download_connection = NULL;
        }
 
+       ret = gb_fw_spi_connection_init(fw_core->spi_connection);
+       if (ret) {
+               /* We may still be able to work with the Interface */
+               dev_err(&bundle->dev, "failed to initialize SPI connection, disable it (%d)\n",
+                       ret);
+               gb_connection_destroy(fw_core->spi_connection);
+               fw_core->spi_connection = NULL;
+       }
+
        ret = gb_fw_mgmt_connection_init(fw_core->mgmt_connection);
        if (ret) {
                /* We may still be able to work with the Interface */
@@ -122,9 +181,11 @@ static int gb_fw_core_probe(struct gb_bundle *bundle,
        return 0;
 
 err_exit_connections:
+       gb_fw_spi_connection_exit(fw_core->spi_connection);
        gb_fw_download_connection_exit(fw_core->download_connection);
 err_destroy_connections:
        gb_connection_destroy(fw_core->mgmt_connection);
+       gb_connection_destroy(fw_core->spi_connection);
        gb_connection_destroy(fw_core->download_connection);
 err_free_fw_core:
        kfree(fw_core);
@@ -137,9 +198,11 @@ static void gb_fw_core_disconnect(struct gb_bundle *bundle)
        struct gb_fw_core *fw_core = greybus_get_drvdata(bundle);
 
        gb_fw_mgmt_connection_exit(fw_core->mgmt_connection);
+       gb_fw_spi_connection_exit(fw_core->spi_connection);
        gb_fw_download_connection_exit(fw_core->download_connection);
 
        gb_connection_destroy(fw_core->mgmt_connection);
+       gb_connection_destroy(fw_core->spi_connection);
        gb_connection_destroy(fw_core->download_connection);
 
        kfree(fw_core);