|
@@ -11,10 +11,12 @@
|
|
|
#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)
|
|
|
{
|
|
@@ -84,6 +115,25 @@ static int gb_fw_core_probe(struct gb_bundle *bundle,
|
|
|
fw_core->download_connection = connection;
|
|
|
}
|
|
|
|
|
|
+ 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",
|
|
@@ -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);
|