summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus
diff options
context:
space:
mode:
authorViresh Kumar2016-05-14 20:12:19 +0200
committerGreg Kroah-Hartman2016-05-14 23:18:32 +0200
commit4c412921c78732f8f803a5906c97746ede5cf77c (patch)
tree34a66afaf78d53f9cf5b6bb945bd8474f747d0a1 /drivers/staging/greybus
parentgreybus: Remove bridge PHY protocol specific classes (diff)
downloadkernel-qcow2-linux-4c412921c78732f8f803a5906c97746ede5cf77c.tar.gz
kernel-qcow2-linux-4c412921c78732f8f803a5906c97746ede5cf77c.tar.xz
kernel-qcow2-linux-4c412921c78732f8f803a5906c97746ede5cf77c.zip
greybus: spi: Restructure spi.c to share it with other bundle drivers
This patch restructures spi.c as spilib core, so that the same logic can be reused for SPI connections implemented as part of different bundle types. This is required for Firmware Management Bundle. Note that the 'struct gb_protocol' and its callback aren't moved to a separate file in this commit to make its reviews easier. That will be done by a following patch. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Rui Miguel Silva <rui.silva@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus')
-rw-r--r--drivers/staging/greybus/Makefile4
-rw-r--r--drivers/staging/greybus/spilib.c (renamed from drivers/staging/greybus/spi.c)126
-rw-r--r--drivers/staging/greybus/spilib.h18
3 files changed, 93 insertions, 55 deletions
diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile
index 2680f7e7dc4a..a9802dacb7f1 100644
--- a/drivers/staging/greybus/Makefile
+++ b/drivers/staging/greybus/Makefile
@@ -33,7 +33,7 @@ gb-audio-manager-y += audio_manager.o
gb-audio-manager-y += audio_manager_module.o
gb-camera-y := camera.o
gb-firmware-y := fw-core.o fw-download.o
-gb-spi-y := spi.o
+gb-spilib-y := spilib.o
gb-sdio-y := sdio.o
gb-uart-y := uart.o
gb-pwm-y := pwm.o
@@ -62,7 +62,7 @@ obj-m += gb-audio-gb.o
obj-m += gb-audio-apbridgea.o
obj-m += gb-audio-manager.o
obj-m += gb-firmware.o
-obj-m += gb-spi.o
+obj-m += gb-spilib.o
obj-m += gb-sdio.o
obj-m += gb-uart.o
obj-m += gb-pwm.o
diff --git a/drivers/staging/greybus/spi.c b/drivers/staging/greybus/spilib.c
index 6cf18d179a75..c7fe87801187 100644
--- a/drivers/staging/greybus/spi.c
+++ b/drivers/staging/greybus/spilib.c
@@ -1,8 +1,8 @@
/*
- * SPI bridge driver for the Greybus "generic" SPI module.
+ * Greybus SPI library
*
- * Copyright 2014-2015 Google Inc.
- * Copyright 2014-2015 Linaro Ltd.
+ * Copyright 2014-2016 Google Inc.
+ * Copyright 2014-2016 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
@@ -15,10 +15,11 @@
#include "greybus.h"
#include "gpbridge.h"
+#include "spilib.h"
-struct gb_spi {
+struct gb_spilib {
struct gb_connection *connection;
- struct gpbridge_device *gpbdev;
+ struct device *parent;
struct spi_transfer *first_xfer;
struct spi_transfer *last_xfer;
u32 rx_xfer_offset;
@@ -42,7 +43,7 @@ struct gb_spi {
#define XFER_TIMEOUT_TOLERANCE 200
-static struct spi_master *get_master_from_spi(struct gb_spi *spi)
+static struct spi_master *get_master_from_spi(struct gb_spilib *spi)
{
return gb_connection_get_data(spi->connection);
}
@@ -92,7 +93,7 @@ static size_t calc_tx_xfer_size(u32 tx_size, u32 count, size_t len,
return len;
}
-static void clean_xfer_state(struct gb_spi *spi)
+static void clean_xfer_state(struct gb_spilib *spi)
{
spi->first_xfer = NULL;
spi->last_xfer = NULL;
@@ -102,7 +103,7 @@ static void clean_xfer_state(struct gb_spi *spi)
spi->op_timeout = 0;
}
-static int setup_next_xfer(struct gb_spi *spi, struct spi_message *msg)
+static int setup_next_xfer(struct gb_spilib *spi, struct spi_message *msg)
{
struct spi_transfer *last_xfer = spi->last_xfer;
@@ -149,9 +150,8 @@ static struct spi_transfer *get_next_xfer(struct spi_transfer *xfer,
}
/* Routines to transfer data */
-static struct gb_operation *
-gb_spi_operation_create(struct gb_spi *spi, struct gb_connection *connection,
- struct spi_message *msg)
+static struct gb_operation *gb_spi_operation_create(struct gb_spilib *spi,
+ struct gb_connection *connection, struct spi_message *msg)
{
struct gb_spi_transfer_request *request;
struct spi_device *dev = msg->spi;
@@ -175,7 +175,7 @@ gb_spi_operation_create(struct gb_spi *spi, struct gb_connection *connection,
spi->last_xfer = xfer;
if (!xfer->tx_buf && !xfer->rx_buf) {
- dev_err(&spi->gpbdev->dev,
+ dev_err(spi->parent,
"bufferless transfer, length %u\n", xfer->len);
msg->state = GB_SPI_STATE_MSG_ERROR;
return NULL;
@@ -279,7 +279,8 @@ gb_spi_operation_create(struct gb_spi *spi, struct gb_connection *connection,
return operation;
}
-static void gb_spi_decode_response(struct gb_spi *spi, struct spi_message *msg,
+static void gb_spi_decode_response(struct gb_spilib *spi,
+ struct spi_message *msg,
struct gb_spi_transfer_response *response)
{
struct spi_transfer *xfer = spi->first_xfer;
@@ -311,7 +312,7 @@ static void gb_spi_decode_response(struct gb_spi *spi, struct spi_message *msg,
static int gb_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
- struct gb_spi *spi = spi_master_get_devdata(master);
+ struct gb_spilib *spi = spi_master_get_devdata(master);
struct gb_connection *connection = spi->connection;
struct gb_spi_transfer_response *response;
struct gb_operation *operation;
@@ -343,7 +344,7 @@ static int gb_spi_transfer_one_message(struct spi_master *master,
if (response)
gb_spi_decode_response(spi, msg, response);
} else {
- dev_err(&spi->gpbdev->dev,
+ dev_err(spi->parent,
"transfer operation failed: %d\n", ret);
msg->state = GB_SPI_STATE_MSG_ERROR;
}
@@ -381,7 +382,7 @@ static void gb_spi_cleanup(struct spi_device *spi)
#define gb_spi_mode_map(mode) mode
#define gb_spi_flags_map(flags) flags
-static int gb_spi_get_master_config(struct gb_spi *spi)
+static int gb_spi_get_master_config(struct gb_spilib *spi)
{
struct gb_spi_master_config_response response;
u16 mode, flags;
@@ -407,7 +408,7 @@ static int gb_spi_get_master_config(struct gb_spi *spi)
return 0;
}
-static int gb_spi_setup_device(struct gb_spi *spi, u8 cs)
+static int gb_spi_setup_device(struct gb_spilib *spi, u8 cs)
{
struct spi_master *master = get_master_from_spi(spi);
struct gb_spi_device_config_request request;
@@ -451,48 +452,29 @@ static int gb_spi_setup_device(struct gb_spi *spi, u8 cs)
return 0;
}
-static int gb_spi_probe(struct gpbridge_device *gpbdev,
- const struct gpbridge_device_id *id)
+int gb_spilib_master_init(struct gb_connection *connection, struct device *dev)
{
- struct gb_connection *connection;
- struct gb_spi *spi;
+ struct gb_spilib *spi;
struct spi_master *master;
int ret;
u8 i;
/* Allocate master with space for data */
- master = spi_alloc_master(&gpbdev->dev, sizeof(*spi));
+ master = spi_alloc_master(dev, sizeof(*spi));
if (!master) {
- dev_err(&gpbdev->dev, "cannot alloc SPI master\n");
+ dev_err(dev, "cannot alloc SPI master\n");
return -ENOMEM;
}
- connection = gb_connection_create(gpbdev->bundle,
- le16_to_cpu(gpbdev->cport_desc->id),
- NULL);
- if (IS_ERR(connection)) {
- ret = PTR_ERR(connection);
- goto exit_spi_put;
- }
-
spi = spi_master_get_devdata(master);
spi->connection = connection;
gb_connection_set_data(connection, master);
- spi->gpbdev = gpbdev;
- gb_gpbridge_set_data(gpbdev, master);
-
- ret = gb_connection_enable(connection);
- if (ret)
- goto exit_connection_destroy;
-
- ret = gb_gpbridge_get_version(connection);
- if (ret)
- goto exit_connection_disable;
+ spi->parent = dev;
/* get master configuration */
ret = gb_spi_get_master_config(spi);
if (ret)
- goto exit_connection_disable;
+ goto exit_spi_put;
master->bus_num = -1; /* Allow spi-core to allocate it dynamically */
master->num_chipselect = spi->num_chipselect;
@@ -507,43 +489,81 @@ static int gb_spi_probe(struct gpbridge_device *gpbdev,
ret = spi_register_master(master);
if (ret < 0)
- goto exit_connection_disable;
+ goto exit_spi_put;
/* now, fetch the devices configuration */
for (i = 0; i < spi->num_chipselect; i++) {
ret = gb_spi_setup_device(spi, i);
if (ret < 0) {
- dev_err(&gpbdev->dev,
- "failed to allocate spi device %d: %d\n",
+ dev_err(dev, "failed to allocate spi device %d: %d\n",
i, ret);
goto exit_spi_unregister;
}
}
- return ret;
+ return 0;
exit_spi_unregister:
spi_unregister_master(master);
+exit_spi_put:
+ spi_master_put(master);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gb_spilib_master_init);
+
+void gb_spilib_master_exit(struct gb_connection *connection)
+{
+ struct spi_master *master = gb_connection_get_data(connection);
+
+ spi_unregister_master(master);
+ spi_master_put(master);
+}
+EXPORT_SYMBOL_GPL(gb_spilib_master_exit);
+
+static int gb_spi_probe(struct gpbridge_device *gpbdev,
+ const struct gpbridge_device_id *id)
+{
+ struct gb_connection *connection;
+ int ret;
+
+ connection = gb_connection_create(gpbdev->bundle,
+ le16_to_cpu(gpbdev->cport_desc->id),
+ NULL);
+ if (IS_ERR(connection))
+ return PTR_ERR(connection);
+
+ ret = gb_connection_enable(connection);
+ if (ret)
+ goto exit_connection_destroy;
+
+ ret = gb_gpbridge_get_version(connection);
+ if (ret)
+ goto exit_connection_disable;
+
+ ret = gb_spilib_master_init(connection, &gpbdev->dev);
+ if (ret)
+ goto exit_connection_disable;
+
+ gb_gpbridge_set_data(gpbdev, connection);
+
+ return 0;
+
exit_connection_disable:
gb_connection_disable(connection);
exit_connection_destroy:
gb_connection_destroy(connection);
-exit_spi_put:
- spi_master_put(master);
return ret;
}
static void gb_spi_remove(struct gpbridge_device *gpbdev)
{
- struct spi_master *master = gb_gpbridge_get_data(gpbdev);
- struct gb_spi *spi = spi_master_get_devdata(master);
- struct gb_connection *connection = spi->connection;
+ struct gb_connection *connection = gb_gpbridge_get_data(gpbdev);
- spi_unregister_master(master);
+ gb_spilib_master_exit(connection);
gb_connection_disable(connection);
gb_connection_destroy(connection);
- spi_master_put(master);
}
static const struct gpbridge_device_id gb_spi_id_table[] = {
diff --git a/drivers/staging/greybus/spilib.h b/drivers/staging/greybus/spilib.h
new file mode 100644
index 000000000000..9be1b3189834
--- /dev/null
+++ b/drivers/staging/greybus/spilib.h
@@ -0,0 +1,18 @@
+/*
+ * Greybus SPI library header
+ *
+ * copyright 2016 google inc.
+ * copyright 2016 linaro ltd.
+ *
+ * released under the gplv2 only.
+ */
+
+#ifndef __SPILIB_H
+#define __SPILIB_H
+
+struct gb_connection;
+
+int gb_spilib_master_init(struct gb_connection *connection, struct device *dev);
+void gb_spilib_master_exit(struct gb_connection *connection);
+
+#endif /* __SPILIB_H */