greybus: spi: add master and device config operations
authorRui Miguel Silva <rui.silva@linaro.org>
Wed, 2 Dec 2015 11:12:28 +0000 (11:12 +0000)
committerGreg Kroah-Hartman <gregkh@google.com>
Thu, 3 Dec 2015 01:04:58 +0000 (17:04 -0800)
Add master and device config operations, one is to merge all the master
operations and the device config will allow to fetch and add devices for
each chip select.

Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/greybus_protocols.h
drivers/staging/greybus/spi.c

index 23d4cce..e8c4bce 100644 (file)
@@ -651,30 +651,29 @@ struct gb_pwm_disable_request {
 #define GB_SPI_FLAG_NO_TX              BIT(2)          /* can't do buffer write */
 
 /* Greybus spi operation types */
-#define GB_SPI_TYPE_MODE               0x02
-#define GB_SPI_TYPE_FLAGS              0x03
-#define GB_SPI_TYPE_BITS_PER_WORD_MASK 0x04
-#define GB_SPI_TYPE_NUM_CHIPSELECT     0x05
-#define GB_SPI_TYPE_TRANSFER           0x06
+#define GB_SPI_TYPE_MASTER_CONFIG      0x02
+#define GB_SPI_TYPE_DEVICE_CONFIG      0x03
+#define GB_SPI_TYPE_TRANSFER           0x04
 
 /* mode request has no payload */
-struct gb_spi_mode_response {
+struct gb_spi_master_config_response {
+       __le32  bits_per_word_mask;
+       __le32  min_speed_hz;
+       __le32  max_speed_hz;
        __le16  mode;
-} __packed;
-
-/* flags request has no payload */
-struct gb_spi_flags_response {
        __le16  flags;
+       __le16  num_chipselect;
 } __packed;
 
-/* bits-per-word request has no payload */
-struct gb_spi_bpw_response {
-       __le32  bits_per_word_mask;
+struct gb_spi_device_config_request {
+       __le16  chip_select;
 } __packed;
 
-/* num-chipselects request has no payload */
-struct gb_spi_chipselect_response {
-       __le16  num_chipselect;
+struct gb_spi_device_config_response {
+       __le16  mode;
+       __u8    bits_per_word;
+       __le32  max_speed_hz;
+       __u8    name[32];
 } __packed;
 
 /**
index 1b9c973..8e0e403 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * SPI bridge driver for the Greybus "generic" SPI module.
  *
- * Copyright 2014 Google Inc.
- * Copyright 2014 Linaro Ltd.
+ * Copyright 2014-2015 Google Inc.
+ * Copyright 2014-2015 Linaro Ltd.
  *
  * Released under the GPLv2 only.
  */
 
 struct gb_spi {
        struct gb_connection    *connection;
-
-       /* Modes supported by spi controller */
        u16                     mode;
-       /* constraints of the spi controller */
        u16                     flags;
-
-       /*
-        * copied from kernel:
-        *
-        * A mask indicating which values of bits_per_word are supported by the
-        * controller. Bit n indicates that a bits_per_word n+1 is suported. If
-        * set, the SPI core will reject any transfer with an unsupported
-        * bits_per_word. If not set, this value is simply ignored, and it's up
-        * to the individual driver to perform any validation.
-        */
        u32                     bits_per_word_mask;
-
-       /*
-        * chipselects will be integral to many controllers; some others might
-        * use board-specific GPIOs.
-        */
        u16                     num_chipselect;
+       u32                     min_speed_hz;
+       u32                     max_speed_hz;
+       struct spi_device       *spi_devices;
 };
 
+static struct spi_master *get_master_from_spi(struct gb_spi *spi)
+{
+       return spi->connection->private;
+}
+
 /* Routines to transfer data */
 static struct gb_operation *
 gb_spi_operation_create(struct gb_connection *connection,
@@ -181,7 +171,7 @@ static void gb_spi_cleanup(struct spi_device *spi)
 }
 
 
-/* Routines to get controller infomation */
+/* Routines to get controller information */
 
 /*
  * Map Greybus spi mode bits/flags/bpw into Linux ones.
@@ -190,103 +180,86 @@ 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_mode_operation(struct gb_spi *spi)
+static int gb_spi_get_master_config(struct gb_spi *spi)
 {
-       struct gb_spi_mode_response response;
-       u16 mode;
+       struct gb_spi_master_config_response response;
+       u16 mode, flags;
        int ret;
 
-       ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_MODE,
+       ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_MASTER_CONFIG,
                                NULL, 0, &response, sizeof(response));
-       if (ret)
+       if (ret < 0)
                return ret;
 
        mode = le16_to_cpu(response.mode);
        spi->mode = gb_spi_mode_map(mode);
 
-       return 0;
-}
-
-static int gb_spi_flags_operation(struct gb_spi *spi)
-{
-       struct gb_spi_flags_response response;
-       u16 flags;
-       int ret;
-
-       ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_FLAGS,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
        flags = le16_to_cpu(response.flags);
        spi->flags = gb_spi_flags_map(flags);
 
-       return 0;
-}
-
-static int gb_spi_bpw_operation(struct gb_spi *spi)
-{
-       struct gb_spi_bpw_response response;
-       int ret;
-
-       ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_BITS_PER_WORD_MASK,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
-               return ret;
-
        spi->bits_per_word_mask = le32_to_cpu(response.bits_per_word_mask);
+       spi->num_chipselect = le16_to_cpu(response.num_chipselect);
+
+       spi->min_speed_hz = le32_to_cpu(response.min_speed_hz);
+       spi->max_speed_hz = le32_to_cpu(response.max_speed_hz);
 
        return 0;
 }
 
-static int gb_spi_chipselect_operation(struct gb_spi *spi)
+static int gb_spi_setup_device(struct gb_spi *spi, uint16_t cs)
 {
-       struct gb_spi_chipselect_response response;
+       struct spi_master *master = get_master_from_spi(spi);
+       struct gb_spi_device_config_request request;
+       struct gb_spi_device_config_response response;
+       struct spi_board_info spi_board = { {0} };
+       struct spi_device *spidev = &spi->spi_devices[cs];
        int ret;
 
-       ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_NUM_CHIPSELECT,
-                               NULL, 0, &response, sizeof(response));
-       if (ret)
+       request.chip_select = cpu_to_le16(cs);
+
+       ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_DEVICE_CONFIG,
+                               &request, sizeof(request),
+                               &response, sizeof(response));
+       if (ret < 0)
                return ret;
 
-       spi->num_chipselect = le16_to_cpu(response.num_chipselect);
+       memcpy(spi_board.modalias, response.name, sizeof(spi_board.modalias));
+       spi_board.mode          = le16_to_cpu(response.mode);
+       spi_board.bus_num       = master->bus_num;
+       spi_board.chip_select   = cs;
+       spi_board.max_speed_hz  = le32_to_cpu(response.max_speed_hz);
+
+       spidev = spi_new_device(master, &spi_board);
+       if (!spidev)
+               ret = -EINVAL;
 
        return 0;
 }
 
-/*
- * Initialize the spi device. This includes verifying we can support it (based
- * on the protocol version it advertises). If that's OK, we get and cached its
- * mode bits & flags.
- */
 static int gb_spi_init(struct gb_spi *spi)
 {
        int ret;
 
-       /* mode never changes, just get it once */
-       ret = gb_spi_mode_operation(spi);
-       if (ret)
-               return ret;
-
-       /* flags never changes, just get it once */
-       ret = gb_spi_flags_operation(spi);
+       /* get master configuration */
+       ret = gb_spi_get_master_config(spi);
        if (ret)
                return ret;
 
-       /* total number of chipselects never changes, just get it once */
-       ret = gb_spi_chipselect_operation(spi);
-       if (ret)
-               return ret;
+       spi->spi_devices = kcalloc(spi->num_chipselect,
+                                  sizeof(struct spi_device), GFP_KERNEL);
+       if (!spi->spi_devices)
+               return -ENOMEM;
 
-       /* bits-per-word-mask never changes, just get it once */
-       return gb_spi_bpw_operation(spi);
+       return ret;
 }
 
+
 static int gb_spi_connection_init(struct gb_connection *connection)
 {
        struct gb_spi *spi;
        struct spi_master *master;
        int ret;
+       int i;
 
        /* Allocate master with space for data */
        master = spi_alloc_master(&connection->bundle->dev, sizeof(*spi));
@@ -315,8 +288,15 @@ static int gb_spi_connection_init(struct gb_connection *connection)
        master->transfer_one_message = gb_spi_transfer_one_message;
 
        ret = spi_register_master(master);
-       if (!ret)
-               return 0;
+
+       /* now, fetch the devices configuration */
+       for (i = 0; i < spi->num_chipselect; i++) {
+               ret = gb_spi_setup_device(spi, i);
+               if (ret < 0)
+                       break;
+       }
+
+       return ret;
 
 out_err:
        spi_master_put(master);