diff options
Diffstat (limited to 'drivers/barcode_emul/barcode_emul_ice4.c')
-rwxr-xr-x | drivers/barcode_emul/barcode_emul_ice4.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/drivers/barcode_emul/barcode_emul_ice4.c b/drivers/barcode_emul/barcode_emul_ice4.c new file mode 100755 index 0000000..7032e6e --- /dev/null +++ b/drivers/barcode_emul/barcode_emul_ice4.c @@ -0,0 +1,626 @@ +/* + * driver/barcode_emul Barcode emulator driver + * + * Copyright (C) 2012 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/device.h> +#include <linux/earlysuspend.h> +#include <linux/spinlock.h> +#include <linux/gpio.h> +#include <linux/uaccess.h> +#include <linux/fs.h> +#include "barcode_emul_ice4.h" + +#if defined(TEST_DEBUG) +#define pr_barcode pr_emerg +#else +#define pr_barcode pr_info +#endif + +#define LOOP_BACK 48 +#define TEST_CODE1 49 +#define TEST_CODE2 50 +#define FW_VER_ADDR 0x80 +#define BEAM_STATUS_ADDR 0xFE +#define BARCODE_EMUL_MAX_FW_PATH 255 +#define BARCODE_EMUL_FW_FILENAME "i2c_top_bitmap.bin" + +struct barcode_emul_data { + struct i2c_client *client; +}; + +static struct workqueue_struct *barcode_init_wq; +static void barcode_init_workfunc(struct work_struct *work); +static DECLARE_WORK(barcode_init_work, barcode_init_workfunc); +/* + * Send barcode emulator firmware data thougth spi communication + */ +static int barcode_send_firmware_data(unsigned char *data) +{ + unsigned int i,j; + unsigned char spibit; + + i=0; + while (i < CONFIGURATION_SIZE) { + j=0; + spibit = data[i]; + while (j < 8) { + gpio_set_value(GPIO_FPGA_SPI_CLK,GPIO_LEVEL_LOW); + + if (spibit & 0x80) + { + gpio_set_value(GPIO_FPGA_SPI_SI,GPIO_LEVEL_HIGH); + } + else + { + gpio_set_value(GPIO_FPGA_SPI_SI,GPIO_LEVEL_LOW); + } + + j = j+1; + gpio_set_value(GPIO_FPGA_SPI_CLK,GPIO_LEVEL_HIGH); + spibit = spibit<<1; + } + i = i+1; + } + + i = 0; + while (i < 200) { + gpio_set_value(GPIO_FPGA_SPI_CLK,GPIO_LEVEL_LOW); + i = i+1; + gpio_set_value(GPIO_FPGA_SPI_CLK,GPIO_LEVEL_HIGH); + } + return 0; +} + +static int check_fpga_cdone(void) +{ + /* Device in Operation when CDONE='1'; Device Failed when CDONE='0'. */ + if (gpio_get_value(GPIO_FPGA_CDONE) != 1) { + pr_barcode("CDONE_FAIL\n"); + return 0; + } else { + pr_barcode("CDONE_SUCCESS\n"); + return 1; + } +} + +static int barcode_fpga_fimrware_update_start(unsigned char *data) +{ + pr_barcode("%s\n", __func__); + + gpio_request_one(GPIO_FPGA_CDONE, GPIOF_IN, "FPGA_CDONE"); + gpio_request_one(GPIO_FPGA_SPI_CLK, GPIOF_OUT_INIT_LOW, "FPGA_SPI_CLK"); + gpio_request_one(GPIO_FPGA_SPI_SI, GPIOF_OUT_INIT_LOW, "FPGA_SPI_SI"); + gpio_request_one(GPIO_FPGA_SPI_EN, GPIOF_OUT_INIT_LOW, "FPGA_SPI_EN"); + gpio_request_one(GPIO_FPGA_CRESET_B, GPIOF_OUT_INIT_HIGH, "FPGA_CRESET_B"); + gpio_request_one(GPIO_FPGA_RST_N, GPIOF_OUT_INIT_LOW, "FPGA_RST_N"); + + gpio_set_value(GPIO_FPGA_CRESET_B, GPIO_LEVEL_LOW); + udelay(30); + + gpio_set_value(GPIO_FPGA_CRESET_B, GPIO_LEVEL_HIGH); + udelay(1000); + + check_fpga_cdone(); + + barcode_send_firmware_data(data); + udelay(50); + + if (check_fpga_cdone()) { + udelay(5); + gpio_set_value(GPIO_FPGA_RST_N, GPIO_LEVEL_HIGH); + pr_barcode("barcode firmware update success\n"); + } else { + pr_barcode("barcode firmware update fail\n"); + } + return 0; +} + +void barcode_fpga_firmware_update(void) +{ + barcode_fpga_fimrware_update_start(spiword); +} + +static ssize_t barcode_emul_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret; + struct barcode_emul_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + if (gpio_get_value(GPIO_FPGA_CDONE) != 1) { + pr_err("%s: cdone fail !!\n", __func__); + return 0; + } + + ret = i2c_master_send(client, buf, size); + if (ret < 0) { + pr_err("%s: i2c err1 %d\n", __func__, ret); + ret = i2c_master_send(client, buf, size); + if (ret < 0) + pr_err("%s: i2c err2 %d\n", __func__, ret); + } + + return size; +} + +static ssize_t barcode_emul_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return strlen(buf); +} +static DEVICE_ATTR(barcode_send, 0664, barcode_emul_show, barcode_emul_store); + +static ssize_t barcode_emul_fw_update_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct file *fp = NULL; + long fsize = 0, nread = 0; + const u8 *buff = 0; + char fw_path[BARCODE_EMUL_MAX_FW_PATH+1]; + mm_segment_t old_fs = get_fs(); + + pr_barcode("%s\n", __func__); + + old_fs = get_fs(); + set_fs(get_ds()); + + snprintf(fw_path, BARCODE_EMUL_MAX_FW_PATH, + "/sdcard/%s", BARCODE_EMUL_FW_FILENAME); + + fp = filp_open(fw_path, O_RDONLY, 0); + if (IS_ERR(fp)) { + pr_err("file %s open error:%d\n", + fw_path, (s32)fp); + goto err_open; + } + + fsize = fp->f_path.dentry->d_inode->i_size; + pr_barcode("barcode firmware size: %ld\n", fsize); + + buff = kzalloc((size_t)fsize, GFP_KERNEL); + if (!buff) { + pr_err("fail to alloc buffer for fw\n"); + goto err_alloc; + } + + nread = vfs_read(fp, (char __user *)buff, fsize, &fp->f_pos); + if (nread != fsize) { + pr_err("fail to read file %s (nread = %ld)\n", + fw_path, nread); + goto err_fw_size; + } + + barcode_fpga_fimrware_update_start((unsigned char *)buff); + + if (fp != NULL) { + err_fw_size: + kfree(buff); + err_alloc: + filp_close(fp, NULL); + err_open: + set_fs(old_fs); + } + + return size; +} + +static ssize_t barcode_emul_fw_update_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return strlen(buf); +} +static DEVICE_ATTR(barcode_fw_update, 0664, barcode_emul_fw_update_show, barcode_emul_fw_update_store); + +static int barcode_emul_read(struct i2c_client *client, u16 addr, u8 length, u8 *value) +{ + + struct i2c_msg msg[2]; + int ret; + + msg[0].addr = client->addr; + msg[0].flags = 0x00; + msg[0].len = 1; + msg[0].buf = (u8 *) &addr; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = length; + msg[1].buf = (u8 *) value; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret == 2) { + return 0; + } else { + pr_barcode("%s: err1 %d\n", __func__, ret); + return -EIO; + } +} + +static ssize_t barcode_emul_test_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + int ret, i; + struct barcode_emul_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + struct { + unsigned char addr; + unsigned char data[20]; + } i2c_block_transfer; + unsigned char barcode_data[14] = {0xFF, 0xAC, 0xDB, 0x36, 0x42, 0x85, 0x0A, 0xA8, 0xD1, 0xA3, 0x46, 0xC5, 0xDA, 0xFF}; + + if (gpio_get_value(GPIO_FPGA_CDONE) != 1) { + pr_err("%s: cdone fail !!\n", __func__); + return 0; + } + + if (buf[0] == LOOP_BACK) { + for (i = 0; i < size; i++) + i2c_block_transfer.data[i] = *buf++; + + i2c_block_transfer.addr = 0x01; + + pr_barcode("%s: write addr: %d, value: %d\n", __func__, + i2c_block_transfer.addr, i2c_block_transfer.data[0]); + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_barcode("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_barcode("%s: err2 %d\n", __func__, ret); + } + + } else if (buf[0] == TEST_CODE1) { + unsigned char BSR_data[6] =\ + {0xC8, 0x00, 0x32, 0x01, 0x00, 0x32}; + + pr_barcode("barcode test code start\n"); + + /* send NH */ + i2c_block_transfer.addr = 0x80; + i2c_block_transfer.data[0] = 0x05; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + /* setup BSR data */ + for (i = 0; i < 6; i++) + i2c_block_transfer.data[i+1] = BSR_data[i]; + + /* send BSR1 => NS 1= 200, ISD 1 = 100us, IPD 1 = 200us, BL 1=14, BW 1=4MHZ */ + i2c_block_transfer.addr = 0x81; + i2c_block_transfer.data[0] = 0x00; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + /* send BSR2 => NS 2= 200, ISD 2 = 100us, IPD 2 = 200us, BL 2=14, BW 2=2MHZ*/ + i2c_block_transfer.addr = 0x88; + i2c_block_transfer.data[0] = 0x01; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + + /* send BSR3 => NS 3= 200, ISD 3 = 100us, IPD 3 = 200us, BL 3=14, BW 3=1MHZ*/ + i2c_block_transfer.addr = 0x8F; + i2c_block_transfer.data[0] = 0x02; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + /* send BSR4 => NS 4= 200, ISD 4 = 100us, IPD 4 = 200us, BL 4=14, BW 4=500KHZ*/ + i2c_block_transfer.addr = 0x96; + i2c_block_transfer.data[0] = 0x04; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + /* send BSR5 => NS 5= 200, ISD 5 = 100us, IPD 5 = 200us, BL 5=14, BW 5=250KHZ*/ + i2c_block_transfer.addr = 0x9D; + i2c_block_transfer.data[0] = 0x08; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 8); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + /* send barcode data */ + i2c_block_transfer.addr = 0x00; + for (i = 0; i < 14; i++) + i2c_block_transfer.data[i] = barcode_data[i]; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 15); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 15); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + /* send START */ + i2c_block_transfer.addr = 0xFF; + i2c_block_transfer.data[0] = 0x0E; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + } else if (buf[0] == TEST_CODE2) { + pr_barcode("barcode test code stop\n"); + + i2c_block_transfer.addr = 0xFF; + i2c_block_transfer.data[0] = 0x00; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + /* + pr_barcode("barcode test code send 02\n"); + + i2c_block_transfer.addr = 0x00; + i2c_block_transfer.data[0] = 0x00; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + i2c_block_transfer.addr = 0x01; + i2c_block_transfer.data[0] = 0x01; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + i2c_block_transfer.addr = 0x02; + for (i = 0; i < 14; i++) + i2c_block_transfer.data[i] = barcode_data[i]; + + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 15); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 15); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + + i2c_block_transfer.addr = 0x00; + i2c_block_transfer.data[0] = 0x01; + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) { + pr_err("%s: err1 %d\n", __func__, ret); + ret = i2c_master_send(client, (unsigned char *) &i2c_block_transfer, 2); + if (ret < 0) + pr_err("%s: err2 %d\n", __func__, ret); + } + */ + } + return size; +} + +static ssize_t barcode_emul_test_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return strlen(buf); +} +static DEVICE_ATTR(barcode_test_send, 0664, barcode_emul_test_show, barcode_emul_test_store); + +static ssize_t barcode_ver_check_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct barcode_emul_data *data = dev_get_drvdata(dev); + u8 fw_ver; + + barcode_emul_read(data->client, FW_VER_ADDR, 1, &fw_ver); + fw_ver = (fw_ver >> 5) & 0x7; + return sprintf(buf, "%d\n", fw_ver+14); + +} +static DEVICE_ATTR(barcode_ver_check, 0664, barcode_ver_check_show, NULL); + +static ssize_t barcode_led_status_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct barcode_emul_data *data = dev_get_drvdata(dev); + u8 status; + + barcode_emul_read(data->client, BEAM_STATUS_ADDR, 1, &status); + status = status & 0x1; + return sprintf(buf, "%d\n", status); + +} +static DEVICE_ATTR(barcode_led_status, 0664, barcode_led_status_show, NULL); + +static int __devinit barcode_emul_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct barcode_emul_data *data; + struct device *barcode_emul_dev; + int error; + + pr_barcode("%s probe!\n", __func__); + + if (gpio_get_value(GPIO_FPGA_CDONE) != 1) { + pr_err("%s: cdone fail !!\n", __func__); + return 0; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -EIO; + + data = kzalloc(sizeof(struct barcode_emul_data), GFP_KERNEL); + if (NULL == data) { + pr_err("Failed to data allocate %s\n", __func__); + error = -ENOMEM; + goto err_free_mem; + } + data->client = client; + i2c_set_clientdata(client, data); + + barcode_emul_dev = device_create(sec_class, NULL, 0, data, "sec_barcode_emul"); + + if (IS_ERR(barcode_emul_dev)) + pr_err("Failed to create barcode_emul_dev device\n"); + + if (device_create_file(barcode_emul_dev, &dev_attr_barcode_send) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_barcode_send.attr.name); + if (device_create_file(barcode_emul_dev, &dev_attr_barcode_test_send) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_barcode_test_send.attr.name); + if (device_create_file(barcode_emul_dev, &dev_attr_barcode_fw_update) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_barcode_fw_update.attr.name); + if (device_create_file(barcode_emul_dev, &dev_attr_barcode_ver_check) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_barcode_ver_check.attr.name); + if (device_create_file(barcode_emul_dev, &dev_attr_barcode_led_status) < 0) + pr_err("Failed to create device file(%s)!\n", + dev_attr_barcode_led_status.attr.name); + + return 0; + +err_free_mem: + kfree(data); + return error; +} + +static int __devexit barcode_emul_remove(struct i2c_client *client) +{ + struct barcode_emul_data *data = i2c_get_clientdata(client); + + i2c_set_clientdata(client, NULL); + kfree(data); + return 0; +} + +#ifdef CONFIG_PM +static int barcode_emul_suspend(struct device *dev) +{ + gpio_set_value(GPIO_FPGA_RST_N, GPIO_LEVEL_LOW); + return 0; +} + +static int barcode_emul_resume(struct device *dev) +{ + gpio_set_value(GPIO_FPGA_RST_N, GPIO_LEVEL_HIGH); + return 0; +} + +static const struct dev_pm_ops barcode_emul_pm_ops = { + .suspend = barcode_emul_suspend, + .resume = barcode_emul_resume, +}; +#endif + +static const struct i2c_device_id ice4_id[] = { + {"ice4", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ice4_id); + +static struct i2c_driver ice4_i2c_driver = { + .driver = { + .name = "ice4", +#ifdef CONFIG_PM + .pm = &barcode_emul_pm_ops, +#endif + }, + .probe = barcode_emul_probe, + .remove = __devexit_p(barcode_emul_remove), + .id_table = ice4_id, +}; + +static void barcode_init_workfunc(struct work_struct *work) +{ + barcode_fpga_firmware_update(); + i2c_add_driver(&ice4_i2c_driver); +} + +static int __init barcode_emul_init(void) +{ + barcode_init_wq = create_singlethread_workqueue("barcode_init"); + queue_work(barcode_init_wq, &barcode_init_work); + + return 0; +} +late_initcall(barcode_emul_init); + +static void __exit barcode_emul_exit(void) +{ + i2c_del_driver(&ice4_i2c_driver); + destroy_workqueue(barcode_init_wq); +} +module_exit(barcode_emul_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SEC Barcode emulator"); |