greybus: add i2c driver

This patch adds the i2c driver, based on the use of Greybus operations
over Greybus connections.  It basically replaces almost all of what
was previously found in "i2c-gb.c".

When gb_connection_device_init(connection) is called, any connection
that talks the GREYBUS_PROTOCOL_I2C is passed to gb_i2c_device_init()
to be initialized.

Initialization involves verifying the code is able to support the
version of the protocol.  For I2C, we then query the functionality
mask, and set the retry count and timeout to default values.

After that, we set up the i2c device and associate it with the
connection.  The i2c_algorithm methods are then implemented
by translating them into Greybus operations.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 0143a4f..fc692f0 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -202,6 +202,7 @@
 {
 	switch (connection->protocol) {
 	case GREYBUS_PROTOCOL_I2C:
+		return gb_i2c_device_init(connection);
 	case GREYBUS_PROTOCOL_CONTROL:
 	case GREYBUS_PROTOCOL_AP:
 	case GREYBUS_PROTOCOL_GPIO:
diff --git a/drivers/staging/greybus/i2c-gb.c b/drivers/staging/greybus/i2c-gb.c
index 0da1958..c4e47ef 100644
--- a/drivers/staging/greybus/i2c-gb.c
+++ b/drivers/staging/greybus/i2c-gb.c
@@ -14,127 +14,516 @@
 #include "greybus.h"
 
 struct gb_i2c_device {
-	struct i2c_adapter *adapter;
-	struct gb_module *gmod;
+	struct gb_connection	*connection;
+	u8			version_major;
+	u8			version_minor;
+
+	u32			functionality;
+	u16			timeout_msec;
+	u8			retries;
+
+	struct i2c_adapter	*adapter;
 };
 
-static const struct greybus_module_id id_table[] = {
-	{ GREYBUS_DEVICE(0x42, 0x42) },	/* make shit up */
-	{ },	/* terminating NULL entry */
+/* Version of the Greybus i2c protocol we support */
+#define	GB_I2C_VERSION_MAJOR		0x00
+#define	GB_I2C_VERSION_MINOR		0x01
+
+/* Greybus i2c request types */
+#define	GB_I2C_TYPE_INVALID		0x00
+#define	GB_I2C_TYPE_PROTOCOL_VERSION	0x01
+#define	GB_I2C_TYPE_FUNCTIONALITY	0x02
+#define	GB_I2C_TYPE_TIMEOUT		0x03
+#define	GB_I2C_TYPE_RETRIES		0x04
+#define	GB_I2C_TYPE_TRANSFER		0x05
+#define	GB_I2C_TYPE_RESPONSE		0x80	/* OR'd with rest */
+
+#define	GB_I2C_RETRIES_DEFAULT		3
+#define	GB_I2C_TIMEOUT_DEFAULT		1000	/* milliseconds */
+
+/* version request has no payload */
+struct gb_i2c_proto_version_response {
+	__u8	status;
+	__u8	major;
+	__u8	minor;
 };
 
-/* We BETTER be able to do SMBUS protocl calls, otherwise we are bit-banging the
- * slowest thing possible over the fastest bus possible, crazy...
- * FIXME - research this, for now just assume we can
+/* functionality request has no payload */
+struct gb_i2c_functionality_response {
+	__u8	status;
+	__le32	functionality;
+};
+
+struct gb_i2c_timeout_request {
+	__le16	msec;
+};
+struct gb_i2c_timeout_response {
+	__u8	status;
+};
+
+struct gb_i2c_retries_request {
+	__u8	retries;
+};
+struct gb_i2c_retries_response {
+	__u8	status;
+};
+
+/*
+ * Outgoing data immediately follows the op count and ops array.
+ * The data for each write (master -> slave) op in the array is sent
+ * in order, with no (e.g. pad) bytes separating them.
+ *
+ * Short reads cause the entire transfer request to fail So response
+ * payload consists only of bytes read, and the number of bytes is
+ * exactly what was specified in the corresponding op.  Like
+ * outgoing data, the incoming data is in order and contiguous.
  */
+struct gb_i2c_transfer_op {
+	__le16	addr;
+	__le16	flags;
+	__le16	size;
+};
+
+struct gb_i2c_transfer_request {
+	__le16				op_count;
+	struct gb_i2c_transfer_op	ops[0];		/* op_count of these */
+};
+struct gb_i2c_transfer_response {
+	__u8				status;
+	__u8				data[0];	/* inbound data */
+};
+
+/*
+ * This request only uses the connection field, and if successful,
+ * fills in the major and minor protocol version of the target.
+ */
+static int gb_i2c_proto_version_operation(struct gb_i2c_device *gb_i2c_dev)
+{
+	struct gb_connection *connection = gb_i2c_dev->connection;
+	struct gb_operation *operation;
+	struct gb_i2c_proto_version_response *response;
+	int ret;
+
+	/* A protocol version request has no payload */
+	operation = gb_operation_create(connection,
+					GB_I2C_TYPE_PROTOCOL_VERSION,
+					0, sizeof(*response));
+	if (!operation)
+		return -ENOMEM;
+
+	/* Synchronous operation--no callback */
+	ret = gb_operation_request_send(operation, NULL);
+	if (ret) {
+		pr_err("version operation failed (%d)\n", ret);
+		goto out;
+	}
+
+	response = operation->response_payload;
+	if (response->status) {
+		gb_connection_err(connection, "version response %hhu",
+			response->status);
+		ret = -EIO;
+	} else {
+		if (response->major > GB_I2C_VERSION_MAJOR) {
+			pr_err("unsupported major version (%hhu > %hhu)\n",
+				response->major, GB_I2C_VERSION_MAJOR);
+			ret = -ENOTSUPP;
+			goto out;
+		}
+		gb_i2c_dev->version_major = response->major;
+		gb_i2c_dev->version_minor = response->minor;
+	}
+out:
+
+	gb_operation_destroy(operation);
+
+	return ret;
+}
+
+/*
+ * Map Greybus i2c functionality bits into Linux ones
+ */
+static u32 gb_i2c_functionality_map(u32 gb_i2c_functionality)
+{
+	return gb_i2c_functionality;	/* All bits the same for now */
+}
+
+static int gb_i2c_functionality_operation(struct gb_i2c_device *gb_i2c_dev)
+{
+	struct gb_connection *connection = gb_i2c_dev->connection;
+	struct gb_operation *operation;
+	struct gb_i2c_functionality_response *response;
+	u32 functionality;
+	int ret;
+
+	/* A functionality request has no payload */
+	operation = gb_operation_create(connection,
+					GB_I2C_TYPE_FUNCTIONALITY,
+					0, sizeof(*response));
+	if (!operation)
+		return -ENOMEM;
+
+	/* Synchronous operation--no callback */
+	ret = gb_operation_request_send(operation, NULL);
+	if (ret) {
+		pr_err("functionality operation failed (%d)\n", ret);
+		goto out;
+	}
+
+	response = operation->response_payload;
+	if (response->status) {
+		gb_connection_err(connection, "functionality response %hhu",
+			response->status);
+		ret = -EIO;
+	} else {
+		functionality = le32_to_cpu(response->functionality);
+		gb_i2c_dev->functionality =
+			gb_i2c_functionality_map(functionality);
+	}
+out:
+	gb_operation_destroy(operation);
+
+	return ret;
+}
+
+static int gb_i2c_timeout_operation(struct gb_i2c_device *gb_i2c_dev, u16 msec)
+{
+	struct gb_connection *connection = gb_i2c_dev->connection;
+	struct gb_operation *operation;
+	struct gb_i2c_timeout_request *request;
+	struct gb_i2c_timeout_response *response;
+	int ret;
+
+	operation = gb_operation_create(connection, GB_I2C_TYPE_TIMEOUT,
+					sizeof(*request), sizeof(*response));
+	if (!operation)
+		return -ENOMEM;
+	request = operation->request_payload;
+	request->msec = cpu_to_le16(msec);
+
+	/* Synchronous operation--no callback */
+	ret = gb_operation_request_send(operation, NULL);
+	if (ret) {
+		pr_err("timeout operation failed (%d)\n", ret);
+		goto out;
+	}
+
+	response = operation->response_payload;
+	if (response->status) {
+		gb_connection_err(connection, "timeout response %hhu",
+			response->status);
+		ret = -EIO;
+	} else {
+		gb_i2c_dev->timeout_msec = msec;
+	}
+out:
+	gb_operation_destroy(operation);
+
+	return ret;
+}
+
+static int gb_i2c_retries_operation(struct gb_i2c_device *gb_i2c_dev,
+				u8 retries)
+{
+	struct gb_connection *connection = gb_i2c_dev->connection;
+	struct gb_operation *operation;
+	struct gb_i2c_retries_request *request;
+	struct gb_i2c_retries_response *response;
+	int ret;
+
+	operation = gb_operation_create(connection, GB_I2C_TYPE_RETRIES,
+					sizeof(*request), sizeof(*response));
+	if (!operation)
+		return -ENOMEM;
+	request = operation->request_payload;
+	request->retries = retries;
+
+	/* Synchronous operation--no callback */
+	ret = gb_operation_request_send(operation, NULL);
+	if (ret) {
+		pr_err("retries operation failed (%d)\n", ret);
+		goto out;
+	}
+
+	response = operation->response_payload;
+	if (response->status) {
+		gb_connection_err(connection, "retries response %hhu",
+			response->status);
+		ret = -EIO;
+	} else {
+		gb_i2c_dev->retries = retries;
+	}
+out:
+	gb_operation_destroy(operation);
+
+	return ret;
+}
 
 
-static s32 i2c_gb_access(struct i2c_adapter *adap, u16 addr,
-			 unsigned short flags, char read_write, u8 command,
-			 int size, union i2c_smbus_data *data)
+/*
+ * Map Linux i2c_msg flags into Greybus i2c transfer op flags.
+ */
+static u16 gb_i2c_transfer_op_flags_map(u16 flags)
+{
+	return flags;	/* All flags the same for now */
+}
+
+static void
+gb_i2c_fill_transfer_op(struct gb_i2c_transfer_op *op, struct i2c_msg *msg)
+{
+	u16 flags = gb_i2c_transfer_op_flags_map(msg->flags);
+
+	op->addr = cpu_to_le16(msg->addr);
+	op->flags = cpu_to_le16(flags);
+	op->size = cpu_to_le16(msg->len);
+}
+
+static struct gb_operation *
+gb_i2c_transfer_request(struct gb_connection *connection,
+				struct i2c_msg *msgs, u32 msg_count)
+{
+	struct gb_i2c_transfer_request *request;
+	struct gb_operation *operation;
+	struct gb_i2c_transfer_op *op;
+	struct i2c_msg *msg;
+	u32 data_out_size = 0;
+	u32 data_in_size = 1;	/* Response begins with a status byte */
+	size_t request_size;
+	void *data;
+	u16 op_count;
+	u32 i;
+
+	if (msg_count > (u32)U16_MAX) {
+		gb_connection_err(connection, "msg_count (%u) too big",
+					msg_count);
+		return NULL;
+	}
+	op_count = (u16)msg_count;
+
+	/*
+	 * In addition to space for all message descriptors we need
+	 * to have enough to hold all outbound message data.
+	 */
+	msg = msgs;
+	for (i = 0; i < msg_count; i++, msg++)
+		if (msg->flags & I2C_M_RD)
+			data_in_size += (u32)msg->len;
+		else
+			data_out_size += (u32)msg->len;
+
+	request_size = sizeof(struct gb_i2c_transfer_request);
+	request_size += msg_count * sizeof(struct gb_i2c_transfer_op);
+	request_size += data_out_size;
+
+	/* Response consists only of incoming data */
+	operation = gb_operation_create(connection, GB_I2C_TYPE_TRANSFER,
+				request_size, data_in_size);
+	if (!operation)
+		return NULL;
+
+	request = operation->request_payload;
+	request->op_count = cpu_to_le16(op_count);
+	/* Fill in the ops array */
+	op = &request->ops[0];
+	msg = msgs;
+	for (i = 0; i < msg_count; i++)
+		gb_i2c_fill_transfer_op(op++, msg++);
+
+	if (!data_out_size)
+		return operation;
+
+	/* Copy over the outgoing data; it starts after the last op */
+	data = op;
+	msg = msgs;
+	for (i = 0; i < msg_count; i++) {
+		if (!(msg->flags & I2C_M_RD)) {
+			memcpy(data, msg->buf, msg->len);
+			data += msg->len;
+		}
+		msg++;
+	}
+
+	return operation;
+}
+
+static void gb_i2c_transfer_response(struct i2c_msg *msgs, u32 msg_count,
+					void *data)
+{
+	struct i2c_msg *msg = msgs;
+	u32 i;
+
+	for (i = 0; i < msg_count; i++) {
+		if (msg->flags & I2C_M_RD) {
+			memcpy(msg->buf, data, msg->len);
+			data += msg->len;
+		}
+		msg++;
+	}
+}
+
+static int gb_i2c_transfer_operation(struct gb_i2c_device *gb_i2c_dev,
+					struct i2c_msg *msgs, u32 msg_count)
+{
+	struct gb_connection *connection = gb_i2c_dev->connection;
+	struct gb_i2c_transfer_response *response;
+	struct gb_operation *operation;
+	int ret;
+
+	operation = gb_i2c_transfer_request(connection, msgs, msg_count);
+	if (!operation)
+		return -ENOMEM;
+
+	/* Synchronous operation--no callback */
+	ret = gb_operation_request_send(operation, NULL);
+	if (ret) {
+		pr_err("transfer operation failed (%d)\n", ret);
+		goto out;
+	}
+
+	response = operation->response_payload;
+	if (response->status) {
+		gb_connection_err(connection, "transfer response %hhu",
+			response->status);
+		ret = -EIO;
+	} else {
+		gb_i2c_transfer_response(msgs, msg_count, response->data);
+		ret = msg_count;
+	}
+out:
+	gb_operation_destroy(operation);
+
+	return ret;
+}
+
+static int gb_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+		int msg_count)
 {
 	struct gb_i2c_device *gb_i2c_dev;
-	struct gb_module *gmod;
 
 	gb_i2c_dev = i2c_get_adapdata(adap);
-	gmod = gb_i2c_dev->gmod;
 
-	// FIXME - do the actual work of sending a i2c message here...
-	switch (size) {
-	case I2C_SMBUS_QUICK:
-	case I2C_SMBUS_BYTE:
-	case I2C_SMBUS_BYTE_DATA:
-	case I2C_SMBUS_WORD_DATA:
-	case I2C_SMBUS_PROC_CALL:
-	case I2C_SMBUS_BLOCK_DATA:
-	case I2C_SMBUS_I2C_BLOCK_BROKEN:
-	case I2C_SMBUS_BLOCK_PROC_CALL:
-	case I2C_SMBUS_I2C_BLOCK_DATA:
-	default:
-		dev_err(&gmod->dev, "Unsupported transaction %d\n", size);
-		return -EOPNOTSUPP;
-	}
+	return gb_i2c_transfer_operation(gb_i2c_dev, msgs, msg_count);
+}
+
+#if 0
+/* Later */
+static int gb_i2c_smbus_xfer(struct i2c_adapter *adap,
+			u16 addr, unsigned short flags, char read_write,
+			u8 command, int size, union i2c_smbus_data *data)
+{
+	struct gb_i2c_device *gb_i2c_dev;
+
+	gb_i2c_dev = i2c_get_adapdata(adap);
 
 	return 0;
 }
+#endif
 
-static u32 i2c_gb_func(struct i2c_adapter *adapter)
+static u32 gb_i2c_functionality(struct i2c_adapter *adap)
 {
-	// FIXME - someone figure out what we really can support, for now just guess...
-	return I2C_FUNC_SMBUS_QUICK |
-		I2C_FUNC_SMBUS_BYTE |
-		I2C_FUNC_SMBUS_BYTE_DATA |
-		I2C_FUNC_SMBUS_WORD_DATA |
-		I2C_FUNC_SMBUS_BLOCK_DATA |
-		I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
-		I2C_FUNC_SMBUS_PEC |
-		I2C_FUNC_SMBUS_READ_I2C_BLOCK;
+	struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap);
+
+	return gb_i2c_dev->functionality;
 }
 
-static const struct i2c_algorithm smbus_algorithm = {
-	.smbus_xfer	= i2c_gb_access,
-	.functionality	= i2c_gb_func,
+static const struct i2c_algorithm gb_i2c_algorithm = {
+	.master_xfer	= gb_i2c_master_xfer,
+	/* .smbus_xfer	= gb_i2c_smbus_xfer, */
+	.functionality	= gb_i2c_functionality,
 };
 
-int gb_i2c_probe(struct gb_module *gmod,
-		 const struct greybus_module_id *id)
+/*
+ * Do initial setup of the i2c device.  This includes verifying we
+ * can support it (based on the protocol version it advertises).
+ * If that's OK, we get and cached its functionality bits, and
+ * set up the retry count and timeout.
+ *
+ * Note: gb_i2c_dev->connection is assumed to have been valid.
+ */
+static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
+{
+	int ret;
+
+	/* First thing we need to do is check the version */
+	ret = gb_i2c_proto_version_operation(gb_i2c_dev);
+	if (ret)
+		return ret;
+
+	/* Assume the functionality never changes, just get it once */
+	ret = gb_i2c_functionality_operation(gb_i2c_dev);
+	if (ret)
+		return ret;
+
+	/* Set up our default retry count and timeout */
+	ret = gb_i2c_retries_operation(gb_i2c_dev, GB_I2C_RETRIES_DEFAULT);
+	if (ret)
+		return ret;
+
+	return gb_i2c_timeout_operation(gb_i2c_dev, GB_I2C_TIMEOUT_DEFAULT);
+}
+
+int gb_i2c_device_init(struct gb_connection *connection)
 {
 	struct gb_i2c_device *gb_i2c_dev;
-	struct i2c_adapter *adapter;
-	int retval;
+	struct i2c_adapter *adapter = NULL;
+	int ret;
 
 	gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL);
 	if (!gb_i2c_dev)
 		return -ENOMEM;
+
+	gb_i2c_dev->connection = connection;	/* refcount? */
+
+	ret = gb_i2c_device_setup(gb_i2c_dev);
+	if (ret)
+		goto out_err;
+
+	/* Looks good; allocate and set up our i2c adapter */
 	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
 	if (!adapter) {
-		kfree(gb_i2c_dev);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto out_err;
 	}
 
-	i2c_set_adapdata(adapter, gb_i2c_dev);
 	adapter->owner = THIS_MODULE;
 	adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
-	adapter->algo = &smbus_algorithm;
-	adapter->dev.parent = &gmod->dev;
-	adapter->retries = 3;	/* we have to pick something... */
+	adapter->algo = &gb_i2c_algorithm;
+	/* adapter->algo_data = what? */
+	adapter->timeout = gb_i2c_dev->timeout_msec * HZ / 1000;
+	adapter->retries = gb_i2c_dev->retries;
+
+	/* XXX I think this parent device is wrong, but it uses existing code */
+	adapter->dev.parent = &connection->interface->gmod->dev;
 	snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter");
-	retval = i2c_add_adapter(adapter);
-	if (retval) {
-		dev_err(&gmod->dev, "Can not add SMBus adapter\n");
-		goto error;
-	}
+	i2c_set_adapdata(adapter, gb_i2c_dev);
 
-	gb_i2c_dev->gmod = gmod;
+	ret = i2c_add_adapter(adapter);
+	if (ret)
+		goto out_err;
+
 	gb_i2c_dev->adapter = adapter;
+	connection->private = gb_i2c_dev;
 
-	gmod->gb_i2c_dev = gb_i2c_dev;
 	return 0;
-error:
+out_err:
 	kfree(adapter);
+	/* kref_put(gb_i2c_dev->connection) */
 	kfree(gb_i2c_dev);
-	return retval;
+
+	return ret;
 }
 
-void gb_i2c_disconnect(struct gb_module *gmod)
+void gb_i2c_device_exit(struct gb_connection *connection)
 {
-	struct gb_i2c_device *gb_i2c_dev;
+	struct gb_i2c_device *gb_i2c_dev = connection->private;
 
-	gb_i2c_dev = gmod->gb_i2c_dev;
-	if (!gb_i2c_dev)
-		return;
 	i2c_del_adapter(gb_i2c_dev->adapter);
 	kfree(gb_i2c_dev->adapter);
+	/* kref_put(gb_i2c_dev->connection) */
 	kfree(gb_i2c_dev);
 }
 
 #if 0
-static struct greybus_driver i2c_gb_driver = {
-	.probe =	gb_i2c_probe,
-	.disconnect =	gb_i2c_disconnect,
-	.id_table =	id_table,
-};
-
 module_greybus_driver(i2c_gb_driver);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 7753bf7..a49d929 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -148,13 +148,21 @@
 
 }
 
+/*
+ * This handler is used if no operation response messages are ever
+ * expected for a given protocol.
+ */
+static void gb_operation_recv_none(struct gb_operation *operation)
+{
+	/* Nothing to do! */
+}
 
 typedef void (*gb_operation_recv_handler)(struct gb_operation *operation);
 static gb_operation_recv_handler gb_operation_recv_handlers[] = {
 	[GREYBUS_PROTOCOL_CONTROL]	= NULL,
 	[GREYBUS_PROTOCOL_AP]		= NULL,
 	[GREYBUS_PROTOCOL_GPIO]		= NULL,
-	[GREYBUS_PROTOCOL_I2C]		= NULL,
+	[GREYBUS_PROTOCOL_I2C]		= gb_operation_recv_none,
 	[GREYBUS_PROTOCOL_UART]		= NULL,
 	[GREYBUS_PROTOCOL_HID]		= NULL,
 	[GREYBUS_PROTOCOL_VENDOR]	= NULL,