Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+15 −16
Original line number Original line Diff line number Diff line
@@ -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;


/**
/**
+59 −79
Original line number Original line Diff line number Diff line
/*
/*
 * 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 @@


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)
}
}




/* 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)
#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)
	if (ret)
		return ret;
		return ret;


	/* flags never changes, just get it once */
	spi->spi_devices = kcalloc(spi->num_chipselect,
	ret = gb_spi_flags_operation(spi);
				   sizeof(struct spi_device), GFP_KERNEL);
	if (ret)
	if (!spi->spi_devices)
		return ret;
		return -ENOMEM;


	/* total number of chipselects never changes, just get it once */
	ret = gb_spi_chipselect_operation(spi);
	if (ret)
	return ret;
	return ret;

	/* bits-per-word-mask never changes, just get it once */
	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)
	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);