Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Alex Elder | 795 | 60.87% | 11 | 31.43% |
Greg Kroah-Hartman | 395 | 30.25% | 12 | 34.29% |
David Lin | 49 | 3.75% | 1 | 2.86% |
Sandeep Patil | 24 | 1.84% | 1 | 2.86% |
Johan Hovold | 21 | 1.61% | 4 | 11.43% |
Viresh Kumar | 19 | 1.45% | 4 | 11.43% |
Michael Mogenson | 2 | 0.15% | 1 | 2.86% |
Alexandre Bailon | 1 | 0.08% | 1 | 2.86% |
Total | 1306 | 35 |
// SPDX-License-Identifier: GPL-2.0 /* * I2C bridge driver for the Greybus "generic" I2C module. * * Copyright 2014 Google Inc. * Copyright 2014 Linaro Ltd. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> #include "greybus.h" #include "gbphy.h" struct gb_i2c_device { struct gb_connection *connection; struct gbphy_device *gbphy_dev; u32 functionality; struct i2c_adapter adapter; }; /* * 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_i2c_functionality_response response; u32 functionality; int ret; ret = gb_operation_sync(gb_i2c_dev->connection, GB_I2C_TYPE_FUNCTIONALITY, NULL, 0, &response, sizeof(response)); if (ret) return ret; functionality = le32_to_cpu(response.functionality); gb_i2c_dev->functionality = gb_i2c_functionality_map(functionality); return 0; } /* * 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_operation_create(struct gb_connection *connection, struct i2c_msg *msgs, u32 msg_count) { struct gb_i2c_device *gb_i2c_dev = gb_connection_get_data(connection); 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 = 0; size_t request_size; void *data; u16 op_count; u32 i; if (msg_count > (u32)U16_MAX) { dev_err(&gb_i2c_dev->gbphy_dev->dev, "msg_count (%u) too big\n", 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(*request); request_size += msg_count * sizeof(*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, GFP_KERNEL); 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_decode_response(struct i2c_msg *msgs, u32 msg_count, struct gb_i2c_transfer_response *response) { struct i2c_msg *msg = msgs; u8 *data; u32 i; if (!response) return; data = response->data; for (i = 0; i < msg_count; i++) { if (msg->flags & I2C_M_RD) { memcpy(msg->buf, data, msg->len); data += msg->len; } msg++; } } /* * Some i2c transfer operations return results that are expected. */ static bool gb_i2c_expected_transfer_error(int errno) { return errno == -EAGAIN || errno == -ENODEV; } 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 device *dev = &gb_i2c_dev->gbphy_dev->dev; struct gb_operation *operation; int ret; operation = gb_i2c_operation_create(connection, msgs, msg_count); if (!operation) return -ENOMEM; ret = gbphy_runtime_get_sync(gb_i2c_dev->gbphy_dev); if (ret) goto exit_operation_put; ret = gb_operation_request_send_sync(operation); if (!ret) { struct gb_i2c_transfer_response *response; response = operation->response->payload; gb_i2c_decode_response(msgs, msg_count, response); ret = msg_count; } else if (!gb_i2c_expected_transfer_error(ret)) { dev_err(dev, "transfer operation failed (%d)\n", ret); } gbphy_runtime_put_autosuspend(gb_i2c_dev->gbphy_dev); exit_operation_put: gb_operation_put(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; gb_i2c_dev = i2c_get_adapdata(adap); 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 gb_i2c_functionality(struct i2c_adapter *adap) { struct gb_i2c_device *gb_i2c_dev = i2c_get_adapdata(adap); return gb_i2c_dev->functionality; } static const struct i2c_algorithm gb_i2c_algorithm = { .master_xfer = gb_i2c_master_xfer, /* .smbus_xfer = gb_i2c_smbus_xfer, */ .functionality = gb_i2c_functionality, }; /* * 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. * * Note: gb_i2c_dev->connection is assumed to have been valid. */ static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev) { /* Assume the functionality never changes, just get it once */ return gb_i2c_functionality_operation(gb_i2c_dev); } static int gb_i2c_probe(struct gbphy_device *gbphy_dev, const struct gbphy_device_id *id) { struct gb_connection *connection; struct gb_i2c_device *gb_i2c_dev; struct i2c_adapter *adapter; int ret; gb_i2c_dev = kzalloc(sizeof(*gb_i2c_dev), GFP_KERNEL); if (!gb_i2c_dev) return -ENOMEM; connection = gb_connection_create(gbphy_dev->bundle, le16_to_cpu(gbphy_dev->cport_desc->id), NULL); if (IS_ERR(connection)) { ret = PTR_ERR(connection); goto exit_i2cdev_free; } gb_i2c_dev->connection = connection; gb_connection_set_data(connection, gb_i2c_dev); gb_i2c_dev->gbphy_dev = gbphy_dev; gb_gbphy_set_data(gbphy_dev, gb_i2c_dev); ret = gb_connection_enable(connection); if (ret) goto exit_connection_destroy; ret = gb_i2c_device_setup(gb_i2c_dev); if (ret) goto exit_connection_disable; /* Looks good; up our i2c adapter */ adapter = &gb_i2c_dev->adapter; adapter->owner = THIS_MODULE; adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adapter->algo = &gb_i2c_algorithm; /* adapter->algo_data = what? */ adapter->dev.parent = &gbphy_dev->dev; snprintf(adapter->name, sizeof(adapter->name), "Greybus i2c adapter"); i2c_set_adapdata(adapter, gb_i2c_dev); ret = i2c_add_adapter(adapter); if (ret) goto exit_connection_disable; gbphy_runtime_put_autosuspend(gbphy_dev); return 0; exit_connection_disable: gb_connection_disable(connection); exit_connection_destroy: gb_connection_destroy(connection); exit_i2cdev_free: kfree(gb_i2c_dev); return ret; } static void gb_i2c_remove(struct gbphy_device *gbphy_dev) { struct gb_i2c_device *gb_i2c_dev = gb_gbphy_get_data(gbphy_dev); struct gb_connection *connection = gb_i2c_dev->connection; int ret; ret = gbphy_runtime_get_sync(gbphy_dev); if (ret) gbphy_runtime_get_noresume(gbphy_dev); i2c_del_adapter(&gb_i2c_dev->adapter); gb_connection_disable(connection); gb_connection_destroy(connection); kfree(gb_i2c_dev); } static const struct gbphy_device_id gb_i2c_id_table[] = { { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_I2C) }, { }, }; MODULE_DEVICE_TABLE(gbphy, gb_i2c_id_table); static struct gbphy_driver i2c_driver = { .name = "i2c", .probe = gb_i2c_probe, .remove = gb_i2c_remove, .id_table = gb_i2c_id_table, }; module_gbphy_driver(i2c_driver); MODULE_LICENSE("GPL v2");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1