diff options
author | Rui Miguel Silva <rui.silva@linaro.org> | 2015-12-02 11:12:28 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@google.com> | 2015-12-02 17:04:58 -0800 |
commit | b343f6afd7635c86e1c001f1623e07f218c694db (patch) | |
tree | 2de2609fbdac5fa0a3613909bf8772ac93b9032f /drivers/staging/greybus/spi.c | |
parent | b455c84655d5bdfc5157d2100279e3ff2454b596 (diff) |
greybus: spi: add master and device config operations
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>
Diffstat (limited to 'drivers/staging/greybus/spi.c')
-rw-r--r-- | drivers/staging/greybus/spi.c | 138 |
1 files changed, 59 insertions, 79 deletions
diff --git a/drivers/staging/greybus/spi.c b/drivers/staging/greybus/spi.c index 1b9c97336451..8e0e403795f4 100644 --- a/drivers/staging/greybus/spi.c +++ b/drivers/staging/greybus/spi.c @@ -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. */ @@ -17,30 +17,20 @@ 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); |