Commit b343f6af authored by Rui Miguel Silva's avatar Rui Miguel Silva Committed by Greg Kroah-Hartman

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: default avatarRui Miguel Silva <rui.silva@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent b455c846
...@@ -651,30 +651,29 @@ struct gb_pwm_disable_request { ...@@ -651,30 +651,29 @@ struct gb_pwm_disable_request {
#define GB_SPI_FLAG_NO_TX BIT(2) /* can't do buffer write */ #define GB_SPI_FLAG_NO_TX BIT(2) /* can't do buffer write */
/* Greybus spi operation types */ /* Greybus spi operation types */
#define GB_SPI_TYPE_MODE 0x02 #define GB_SPI_TYPE_MASTER_CONFIG 0x02
#define GB_SPI_TYPE_FLAGS 0x03 #define GB_SPI_TYPE_DEVICE_CONFIG 0x03
#define GB_SPI_TYPE_BITS_PER_WORD_MASK 0x04 #define GB_SPI_TYPE_TRANSFER 0x04
#define GB_SPI_TYPE_NUM_CHIPSELECT 0x05
#define GB_SPI_TYPE_TRANSFER 0x06
/* mode request has no payload */ /* 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; __le16 mode;
} __packed;
/* flags request has no payload */
struct gb_spi_flags_response {
__le16 flags; __le16 flags;
__le16 num_chipselect;
} __packed; } __packed;
/* bits-per-word request has no payload */ struct gb_spi_device_config_request {
struct gb_spi_bpw_response { __le16 chip_select;
__le32 bits_per_word_mask;
} __packed; } __packed;
/* num-chipselects request has no payload */ struct gb_spi_device_config_response {
struct gb_spi_chipselect_response { __le16 mode;
__le16 num_chipselect; __u8 bits_per_word;
__le32 max_speed_hz;
__u8 name[32];
} __packed; } __packed;
/** /**
......
/* /*
* SPI bridge driver for the Greybus "generic" SPI module. * SPI bridge driver for the Greybus "generic" SPI module.
* *
* Copyright 2014 Google Inc. * Copyright 2014-2015 Google Inc.
* Copyright 2014 Linaro Ltd. * Copyright 2014-2015 Linaro Ltd.
* *
* Released under the GPLv2 only. * Released under the GPLv2 only.
*/ */
...@@ -17,30 +17,20 @@ ...@@ -17,30 +17,20 @@
struct gb_spi { struct gb_spi {
struct gb_connection *connection; struct gb_connection *connection;
/* Modes supported by spi controller */
u16 mode; u16 mode;
/* constraints of the spi controller */
u16 flags; 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; u32 bits_per_word_mask;
/*
* chipselects will be integral to many controllers; some others might
* use board-specific GPIOs.
*/
u16 num_chipselect; 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 */ /* Routines to transfer data */
static struct gb_operation * static struct gb_operation *
gb_spi_operation_create(struct gb_connection *connection, gb_spi_operation_create(struct gb_connection *connection,
...@@ -181,7 +171,7 @@ static void gb_spi_cleanup(struct spi_device *spi) ...@@ -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. * Map Greybus spi mode bits/flags/bpw into Linux ones.
...@@ -190,103 +180,86 @@ static void gb_spi_cleanup(struct spi_device *spi) ...@@ -190,103 +180,86 @@ static void gb_spi_cleanup(struct spi_device *spi)
#define gb_spi_mode_map(mode) mode #define gb_spi_mode_map(mode) mode
#define gb_spi_flags_map(flags) flags #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; struct gb_spi_master_config_response response;
u16 mode; u16 mode, flags;
int ret; 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)); NULL, 0, &response, sizeof(response));
if (ret) if (ret < 0)
return ret; return ret;
mode = le16_to_cpu(response.mode); mode = le16_to_cpu(response.mode);
spi->mode = gb_spi_mode_map(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); flags = le16_to_cpu(response.flags);
spi->flags = gb_spi_flags_map(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->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; 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; int ret;
ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_NUM_CHIPSELECT, request.chip_select = cpu_to_le16(cs);
NULL, 0, &response, sizeof(response));
if (ret) ret = gb_operation_sync(spi->connection, GB_SPI_TYPE_DEVICE_CONFIG,
&request, sizeof(request),
&response, sizeof(response));
if (ret < 0)
return ret; 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; 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) static int gb_spi_init(struct gb_spi *spi)
{ {
int ret; int ret;
/* mode never changes, just get it once */ /* get master configuration */
ret = gb_spi_mode_operation(spi); ret = gb_spi_get_master_config(spi);
if (ret)
return ret;
/* flags never changes, just get it once */
ret = gb_spi_flags_operation(spi);
if (ret) if (ret)
return ret; return ret;
/* total number of chipselects never changes, just get it once */ spi->spi_devices = kcalloc(spi->num_chipselect,
ret = gb_spi_chipselect_operation(spi); sizeof(struct spi_device), GFP_KERNEL);
if (ret) if (!spi->spi_devices)
return ret; return -ENOMEM;
/* bits-per-word-mask never changes, just get it once */ return ret;
return gb_spi_bpw_operation(spi);
} }
static int gb_spi_connection_init(struct gb_connection *connection) static int gb_spi_connection_init(struct gb_connection *connection)
{ {
struct gb_spi *spi; struct gb_spi *spi;
struct spi_master *master; struct spi_master *master;
int ret; int ret;
int i;
/* Allocate master with space for data */ /* Allocate master with space for data */
master = spi_alloc_master(&connection->bundle->dev, sizeof(*spi)); master = spi_alloc_master(&connection->bundle->dev, sizeof(*spi));
...@@ -315,8 +288,15 @@ static int gb_spi_connection_init(struct gb_connection *connection) ...@@ -315,8 +288,15 @@ static int gb_spi_connection_init(struct gb_connection *connection)
master->transfer_one_message = gb_spi_transfer_one_message; master->transfer_one_message = gb_spi_transfer_one_message;
ret = spi_register_master(master); 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: out_err:
spi_master_put(master); spi_master_put(master);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment