diff options
Diffstat (limited to 'drivers/i2c-slave/i2c_slave_device.c')
-rw-r--r-- | drivers/i2c-slave/i2c_slave_device.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/drivers/i2c-slave/i2c_slave_device.c b/drivers/i2c-slave/i2c_slave_device.c new file mode 100644 index 000000000000..1968a00aa693 --- /dev/null +++ b/drivers/i2c-slave/i2c_slave_device.c @@ -0,0 +1,271 @@ +/* + * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/slab.h> +#include <linux/major.h> +#include <linux/mm.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/kdev_t.h> +#include "i2c_slave_device.h" +static i2c_slave_device_t *i2c_slave_devices[I2C_SLAVE_DEVICE_MAX]; +struct class *i2c_slave_class; +static int i2c_slave_device_get_id(void) +{ + int i; + for (i = 0; i < I2C_SLAVE_DEVICE_MAX; i++) { + if (!i2c_slave_devices[i]) + return i; + } + return -1; +} + +i2c_slave_device_t *i2c_slave_device_find(int id) +{ + if (id >= 0 && id < I2C_SLAVE_DEVICE_MAX) + return i2c_slave_devices[id]; + + else + return NULL; +} +void i2c_slave_device_set_name(i2c_slave_device_t *device, char *name) +{ + device->name = name; +} + +void i2c_slave_device_set_address(i2c_slave_device_t *device, u8 address) +{ + device->address = address; +} + +u8 i2c_slave_device_get_addr(i2c_slave_device_t *device) +{ + return device->address; +} + +int i2c_slave_device_set_freq(i2c_slave_device_t *device, u32 freq) +{ + /*TODO: freq check */ + device->scl_freq = freq; + return 0; +} + +u32 i2c_slave_device_get_freq(i2c_slave_device_t *device) +{ + return device->scl_freq; +} + +/*used by the specific i2c device to register itself to the core.*/ +i2c_slave_device_t *i2c_slave_device_alloc(void) +{ + int id; + i2c_slave_device_t *device; + id = i2c_slave_device_get_id(); + if (id < 0) { + goto error; + } + device = + (i2c_slave_device_t *) kzalloc(sizeof(i2c_slave_device_t), + GFP_KERNEL); + if (!device) { + printk(KERN_ERR "%s: alloc device error\n", __func__); + goto error_device; + } + device->receive_buffer = i2c_slave_rb_alloc(PAGE_SIZE); + if (!device->receive_buffer) { + printk(KERN_ERR "%s: alloc receive buffer error\n", __func__); + goto error_receive_buffer; + } + device->send_buffer = i2c_slave_rb_alloc(PAGE_SIZE); + if (!device->send_buffer) { + printk(KERN_ERR "%s: alloc send buffer error\n", __func__); + goto error_send_buffer; + } + device->id = id; + return device; + + error_send_buffer: + kfree(device->receive_buffer); + error_receive_buffer: + kfree((void *)device); + error_device: + pr_debug(KERN_ERR "%s: no memory\n", __func__); + error: + return 0; +} + +void i2c_slave_device_free(i2c_slave_device_t *dev) +{ + i2c_slave_rb_release(dev->receive_buffer); + i2c_slave_rb_release(dev->send_buffer); + kfree(dev); +} + +int i2c_slave_device_register(i2c_slave_device_t *device) +{ + device->dev = device_create(i2c_slave_class, NULL, + MKDEV(i2c_slave_major, device->id), + NULL, "slave-i2c-%d", device->id); + if (!device->dev) { + return -1; + } + i2c_slave_devices[device->id] = device; + return 0; +} + +void i2c_slave_device_unregister(i2c_slave_device_t *device) +{ + device_destroy(i2c_slave_class, MKDEV(i2c_slave_major, device->id)); + i2c_slave_devices[device->id] = 0; + i2c_slave_device_free(device); +} + +/* + this two functions are used by i2c slave core to start or stop the specific i2c device. +*/ +int i2c_slave_device_start(i2c_slave_device_t *device) +{ + return device->start(device); +} + +int i2c_slave_device_stop(i2c_slave_device_t *device) +{ + return device->stop(device); +} + +/* + this two functions are used by i2c slave core to get data by the specific i2c slave device + or send data to it to feed i2c master's need. + + @mod: async(1) or sync(0) mode. +*/ +int i2c_slave_device_read(i2c_slave_device_t *device, int num, u8 *data) +{ + int read_num, read_total = 0; + int step = 1000; + u8 *read_buf = data; + printk(KERN_INFO "%s: device id=%d, num=%d\n", __func__, device->id, + num); + read_num = i2c_slave_rb_consume(device->receive_buffer, num, read_buf); + read_total += read_num; + read_buf += read_num; + step--; + while ((read_total < num) && step) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + if (!signal_pending(current)) { + } else { + /*TODO*/ break; + } + read_num = + i2c_slave_rb_consume(device->receive_buffer, + num - read_total, read_buf); + num -= read_num; + read_buf += read_num; + step--; + } + return read_total; +} +int i2c_slave_device_write(i2c_slave_device_t *device, int num, u8 *data) +{ + int write_num, write_total = 0; + int step = 1000; + u8 *buf_index = data; + write_num = i2c_slave_rb_produce(device->send_buffer, num, buf_index); + write_total += write_num; + buf_index += write_num; + step--; + while (write_total < num && step) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + if (!signal_pending(current)) { + } else { + /*TODO*/ step = 0; + break; + } + write_num = + i2c_slave_rb_produce(device->send_buffer, num - write_total, + buf_index); + write_total += write_num; + buf_index += write_num; + step--; + } + while (step && i2c_slave_rb_num(device->send_buffer)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + if (!signal_pending(current)) { + step--; + } else { + /*TODO*/ step = 0; + break; + } + } + if (!step) { + write_total -= i2c_slave_rb_num(device->send_buffer); + i2c_slave_rb_clear(device->send_buffer); + } + return write_total; +} + +/* + * this 2 functions used by the specific i2c slave device when they got data from master(produce), + * or is request by master(consume). + */ +int i2c_slave_device_produce(i2c_slave_device_t *device, int num, u8 *data) +{ + int ret; + ret = i2c_slave_rb_produce(device->receive_buffer, num, data); + return ret; +} +int i2c_slave_device_consume(i2c_slave_device_t *device, int num, u8 *data) +{ + return i2c_slave_rb_consume(device->send_buffer, num, data); +} + +EXPORT_SYMBOL(i2c_slave_device_set_name); +EXPORT_SYMBOL(i2c_slave_device_set_address); +EXPORT_SYMBOL(i2c_slave_device_get_addr); +EXPORT_SYMBOL(i2c_slave_device_find); +EXPORT_SYMBOL(i2c_slave_device_set_freq); +EXPORT_SYMBOL(i2c_slave_device_get_freq); + +/* +* used by the specific i2c device to register itself to the core. +*/ +EXPORT_SYMBOL(i2c_slave_device_alloc); +EXPORT_SYMBOL(i2c_slave_device_free); +EXPORT_SYMBOL(i2c_slave_device_register); +EXPORT_SYMBOL(i2c_slave_device_unregister); + +/* + this two functions are used by i2c slave core to start or stop the specific i2c device. +*/ +EXPORT_SYMBOL(i2c_slave_device_start); +EXPORT_SYMBOL(i2c_slave_device_stop); + +/* + this two functions are used by i2c slave core to get data by the specific i2c slave device + or send data to it for it to feed i2c master's need. + + @mod: async(1) or sync(0) mode. +*/ +EXPORT_SYMBOL(i2c_slave_device_read); +EXPORT_SYMBOL(i2c_slave_device_write); + +/* +* this 2 functions used by the specific i2c slave device when they got data from master, +* or is request by master. +*/ +EXPORT_SYMBOL(i2c_slave_device_produce); +EXPORT_SYMBOL(i2c_slave_device_consume); |