From 871480933a1c28f8a9fed4c4d34d06c439a7a422 Mon Sep 17 00:00:00 2001 From: Srikant Patnaik Date: Sun, 11 Jan 2015 12:28:04 +0530 Subject: Moved, renamed, and deleted files The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure. --- drivers/i2c/i2c-api.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100755 drivers/i2c/i2c-api.c (limited to 'drivers/i2c/i2c-api.c') diff --git a/drivers/i2c/i2c-api.c b/drivers/i2c/i2c-api.c new file mode 100755 index 00000000..d01335bb --- /dev/null +++ b/drivers/i2c/i2c-api.c @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_API_FAKE_ADDR 0x7f +#define I2C_MINORS 256 + +struct i2c_api { + struct list_head list; + struct i2c_client *client; +}; + +static LIST_HEAD(i2c_api_list); +static DEFINE_SPINLOCK(i2c_api_list_lock); + +static struct i2c_api *get_i2c_api(int bus_id) +{ + struct i2c_api *i2c_api; + + spin_lock(&i2c_api_list_lock); + list_for_each_entry(i2c_api, &i2c_api_list, list) { + if (i2c_api->client->adapter->nr == bus_id) + goto found; + } + i2c_api = NULL; + +found: + spin_unlock(&i2c_api_list_lock); + return i2c_api; +} + +static struct i2c_api *add_i2c_api(struct i2c_client *client) +{ + struct i2c_api *i2c_api; + + if (client->adapter->nr >= I2C_MINORS) { + printk(KERN_ERR "i2c_api: Out of device minors (%d)\n", + client->adapter->nr); + return NULL; + } + + i2c_api = kzalloc(sizeof(*i2c_api), GFP_KERNEL); + if (!i2c_api) + return NULL; + i2c_api->client = client; + + spin_lock(&i2c_api_list_lock); + list_add_tail(&i2c_api->list, &i2c_api_list); + spin_unlock(&i2c_api_list_lock); + return i2c_api; +} + +static void del_i2c_api(struct i2c_api *i2c_api) +{ + spin_lock(&i2c_api_list_lock); + list_del(&i2c_api->list); + spin_unlock(&i2c_api_list_lock); + kfree(i2c_api); +} + +static int i2c_api_do_xfer(int bus_id, char chip_addr, char sub_addr, int mode, + char *buf, unsigned int size) +{ +/** you could define more transfer mode here, implement it following. */ +#define I2C_API_XFER_MODE_SEND 0x0 /* standard send */ +#define I2C_API_XFER_MODE_RECV 0x1 /* standard receive */ +#define I2C_API_XFER_MODE_SEND_NO_SUBADDR 0x2 /* send without sub-address */ +#define I2C_API_XFER_MODE_RECV_NO_SUBADDR 0x3 /* receive without sub-address */ + + int ret = 0; + char *tmp; + struct i2c_api *i2c_api = get_i2c_api(bus_id); + + if (!i2c_api) + return -ENODEV; + + i2c_api->client->addr = chip_addr; + switch (mode) { + case I2C_API_XFER_MODE_SEND: + tmp = kmalloc(size + 1,GFP_KERNEL); + if (tmp == NULL) + return -ENOMEM; + tmp[0] = sub_addr; + memcpy(&tmp[1], buf, size); + ret = i2c_master_send(i2c_api->client, tmp, size + 1); + ret = (ret == size + 1) ? size : ret; + kfree(tmp); + break; + + case I2C_API_XFER_MODE_RECV: + ret = i2c_master_send(i2c_api->client, &sub_addr, 1); + if (ret < 0) + return ret; + ret = i2c_master_recv(i2c_api->client, buf, size); + break; + + case I2C_API_XFER_MODE_SEND_NO_SUBADDR: + ret = i2c_master_send(i2c_api->client, buf, size); + break; + + case I2C_API_XFER_MODE_RECV_NO_SUBADDR: + ret = i2c_master_recv(i2c_api->client, buf, size); + break; + + default: + return -EINVAL; + } + return ret; +} + +int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size) +{ + return i2c_api_do_xfer(bus_id, chip_addr, sub_addr, I2C_API_XFER_MODE_SEND, buf, size); +} + +int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size) +{ + return i2c_api_do_xfer(bus_id, chip_addr, sub_addr, I2C_API_XFER_MODE_RECV, buf, size); +} + +int i2c_api_do_send_without_subaddr(int bus_id, char chip_addr, char *buf, unsigned int size) +{ + return i2c_api_do_xfer(bus_id, chip_addr, 0, I2C_API_XFER_MODE_SEND_NO_SUBADDR, buf, size); +} + +int i2c_api_do_recv_without_subaddr(int bus_id, char chip_addr, char *buf, unsigned int size) +{ + return i2c_api_do_xfer(bus_id, chip_addr, 0, I2C_API_XFER_MODE_RECV_NO_SUBADDR, buf, size); +} + +int i2c_api_attach(struct i2c_adapter *adap) +{ + struct i2c_board_info info; + struct i2c_client *client; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "i2c_api", I2C_NAME_SIZE); + info.addr = I2C_API_FAKE_ADDR; + client = i2c_new_device(adap, &info); + if (client) + add_i2c_api(client); + printk(KERN_INFO "i2c_api_attach adap[%d]\n", adap->nr); + return 0; +} + +int i2c_api_detach(struct i2c_adapter *adap) +{ + struct i2c_api *i2c_api; + + i2c_api = get_i2c_api(adap->nr); + if (i2c_api) + del_i2c_api(i2c_api); + return 0; +} + +static const unsigned short normal_addr[] = { I2C_API_FAKE_ADDR, I2C_CLIENT_END }; +static const unsigned short ignore[] = { I2C_CLIENT_END }; +/*static struct i2c_client_address_data addr_data = +{ + .normal_i2c = normal_addr, + .probe = ignore, + .ignore = ignore, + .forces = NULL, +};*/ + +static const struct i2c_device_id id[] = { + {"I2C-API", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, id); + +static struct i2c_driver i2c_api_driver = { + .id_table = id, + .attach_adapter = i2c_api_attach, + .detach_adapter = i2c_api_detach, + .command = NULL, + .driver = { + .name = "I2C-API", + .owner = THIS_MODULE, + }, + //.address_data = &addr_data, +}; + +static int __init i2c_api_init(void) +{ + int ret = i2c_add_driver(&i2c_api_driver); + + if (ret) { + printk(KERN_ERR "[%s] Driver registration failed, module not inserted.\n", __func__); + return ret; + } + + return 0 ; +} + +static void __exit i2c_api_exit(void) +{ + i2c_del_driver(&i2c_api_driver); +} + +MODULE_AUTHOR("Loon, "); +MODULE_DESCRIPTION("I2C i2c_api Driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_api_init); +module_exit(i2c_api_exit); + +EXPORT_SYMBOL_GPL(i2c_api_do_send); +EXPORT_SYMBOL_GPL(i2c_api_do_recv); +EXPORT_SYMBOL_GPL(i2c_api_do_send_without_subaddr); +EXPORT_SYMBOL_GPL(i2c_api_do_recv_without_subaddr); -- cgit