brintos

brintos / linux-shallow public Read only

0
0
Text · 7.6 KiB · 14f1ff6 Raw
323 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * I2C bridge driver for the Greybus "generic" I2C module.4 *5 * Copyright 2014 Google Inc.6 * Copyright 2014 Linaro Ltd.7 */8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/slab.h>12#include <linux/i2c.h>13#include <linux/greybus.h>14 15#include "gbphy.h"16 17struct gb_i2c_device {18	struct gb_connection	*connection;19	struct gbphy_device	*gbphy_dev;20 21	u32			functionality;22 23	struct i2c_adapter	adapter;24};25 26/*27 * Map Greybus i2c functionality bits into Linux ones28 */29static u32 gb_i2c_functionality_map(u32 gb_i2c_functionality)30{31	return gb_i2c_functionality;	/* All bits the same for now */32}33 34/*35 * Do initial setup of the i2c device.  This includes verifying we36 * can support it (based on the protocol version it advertises).37 * If that's OK, we get and cached its functionality bits.38 *39 * Note: gb_i2c_dev->connection is assumed to have been valid.40 */41static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)42{43	struct gb_i2c_functionality_response response;44	u32 functionality;45	int ret;46 47	ret = gb_operation_sync(gb_i2c_dev->connection,48				GB_I2C_TYPE_FUNCTIONALITY,49				NULL, 0, &response, sizeof(response));50	if (ret)51		return ret;52 53	functionality = le32_to_cpu(response.functionality);54	gb_i2c_dev->functionality = gb_i2c_functionality_map(functionality);55 56	return 0;57}58 59/*60 * Map Linux i2c_msg flags into Greybus i2c transfer op flags.61 */62static u16 gb_i2c_transfer_op_flags_map(u16 flags)63{64	return flags;	/* All flags the same for now */65}66 67static void68gb_i2c_fill_transfer_op(struct gb_i2c_transfer_op *op, struct i2c_msg *msg)69{70	u16 flags = gb_i2c_transfer_op_flags_map(msg->flags);71 72	op->addr = cpu_to_le16(msg->addr);73	op->flags = cpu_to_le16(flags);74	op->size = cpu_to_le16(msg->len);75}76 77static struct gb_operation *78gb_i2c_operation_create(struct gb_connection *connection,79			struct i2c_msg *msgs, u32 msg_count)80{81	struct gb_i2c_device *gb_i2c_dev = gb_connection_get_data(connection);82	struct gb_i2c_transfer_request *request;83	struct gb_operation *operation;84	struct gb_i2c_transfer_op *op;85	struct i2c_msg *msg;86	u32 data_out_size = 0;87	u32 data_in_size = 0;88	size_t request_size;89	void *data;90	u16 op_count;91	u32 i;92 93	if (msg_count > (u32)U16_MAX) {94		dev_err(&gb_i2c_dev->gbphy_dev->dev, "msg_count (%u) too big\n",95			msg_count);96		return NULL;97	}98	op_count = (u16)msg_count;99 100	/*101	 * In addition to space for all message descriptors we need102	 * to have enough to hold all outbound message data.103	 */104	msg = msgs;105	for (i = 0; i < msg_count; i++, msg++)106		if (msg->flags & I2C_M_RD)107			data_in_size += (u32)msg->len;108		else109			data_out_size += (u32)msg->len;110 111	request_size = sizeof(*request);112	request_size += msg_count * sizeof(*op);113	request_size += data_out_size;114 115	/* Response consists only of incoming data */116	operation = gb_operation_create(connection, GB_I2C_TYPE_TRANSFER,117					request_size, data_in_size, GFP_KERNEL);118	if (!operation)119		return NULL;120 121	request = operation->request->payload;122	request->op_count = cpu_to_le16(op_count);123	/* Fill in the ops array */124	op = &request->ops[0];125	msg = msgs;126	for (i = 0; i < msg_count; i++)127		gb_i2c_fill_transfer_op(op++, msg++);128 129	if (!data_out_size)130		return operation;131 132	/* Copy over the outgoing data; it starts after the last op */133	data = op;134	msg = msgs;135	for (i = 0; i < msg_count; i++) {136		if (!(msg->flags & I2C_M_RD)) {137			memcpy(data, msg->buf, msg->len);138			data += msg->len;139		}140		msg++;141	}142 143	return operation;144}145 146static void gb_i2c_decode_response(struct i2c_msg *msgs, u32 msg_count,147				   struct gb_i2c_transfer_response *response)148{149	struct i2c_msg *msg = msgs;150	u8 *data;151	u32 i;152 153	if (!response)154		return;155	data = response->data;156	for (i = 0; i < msg_count; i++) {157		if (msg->flags & I2C_M_RD) {158			memcpy(msg->buf, data, msg->len);159			data += msg->len;160		}161		msg++;162	}163}164 165/*166 * Some i2c transfer operations return results that are expected.167 */168static bool gb_i2c_expected_transfer_error(int errno)169{170	return errno == -EAGAIN || errno == -ENODEV;171}172 173static int gb_i2c_transfer_operation(struct gb_i2c_device *gb_i2c_dev,174				     struct i2c_msg *msgs, u32 msg_count)175{176	struct gb_connection *connection = gb_i2c_dev->connection;177	struct device *dev = &gb_i2c_dev->gbphy_dev->dev;178	struct gb_operation *operation;179	int ret;180 181	operation = gb_i2c_operation_create(connection, msgs, msg_count);182	if (!operation)183		return -ENOMEM;184 185	ret = gbphy_runtime_get_sync(gb_i2c_dev->gbphy_dev);186	if (ret)187		goto exit_operation_put;188 189	ret = gb_operation_request_send_sync(operation);190	if (!ret) {191		struct gb_i2c_transfer_response *response;192 193		response = operation->response->payload;194		gb_i2c_decode_response(msgs, msg_count, response);195		ret = msg_count;196	} else if (!gb_i2c_expected_transfer_error(ret)) {197		dev_err(dev, "transfer operation failed (%d)\n", ret);198	}199 200	gbphy_runtime_put_autosuspend(gb_i2c_dev->gbphy_dev);201 202exit_operation_put:203	gb_operation_put(operation);204 205	return ret;206}207 208static int gb_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,209			      int msg_count)210{211	struct gb_i2c_device *gb_i2c_dev;212 213	gb_i2c_dev = i2c_get_adapdata(adap);214 215	return gb_i2c_transfer_operation(gb_i2c_dev, msgs, msg_count);216}217 218static u32 gb_i2c_functionality(struct i2c_adapter *adap)219{220	struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap);221 222	return gb_i2c_dev->functionality;223}224 225static const struct i2c_algorithm gb_i2c_algorithm = {226	.master_xfer	= gb_i2c_master_xfer,227	.functionality	= gb_i2c_functionality,228};229 230static int gb_i2c_probe(struct gbphy_device *gbphy_dev,231			const struct gbphy_device_id *id)232{233	struct gb_connection *connection;234	struct gb_i2c_device *gb_i2c_dev;235	struct i2c_adapter *adapter;236	int ret;237 238	gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL);239	if (!gb_i2c_dev)240		return -ENOMEM;241 242	connection =243		gb_connection_create(gbphy_dev->bundle,244				     le16_to_cpu(gbphy_dev->cport_desc->id),245				     NULL);246	if (IS_ERR(connection)) {247		ret = PTR_ERR(connection);248		goto exit_i2cdev_free;249	}250 251	gb_i2c_dev->connection = connection;252	gb_connection_set_data(connection, gb_i2c_dev);253	gb_i2c_dev->gbphy_dev = gbphy_dev;254	gb_gbphy_set_data(gbphy_dev, gb_i2c_dev);255 256	ret = gb_connection_enable(connection);257	if (ret)258		goto exit_connection_destroy;259 260	ret = gb_i2c_device_setup(gb_i2c_dev);261	if (ret)262		goto exit_connection_disable;263 264	/* Looks good; up our i2c adapter */265	adapter = &gb_i2c_dev->adapter;266	adapter->owner = THIS_MODULE;267	adapter->class = I2C_CLASS_HWMON;268	adapter->algo = &gb_i2c_algorithm;269 270	adapter->dev.parent = &gbphy_dev->dev;271	snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter");272	i2c_set_adapdata(adapter, gb_i2c_dev);273 274	ret = i2c_add_adapter(adapter);275	if (ret)276		goto exit_connection_disable;277 278	gbphy_runtime_put_autosuspend(gbphy_dev);279	return 0;280 281exit_connection_disable:282	gb_connection_disable(connection);283exit_connection_destroy:284	gb_connection_destroy(connection);285exit_i2cdev_free:286	kfree(gb_i2c_dev);287 288	return ret;289}290 291static void gb_i2c_remove(struct gbphy_device *gbphy_dev)292{293	struct gb_i2c_device *gb_i2c_dev = gb_gbphy_get_data(gbphy_dev);294	struct gb_connection *connection = gb_i2c_dev->connection;295	int ret;296 297	ret = gbphy_runtime_get_sync(gbphy_dev);298	if (ret)299		gbphy_runtime_get_noresume(gbphy_dev);300 301	i2c_del_adapter(&gb_i2c_dev->adapter);302	gb_connection_disable(connection);303	gb_connection_destroy(connection);304	kfree(gb_i2c_dev);305}306 307static const struct gbphy_device_id gb_i2c_id_table[] = {308	{ GBPHY_PROTOCOL(GREYBUS_PROTOCOL_I2C) },309	{ },310};311MODULE_DEVICE_TABLE(gbphy, gb_i2c_id_table);312 313static struct gbphy_driver i2c_driver = {314	.name		= "i2c",315	.probe		= gb_i2c_probe,316	.remove		= gb_i2c_remove,317	.id_table	= gb_i2c_id_table,318};319 320module_gbphy_driver(i2c_driver);321MODULE_DESCRIPTION("I2C bridge driver for the Greybus 'generic' I2C module");322MODULE_LICENSE("GPL v2");323