/* * I2C bridge driver for the Greybus "generic" I2C module. * * Copyright 2014 Google Inc. * Copyright 2014 Linaro Ltd. * * Released under the GPLv2 only. */ #include #include #include #include #include "greybus.h" #include "gpbridge.h" struct gb_i2c_device { struct gb_connection *connection; 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_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(&connection->bundle->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 = &connection->bundle->dev; struct gb_operation *operation; int ret; operation = gb_i2c_operation_create(connection, msgs, msg_count); if (!operation) return -ENOMEM; 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); } 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_connection_init(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; gb_i2c_dev->connection = connection; /* refcount? */ gb_connection_set_data(connection, gb_i2c_dev); ret = gb_i2c_device_setup(gb_i2c_dev); if (ret) goto out_err; /* 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 = &connection->bundle->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 out_err; return 0; out_err: /* kref_put(gb_i2c_dev->connection) */ kfree(gb_i2c_dev); return ret; } static void gb_i2c_connection_exit(struct gb_connection *connection) { struct gb_i2c_device *gb_i2c_dev = gb_connection_get_data(connection); i2c_del_adapter(&gb_i2c_dev->adapter); /* kref_put(gb_i2c_dev->connection) */ kfree(gb_i2c_dev); } static struct gb_protocol i2c_protocol = { .name = "i2c", .id = GREYBUS_PROTOCOL_I2C, .major = GB_I2C_VERSION_MAJOR, .minor = GB_I2C_VERSION_MINOR, .connection_init = gb_i2c_connection_init, .connection_exit = gb_i2c_connection_exit, .request_recv = NULL, /* no incoming requests */ }; gb_builtin_protocol_driver(i2c_protocol);